aws-runtime-bridge 1.9.139 → 1.9.140
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/adapter/AcodeSdkAdapter.d.ts +2 -1
- package/dist/adapter/AcodeSdkAdapter.js +2 -2
- package/dist/config.d.ts +22 -6
- package/dist/config.js +2 -2
- package/dist/index.js +1 -1
- package/dist/remote-desktop/computer-control.d.ts +1 -1
- package/dist/remote-desktop/index.js +2 -2
- package/dist/remote-desktop/screen-capture.js +1 -1
- package/dist/remote-desktop/session-manager.js +1 -1
- package/dist/remote-desktop/types.d.ts +1 -1
- package/dist/remote-desktop/ui-automation.d.ts +2 -2
- package/dist/remote-desktop/ui-automation.js +5 -5
- package/dist/routes/ai-sources.js +1 -1
- package/dist/routes/background-tasks.js +5 -5
- package/dist/routes/dashboard.js +1 -1
- package/dist/routes/git.js +20 -20
- package/dist/routes/terminal.js +27 -27
- package/dist/services/agent-capability-sync.js +1 -1
- package/dist/services/ai-config-service.js +2 -2
- package/dist/services/auto-register.js +1 -1
- package/dist/services/aws-client-agent-mcp.d.ts +5 -0
- package/dist/services/aws-client-agent-mcp.js +2 -2
- package/dist/services/browser-session-manager.js +3 -3
- package/dist/services/capability-config.js +2 -2
- package/dist/services/event-delta-pusher.d.ts +1 -1
- package/dist/services/fileSnapshotStore.js +1 -1
- package/dist/services/instance-ai-config-service.js +1 -1
- package/dist/services/instance-init-service.js +1 -1
- package/dist/services/instance-state.d.ts +1 -1
- package/dist/services/instance-state.js +1 -1
- package/dist/services/legacy-path-migration.d.ts +0 -2
- package/dist/services/legacy-path-migration.js +1 -1
- package/dist/services/mcp-deploy.js +2 -2
- package/dist/services/plugin-manager.d.ts +1 -1
- package/dist/services/plugin-manager.js +9 -9
- package/dist/services/skill-manager.js +2 -2
- package/package/acode/dist/cli.js +2 -2
- package/package/acode/dist/runtime.d.ts +2 -0
- package/package/acode/dist/runtime.js +12 -12
- package/package/acode/dist/types.d.ts +2 -0
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{resolve as
|
|
1
|
+
import{resolve as m}from"node:path";import{getBrowserPool as L,disposeBrowserPool as S}from"../browser/browser-pool.js";import{createBuiltInBrowserTools as y}from"../browser/built-in-browser-tools.js";import{WS_HOST as B}from"../browser/types.js";import{getBrowserWsServer as h,stopBrowserWsServer as d}from"../browser/ws-server.js";let t=null,c=null;const x={headless:!0,stealth:!0,viewportWidth:1280,viewportHeight:720,maxPagesPerSession:5,maxSessionDurationMs:0,idleTimeoutMs:0,profileDir:T()},v={port:W(),host:B,heartbeatMs:30*1e3,idleTimeoutMs:30*60*1e3};function W(){const r=process.env.AWS_BROWSER_WS_PORT;if(r){const e=parseInt(r,10);if(Number.isFinite(e)&&e>0&&e<65536)return e}return 7891}function T(){const r=process.env.AWS_BROWSER_PROFILE_DIR;return r||m(process.cwd(),".browser-profiles")}async function P(r,e){return t||c||(c=(async()=>{const o=L({...x,...r}),s=await h(o,{...v,...e}),{port:n,host:i}=await s.start();o.setListenerTriggerHook((l,f,a,g)=>{try{s.broadcastListenerTriggered(l,f,{listenerId:a.listenerId,selector:g.selector,prompt:a.prompt,url:a.url,text:a.text??"",at:a.triggeredAt,changeType:a.changeType})}catch{}u(l,f).catch(()=>{});try{w.get(l)?.()}catch{}});const p={pool:o,wsServer:s,wsPort:n,wsHost:i};return t=p,c=null,p})(),c)}function O(r,e){return!t||!r?null:t.wsServer.getUrl(r,e)}function U(r){if(!t||!r)return[];const e=t.pool.listSessions(r),o=t;return e.map(s=>({browserId:s.browserId,title:s.title,wsUrl:o.wsServer.getUrl(r,s.browserId)}))}function b(){return t?.wsPort??null}async function H(r,e,o){return r?(await P(),t?y({pool:t.pool,wsServer:t.wsServer,agentId:r,scopeKey:e,ssrfConfig:o}):[]):[]}async function R(r){if(!(!t||!r))try{await t.pool.closeByAgent(r)}catch{}}async function k(r,e){if(!(!t||!r))try{await t.pool.close(r,e)}catch{}}async function D(){if(t)try{await d(),await S()}finally{t=null,c=null}}function F(){return t!==null}async function C(r,e,o){if(!t||!r)throw new Error("browser manager not started");const s=t.pool.get(r,e);if(!s)throw new Error(`Browser session not launched for ${r}/${e}. Call browser_launch first.`);const n=await s.listenerManager.addListener(o);return await u(r,e),n}async function N(r,e,o,s){if(!t||!r)return;const n=t.pool.get(r,e);if(!n)return;const i=await n.listenerManager.updateListener({...s,listenerId:o});return await u(r,e),i}async function G(r,e,o){if(!t||!r)return!1;const s=t.pool.get(r,e);if(!s)return!1;const n=await s.listenerManager.removeListener(o);return await u(r,e),n}async function j(r,e,o,s){if(!t||!r)return;const n=t.pool.get(r,e);if(!n)return;const i=await n.listenerManager.toggleListener(o,s);return await u(r,e),i}async function Y(r,e){if(!t||!r)return[];const o=t.pool.get(r,e);return o?o.listenerManager.listListeners():[]}async function u(r,e){if(!t)return;const o=t.pool.get(r,e);if(o)try{const s=await o.listenerManager.listListeners();t.wsServer.broadcastListenerUpdate(r,e,s)}catch{}}async function q(r){return!t||!r?[]:t.pool.collectListenerEvents(r)}const w=new Map;function z(r,e){r&&w.set(r,e)}function J(r,e){r&&(e&&w.get(r)!==e||w.delete(r))}function K(r){if(r.length===0)return"";const e={added:"\u65B0\u589E",removed:"\u5220\u9664",changed:"\u6539\u53D8"};return`\u7CFB\u7EDF\u63D0\u9192\uFF1A\u4EE5\u4E0B\u6D4F\u89C8\u5668\u76D1\u542C\u5668\u5DF2\u89E6\u53D1\uFF0C\u8BF7\u7ACB\u5373\u5904\u7406\uFF1A
|
|
2
2
|
|
|
3
3
|
`+r.map((s,n)=>{const i=s.browserId&&s.browserId!=="default"?`\u6D4F\u89C8\u5668[${s.browserId}]`:"\u6D4F\u89C8\u5668",p=s.selector?`\u5143\u7D20\u9009\u62E9\u5668: ${s.selector}
|
|
4
|
-
`:"",
|
|
5
|
-
${p}\u53D8\u5316\u7C7B\u578B: ${
|
|
4
|
+
`:"",l=e[s.changeType??"changed"]??"\u6539\u53D8",f=new Date(s.triggeredAt).toISOString();return`\u3010\u76D1\u542C\u5668\u4E8B\u4EF6 ${n+1} | ${i} | URL: ${s.url}\u3011
|
|
5
|
+
${p}\u53D8\u5316\u7C7B\u578B: ${l}
|
|
6
6
|
\u89E6\u53D1\u65F6\u95F4: ${f}
|
|
7
7
|
\u63D0\u793A\u8BCD: ${s.prompt}`}).join(`
|
|
8
8
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{existsSync as m,readFileSync as
|
|
2
|
-
`)}function s(e,t){const r=t[e];if(!r||typeof r!="object"||Array.isArray(r))return{};const
|
|
1
|
+
import{existsSync as m,readFileSync as h,readdirSync as j}from"node:fs";import d from"node:path";import{getBridgeTemplateMcpDir as x,getBridgeTemplatePluginsDir as v,getBridgeTemplateSkillsDir as A}from"../config.js";import{atomicWriteFileSync as J,sanitizeAgentId as b}from"../utils/file-utils.js";const M=["skills","mcp","plugins"];function a(e){switch(e){case"skills":return A();case"mcp":return x();case"plugins":return v();default:throw new Error(`\u672A\u77E5\u80FD\u529B\u7C7B\u578B: ${String(e)}`)}}const c=new Map;function W(e,t){t?c.set(e,t):c.delete(e)}function w(e,t){const r=c.get(e);if(r)try{return r()[t]}catch{return}}function l(e){try{if(!m(e))return{};const t=JSON.parse(h(e,"utf8"));return!t||typeof t!="object"||Array.isArray(t)?{}:t}catch{return{}}}function y(e,t){J(e,`${JSON.stringify(t,null,2)}
|
|
2
|
+
`)}function s(e,t){const r=t[e];if(!r||typeof r!="object"||Array.isArray(r))return{};const i={};for(const[n,o]of Object.entries(r))n.trim()&&typeof o=="boolean"&&(i[n.trim()]=o);return i}function D(e,t,r,i){const n={...s(t,e)};i==null?delete n[r]:n[r]=i,e[t]=n}function O(e){return d.join(a(e),"config.json")}function S(e,t){return d.join(a(e),"agents",`${b(t)}.json`)}function p(e){return s(e,l(O(e)))}function F(e,t){return e?s(t,l(S(t,e))):{}}function N(e,t,r,i){const o=F(e,t)[r];if(o!==void 0)return o;const u=p(t)[r];if(u!==void 0)return u;if(i!==void 0)return i;const g=w(t,r);return g!==void 0?g:!1}function P(e,t,r){const i=O(e),n=l(i),o=s(e,n);D(n,e,t,r);const f=s(e,n);return JSON.stringify(o)===JSON.stringify(f)?!1:(y(i,n),!0)}function $(e,t,r,i){if(!e)return!1;const n=S(t,e),o=l(n),f=s(t,o);D(o,t,r,i);const u=s(t,o);return JSON.stringify(f)===JSON.stringify(u)?!1:(y(n,o),!0)}function V(e){const t=d.join(a(e),"agents");try{return m(t)?j(t).filter(r=>r.endsWith(".json")&&!r.startsWith(".")).map(r=>r.slice(0,-5)):[]}catch{return[]}}function Y(e){const t=c.get(e);if(!t)return 0;let r=0;const i=p(e),n=t()??{};for(const o of Object.keys(n))o in i||n[o]===!0&&(P(e,o,!1),r++);return r}function z(e){return Object.keys(p(e)).length>0}function C(e,t,r){const i={};for(const n of r)i[n]=N(e,t,n);return i}export{M as CAPABILITY_TYPES,p as getDefaults,N as getEffective,C as getEffectiveMap,F as getOverrides,z as hasAnyDefault,V as listOverrideAgents,Y as reconcileDefaultsFromDeployed,P as setDefault,W as setDeployedDefaultsProvider,$ as setOverride};
|
|
3
3
|
|
|
@@ -15,7 +15,7 @@ export interface PushStatEntry {
|
|
|
15
15
|
lastError?: string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export declare function scheduleEventPush(agentId: string, _entry: RingBufferEntry<BridgeEventPayload>,
|
|
18
|
+
export declare function scheduleEventPush(agentId: string, _entry: RingBufferEntry<BridgeEventPayload>, _authOptions?: RuntimeCallbackAuthOptions): Promise<void>;
|
|
19
19
|
|
|
20
20
|
export declare function startHeartbeatScheduler(): void;
|
|
21
21
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createHash as
|
|
1
|
+
import{createHash as b}from"node:crypto";import{promises as e}from"node:fs";import s from"node:path";import{getRuntimeHomeDir as M}from"../config.js";import{createLogger as U}from"../utils/logger.js";const p=U("file-snapshot-store");function T(){const t=String(process.env.AWS_RUNTIME_SNAPSHOT_ROOT||"").trim();return t||s.join(M(),".aws-bridge","snapshots")}function A(){const t=Number(process.env.AWS_RUNTIME_SNAPSHOT_TIMEOUT_MS);return Number.isFinite(t)&&t>=5e3?t:12e4}const C=new Set([".git","node_modules",".agentswork-snapshots","__pycache__",".cache",".next","target","dist",".idea",".vscode"]),B=Number(process.env.AWS_RUNTIME_SNAPSHOT_MAX_FILE_SIZE||50*1024*1024),v=Number(process.env.AWS_RUNTIME_SNAPSHOT_MAX_FILES||5e4);function E(t){return b("sha256").update(t).digest("hex").slice(0,16)}function x(t){return E(s.resolve(t))}function I(t,i,h){return s.join(t,i,h)}async function O(t,i,h,o){let n;try{n=await e.readdir(t,{withFileTypes:!0})}catch(r){const a=r;if(a.code==="ENOENT"||a.code==="EACCES")return;throw r}for(const r of n){if(h.length>=o){p.warn(`[FileSnapshot] \u6587\u4EF6\u6570\u5DF2\u8FBE\u4E0A\u9650 ${o}\uFF0C\u505C\u6B62\u904D\u5386`);return}if(C.has(r.name))continue;const a=s.join(t,r.name),d=s.relative(i,a);r.isDirectory()?await O(a,i,h,o):r.isFile()&&h.push(d)}}async function H(t){try{await e.unlink(t)}catch(i){if(i.code!=="ENOENT")throw i}}async function P(t,i){if(t!==i)try{(await e.readdir(t)).length===0&&(await e.rmdir(t),await P(s.dirname(t),i))}catch{}}async function K(t){const i=Date.now(),h=T(),o=s.resolve(String(t.workspacePath).trim()),n=x(o);try{if(!(await e.stat(o)).isDirectory())return{ok:!1,snapshotId:"",snapshotKey:"",fileCount:0,totalBytes:0,workspaceHash:n,error:"workspace path is not a directory"}}catch{return{ok:!1,snapshotId:"",snapshotKey:"",fileCount:0,totalBytes:0,workspaceHash:n,error:"workspace path does not exist"}}const r=t.snapshotId?.trim()||crypto.randomUUID(),a=t.snapshotName?.trim()||`snapshot-${new Date().toISOString()}`,d=t.triggerType?.trim()||"MANUAL",m=`${n}/${r}`,f=I(h,n,r),c=s.join(f,"files");try{await e.mkdir(c,{recursive:!0});const y=[];await O(o,o,y,v);const w={};let F=0,k=0;const g=A(),N=Date.now()+g;for(const $ of y){if(Date.now()>N){p.warn(`[FileSnapshot] \u5FEB\u7167\u8D85\u65F6 ${g}ms\uFF0C\u5DF2\u5907\u4EFD ${k}/${y.length} \u4E2A\u6587\u4EF6`);break}const u=s.join(o,$);try{const l=await e.stat(u);if(!l.isFile())continue;if(l.size>B){p.warn(`[FileSnapshot] \u8DF3\u8FC7\u5927\u6587\u4EF6: ${$} (${(l.size/1024/1024).toFixed(1)}MB)`);continue}const S=await e.readFile(u),_=E(S),D=s.join(c,_);try{await e.access(D)}catch{await e.writeFile(D,S)}w[$]={backupName:_,size:l.size,mtime:l.mtimeMs,mode:l.mode},F+=l.size,k++}catch(l){const S=l;if(S.code==="ENOENT"||S.code==="EACCES"){p.warn(`[FileSnapshot] \u8DF3\u8FC7\u4E0D\u53EF\u8BFB\u6587\u4EF6: ${$}`);continue}throw l}}await e.writeFile(s.join(f,"index.json"),JSON.stringify(w,null,2));const j={snapshotId:r,workspacePath:o,snapshotName:a,triggerType:d,createdAt:new Date().toISOString(),fileCount:k,totalBytes:F,workspaceHash:n};await e.writeFile(s.join(f,"meta.json"),JSON.stringify(j,null,2));const R=Date.now()-i;return p.info(`[FileSnapshot] \u521B\u5EFA\u5FEB\u7167\u5B8C\u6210: ${m}, ${k} files, ${(F/1024/1024).toFixed(1)}MB, ${R}ms`),{ok:!0,snapshotId:r,snapshotKey:m,fileCount:k,totalBytes:F,workspaceHash:n}}catch(y){const w=y;p.error(`[FileSnapshot] \u521B\u5EFA\u5FEB\u7167\u5931\u8D25: ${w.message}`);try{await e.rm(f,{recursive:!0,force:!0})}catch{}return{ok:!1,snapshotId:r,snapshotKey:m,fileCount:0,totalBytes:0,workspaceHash:n,error:w.message}}}async function G(t){const i=Date.now(),h=T(),o=s.resolve(String(t.workspacePath).trim()),n=t.preRestoreBackup!==!1,[r,a]=t.snapshotKey.split("/");if(!r||!a)return{ok:!1,filesRestored:0,filesDeleted:0,filesSkipped:0,error:"invalid snapshotKey format"};const d=I(h,r,a),m=s.join(d,"index.json");try{await e.access(m)}catch{return{ok:!1,filesRestored:0,filesDeleted:0,filesSkipped:0,error:`snapshot not found: ${t.snapshotKey}`}}try{let f;if(n)try{const u=await K({workspacePath:o,snapshotName:`pre-restore-guard-${a}`,triggerType:"AUTO_RESTORE_GUARD"});u.ok?(f=u.snapshotKey,p.info(`[FileSnapshot] \u8FD8\u539F\u524D\u5B89\u5168\u7F51\u5FEB\u7167: ${f}`)):p.warn(`[FileSnapshot] \u8FD8\u539F\u524D\u5B89\u5168\u7F51\u5FEB\u7167\u5931\u8D25: ${u.error}`)}catch(u){p.warn(`[FileSnapshot] \u8FD8\u539F\u524D\u5B89\u5168\u7F51\u5FEB\u7167\u5F02\u5E38: ${u.message}`)}const c=await e.readFile(m,"utf-8"),y=JSON.parse(c);await e.mkdir(o,{recursive:!0});const w=[];await O(o,o,w,v*2);const F=new Set(Object.keys(y));let k=0,g=0,N=0;for(const u of w)if(!F.has(u)){const l=s.join(o,u);await H(l),k++;const S=s.dirname(l);S!==o&&await P(S,o)}const j=A(),R=Date.now()+j;for(const[u,l]of Object.entries(y)){if(Date.now()>R){p.warn(`[FileSnapshot] \u8FD8\u539F\u8D85\u65F6 ${j}ms\uFF0C\u5DF2\u8FD8\u539F ${g} \u4E2A\u6587\u4EF6`);break}const S=s.join(o,u),_=s.join(d,"files",l.backupName);try{try{await e.access(_)}catch{p.warn(`[FileSnapshot] \u5907\u4EFD\u6587\u4EF6\u4E22\u5931\uFF0C\u8DF3\u8FC7: ${u}`),N++;continue}try{const D=await e.readFile(S);if(E(D)===l.backupName){N++;continue}}catch{}await e.mkdir(s.dirname(S),{recursive:!0}),await e.copyFile(_,S);try{await e.chmod(S,l.mode)}catch{}g++}catch(D){p.warn(`[FileSnapshot] \u8FD8\u539F\u6587\u4EF6\u5931\u8D25: ${u} - ${D.message}`),N++}}const $=Date.now()-i;return p.info(`[FileSnapshot] \u8FD8\u539F\u5B8C\u6210: ${t.snapshotKey}, restored=${g}, deleted=${k}, skipped=${N}, ${$}ms`),{ok:!0,filesRestored:g,filesDeleted:k,filesSkipped:N,preRestoreSnapshotKey:f}}catch(f){const c=f;return p.error(`[FileSnapshot] \u8FD8\u539F\u5FEB\u7167\u5931\u8D25: ${c.message}`),{ok:!1,filesRestored:0,filesDeleted:0,filesSkipped:0,error:c.message}}}async function q(t){const i=T(),h=s.resolve(String(t).trim()),o=x(h),n=s.join(i,o);try{await e.access(n)}catch{return[]}const r=await e.readdir(n,{withFileTypes:!0}),a=[];for(const d of r){if(!d.isDirectory())continue;const m=s.join(n,d.name,"meta.json");try{const f=await e.readFile(m,"utf-8"),c=JSON.parse(f);a.push({snapshotId:c.snapshotId,snapshotKey:`${o}/${c.snapshotId}`,snapshotName:c.snapshotName,triggerType:c.triggerType,createdAt:c.createdAt,fileCount:c.fileCount,totalBytes:c.totalBytes})}catch{p.warn(`[FileSnapshot] \u8DF3\u8FC7\u635F\u574F\u5FEB\u7167: ${d.name}`)}}return a.sort((d,m)=>new Date(m.createdAt).getTime()-new Date(d.createdAt).getTime()),a}async function Q(t){const i=T(),[h,o]=t.split("/");if(!h||!o)return{ok:!1,error:"invalid snapshotKey format"};const n=I(i,h,o);try{await e.access(n)}catch{return{ok:!1,error:`snapshot not found: ${t}`}}try{const r=await e.readFile(s.join(n,"index.json"),"utf-8"),a=JSON.parse(r),d=new Set(Object.values(a).map(f=>f.backupName));await e.rm(n,{recursive:!0,force:!0});const m=s.join(i,h);try{const f=await e.readdir(m,{withFileTypes:!0}),c=new Set;for(const w of f)if(w.isDirectory())try{const F=await e.readFile(s.join(m,w.name,"index.json"),"utf-8"),k=JSON.parse(F);for(const g of Object.values(k))c.add(g.backupName)}catch{}const y=s.join(n,"files");try{for(const w of d)c.has(w)||await H(s.join(y,w))}catch{}}catch{}return p.info(`[FileSnapshot] \u5220\u9664\u5FEB\u7167: ${t}`),{ok:!0}}catch(r){const a=r;return p.error(`[FileSnapshot] \u5220\u9664\u5FEB\u7167\u5931\u8D25: ${a.message}`),{ok:!1,error:a.message}}}function V(){return T()}export{K as createSnapshot,Q as deleteSnapshot,V as getSnapshotRootPath,q as listSnapshots,G as restoreSnapshot};
|
|
2
2
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import p from"node:fs/promises";import U from"node:path";import{getBridgeInstanceConfigFile as S,getBridgeInstanceMcpExtraFile as A,getBridgeTemplateConfigFile as F}from"../config.js";import{getInstanceAiConfigDebugLogger as _}from"../utils/instance-ai-config-debug-logger.js";import{mcpDeployManager as w}from"./mcp-deploy.js";const h=new Set(["apiKey","api_key","apikey","key","secret","token","password"]);function D(e){const t={...e};for(const r of Object.keys(t))if(h.has(r)){const o=t[r];typeof o=="string"&&o.length>0&&(t[r]=o.length>8?`${o.slice(0,4)}...${o.slice(-4)}`:"***")}else typeof t[r]=="object"&&t[r]!==null&&(t[r]=D(t[r]));return t}function M(){return{...process.env.ACODE_MODEL?{model:process.env.ACODE_MODEL}:{},...process.env.ACODE_BASE_URL?{baseURL:process.env.ACODE_BASE_URL}:{},...process.env.ACODE_API_KEY?{apiKey:process.env.ACODE_API_KEY}:{},...process.env.ACODE_EFFORT?{effort:process.env.ACODE_EFFORT}:{}}}async function k(e){try{const t=await p.readFile(e,"utf-8"),a=JSON.parse(t).provider?.default,n=a?.options;return{...a?.model?{model:a.model}:{},...n?.baseURL||n?.baseUrl?{baseURL:n.baseURL||n.baseUrl}:{},...n?.apiKey?{apiKey:n.apiKey}:{}}}catch{return{}}}function m(e,t,r,o){return t!==void 0?"api":r!==void 0?"env":o!==void 0?"file":"default"}function O(e){return A(e)}async function x(e){try{const t=await p.readFile(O(e),"utf-8"),r=JSON.parse(t);return r.servers&&typeof r.servers=="object"?r.servers:{}}catch{return{}}}function T(e){return O(e)}async function $(e){const t=F(),r=S(e.agentId),o=e.apiOverrides??{},a=M(),n=await k(t),l=o.model??a.model??n.model,g=o.baseURL??a.baseURL??n.baseURL,y=o.apiKey??a.apiKey??n.apiKey,u=o.effort??a.effort,f={};l&&(f.model=l),g&&(f.baseURL=g),y&&(f.apiKey=y),u&&(f.effort=u);const L={model:m("model",o.model,a.model,n.model),baseURL:m("baseURL",o.baseURL,a.baseURL,n.baseURL),apiKey:m("apiKey",o.apiKey,a.apiKey,n.apiKey),effort:m("effort",o.effort,a.effort,void 0)},v=_();try{await p.mkdir(U.dirname(r),{recursive:!0});let c={};try{const i=await p.readFile(t,"utf-8");c=JSON.parse(i)}catch{}const s=JSON.parse(JSON.stringify(c)),b=s.provider??{},E=b.default??{},d=E.options??{};l&&(d.model=l),g&&(d.baseURL=g),y&&(d.apiKey=y),u&&(d.effort=u),E.options=d,b.default=E,s.provider=b;try{const i=s.mcpServers??{},I=w.resolveEnabledMcp(e.agentId,i),R=await x(e.agentId);for(const[C,K]of Object.entries(R))I[C]=K;s.mcpServers=I}catch(i){v.log({level:"error",category:"apply",message:`MCP \u80FD\u529B\u8FC7\u6EE4/\u79C1\u6709\u5408\u5E76\u5931\u8D25\uFF08fail-open\uFF0C\u4FDD\u6301\u539F\u914D\u7F6E\uFF09: ${i instanceof Error?i.message:String(i)}`,source:"bridge",agentId:e.agentId,sessionId:e.sessionId})}await p.writeFile(r,JSON.stringify(s,null,2),"utf-8"),v.log({level:"info",category:"apply",message:"per-instance acode.json \u5DF2\u5199\u5165",source:"bridge",agentId:e.agentId,sessionId:e.sessionId,details:{perInstanceConfigPath:r,source:L}})}catch(c){const s=c instanceof Error?c.message:String(c);v.log({level:"error",category:"apply",message:`per-instance acode.json \u5199\u5165\u5931\u8D25: ${s}`,source:"bridge",agentId:e.agentId})}return{instanceConfig:{config:f,source:L},perInstanceConfigPath:r}}export{T as getAgentMcpExtraFilePath,$ as prepareAcodeInstanceConfig,D as redactForLog};
|
|
2
2
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{promises as P}from"node:fs";import w from"node:path";import{downloadPluginZip as
|
|
1
|
+
import{promises as P}from"node:fs";import w from"node:path";import{downloadPluginZip as I,downloadSkillZip as O,ensureDir as y}from"../utils/file-utils.js";import{createLogger as j}from"../utils/logger.js";import{normalizeMcpPayload as z}from"../utils/mcp-utils.js";import{ensureEnabledTools as B,parseBoolean as D}from"../utils/validation.js";import{buildBuiltinAwsMcpDeploySpec as $,BUILTIN_AWS_MCP_SERVER_NAME as v}from"./aws-client-agent-mcp.js";import{setDefault as F}from"./capability-config.js";import{getAgentInitRoot as R,loadInstanceState as _,saveInstanceState as L}from"./instance-state.js";import{mcpDeployManager as N,reconcileMcpDefaultsFromDeployed as U}from"./mcp-deploy.js";import{reconcilePluginsDefaultsFromDeployed as W,pluginManager as Z}from"./plugin-manager.js";import{reconcileSkillsDefaultsFromDeployed as q,skillManager as x}from"./skill-manager.js";import{detectToolStatuses as V}from"./tool-installer.js";const G=j("instance-init");function H(a,g){const s=new Set(Object.values(g).filter(r=>r.installed).map(r=>r.tool));return a.filter(r=>s.has(r))}async function J(a,g){try{const s=await O(a,g);if(!s)return null;const r=await P.readFile(s.outputPath),c=a.defaultEnabled!==!1,k=String(a.skillName||"").trim()||void 0,l=await x.saveSharedSkill(r,s.fileName,c,a.sha256,k);return!l.ok||!l.skillName?null:{id:l.skillName,name:l.skillName,fileName:s.fileName,filePath:"",bytes:s.bytes,installedAt:new Date().toISOString()}}catch(s){return G.warn("\u6280\u80FD\u5305\u90E8\u7F72\u5230 bridge \u5931\u8D25\uFF08\u6309\u8DF3\u8FC7\u5904\u7406\uFF09: %s. %s",a.skillName||a.fileName||"(\u672A\u547D\u540D)",s instanceof Error?s.message:String(s)),null}}async function ce(a,g,s){const r=w.resolve(g),c=R(a),k=[];function l(t,o,e,n){k.push({step:t,status:o,message:e,timestamp:new Date().toISOString(),details:n})}l("prepare","running","\u5F00\u59CB\u521D\u59CB\u5316\u5B9E\u4F8B",{agentId:String(a),workspacePath:r}),await y(c),l("prepare","success","\u521D\u59CB\u5316\u76EE\u5F55\u5DF2\u5C31\u7EEA",{initRoot:c});const u=B(s.ccSwitchEnabledTools);l("detect-tools","running","\u5F00\u59CB\u68C0\u6D4B\u5DE5\u5177\u5B89\u88C5\u72B6\u6001",{tools:u});const d=await V(u);l("detect-tools","success","\u5DE5\u5177\u5B89\u88C5\u72B6\u6001\u68C0\u6D4B\u5B8C\u6210",{installedTools:Object.values(d).filter(t=>t.installed).map(t=>t.tool),missingTools:Object.values(d).filter(t=>!t.installed).map(t=>t.tool)});const C=H(u,d),b=Object.values(d).filter(t=>!t.installed),i={ok:!0,agentId:String(a),workspacePath:r,initRoot:c,enabledTools:u,toolStatus:d,logs:k,skill:{enabled:D(s.skillEnabled,!0),packagePresent:!1},mcp:{enabled:D(s.mcpEnabled,!0),configPath:null}},p=await _(a);if(b.length>0&&l("skip-uninstalled-tools","skipped","\u5DF2\u8DF3\u8FC7\u672A\u5B89\u88C5\u5DE5\u5177",{skippedTools:b.map(t=>({tool:t.tool,error:t.error}))}),l("select-installed-tools","success","\u5DF2\u9009\u62E9\u53EF\u521D\u59CB\u5316\u5DE5\u5177",{enabledTools:u,installedTools:C}),l("load-sdk","running","\u5F00\u59CB\u90E8\u7F72\u6280\u80FD/MCP \u6A21\u677F\u5230\u672C bridge"),l("load-sdk","success","\u6280\u80FD/MCP \u6A21\u677F\u90E8\u7F72\u51C6\u5907\u5B8C\u6210",{tools:u}),i.skill.enabled){l("install-skills","running","\u5F00\u59CB\u90E8\u7F72\u6280\u80FD\u5305",{count:Array.isArray(s.skillPackages)?s.skillPackages.length:s.skillPackage?1:0});const t=await y(w.join(c,"skills")),o=Array.isArray(s.skillPackages)&&s.skillPackages.length>0?s.skillPackages:s.skillPackage?[s.skillPackage]:[],e=[];for(const n of o){const f=await J(n,t);f&&e.push(f)}e.length>0?(i.skill.packagePresent=!0,i.skill.installedCount=e.length,i.skill.installed=e,l("install-skills","success","\u6280\u80FD\u5305\u90E8\u7F72\u5B8C\u6210",{installedCount:e.length,skills:e.map(n=>n.name)})):l("install-skills","skipped","\u6CA1\u6709\u53EF\u90E8\u7F72\u7684\u6280\u80FD\u5305")}else l("install-skills","skipped","\u5DF2\u8DF3\u8FC7\u6280\u80FD\u5305\u90E8\u7F72\uFF08skillEnabled=false\uFF09");const S=Array.isArray(s.pluginPackages)?s.pluginPackages:[];if(S.length>0){l("install-plugins","running","\u5F00\u59CB\u90E8\u7F72\u63D2\u4EF6\u6A21\u677F\u5305",{count:S.length});const t=await y(w.join(c,"plugins-tmp"));let o=0;for(const e of S)if(!(!e||!String(e.downloadUrl||"").trim()))try{const n=await I(e,t);if(!n)continue;const f=await P.readFile(n.outputPath),T=e.defaultEnabled!==!1,h=await Z.saveSharedPlugin(f,n.fileName,T,e.sha256);h.ok?(o++,l("install-plugins","success",`\u63D2\u4EF6 ${h.pluginName||n.fileName} \u5DF2\u90E8\u7F72\u5230\u672C bridge`)):l("install-plugins","error",`\u63D2\u4EF6 ${n.fileName} \u90E8\u7F72\u5931\u8D25: ${h.error||"\u672A\u77E5\u9519\u8BEF"}`)}catch(n){l("install-plugins","error",`\u63D2\u4EF6 ${e.fileName||"(\u672A\u547D\u540D)"} \u90E8\u7F72\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}i.plugin={enabled:!0,packagePresent:S.length>0,installedCount:o},o>0?l("install-plugins","success","\u63D2\u4EF6\u6A21\u677F\u5305\u90E8\u7F72\u5B8C\u6210",{installedCount:o}):l("install-plugins","skipped","\u6CA1\u6709\u53EF\u90E8\u7F72\u7684\u63D2\u4EF6\u5305"),await P.rm(t,{recursive:!0,force:!0}).catch(()=>{})}const m=[];if(i.mcp.enabled){l("install-mcp","running","\u5F00\u59CB\u90E8\u7F72 MCP \u6A21\u677F",{count:(Array.isArray(s.mcpServers)?s.mcpServers.length:0)+1});let t;try{const e=$();t=N.saveMcp(v,e,!0),t.ok&&(F("mcp",v,!0),m.push({id:"",name:v,transport:"stdio",command:e.command||"",url:e.url||"",args:e.args||[],env:e.env||{},enabled:!0,installedAt:new Date().toISOString()}))}catch(e){t={ok:!1,error:e instanceof Error?e.message:String(e)}}t.ok||l("install-mcp","error",`\u5185\u7F6E\u901A\u8BAF MCP \u90E8\u7F72\u5931\u8D25: ${t.error||"\u672A\u77E5\u9519\u8BEF"}`);const o=(Array.isArray(s.mcpServers)?s.mcpServers:[]).map(e=>z(e)).filter(e=>e!==null);for(const e of o){const n={type:e.transport||"stdio",command:e.command||void 0,url:e.url||void 0,args:e.args||void 0,env:e.env||void 0};N.saveMcp(e.name,n,e.enabled!==!1).ok&&m.push({id:e.id||"",name:e.name,transport:e.transport||"stdio",command:e.command||"",url:e.url||"",args:e.args||[],env:e.env||{},enabled:e.enabled!==!1,installedAt:new Date().toISOString()})}i.mcp.installedCount=m.length,l("install-mcp","success","MCP \u6A21\u677F\u90E8\u7F72\u5B8C\u6210",{installedCount:m.length,mcpServers:m.map(e=>e.name)})}else l("install-mcp","skipped","\u5DF2\u8DF3\u8FC7 MCP \u6A21\u677F\uFF08mcpEnabled=false\uFF09");l("persist-state","running","\u5F00\u59CB\u4FDD\u5B58\u5B9E\u4F8B\u72B6\u6001"),p.initialized=!0,p.enabledTools=u,p.toolStatus=d,p.skillEnabled=i.skill.enabled,p.mcpEnabled=i.mcp.enabled,await L(a,p),l("persist-state","success","\u5B9E\u4F8B\u72B6\u6001\u4FDD\u5B58\u5B8C\u6210");const M=q(),E=U(),A=W();return(M||E||A)&&l("sync-state","success","\u80FD\u529B\u9ED8\u8BA4\u5F00\u5173\u5DF2\u5BF9\u8D26\uFF08\u65B0\u589E\u9879\u9ED8\u8BA4\u5173\u95ED\uFF09",{reconciledSkills:M,reconciledMcp:E,reconciledPlugins:A}),l("sync-state","success","\u6280\u80FD/MCP \u6A21\u677F\u90E8\u7F72\u72B6\u6001\u5DF2\u5C31\u7EEA"),l("complete","success",b.length>0?"\u5B9E\u4F8B\u521D\u59CB\u5316\u5B8C\u6210\uFF0C\u672A\u5B89\u88C5\u5DE5\u5177\u5DF2\u8DF3\u8FC7":"\u5B9E\u4F8B\u521D\u59CB\u5316\u5B8C\u6210"),{...i,installed:{skills:i.skill.installed||[],mcpServers:m}}}export{ce as initInstance};
|
|
2
2
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{promises as
|
|
1
|
+
import{promises as i}from"node:fs";import d from"node:os";import a from"node:path";import{getBridgeInstanceRuntimeDir as l}from"../config.js";import{atomicWriteJsonFile as s,ensureDir as p,sanitizeAgentId as m}from"../utils/file-utils.js";import{ensureEnabledTools as S,parseBoolean as c}from"../utils/validation.js";function f(e){return a.join(d.tmpdir(),"agentswork-runtime-init",m(String(e)),"state.json")}function g(){return{initialized:!1,skills:[],mcpServers:[],enabledTools:["acode","claude","opencode","codex"],toolStatus:{},skillEnabled:!0,mcpEnabled:!0,updatedAt:null}}function u(e){return a.join(l(String(e)),"state.json")}async function E(e){const t=u(e),n=f(e);try{const r=await i.readFile(t,"utf-8");return JSON.parse(r)}catch{try{const r=await i.readFile(n,"utf-8"),o=JSON.parse(r);return await s(t,o),o}catch{return g()}}}async function h(e,t){const n=u(e);await p(a.dirname(n));const r={initialized:!!t?.initialized,skills:Array.isArray(t?.skills)?t.skills:[],mcpServers:Array.isArray(t?.mcpServers)?t.mcpServers:[],enabledTools:S(t?.enabledTools),toolStatus:t?.toolStatus&&typeof t.toolStatus=="object"&&!Array.isArray(t.toolStatus)?t.toolStatus:{},skillEnabled:c(t?.skillEnabled,!0),mcpEnabled:c(t?.mcpEnabled,!0),updatedAt:new Date().toISOString()};return await s(n,r),r}function x(e){return l(String(e))}export{x as getAgentInitRoot,u as getInstanceStateFile,E as loadInstanceState,h as saveInstanceState};
|
|
2
2
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as i,mkdirSync as a,copyFileSync as f,readdirSync as u}from"node:fs";import o from"node:path";import{getRuntimeHomeDir as r}from"../config.js";import{createLogger as p}from"../utils/logger.js";import{migrateOldBindingDir as j}from"./runtime-binding.js";const e=p("legacy-path-migration");function m(){return o.join(r(),".agentswork","runtime-bridge")}function s(){return o.join(r(),".aws-bridge")}function y(){const n=o.join(m(),"lifecycle-state.json"),t=o.join(s(),"lifecycle-state.json");i(n)&&!i(t)&&(a(s(),{recursive:!0}),f(n,t),e.info(`[runtime-bridge] \u5DF2\u8FC1\u79FB lifecycle-state.json \u2192 ${t}`))}function h(){const n=o.join(r(),".agentswork","snapshots"),t=o.join(s(),"snapshots");if(i(n)&&!i(t)){a(t,{recursive:!0});try{const g=u(n);for(const c of g){const d=o.join(n,c),l=o.join(t,c);f(d,l)}e.info(`[runtime-bridge] \u5DF2\u8FC1\u79FB snapshots/ \u5230 ${t}`)}catch{e.warn("[runtime-bridge] snapshots/ \u8FC1\u79FB\u5931\u8D25\uFF08\u90E8\u5206\u6587\u4EF6\u53EF\u80FD\u88AB\u8DF3\u8FC7\uFF09")}}}function R(){const n=m();if(!i(n)){const t=o.join(r(),".agentswork","snapshots");if(!i(t))return}e.info("[runtime-bridge] \u68C0\u6D4B\u5230\u65E7\u8DEF\u5F84 ~/.agentswork/\uFF0C\u6B63\u5728\u8FC1\u79FB\u5230 ~/.aws-bridge/ ..."),j(),y(),h()}export{R as migrateOldPathsOnStartup};
|
|
2
2
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{existsSync as h,mkdirSync as a,readFileSync as l,rmSync as
|
|
1
|
+
import{existsSync as h,mkdirSync as a,readFileSync as l,rmSync as y,writeFileSync as f}from"node:fs";import n from"node:path";import{getBridgeTemplateMcpDir as m}from"../config.js";import{createLogger as d}from"../utils/logger.js";import{setDeployedDefaultsProvider as M,reconcileDefaultsFromDeployed as g}from"./capability-config.js";import{isCapabilityEnabled as p}from"./instance-features.js";const u=d("mcp-deploy"),D=1;class c{static getInstance(){return this._instance||(this._instance=new c(n.join(m(),"deployed"))),this._instance}constructor(e){this.rootDir=e}manifestFile(){return n.join(this.rootDir,"manifest.json")}specFile(e){const t=n.join(this.rootDir,`${e}.json`),r=n.resolve(this.rootDir);if(n.resolve(t)!==n.join(r,`${e}.json`))throw new Error(`MCP \u6A21\u677F\u6587\u4EF6\u8D8A\u51FA\u90E8\u7F72\u533A: ${e}`);return t}isHealthy(e){return h(this.specFile(e))}readManifest(){try{const e=JSON.parse(l(this.manifestFile(),"utf8"));return Array.isArray(e.servers)?e.servers.filter(t=>t&&t.name):[]}catch{return[]}}writeManifest(e){a(this.rootDir,{recursive:!0}),f(this.manifestFile(),`${JSON.stringify({version:D,servers:e},null,2)}
|
|
2
2
|
`,"utf8")}saveMcp(e,t,r=!0,i){if(!e||!/^[a-zA-Z0-9_.-]+$/.test(e))return{ok:!1,error:`MCP \u540D\u975E\u6CD5: ${JSON.stringify(e)}`};a(this.rootDir,{recursive:!0});try{f(this.specFile(e),`${JSON.stringify(t,null,2)}
|
|
3
|
-
`,"utf8")}catch(o){return{ok:!1,error:`MCP \u6A21\u677F\u5199\u5165\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`}}const s=this.readManifest().filter(o=>o.name!==e);return s.push({name:e,fileName:`${e}.json`,defaultEnabled:r,sha256:i}),this.writeManifest(s),u.info("[mcp] MCP \u6A21\u677F\u5DF2\u90E8\u7F72\u5230 bridge: %s",e),{ok:!0,name:e}}removeMcp(e){if(!e||!/^[a-zA-Z0-9_.-]+$/.test(e))return{ok:!1,error:"name \u975E\u6CD5"};const t=this.readManifest().filter(r=>r.name!==e);this.writeManifest(t);try{
|
|
3
|
+
`,"utf8")}catch(o){return{ok:!1,error:`MCP \u6A21\u677F\u5199\u5165\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`}}const s=this.readManifest().filter(o=>o.name!==e);return s.push({name:e,fileName:`${e}.json`,defaultEnabled:r,sha256:i}),this.writeManifest(s),u.info("[mcp] MCP \u6A21\u677F\u5DF2\u90E8\u7F72\u5230 bridge: %s",e),{ok:!0,name:e}}removeMcp(e){if(!e||!/^[a-zA-Z0-9_.-]+$/.test(e))return{ok:!1,error:"name \u975E\u6CD5"};const t=this.readManifest().filter(r=>r.name!==e);this.writeManifest(t);try{y(this.specFile(e),{force:!0})}catch(r){return{ok:!1,error:`\u6A21\u677F\u6587\u4EF6\u6E05\u7406\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`}}return u.info("[mcp] MCP \u6A21\u677F\u5DF2\u4ECE bridge \u79FB\u9664\u90E8\u7F72: %s",e),{ok:!0}}listDeployed(){return this.readManifest().map(e=>({...e,deployed:this.isHealthy(e.name)}))}getSpec(e){if(!this.isHealthy(e))return null;try{return JSON.parse(l(this.specFile(e),"utf8"))}catch{return null}}resolveEnabledMcp(e,t){const r={};for(const i of this.readManifest()){if(!p(e,"mcp",i.name)||!this.isHealthy(i.name))continue;const s=this.getSpec(i.name);s&&(r[i.name]={...s,type:s.type||"stdio"})}for(const[i,s]of Object.entries(t))p(e,"mcp",i)&&(r[i]||(r[i]=s));return r}deployedDefaultEnabled(){const e={};for(const t of this.readManifest())e[t.name]=t.defaultEnabled;return e}}c._instance=null;const S=c.getInstance();M("mcp",()=>S.deployedDefaultEnabled());const w=()=>g("mcp");export{c as McpDeployManager,S as mcpDeployManager,w as reconcileMcpDefaultsFromDeployed};
|
|
4
4
|
|
|
@@ -84,7 +84,7 @@ export interface PluginManagerOptions {
|
|
|
84
84
|
export declare class PluginManager {
|
|
85
85
|
private agents;
|
|
86
86
|
private readonly rootDir;
|
|
87
|
-
private readonly runtimeRootDir
|
|
87
|
+
private readonly runtimeRootDir?;
|
|
88
88
|
|
|
89
89
|
private moduleNonce;
|
|
90
90
|
constructor(options?: PluginManagerOptions);
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import{spawn as _}from"node:child_process";import{cpSync as F,existsSync as w,lstatSync as
|
|
1
|
+
import{spawn as _}from"node:child_process";import{cpSync as F,existsSync as w,lstatSync as ie,mkdirSync as D,readFileSync as k,readdirSync as j,renameSync as H,rmSync as E,symlinkSync as se,writeFileSync as U}from"node:fs";import{dirname as J,join as m,resolve as Z}from"node:path";import{fileURLToPath as oe,pathToFileURL as ae}from"node:url";import{parseAcodeCommandMarkdown as le,splitQualifiedToolName as ue}from"@agentswork/acode";import{getBridgeInstancePluginsDir as ce,getBridgeTemplatePluginsDir as de,getBridgeVersion as fe}from"../config.js";import{sanitizeAgentId as N,withFileLock as W,downloadPluginZip as ge,sanitizeArchiveFileName as pe}from"../utils/file-utils.js";import{createLogger as me}from"../utils/logger.js";import{setDeployedDefaultsProvider as he,reconcileDefaultsFromDeployed as ye}from"./capability-config.js";import{isCapabilityEnabled as Se,getAgentPluginSources as we}from"./instance-features.js";import{PluginEventBuffer as ve}from"./plugin-event-buffer.js";import{extractPluginZip as x}from"./plugin-package.js";const f=me("plugin-manager"),$="plugin-manager",X="\u7CFB\u7EDF\u5185\u7F6E\uFF1A\u7BA1\u7406\u63D2\u4EF6\u7684\u751F\u547D\u5468\u671F\uFF08\u5B89\u88C5/\u5378\u8F7D/\u542F\u505C/\u91CD\u8F7D\uFF09\uFF1B\u5F00\u53D1\u63D2\u4EF6\u7528\u5185\u7F6E /create-plugin \u547D\u4EE4",Q=`\u300C\u63D2\u4EF6\u7BA1\u7406\u63D2\u4EF6\u300D\u7684\u751F\u547D\u5468\u671F\u5DE5\u5177\uFF1A\u7BA1\u7406\u63D2\u4EF6\uFF08\u5B89\u88C5/\u5378\u8F7D/\u91CD\u8F7D/\u542F\u505C/\u5217\u8868\uFF09\u3002\u4EC5\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u5B89\u88C5\u3001\u79FB\u9664\u6216\u4FEE\u590D\u63D2\u4EF6\u65F6\u4F7F\u7528\u3002
|
|
2
2
|
- action=list\uFF1A\u5217\u51FA\u5DF2\u5B89\u88C5\u63D2\u4EF6\uFF08\u72B6\u6001\u3001\u76D1\u542C\u5668\u5065\u5EB7\u3001\u5DE5\u5177\u6570\uFF09\u3002
|
|
3
3
|
- action=install\uFF1Asource \u4E3A\u63D2\u4EF6\u6765\u6E90\uFF0C\u5F53\u524D\u652F\u6301 "local:<\u4EFB\u610F\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>"\uFF08\u4E0D\u505A\u76EE\u5F55\u4F4D\u7F6E\u9650\u5236\uFF09\uFF1Bconfig \u4F20\u63D2\u4EF6 manifest \u91CC userConfig \u58F0\u660E\u7684\u914D\u7F6E\u503C\u3002\u5B89\u88C5\u65F6\u4F1A\u5148\u628A\u8BE5\u76EE\u5F55\u79FB\u52A8\u5230\u672C agent \u52A0\u8F7D\u63D2\u4EF6\u7684\u4F4D\u7F6E\uFF0C\u518D\u52A0\u8F7D\u79FB\u52A8\u540E\u7684\u526F\u672C\uFF08\u79FB\u52A8\u540E\u6E90\u76EE\u5F55\u4E0D\u518D\u4FDD\u7559\uFF09\uFF0C\u5B89\u88C5\u540E\u7ACB\u5373\u751F\u6548\uFF1A\u4E0B\u4E00\u6B21 poll_message \u7684 pluginCatalog \u5373\u53EF\u89C1\u3002
|
|
4
4
|
- action=reload\uFF1A\u91CD\u8F7D\u6307\u5B9A\u63D2\u4EF6\uFF08\u6539\u8FC7\u63D2\u4EF6\u6587\u4EF6\u540E\u4F7F\u7528\uFF09\uFF0C\u539F\u5B50\u6362\u88C5\uFF0C\u76D1\u542C\u5668\u91CD\u542F\u3002
|
|
5
5
|
- action=enable / disable\uFF1A\u505C\u7528/\u542F\u7528\uFF08disable \u4FDD\u7559\u5B89\u88C5\u4E0E\u914D\u7F6E\uFF0C\u4EC5\u505C\u6B62\u76D1\u542C\u4E0E\u5DE5\u5177\u8C03\u7528\uFF09\u3002
|
|
6
|
-
- action=uninstall\uFF1A\u5378\u8F7D\u5E76\u5220\u9664\u63D2\u4EF6\u76EE\u5F55\uFF08\u4E0D\u53EF\u9006\uFF0C\u9700\u7528\u6237\u660E\u786E\u8981\u6C42\uFF09\u3002`,ve={type:"object",properties:{action:{type:"string",enum:["install","uninstall","reload","enable","disable","list"],description:"\u751F\u547D\u5468\u671F\u52A8\u4F5C"},name:{type:"string",description:"\u63D2\u4EF6\u540D\uFF08uninstall/reload/enable/disable \u5FC5\u586B\uFF09"},source:{type:"string",description:'install \u6765\u6E90\uFF0C\u5F53\u524D\u652F\u6301 "local:<\u4EFB\u610F\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>"\uFF08\u5B89\u88C5\u65F6\u81EA\u52A8\u79FB\u52A8\u5230\u672C agent \u63D2\u4EF6\u4F4D\u7F6E\u540E\u52A0\u8F7D\uFF09'},config:{type:"object",description:"install \u65F6\u63D2\u4EF6 userConfig \u58F0\u660E\u7684\u914D\u7F6E\u503C\uFF08\u952E\u503C\u5BF9\uFF09",additionalProperties:{type:"string"}}},required:["action"],additionalProperties:!1},Pe=new Set(["install","uninstall","reload","enable","disable","list"]);function te(){const l=de();return l&&l!=="unknown"?l:void 0}function $e(){return ae(new URL("./builtin-commands/",import.meta.url))}const Ee=200,R=256*1024,ke=4*1024,ne=6e4,q=6e4,Ae=/^[a-zA-Z0-9_][a-zA-Z0-9_-]*$/,z=/^[a-z0-9][a-z0-9-]*$/,be=["system.","aws-","acode-"],De=new Set(["NODE_OPTIONS","NODE_PATH","NODE_EXTRA_CA_CERTS","NODE_REPL_HISTORY","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","PYTHONPATH","PYTHONSTARTUP","PYTHONHOME","PERL5LIB","PERL5OPT","RUBYOPT","RUBYLIB","BASH_ENV","ENV","SHELLOPTS","BASHOPTS","IFS","PS1","PS4","GIT_SSH","GIT_SSH_COMMAND","GIT_CONFIG","GIT_CONFIG_GLOBAL","PATH","HOME","USERPROFILE","SYSTEMROOT","COMSPEC","TEMP","TMP","LANG","TZ"]),Le=/^[A-Za-z_][A-Za-z0-9_]*$/,Oe=process.platform==="win32"?"junction":"dir",Te=/[^\x20-\x7E]/,Ne=6e4,G=20,re=80;function P(l){return typeof l=="object"&&l!==null&&!Array.isArray(l)}function I(l,e){let t=l;for(const n of e.split(".")){if(!P(t))return;t=t[n]}return t}function A(l,e){return l.length<=e?l:`${l.slice(0,e)}\u2026(\u622A\u65AD,\u5171 ${l.length} \u5B57\u7B26)`}async function C(l,e=8,t=200){for(let n=0;;n++)try{E(l,{recursive:!0,force:!0});return}catch(r){if(n>=e-1)throw r;await new Promise(i=>setTimeout(i,t))}}async function ie(l,e){D(J(e),{recursive:!0});try{H(l,e);return}catch(t){const n=t?.code;if(!n||!["EXDEV","EPERM","EACCES","EBUSY","EINVAL"].includes(n))throw t}F(l,e,{recursive:!0,filter:t=>!/[\\/]\.git([\\/]|$)/.test(t)&&!/[\\/]node_modules([\\/]|$)/.test(t)}),await C(l)}function b(l,e){l.logs.push(`${new Date().toISOString()} ${e}`),l.logs.length>Ee&&l.logs.shift()}function V(l,e,t="params"){if(!P(l))return[];const n=[],r=l.type;if(typeof r=="string"&&!Ie(r,e))return[`${t}: \u671F\u671B ${r}\uFF0C\u5B9E\u9645 ${Ce(e)}`];if(Array.isArray(l.enum)&&l.enum.length>0&&(l.enum.some(s=>JSON.stringify(s)===JSON.stringify(e))||n.push(`${t}: \u503C ${JSON.stringify(e)} \u4E0D\u5728\u679A\u4E3E ${JSON.stringify(l.enum)} \u5185`)),r==="object"&&P(e)){const i=P(l.properties)?l.properties:{},s=Array.isArray(l.required)?l.required:[];for(const o of s)(!(o in e)||e[o]===void 0)&&n.push(`${t}.${o}: \u5FC5\u586B\u53C2\u6570\u7F3A\u5931`);for(const[o,a]of Object.entries(i))o in e&&e[o]!==void 0&&n.push(...V(a,e[o],`${t}.${o}`));if(l.additionalProperties===!1)for(const o of Object.keys(e))o in i||n.push(`${t}.${o}: \u4E0D\u5141\u8BB8\u7684\u672A\u77E5\u53C2\u6570\uFF08schema additionalProperties=false\uFF09`)}return r==="array"&&Array.isArray(e)&&P(l.items)&&e.forEach((i,s)=>{n.push(...V(l.items,i,`${t}[${s}]`))}),n}function Ie(l,e){switch(l){case"string":return typeof e=="string";case"number":return typeof e=="number"&&Number.isFinite(e);case"boolean":return typeof e=="boolean";case"object":return P(e);case"array":return Array.isArray(e);case"null":return e===null;default:return!0}}function Ce(l){return l===null?"null":Array.isArray(l)?"array":typeof l}class Re{constructor(e={}){this.agents=new Map,this.moduleNonce=0,this.templatePullInFlight=new Set,this.backgroundTemplatePulls=new Set,this.rootDir=e.rootDir??g(W(),"plugins"),this.runtimeRootDir=e.runtimeRootDir??g(W(),"plugins-runtime")}forAgent(e){return{listPlugins:()=>this.list(e),getCatalog:()=>this.getCatalog(e),getToolSchema:t=>this.getToolSchema(e,t),invokeTool:(t,n,r,i)=>this.invokeTool(e,t,n,r,i),manage:t=>this.manage(e,t),getCommandDirs:()=>this.getCommandDirs(e)}}setOnPluginsChanged(e){this.onPluginsChanged=e}notifyPluginsChanged(e){try{this.onPluginsChanged?.(e)}catch(t){f.warn("[agent:%s] onPluginsChanged \u56DE\u8C03\u5931\u8D25: %s",e,t instanceof Error?t.message:String(t))}}async getCommandDirs(e){return[...(await this.hydrate(e)).plugins.values()].filter(n=>n.enabled&&n.commandDir).map(n=>n.commandDir)}async getPluginCommands(e){const t=await this.hydrate(e),n=[];n.push(...this.parseCommandDir($,$e()));for(const r of t.plugins.values())!r.enabled||!r.commandDir||n.push(...this.parsePluginCommandDir(r));return n}parsePluginCommandDir(e){return this.parseCommandDir(e.name,e.commandDir)}parseCommandDir(e,t){const n=[];if(!t)return n;try{for(const r of j(t)){if(!r.endsWith(".md"))continue;const i=g(t,r);try{const s=ue(i,k(i,"utf8"));s.plugin=e,n.push(s)}catch(s){f.warn("[plugin:%s] \u547D\u4EE4\u89E3\u6790\u5931\u8D25 %s: %s",e,r,s instanceof Error?s.message:String(s))}}}catch{}return n}async list(e){const t=await this.hydrate(e),n=new Map;for(const r of t.plugins.values()){const i=this.toSummary(r);n.set(i.name,i)}n.has($)||n.set($,{name:$,version:te(),description:Q,status:"enabled",enabled:!0,source:"builtin",installedAt:new Date().toISOString(),toolCount:1,tools:[{name:"plugin-manager.manage",description:"\u63D2\u4EF6\u751F\u547D\u5468\u671F\u7BA1\u7406\uFF08install/uninstall/reload/disable/enable/list\uFF09"}],listeners:[],builtin:!0});for(const r of this.readSharedManifest()){const i=r.pluginName;if(!this.deployedPluginHealthy(i))continue;const o=n.get(i);if(o){String(o.source||"").startsWith("shared:")&&(o.enabled=this.effectiveSharedEnabled(e,r));continue}n.set(i,{name:i,version:this.deployedPluginVersion(i),status:"enabled",enabled:this.effectiveSharedEnabled(e,r),source:`shared:${r.fileName??`${i}.zip`}`,installedAt:new Date().toISOString(),toolCount:0,listeners:[]})}return[...n.values()].sort((r,i)=>r.name.localeCompare(i.name))}deployedPluginVersion(e){try{const t=JSON.parse(k(g(this.deployedPluginDir(e),"plugin.json"),"utf8"));return typeof t.version=="string"?t.version:void 0}catch{return}}async getCatalog(e){const t=await this.hydrate(e),n=[];for(const r of t.plugins.values()){if(!r.enabled||r.status==="error")continue;const i=r.tools.slice(0,G).map(s=>({name:s.name,description:A(s.title||s.description,re),requiredParams:this.requiredParamsOf(s)}));r.tools.length>G&&i.push({name:`(\u53E6\u6709 ${r.tools.length-G} \u4E2A\u5DE5\u5177\u672A\u5217\u51FA)`,description:'\u7528 function_call {action:"catalog"} \u67E5\u770B\u5168\u91CF',requiredParams:void 0}),n.push({plugin:r.name,version:r.version,description:r.description,status:r.status,tools:i})}return n.push({plugin:$,version:te(),description:Q,status:"enabled",tools:[{name:"manage",description:A(ee,re),requiredParams:["action"]}]}),{revision:t.catalogRevision,plugins:n}}async getToolSchema(e,t){const n=ce(t);if(!n)return null;if(n.plugin===$&&n.tool==="manage")return{plugin:$,name:"manage",description:ee,inputSchema:ve};const i=(await this.hydrate(e)).plugins.get(n.plugin);if(!i||!i.enabled)return null;const s=i.tools.find(o=>o.name===n.tool);return s?{plugin:i.name,name:s.name,title:s.title,description:s.description,inputSchema:s.inputSchema??{type:"object",properties:{}}}:null}async invokeTool(e,t,n,r,i){if(t===$&&n==="manage"){const u=this.buildManageRequest(r);if(!u)return{ok:!1,error:"plugin-manager.manage \u7F3A\u5C11 action"};const c=await this.manage(e,u);if(!c.ok)return{ok:!1,error:c.error??"\u63D2\u4EF6\u7BA1\u7406\u64CD\u4F5C\u5931\u8D25"};const d={ok:!0};return c.plugins&&(d.plugins=c.plugins),c.summary&&(d.summary=c.summary),{ok:!0,result:d}}const s=await this.hydrate(e),o=s.plugins.get(t);if(!o)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\uFF08\u53EF\u7528\u63D2\u4EF6: ${[...s.plugins.keys()].join(", ")||"\u65E0"}\uFF09`};if(!o.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u5DF2\u505C\u7528\uFF0C\u53EF\u8BA9\u7528\u6237\u5728\u9762\u677F\u6216\u7528 plugin-manager.manage enable \u542F\u7528`};const a=o.tools.find(u=>u.name===n);if(!a)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5DE5\u5177 ${n}\uFF08\u53EF\u7528: ${o.tools.map(u=>u.name).join(", ")||"\u65E0"}\uFF09`};if(a.inputSchema){const u=V(a.inputSchema,r);if(u.length>0)return{ok:!1,error:`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${u.join("; ")}`,inputSchema:a.inputSchema}}return this.executeHandler(e,o,a,r,i)}buildManageRequest(e){const t=e.action;if(typeof t!="string"||!Pe.has(t))return null;const n={action:t};if(typeof e.name=="string"&&e.name.trim()&&(n.name=e.name.trim()),typeof e.source=="string"&&e.source.trim()&&(n.source=e.source.trim()),e.config&&typeof e.config=="object"&&!Array.isArray(e.config)){const r={};for(const[i,s]of Object.entries(e.config))typeof s=="string"&&(r[i]=s);n.config=r}return n}async executeHandler(e,t,n,r,i){const s=Date.now(),o=n.handler??{type:"process"};try{return o.type==="mcp"?{ok:!1,error:"handler.type=mcp \u5C06\u5728\u540E\u7EED\u7248\u672C\u652F\u6301\uFF0C\u8BF7\u6539\u7528 process/module handler"}:o.type==="module"?{ok:!0,result:await this.invokeModuleHandler(t,o,r,e,i),durationMs:Date.now()-s}:!o.command||!o.command.trim()?{ok:!1,error:`\u5DE5\u5177 ${n.name} \u7684 process handler \u7F3A\u5C11 command`}:{ok:!0,result:await this.invokeProcessHandler(t,o,r,e,i),durationMs:Date.now()-s}}catch(a){return{ok:!1,error:a instanceof Error?a.message:String(a),durationMs:Date.now()-s}}}async invokeProcessHandler(e,t,n,r,i){const s=Y(t.command??"",{params:n});if(s.length===0)throw new Error("process handler command \u4E3A\u7A7A");const o=typeof t.timeoutMs=="number"&&t.timeoutMs>0?t.timeoutMs:ne,a=new AbortController,u=()=>a.abort();i?.signal?.addEventListener("abort",u,{once:!0});const c=setTimeout(()=>a.abort(),o);try{return await new Promise((d,y)=>{f.info("[plugin:%s] spawn: %s",e.name,s.join(" "));const h=_(s[0],s.slice(1),{cwd:e.dir,env:this.buildPluginEnv(e,r),shell:t.shell===!0,windowsHide:!0,signal:a.signal});let p="",m="";h.stdin?.on("error",()=>{}),h.stdout?.on("data",v=>{p.length<R&&(p+=v.toString("utf8"))}),h.stderr?.on("data",v=>{m.length<R&&(m+=v.toString("utf8"))}),h.on("error",v=>{y(new Error(`\u63D2\u4EF6\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${v.message}`))}),h.on("close",v=>{const L=p.trim();if(v!==0){const O=A(m.trim()||L||"(\u65E0\u8F93\u51FA)",600);y(new Error(a.signal.aborted?`\u63D2\u4EF6\u8FDB\u7A0B\u8D85\u65F6(${o}ms)\u6216\u88AB\u4E2D\u6B62`:`\u63D2\u4EF6\u8FDB\u7A0B\u9000\u51FA\u7801 ${v}: ${O}`));return}if(!L){d({ok:!0});return}try{d(JSON.parse(L))}catch{d(L)}});try{t.stdin==="params"?h.stdin?.end(`${JSON.stringify(n)}
|
|
7
|
-
`):h.stdin?.end()}catch{}})}finally{clearTimeout(c),i?.signal?.removeEventListener("abort",u)}}async invokeModuleHandler(e,t,n,r,i){if(!t.module)throw new Error("module handler \u7F3A\u5C11 module \u8DEF\u5F84");const s=
|
|
8
|
-
`,"utf8")}async migrateLegacySharedIfNeeded(){try{if(w(this.deployedManifestFile()))return;const e=g(this.legacySharedDir(),"manifest.json");if(!w(e))return;const t=JSON.parse(k(e,"utf8")),n=Array.isArray(t.plugins)?t.plugins:[];if(n.length===0)return;const r=[];for(const i of n){const s=g(this.legacySharedDir(),i.zipFile);if(!(!i.pluginName||!w(s)))try{const o=await this.deployPluginZipToPersistentDir(k(s),i.pluginName);if(!o)continue;r.push(o),f.info("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u5230\u90E8\u7F72\u533A: %s",i.pluginName)}catch(o){f.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6 %s \u8FC1\u79FB\u5931\u8D25: %s",i.pluginName,o instanceof Error?o.message:String(o))}}r.length>0&&this.writeSharedManifest(r),E(this.legacySharedDir(),{recursive:!0,force:!0})}catch(e){f.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u672A\u6267\u884C\uFF08\u4E0B\u6B21\u91CD\u8BD5\uFF09: %s",e instanceof Error?e.message:String(e))}}deployedPluginHealthy(e){return w(g(this.deployedPluginDir(e),"plugin.json"))}runtimeDirFor(e){return g(this.runtimeRootDir,N(e))}runtimeLinkPath(e,t){return g(this.runtimeDirFor(e),t)}ensureRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t),r=this.deployedPluginDir(t);if(!w(g(r,"plugin.json")))return!1;D(this.runtimeDirFor(e),{recursive:!0});try{if(w(n)){let i=!1;try{i=se(n).isSymbolicLink()}catch{i=!1}if(i)try{return j(n),!0}catch{}E(n,{recursive:!0,force:!0})}return oe(r,n,Oe),f.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u5EFA\u7ACB: %s \u2192 %s",e,n,r),!0}catch(i){return f.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5931\u8D25\uFF08%s \u2192 %s\uFF09: %s",e,t,r,i instanceof Error?i.message:String(i)),!1}}removeRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t);try{w(n)&&(E(n,{recursive:!0,force:!0}),f.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u79FB\u9664: %s",e,t))}catch(r){f.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u79FB\u9664\u5931\u8D25\uFF08%s\uFF09: %s",e,t,r instanceof Error?r.message:String(r))}}async saveSharedPlugin(e,t,n=!0,r){if(!e||e.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};await this.migrateLegacySharedIfNeeded();const i=g(this.rootDir,"tmp",`deploy-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const s=await x(e,i),o=this.loadManifestOnly(s.pluginDir);if(!o.ok)return o;const a=o.manifest.name,u=this.readSharedManifest().find(p=>p.pluginName===a);if(u&&u.sha256===r&&this.deployedPluginHealthy(a))return{ok:!0,pluginName:a};await this.suspendDeployedPluginAcrossAgents(a),D(this.deployedDir(),{recursive:!0});const c=this.deployedPluginDir(a),d=g(this.deployedDir(),`.old-${a}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);if(w(c))try{H(c,d)}catch{E(c,{recursive:!0,force:!0})}try{F(s.pluginDir,c,{recursive:!0,filter:p=>!/[\\/]\.git([\\/]|$)/.test(p)&&!/[\\/]node_modules([\\/]|$)/.test(p)})}catch(p){throw w(d)&&(E(c,{recursive:!0,force:!0}),H(d,c)),p}w(d)&&E(d,{recursive:!0,force:!0}),await X(this.deployedManifestFile(),async()=>{const p=this.readSharedManifest().filter(m=>m.pluginName!==a);p.push({pluginName:a,zipFile:u?.zipFile??`${a}.zip`,fileName:t,defaultEnabled:n,sha256:r}),this.writeSharedManifest(p)}),f.info("[shared] \u63D2\u4EF6\u5DF2\u90E8\u7F72\u5230 bridge: %s\uFF08\u6765\u6E90 %s%s\uFF09",a,t,r?`, sha256=${r.slice(0,12)}\u2026`:"");const h=(await this.applySharedToKnownAgents()).find(p=>p.installed.includes(a));return h&&f.info("[shared] \u5DF2\u540C\u6B65\u5230\u8FD0\u884C\u4E2D agent: %s",h.agentId),{ok:!0,pluginName:a}}catch(s){const o=s instanceof Error?s.message:String(s);return f.warn("[shared] \u63D2\u4EF6\u90E8\u7F72\u5931\u8D25\uFF08%s\uFF09: %s",t,o),{ok:!1,error:`\u63D2\u4EF6\u90E8\u7F72\u5931\u8D25: ${o}`}}finally{await C(i,3,100).catch(()=>{})}}async deployPluginZipToPersistentDir(e,t){if(!e||e.length===0)return null;const n=g(this.rootDir,"tmp",`migrate-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const r=await x(e,n),i=this.loadManifestOnly(r.pluginDir);if(!i.ok)return null;const s=i.manifest.name;if(t&&s!==t)return null;D(this.deployedDir(),{recursive:!0});const o=this.deployedPluginDir(s);return w(o)&&E(o,{recursive:!0,force:!0}),F(r.pluginDir,o,{recursive:!0,filter:a=>!/[\\/]\.git([\\/]|$)/.test(a)&&!/[\\/]node_modules([\\/]|$)/.test(a)}),{pluginName:s,zipFile:`${s}.zip`,fileName:`${s}.zip`,defaultEnabled:!0}}finally{E(n,{recursive:!0,force:!0})}}async suspendDeployedPluginAcrossAgents(e){for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const n=t.queue.then(async()=>{const r=t.plugins.get(e);r&&(this.stopAllListeners(r),t.plugins.delete(e),this.bumpCatalogRevision(t),f.info("[agent:%s] \u5DF2\u6458\u9664\u63D2\u4EF6\u7B49\u5F85\u90E8\u7F72\u533A\u66F4\u65B0: %s",t.agentId,e))});t.queue=n.catch(()=>{}),await n}}async applySharedToKnownAgents(){const e=[];for(const t of this.agents.values()){if(!t.hydrated)continue;const n=await this.syncSharedIntoStateQueued(t);n.length>0&&e.push({agentId:t.agentId,installed:n})}return e}async syncSharedIntoStateQueued(e){const t=e.queue.then(()=>this.syncSharedIntoState(e));return e.queue=t.catch(()=>[]),t}effectiveSharedEnabled(e,t){return ye(e,"plugins",t.pluginName)&&(t.defaultEnabled??!0)}async pullTemplatePluginsFromCapabilities(e){const t=Se(e.agentId);if(!t)return;const n=this.readSharedManifest();for(const[r,i]of Object.entries(t)){if(!i.url)continue;const s=n.find(a=>a.pluginName===r);if(!s||!s.sha256||s.sha256===i.sha256&&this.deployedPluginHealthy(r)||this.templatePullInFlight.has(r))continue;this.templatePullInFlight.add(r);const o=g(this.rootDir,"tmp",`pull-${N(e.agentId)}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{D(o,{recursive:!0});let a=`${r}.zip`;try{const y=decodeURIComponent(i.url.split("/").pop()||"");y.toLowerCase().endsWith(".zip")&&(a=ge(y,`${r}.zip`))}catch{}const u=await fe({downloadUrl:i.url,fileName:a,sha256:i.sha256},o);if(!u)continue;const c=k(u.outputPath),d=await this.saveSharedPlugin(c,u.fileName,s.defaultEnabled??!0,i.sha256);d.ok?f.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u81EA\u52A8\u5BF9\u8D26\u66F4\u65B0\u6210\u529F: %s",e.agentId,d.pluginName??r):f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u66F4\u65B0\u5931\u8D25: %s: %s",e.agentId,r,d.error)}catch(a){f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6 %s \u66F4\u65B0\u5931\u8D25: %s",e.agentId,r,a instanceof Error?a.message:String(a))}finally{this.templatePullInFlight.delete(r),await C(o,3,100).catch(()=>{})}}}queueTemplatePull(e){this.backgroundTemplatePulls.has(e.agentId)||(this.backgroundTemplatePulls.add(e.agentId),this.pullTemplatePluginsFromCapabilities(e).catch(t=>{f.warn("[agent:%s] \u540E\u53F0\u63D2\u4EF6\u5BF9\u8D26\u66F4\u65B0\u5931\u8D25: %s",e.agentId,t instanceof Error?t.message:String(t))}).finally(()=>{this.backgroundTemplatePulls.delete(e.agentId)}))}async syncSharedIntoState(e){this.queueTemplatePull(e);const t=this.readSharedManifest(),n=new Set,r=[];let i=0;for(const s of t)if(n.add(s.pluginName),this.effectiveSharedEnabled(e.agentId,s)){const a=e.plugins.get(s.pluginName);if(!this.ensureRuntimeLink(e.agentId,s.pluginName))continue;const u=this.runtimeLinkPath(e.agentId,s.pluginName);if(!a){const c=this.loadPluginFromDir(e,u,`shared:${s.fileName}`,new Date().toISOString(),{});c.ok?(e.plugins.set(c.plugin.name,c.plugin),r.push(c.plugin.name),f.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u5DF2\u6309\u5F00\u542F\u6001\u52A0\u8F7D: %s",e.agentId,s.pluginName)):f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25: %s: %s",e.agentId,s.pluginName,c.error)}}else{const a=e.plugins.get(s.pluginName);a&&(this.stopAllListeners(a),e.plugins.delete(s.pluginName),i++),this.removeRuntimeLink(e.agentId,s.pluginName)}return this.cleanupRuntimeDir(e,n),(r.length>0||i>0)&&this.bumpCatalogRevision(e),this.persistInstalled(e),r}cleanupRuntimeDir(e,t){const n=this.runtimeDirFor(e.agentId);try{if(!w(n))return;const r=new Set(t);for(const i of j(n))!r.has(i)&&!e.plugins.has(i)&&this.removeRuntimeLink(e.agentId,i)}catch{}}async applyCapabilities(e){const t=await this.hydrate(e);await this.pullTemplatePluginsFromCapabilities(t),await this.syncSharedIntoState(t)}async drainEvents(e,t={}){const n=await this.hydrate(e);this.ensureListenersRunning(n);const r=n.buffer.drain(t),i=await this.getCatalog(e);return{revision:r.revision,events:r.events,catalog:i,compactionSeq:n.compactionSeq}}markAgentCompacted(e){const t=this.agentState(e);t.compactionSeq++,f.debug("[agent:%s] \u4E0A\u4E0B\u6587\u538B\u7F29\u6807\u8BB0: compactionSeq=%d",e,t.compactionSeq)}async enqueueExternalEvent(e,t,n){const r=await this.hydrate(e),i=r.plugins.get(t);if(!i||!i.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\u6216\u5DF2\u505C\u7528`};const s=typeof n.event=="string"?n.event:"",o=i.listeners.find(a=>a.transport.type==="http-callback"&&(!s||a.event===s));return o?(this.enqueueEvent(r,i,o,n),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5339\u914D\u7684 http-callback \u76D1\u542C\u5668\uFF08event=${s||"(\u7A7A)"}\uFF09`}}bumpCatalogRevision(e){e.catalogRevision++}agentState(e){let t=this.agents.get(e);return t||(t={agentId:e,plugins:new Map,buffer:new we(e),hydrated:!1,queue:Promise.resolve(),catalogRevision:0,eventSeq:0,compactionSeq:0},this.agents.set(e,t)),t}async hydrate(e){const t=this.agentState(e);return t.hydratePromise||(t.hydratePromise=this.doHydrate(t).catch(n=>{throw t.hydratePromise=void 0,n})),await t.hydratePromise,t}async doHydrate(e){const t=e.agentId;await this.migrateLegacySharedIfNeeded();const n=this.installedFile(t);if(!w(n)){await this.syncSharedIntoState(e).catch(()=>{}),e.hydrated=!0;return}try{const r=JSON.parse(k(n,"utf8")),i=this.readSecrets(t);for(const s of r.plugins??[]){if(String(s.source||"").startsWith("shared:"))continue;const a=g(this.rootDir,"cache",N(t),s.name);if(!w(g(a,"plugin.json"))){f.warn("[agent:%s] \u5DF2\u5B89\u88C5\u63D2\u4EF6\u76EE\u5F55\u7F3A\u5931\uFF0C\u8DF3\u8FC7: %s",t,s.name);continue}const u={...s.config,...i[s.name]??{}},c=this.loadPluginFromDir(e,a,s.source,s.installedAt,u);if(c.ok){const d=c.plugin;d.enabled=s.enabled,e.plugins.set(d.name,d)}else f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25: %s: %s",t,s.name,c.error)}}catch(r){const i=r instanceof Error?r.message:String(r);f.error("[agent:%s] installed.json \u89E3\u6790\u5931\u8D25: %s",t,i)}await this.syncSharedIntoState(e).catch(r=>{f.warn("[agent:%s] \u5171\u4EAB\u63D2\u4EF6\u540C\u6B65\u5931\u8D25: %s",t,r instanceof Error?r.message:String(r))}),e.hydrated=!0}installedFile(e){return g(this.rootDir,"agents",N(e),"installed.json")}persistInstalled(e){this.persistSecrets(e);const t=this.installedFile(e.agentId);D(J(t),{recursive:!0});const n=[...e.plugins.values()].map(r=>({name:r.name,source:r.source,installedAt:r.installedAt,enabled:r.enabled,config:this.stripSensitiveValues(r)}));U(t,`${JSON.stringify({version:1,plugins:n},null,2)}
|
|
9
|
-
`,"utf8")}sensitiveKeysOf(e){return(e.userConfig??[]).filter(t=>t?.sensitive===!0&&typeof t.key=="string").map(t=>t.key)}stripSensitiveValues(e){const t=new Set(this.sensitiveKeysOf(e)),n={};for(const[r,i]of Object.entries(e.configValues))t.has(r)||(n[r]=i);return n}secretsFile(e){return
|
|
10
|
-
`,{encoding:"utf8",mode:384})}readJsonFile(e){if(!w(e))return{ok:!0,data:{}};try{const t=JSON.parse(k(e,"utf8"));return P(t)?{ok:!0,data:t}:{ok:!1,error:`${e}: \u6839\u8282\u70B9\u987B\u4E3A\u5BF9\u8C61`}}catch(t){const n=t instanceof Error?t.message:String(t);return{ok:!1,error:`${e}: JSON \u89E3\u6790\u5931\u8D25: ${n}`}}}loadManifestOnly(e){const t=this.readJsonFile(
|
|
6
|
+
- action=uninstall\uFF1A\u5378\u8F7D\u5E76\u5220\u9664\u63D2\u4EF6\u76EE\u5F55\uFF08\u4E0D\u53EF\u9006\uFF0C\u9700\u7528\u6237\u660E\u786E\u8981\u6C42\uFF09\u3002`,Pe={type:"object",properties:{action:{type:"string",enum:["install","uninstall","reload","enable","disable","list"],description:"\u751F\u547D\u5468\u671F\u52A8\u4F5C"},name:{type:"string",description:"\u63D2\u4EF6\u540D\uFF08uninstall/reload/enable/disable \u5FC5\u586B\uFF09"},source:{type:"string",description:'install \u6765\u6E90\uFF0C\u5F53\u524D\u652F\u6301 "local:<\u4EFB\u610F\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>"\uFF08\u5B89\u88C5\u65F6\u81EA\u52A8\u79FB\u52A8\u5230\u672C agent \u63D2\u4EF6\u4F4D\u7F6E\u540E\u52A0\u8F7D\uFF09'},config:{type:"object",description:"install \u65F6\u63D2\u4EF6 userConfig \u58F0\u660E\u7684\u914D\u7F6E\u503C\uFF08\u952E\u503C\u5BF9\uFF09",additionalProperties:{type:"string"}}},required:["action"],additionalProperties:!1},$e=new Set(["install","uninstall","reload","enable","disable","list"]);function ee(){const l=fe();return l&&l!=="unknown"?l:void 0}function Ee(){return oe(new URL("./builtin-commands/",import.meta.url))}const ke=200,R=256*1024,Ae=4*1024,te=6e4,q=6e4,be=/^[a-zA-Z0-9_][a-zA-Z0-9_-]*$/,z=/^[a-z0-9][a-z0-9-]*$/,De=["system.","aws-","acode-"],Le=new Set(["NODE_OPTIONS","NODE_PATH","NODE_EXTRA_CA_CERTS","NODE_REPL_HISTORY","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","PYTHONPATH","PYTHONSTARTUP","PYTHONHOME","PERL5LIB","PERL5OPT","RUBYOPT","RUBYLIB","BASH_ENV","ENV","SHELLOPTS","BASHOPTS","IFS","PS1","PS4","GIT_SSH","GIT_SSH_COMMAND","GIT_CONFIG","GIT_CONFIG_GLOBAL","PATH","HOME","USERPROFILE","SYSTEMROOT","COMSPEC","TEMP","TMP","LANG","TZ"]),Oe=/^[A-Za-z_][A-Za-z0-9_]*$/,Te=process.platform==="win32"?"junction":"dir",Ne=/[^\x20-\x7E]/,Ie=6e4,G=20,ne=80;function P(l){return typeof l=="object"&&l!==null&&!Array.isArray(l)}function I(l,e){let t=l;for(const n of e.split(".")){if(!P(t))return;t=t[n]}return t}function A(l,e){return l.length<=e?l:`${l.slice(0,e)}\u2026(\u622A\u65AD,\u5171 ${l.length} \u5B57\u7B26)`}async function C(l,e=8,t=200){for(let n=0;;n++)try{E(l,{recursive:!0,force:!0});return}catch(r){if(n>=e-1)throw r;await new Promise(i=>setTimeout(i,t))}}async function re(l,e){D(J(e),{recursive:!0});try{H(l,e);return}catch(t){const n=t?.code;if(!n||!["EXDEV","EPERM","EACCES","EBUSY","EINVAL"].includes(n))throw t}F(l,e,{recursive:!0,filter:t=>!/[\\/]\.git([\\/]|$)/.test(t)&&!/[\\/]node_modules([\\/]|$)/.test(t)}),await C(l)}function b(l,e){l.logs.push(`${new Date().toISOString()} ${e}`),l.logs.length>ke&&l.logs.shift()}function B(l,e,t="params"){if(!P(l))return[];const n=[],r=l.type;if(typeof r=="string"&&!Ce(r,e))return[`${t}: \u671F\u671B ${r}\uFF0C\u5B9E\u9645 ${Re(e)}`];if(Array.isArray(l.enum)&&l.enum.length>0&&(l.enum.some(s=>JSON.stringify(s)===JSON.stringify(e))||n.push(`${t}: \u503C ${JSON.stringify(e)} \u4E0D\u5728\u679A\u4E3E ${JSON.stringify(l.enum)} \u5185`)),r==="object"&&P(e)){const i=P(l.properties)?l.properties:{},s=Array.isArray(l.required)?l.required:[];for(const o of s)(!(o in e)||e[o]===void 0)&&n.push(`${t}.${o}: \u5FC5\u586B\u53C2\u6570\u7F3A\u5931`);for(const[o,a]of Object.entries(i))o in e&&e[o]!==void 0&&n.push(...B(a,e[o],`${t}.${o}`));if(l.additionalProperties===!1)for(const o of Object.keys(e))o in i||n.push(`${t}.${o}: \u4E0D\u5141\u8BB8\u7684\u672A\u77E5\u53C2\u6570\uFF08schema additionalProperties=false\uFF09`)}return r==="array"&&Array.isArray(e)&&P(l.items)&&e.forEach((i,s)=>{n.push(...B(l.items,i,`${t}[${s}]`))}),n}function Ce(l,e){switch(l){case"string":return typeof e=="string";case"number":return typeof e=="number"&&Number.isFinite(e);case"boolean":return typeof e=="boolean";case"object":return P(e);case"array":return Array.isArray(e);case"null":return e===null;default:return!0}}function Re(l){return l===null?"null":Array.isArray(l)?"array":typeof l}class Me{constructor(e={}){this.agents=new Map,this.moduleNonce=0,this.templatePullInFlight=new Set,this.backgroundTemplatePulls=new Set,this.rootDir=e.rootDir??de(),this.runtimeRootDir=e.runtimeRootDir}forAgent(e){return{listPlugins:()=>this.list(e),getCatalog:()=>this.getCatalog(e),getToolSchema:t=>this.getToolSchema(e,t),invokeTool:(t,n,r,i)=>this.invokeTool(e,t,n,r,i),manage:t=>this.manage(e,t),getCommandDirs:()=>this.getCommandDirs(e)}}setOnPluginsChanged(e){this.onPluginsChanged=e}notifyPluginsChanged(e){try{this.onPluginsChanged?.(e)}catch(t){f.warn("[agent:%s] onPluginsChanged \u56DE\u8C03\u5931\u8D25: %s",e,t instanceof Error?t.message:String(t))}}async getCommandDirs(e){return[...(await this.hydrate(e)).plugins.values()].filter(n=>n.enabled&&n.commandDir).map(n=>n.commandDir)}async getPluginCommands(e){const t=await this.hydrate(e),n=[];n.push(...this.parseCommandDir($,Ee()));for(const r of t.plugins.values())!r.enabled||!r.commandDir||n.push(...this.parsePluginCommandDir(r));return n}parsePluginCommandDir(e){return this.parseCommandDir(e.name,e.commandDir)}parseCommandDir(e,t){const n=[];if(!t)return n;try{for(const r of j(t)){if(!r.endsWith(".md"))continue;const i=m(t,r);try{const s=le(i,k(i,"utf8"));s.plugin=e,n.push(s)}catch(s){f.warn("[plugin:%s] \u547D\u4EE4\u89E3\u6790\u5931\u8D25 %s: %s",e,r,s instanceof Error?s.message:String(s))}}}catch{}return n}async list(e){const t=await this.hydrate(e),n=new Map;for(const r of t.plugins.values()){const i=this.toSummary(r);n.set(i.name,i)}n.has($)||n.set($,{name:$,version:ee(),description:X,status:"enabled",enabled:!0,source:"builtin",installedAt:new Date().toISOString(),toolCount:1,tools:[{name:"plugin-manager.manage",description:"\u63D2\u4EF6\u751F\u547D\u5468\u671F\u7BA1\u7406\uFF08install/uninstall/reload/disable/enable/list\uFF09"}],listeners:[],builtin:!0});for(const r of this.readSharedManifest()){const i=r.pluginName;if(!this.deployedPluginHealthy(i))continue;const o=n.get(i);if(o){String(o.source||"").startsWith("shared:")&&(o.enabled=this.effectiveSharedEnabled(e,r));continue}n.set(i,{name:i,version:this.deployedPluginVersion(i),status:"enabled",enabled:this.effectiveSharedEnabled(e,r),source:`shared:${r.fileName??`${i}.zip`}`,installedAt:new Date().toISOString(),toolCount:0,listeners:[]})}return[...n.values()].sort((r,i)=>r.name.localeCompare(i.name))}deployedPluginVersion(e){try{const t=JSON.parse(k(m(this.deployedPluginDir(e),"plugin.json"),"utf8"));return typeof t.version=="string"?t.version:void 0}catch{return}}async getCatalog(e){const t=await this.hydrate(e),n=[];for(const r of t.plugins.values()){if(!r.enabled||r.status==="error")continue;const i=r.tools.slice(0,G).map(s=>({name:s.name,description:A(s.title||s.description,ne),requiredParams:this.requiredParamsOf(s)}));r.tools.length>G&&i.push({name:`(\u53E6\u6709 ${r.tools.length-G} \u4E2A\u5DE5\u5177\u672A\u5217\u51FA)`,description:'\u7528 function_call {action:"catalog"} \u67E5\u770B\u5168\u91CF',requiredParams:void 0}),n.push({plugin:r.name,version:r.version,description:r.description,status:r.status,tools:i})}return n.push({plugin:$,version:ee(),description:X,status:"enabled",tools:[{name:"manage",description:A(Q,ne),requiredParams:["action"]}]}),{revision:t.catalogRevision,plugins:n}}async getToolSchema(e,t){const n=ue(t);if(!n)return null;if(n.plugin===$&&n.tool==="manage")return{plugin:$,name:"manage",description:Q,inputSchema:Pe};const i=(await this.hydrate(e)).plugins.get(n.plugin);if(!i||!i.enabled)return null;const s=i.tools.find(o=>o.name===n.tool);return s?{plugin:i.name,name:s.name,title:s.title,description:s.description,inputSchema:s.inputSchema??{type:"object",properties:{}}}:null}async invokeTool(e,t,n,r,i){if(t===$&&n==="manage"){const u=this.buildManageRequest(r);if(!u)return{ok:!1,error:"plugin-manager.manage \u7F3A\u5C11 action"};const c=await this.manage(e,u);if(!c.ok)return{ok:!1,error:c.error??"\u63D2\u4EF6\u7BA1\u7406\u64CD\u4F5C\u5931\u8D25"};const d={ok:!0};return c.plugins&&(d.plugins=c.plugins),c.summary&&(d.summary=c.summary),{ok:!0,result:d}}const s=await this.hydrate(e),o=s.plugins.get(t);if(!o)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\uFF08\u53EF\u7528\u63D2\u4EF6: ${[...s.plugins.keys()].join(", ")||"\u65E0"}\uFF09`};if(!o.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u5DF2\u505C\u7528\uFF0C\u53EF\u8BA9\u7528\u6237\u5728\u9762\u677F\u6216\u7528 plugin-manager.manage enable \u542F\u7528`};const a=o.tools.find(u=>u.name===n);if(!a)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5DE5\u5177 ${n}\uFF08\u53EF\u7528: ${o.tools.map(u=>u.name).join(", ")||"\u65E0"}\uFF09`};if(a.inputSchema){const u=B(a.inputSchema,r);if(u.length>0)return{ok:!1,error:`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${u.join("; ")}`,inputSchema:a.inputSchema}}return this.executeHandler(e,o,a,r,i)}buildManageRequest(e){const t=e.action;if(typeof t!="string"||!$e.has(t))return null;const n={action:t};if(typeof e.name=="string"&&e.name.trim()&&(n.name=e.name.trim()),typeof e.source=="string"&&e.source.trim()&&(n.source=e.source.trim()),e.config&&typeof e.config=="object"&&!Array.isArray(e.config)){const r={};for(const[i,s]of Object.entries(e.config))typeof s=="string"&&(r[i]=s);n.config=r}return n}async executeHandler(e,t,n,r,i){const s=Date.now(),o=n.handler??{type:"process"};try{return o.type==="mcp"?{ok:!1,error:"handler.type=mcp \u5C06\u5728\u540E\u7EED\u7248\u672C\u652F\u6301\uFF0C\u8BF7\u6539\u7528 process/module handler"}:o.type==="module"?{ok:!0,result:await this.invokeModuleHandler(t,o,r,e,i),durationMs:Date.now()-s}:!o.command||!o.command.trim()?{ok:!1,error:`\u5DE5\u5177 ${n.name} \u7684 process handler \u7F3A\u5C11 command`}:{ok:!0,result:await this.invokeProcessHandler(t,o,r,e,i),durationMs:Date.now()-s}}catch(a){return{ok:!1,error:a instanceof Error?a.message:String(a),durationMs:Date.now()-s}}}async invokeProcessHandler(e,t,n,r,i){const s=Y(t.command??"",{params:n});if(s.length===0)throw new Error("process handler command \u4E3A\u7A7A");const o=typeof t.timeoutMs=="number"&&t.timeoutMs>0?t.timeoutMs:te,a=new AbortController,u=()=>a.abort();i?.signal?.addEventListener("abort",u,{once:!0});const c=setTimeout(()=>a.abort(),o);try{return await new Promise((d,y)=>{f.info("[plugin:%s] spawn: %s",e.name,s.join(" "));const h=_(s[0],s.slice(1),{cwd:e.dir,env:this.buildPluginEnv(e,r),shell:t.shell===!0,windowsHide:!0,signal:a.signal});let g="",p="";h.stdin?.on("error",()=>{}),h.stdout?.on("data",v=>{g.length<R&&(g+=v.toString("utf8"))}),h.stderr?.on("data",v=>{p.length<R&&(p+=v.toString("utf8"))}),h.on("error",v=>{y(new Error(`\u63D2\u4EF6\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${v.message}`))}),h.on("close",v=>{const L=g.trim();if(v!==0){const O=A(p.trim()||L||"(\u65E0\u8F93\u51FA)",600);y(new Error(a.signal.aborted?`\u63D2\u4EF6\u8FDB\u7A0B\u8D85\u65F6(${o}ms)\u6216\u88AB\u4E2D\u6B62`:`\u63D2\u4EF6\u8FDB\u7A0B\u9000\u51FA\u7801 ${v}: ${O}`));return}if(!L){d({ok:!0});return}try{d(JSON.parse(L))}catch{d(L)}});try{t.stdin==="params"?h.stdin?.end(`${JSON.stringify(n)}
|
|
7
|
+
`):h.stdin?.end()}catch{}})}finally{clearTimeout(c),i?.signal?.removeEventListener("abort",u)}}async invokeModuleHandler(e,t,n,r,i){if(!t.module)throw new Error("module handler \u7F3A\u5C11 module \u8DEF\u5F84");const s=m(e.dir,t.module);let o=e.moduleCache.get(s);o||(o=await import(`${ae(s).href}?acode_nonce=${e.importNonce}`),e.moduleCache.set(s,o));const a=t.export||"default",c=o[a];if(typeof c!="function")throw new Error(`\u6A21\u5757 ${t.module} \u672A\u5BFC\u51FA\u51FD\u6570 ${a}`);const d=typeof t.timeoutMs=="number"&&t.timeoutMs>0?t.timeoutMs:te;let y;const h=Promise.resolve().then(()=>c(n,{agentId:r,signal:i?.signal,pluginRoot:e.dir}));try{return await Promise.race([h,new Promise((g,p)=>{y=setTimeout(()=>p(new Error(`\u63D2\u4EF6\u6A21\u5757\u6267\u884C\u8D85\u65F6(${d}ms)`)),d)})])}finally{clearTimeout(y)}}buildPluginEnv(e,t){const n={};for(const i of["PATH","HOME","USERPROFILE","SystemRoot","COMSPEC","TEMP","TMP","LANG","TZ"]){const s=process.env[i];s!==void 0&&(n[i]=s)}n.ACODE_PLUGIN_ROOT=e.dir,n.ACODE_AGENT_ID=t,n.ACODE_PLUGIN_NAME=e.name;const r=new Set((e.userConfig??[]).map(i=>i.key));for(const[i,s]of Object.entries(e.configValues))r.has(i)&&(!Oe.test(i)||Le.has(i.toUpperCase())||(n[i]=s));return n}async manage(e,t){const n=this.agentState(e),r=n.queue.then(async()=>{const i=await this.hydrate(e);return this.doManage(i,t)});return n.queue=r.catch(()=>{}),r}async doManage(e,t){if(t.name===$&&(t.action==="uninstall"||t.action==="disable"||t.action==="enable"||t.action==="reload"))return{ok:!1,error:`\u5185\u7F6E\u7CFB\u7EDF\u63D2\u4EF6 ${$} \u4E0D\u53EF${t.action==="uninstall"?"\u5378\u8F7D":t.action==="reload"?"\u91CD\u8F7D":"\u505C\u7528/\u542F\u7528"}`};switch(t.action){case"list":return{ok:!0,plugins:await this.list(e.agentId)};case"install":return this.installPlugin(e,t);case"uninstall":return this.uninstallPlugin(e,t);case"reload":return this.reloadPlugin(e,t);case"enable":case"disable":return this.setEnabled(e,t,t.action==="enable");default:return{ok:!1,error:`\u672A\u77E5 action: ${String(t.action)}`}}}async installPlugin(e,t){const n=(t.source??"").trim();if(!n)return{ok:!1,error:"install \u9700\u8981 source\uFF08\u5F53\u524D\u652F\u6301 local:<\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>\uFF09"};const r=n.split(":",1)[0];if(r!=="local")return{ok:!1,error:`\u6682\u4E0D\u652F\u6301\u63D2\u4EF6\u6765\u6E90 "${r}:"\uFF08npm:/git: \u5728\u8DEF\u7EBF\u56FE\u4E2D\uFF1Bzip \u5305\u8BF7\u7528\u9762\u677F\u5BFC\u5165\u6216 POST /runtime/plugins/:agentId/upload\uFF09`};const i=n.slice(6).trim();return!i||!w(m(i,"plugin.json"))?{ok:!1,error:`\u63D2\u4EF6\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u7F3A\u5C11 plugin.json: ${i}`}:this.installFromDirectory(e,i,n,t.config)}async installFromZip(e,t,n,r){if(!t||t.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};const i=this.agentState(e),s=i.queue.then(async()=>{await this.hydrate(e);const o=m(this.rootDir,"tmp",`upload-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const a=await x(t,o);return w(m(a.pluginDir,"plugin.json"))?(f.info("[agent:%s] zip \u5BFC\u5165: %s\uFF08%d \u4E2A\u6587\u4EF6\uFF09",e,n,a.fileCount),await this.installFromDirectory(i,a.pluginDir,`upload:${n}`,r)):{ok:!1,error:"zip \u5185\u672A\u627E\u5230 plugin.json\uFF08\u8BF7\u6253\u5305\u63D2\u4EF6\u76EE\u5F55\uFF0C\u4E14 zip \u5185\u8DEF\u5F84\u4F7F\u7528\u82F1\u6587\uFF09"}}catch(a){const u=a instanceof Error?a.message:String(a);return f.warn("[agent:%s] zip \u5BFC\u5165\u5931\u8D25: %s",e,u),{ok:!1,error:`zip \u5BFC\u5165\u5931\u8D25: ${u}`}}finally{await C(o,3,100).catch(()=>{})}});return i.queue=s.catch(()=>{}),s}async installFromDirectory(e,t,n,r){const i=this.loadManifestOnly(t);if(!i.ok)return i;const s=i.manifest,o=s.name;if(o===$)return{ok:!1,error:`\u63D2\u4EF6\u540D ${o} \u4E3A\u7CFB\u7EDF\u4FDD\u7559\u540D\u79F0\uFF0C\u4E0D\u5141\u8BB8\u5B89\u88C5\u540C\u540D\u63D2\u4EF6`};const a=this.validateUserConfigValues(s,r??{});if(a)return{ok:!1,error:a};const u=this.loadPluginFromDir(e,t,n,new Date().toISOString(),r??{});if(!u.ok)return f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u6821\u9A8C\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,u.error),u;const c=m(this.rootDir,"cache",N(e.agentId),o),d=t===c,y=e.plugins.get(o);if(y&&this.stopAllListeners(y),!d)try{await C(c),await re(t,c)}catch(p){const v=p instanceof Error?p.message:String(p);return f.warn("[agent:%s] \u63D2\u4EF6\u79FB\u52A8\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,v),y&&this.startAllListeners(e,y),{ok:!1,error:`\u63D2\u4EF6\u79FB\u52A8\u5931\u8D25: ${v}`}}const h=this.loadPluginFromDir(e,c,n,new Date().toISOString(),r??{});if(!h.ok){if(f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,h.error),!d)try{await re(c,t)}catch(p){f.warn("[agent:%s] \u88C5\u8F7D\u5931\u8D25\u540E\u65E0\u6CD5\u79FB\u56DE\u6E90\u76EE\u5F55\uFF08%s\uFF09\uFF0C\u5DF2\u4FDD\u7559\u7F13\u5B58\u526F\u672C",e.agentId,p instanceof Error?p.message:String(p))}if(y)try{this.startAllListeners(e,y)}catch(p){f.warn("[agent:%s] \u6062\u590D\u65E7\u5B9E\u4F8B\u76D1\u542C\u5931\u8D25: %s",e.agentId,p instanceof Error?p.message:String(p))}return h}const g=h.plugin;return e.plugins.set(g.name,g),this.bumpCatalogRevision(e),this.persistInstalled(e),this.startAllListeners(e,g),f.info("[agent:%s] \u63D2\u4EF6\u5DF2\u5B89\u88C5: %s@%s",e.agentId,g.name,g.version??"?"),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(g)}}async uninstallPlugin(e,t){const n=(t.name??"").trim(),r=e.plugins.get(n);return r?(this.stopAllListeners(r),e.plugins.delete(n),this.bumpCatalogRevision(e),this.readSharedManifest().some(s=>s.pluginName===n)&&this.removeRuntimeLink(e.agentId,n),this.persistInstalled(e),await C(r.dir),f.info("[agent:%s] \u63D2\u4EF6\u5DF2\u5378\u8F7D: %s",e.agentId,n),this.notifyPluginsChanged(e.agentId),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${n} \u672A\u5B89\u88C5`}}async reloadPlugin(e,t){const n=(t.name??"").trim(),r=e.plugins.get(n);if(!r)return{ok:!1,error:`\u63D2\u4EF6 ${n} \u672A\u5B89\u88C5`};const i=this.loadPluginFromDir(e,r.dir,r.source,r.installedAt,r.configValues);if(!i.ok)return{ok:!1,error:`\u91CD\u8F7D\u5931\u8D25\uFF08\u4FDD\u7559\u65E7\u7248\u672C\u8FD0\u884C\uFF09: ${i.error}`};const s=i.plugin;return this.stopAllListeners(r),e.plugins.set(n,s),this.bumpCatalogRevision(e),this.persistInstalled(e),this.startAllListeners(e,s),f.info("[agent:%s] \u63D2\u4EF6\u5DF2\u91CD\u8F7D: %s",e.agentId,n),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(s)}}async setEnabled(e,t,n){const r=(t.name??"").trim(),i=e.plugins.get(r);return i?(i.enabled=n,this.bumpCatalogRevision(e),n?this.startAllListeners(e,i):this.stopAllListeners(i),this.persistInstalled(e),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(i)}):{ok:!1,error:`\u63D2\u4EF6 ${r} \u672A\u5B89\u88C5`}}deployedDir(){return m(this.rootDir,"deployed")}deployedManifestFile(){return m(this.deployedDir(),"manifest.json")}deployedPluginDir(e){if(!V(e))throw new Error(`\u975E\u6CD5\u63D2\u4EF6\u540D\uFF08\u4EC5\u5141\u8BB8 ${z}\uFF09: ${JSON.stringify(e)}`);const t=m(this.deployedDir(),e),n=Z(this.deployedDir());if(Z(t)!==m(n,e))throw new Error(`\u63D2\u4EF6\u76EE\u5F55\u8D8A\u51FA\u90E8\u7F72\u533A: ${e}`);return t}legacySharedDir(){return m(this.rootDir,"shared")}readSharedManifest(){try{const e=JSON.parse(k(this.deployedManifestFile(),"utf8"));return Array.isArray(e.plugins)?e.plugins.filter(t=>t&&V(t.pluginName)):[]}catch{return[]}}writeSharedManifest(e){D(this.deployedDir(),{recursive:!0}),U(this.deployedManifestFile(),`${JSON.stringify({version:2,plugins:e},null,2)}
|
|
8
|
+
`,"utf8")}async migrateLegacySharedIfNeeded(){try{if(w(this.deployedManifestFile()))return;const e=m(this.legacySharedDir(),"manifest.json");if(!w(e))return;const t=JSON.parse(k(e,"utf8")),n=Array.isArray(t.plugins)?t.plugins:[];if(n.length===0)return;const r=[];for(const i of n){const s=m(this.legacySharedDir(),i.zipFile);if(!(!i.pluginName||!w(s)))try{const o=await this.deployPluginZipToPersistentDir(k(s),i.pluginName);if(!o)continue;r.push(o),f.info("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u5230\u90E8\u7F72\u533A: %s",i.pluginName)}catch(o){f.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6 %s \u8FC1\u79FB\u5931\u8D25: %s",i.pluginName,o instanceof Error?o.message:String(o))}}r.length>0&&this.writeSharedManifest(r),E(this.legacySharedDir(),{recursive:!0,force:!0})}catch(e){f.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u672A\u6267\u884C\uFF08\u4E0B\u6B21\u91CD\u8BD5\uFF09: %s",e instanceof Error?e.message:String(e))}}deployedPluginHealthy(e){return w(m(this.deployedPluginDir(e),"plugin.json"))}runtimeDirFor(e){return this.runtimeRootDir?m(this.runtimeRootDir,N(e)):ce(e)}runtimeLinkPath(e,t){return m(this.runtimeDirFor(e),t)}ensureRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t),r=this.deployedPluginDir(t);if(!w(m(r,"plugin.json")))return!1;D(this.runtimeDirFor(e),{recursive:!0});try{if(w(n)){let i=!1;try{i=ie(n).isSymbolicLink()}catch{i=!1}if(i)try{return j(n),!0}catch{}E(n,{recursive:!0,force:!0})}return se(r,n,Te),f.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u5EFA\u7ACB: %s \u2192 %s",e,n,r),!0}catch(i){return f.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5931\u8D25\uFF08%s \u2192 %s\uFF09: %s",e,t,r,i instanceof Error?i.message:String(i)),!1}}removeRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t);try{w(n)&&(E(n,{recursive:!0,force:!0}),f.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u79FB\u9664: %s",e,t))}catch(r){f.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u79FB\u9664\u5931\u8D25\uFF08%s\uFF09: %s",e,t,r instanceof Error?r.message:String(r))}}async saveSharedPlugin(e,t,n=!0,r){if(!e||e.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};await this.migrateLegacySharedIfNeeded();const i=m(this.rootDir,"tmp",`deploy-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const s=await x(e,i),o=this.loadManifestOnly(s.pluginDir);if(!o.ok)return o;const a=o.manifest.name,u=this.readSharedManifest().find(g=>g.pluginName===a);if(u&&u.sha256===r&&this.deployedPluginHealthy(a))return{ok:!0,pluginName:a};await this.suspendDeployedPluginAcrossAgents(a),D(this.deployedDir(),{recursive:!0});const c=this.deployedPluginDir(a),d=m(this.deployedDir(),`.old-${a}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);if(w(c))try{H(c,d)}catch{E(c,{recursive:!0,force:!0})}try{F(s.pluginDir,c,{recursive:!0,filter:g=>!/[\\/]\.git([\\/]|$)/.test(g)&&!/[\\/]node_modules([\\/]|$)/.test(g)})}catch(g){throw w(d)&&(E(c,{recursive:!0,force:!0}),H(d,c)),g}w(d)&&E(d,{recursive:!0,force:!0}),await W(this.deployedManifestFile(),async()=>{const g=this.readSharedManifest().filter(p=>p.pluginName!==a);g.push({pluginName:a,zipFile:u?.zipFile??`${a}.zip`,fileName:t,defaultEnabled:n,sha256:r}),this.writeSharedManifest(g)}),f.info("[shared] \u63D2\u4EF6\u5DF2\u90E8\u7F72\u5230 bridge: %s\uFF08\u6765\u6E90 %s%s\uFF09",a,t,r?`, sha256=${r.slice(0,12)}\u2026`:"");const h=(await this.applySharedToKnownAgents()).find(g=>g.installed.includes(a));return h&&f.info("[shared] \u5DF2\u540C\u6B65\u5230\u8FD0\u884C\u4E2D agent: %s",h.agentId),{ok:!0,pluginName:a}}catch(s){const o=s instanceof Error?s.message:String(s);return f.warn("[shared] \u63D2\u4EF6\u90E8\u7F72\u5931\u8D25\uFF08%s\uFF09: %s",t,o),{ok:!1,error:`\u63D2\u4EF6\u90E8\u7F72\u5931\u8D25: ${o}`}}finally{await C(i,3,100).catch(()=>{})}}async deployPluginZipToPersistentDir(e,t){if(!e||e.length===0)return null;const n=m(this.rootDir,"tmp",`migrate-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const r=await x(e,n),i=this.loadManifestOnly(r.pluginDir);if(!i.ok)return null;const s=i.manifest.name;if(t&&s!==t)return null;D(this.deployedDir(),{recursive:!0});const o=this.deployedPluginDir(s);return w(o)&&E(o,{recursive:!0,force:!0}),F(r.pluginDir,o,{recursive:!0,filter:a=>!/[\\/]\.git([\\/]|$)/.test(a)&&!/[\\/]node_modules([\\/]|$)/.test(a)}),{pluginName:s,zipFile:`${s}.zip`,fileName:`${s}.zip`,defaultEnabled:!0}}finally{E(n,{recursive:!0,force:!0})}}async suspendDeployedPluginAcrossAgents(e){for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const n=t.queue.then(async()=>{const r=t.plugins.get(e);r&&(this.stopAllListeners(r),t.plugins.delete(e),this.bumpCatalogRevision(t),f.info("[agent:%s] \u5DF2\u6458\u9664\u63D2\u4EF6\u7B49\u5F85\u90E8\u7F72\u533A\u66F4\u65B0: %s",t.agentId,e))});t.queue=n.catch(()=>{}),await n}}async applySharedToKnownAgents(){const e=[];for(const t of this.agents.values()){if(!t.hydrated)continue;const n=await this.syncSharedIntoStateQueued(t);n.length>0&&e.push({agentId:t.agentId,installed:n})}return e}async syncSharedIntoStateQueued(e){const t=e.queue.then(()=>this.syncSharedIntoState(e));return e.queue=t.catch(()=>[]),t}effectiveSharedEnabled(e,t){return Se(e,"plugins",t.pluginName)&&(t.defaultEnabled??!0)}async pullTemplatePluginsFromCapabilities(e){const t=we(e.agentId);if(!t)return;const n=this.readSharedManifest();for(const[r,i]of Object.entries(t)){if(!i.url)continue;const s=n.find(a=>a.pluginName===r);if(!s||!s.sha256||s.sha256===i.sha256&&this.deployedPluginHealthy(r)||this.templatePullInFlight.has(r))continue;this.templatePullInFlight.add(r);const o=m(this.rootDir,"tmp",`pull-${N(e.agentId)}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{D(o,{recursive:!0});let a=`${r}.zip`;try{const y=decodeURIComponent(i.url.split("/").pop()||"");y.toLowerCase().endsWith(".zip")&&(a=pe(y,`${r}.zip`))}catch{}const u=await ge({downloadUrl:i.url,fileName:a,sha256:i.sha256},o);if(!u)continue;const c=k(u.outputPath),d=await this.saveSharedPlugin(c,u.fileName,s.defaultEnabled??!0,i.sha256);d.ok?f.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u81EA\u52A8\u5BF9\u8D26\u66F4\u65B0\u6210\u529F: %s",e.agentId,d.pluginName??r):f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u66F4\u65B0\u5931\u8D25: %s: %s",e.agentId,r,d.error)}catch(a){f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6 %s \u66F4\u65B0\u5931\u8D25: %s",e.agentId,r,a instanceof Error?a.message:String(a))}finally{this.templatePullInFlight.delete(r),await C(o,3,100).catch(()=>{})}}}queueTemplatePull(e){this.backgroundTemplatePulls.has(e.agentId)||(this.backgroundTemplatePulls.add(e.agentId),this.pullTemplatePluginsFromCapabilities(e).catch(t=>{f.warn("[agent:%s] \u540E\u53F0\u63D2\u4EF6\u5BF9\u8D26\u66F4\u65B0\u5931\u8D25: %s",e.agentId,t instanceof Error?t.message:String(t))}).finally(()=>{this.backgroundTemplatePulls.delete(e.agentId)}))}async syncSharedIntoState(e){this.queueTemplatePull(e);const t=this.readSharedManifest(),n=new Set,r=[];let i=0;for(const s of t)if(n.add(s.pluginName),this.effectiveSharedEnabled(e.agentId,s)){const a=e.plugins.get(s.pluginName);if(!this.ensureRuntimeLink(e.agentId,s.pluginName))continue;const u=this.runtimeLinkPath(e.agentId,s.pluginName);if(!a){const c=this.loadPluginFromDir(e,u,`shared:${s.fileName}`,new Date().toISOString(),{});c.ok?(e.plugins.set(c.plugin.name,c.plugin),r.push(c.plugin.name),f.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u5DF2\u6309\u5F00\u542F\u6001\u52A0\u8F7D: %s",e.agentId,s.pluginName)):f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25: %s: %s",e.agentId,s.pluginName,c.error)}}else{const a=e.plugins.get(s.pluginName);a&&(this.stopAllListeners(a),e.plugins.delete(s.pluginName),i++),this.removeRuntimeLink(e.agentId,s.pluginName)}return this.cleanupRuntimeDir(e,n),(r.length>0||i>0)&&this.bumpCatalogRevision(e),this.persistInstalled(e),r}cleanupRuntimeDir(e,t){const n=this.runtimeDirFor(e.agentId);try{if(!w(n))return;const r=new Set(t);for(const i of j(n))!r.has(i)&&!e.plugins.has(i)&&this.removeRuntimeLink(e.agentId,i)}catch{}}async applyCapabilities(e){const t=await this.hydrate(e);await this.pullTemplatePluginsFromCapabilities(t),await this.syncSharedIntoState(t)}async drainEvents(e,t={}){const n=await this.hydrate(e);this.ensureListenersRunning(n);const r=n.buffer.drain(t),i=await this.getCatalog(e);return{revision:r.revision,events:r.events,catalog:i,compactionSeq:n.compactionSeq}}markAgentCompacted(e){const t=this.agentState(e);t.compactionSeq++,f.debug("[agent:%s] \u4E0A\u4E0B\u6587\u538B\u7F29\u6807\u8BB0: compactionSeq=%d",e,t.compactionSeq)}async enqueueExternalEvent(e,t,n){const r=await this.hydrate(e),i=r.plugins.get(t);if(!i||!i.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\u6216\u5DF2\u505C\u7528`};const s=typeof n.event=="string"?n.event:"",o=i.listeners.find(a=>a.transport.type==="http-callback"&&(!s||a.event===s));return o?(this.enqueueEvent(r,i,o,n),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5339\u914D\u7684 http-callback \u76D1\u542C\u5668\uFF08event=${s||"(\u7A7A)"}\uFF09`}}bumpCatalogRevision(e){e.catalogRevision++}agentState(e){let t=this.agents.get(e);return t||(t={agentId:e,plugins:new Map,buffer:new ve(e),hydrated:!1,queue:Promise.resolve(),catalogRevision:0,eventSeq:0,compactionSeq:0},this.agents.set(e,t)),t}async hydrate(e){const t=this.agentState(e);return t.hydratePromise||(t.hydratePromise=this.doHydrate(t).catch(n=>{throw t.hydratePromise=void 0,n})),await t.hydratePromise,t}async doHydrate(e){const t=e.agentId;await this.migrateLegacySharedIfNeeded();const n=this.installedFile(t);if(!w(n)){await this.syncSharedIntoState(e).catch(()=>{}),e.hydrated=!0;return}try{const r=JSON.parse(k(n,"utf8")),i=this.readSecrets(t);for(const s of r.plugins??[]){if(String(s.source||"").startsWith("shared:"))continue;const a=m(this.rootDir,"cache",N(t),s.name);if(!w(m(a,"plugin.json"))){f.warn("[agent:%s] \u5DF2\u5B89\u88C5\u63D2\u4EF6\u76EE\u5F55\u7F3A\u5931\uFF0C\u8DF3\u8FC7: %s",t,s.name);continue}const u={...s.config,...i[s.name]??{}},c=this.loadPluginFromDir(e,a,s.source,s.installedAt,u);if(c.ok){const d=c.plugin;d.enabled=s.enabled,e.plugins.set(d.name,d)}else f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25: %s: %s",t,s.name,c.error)}}catch(r){const i=r instanceof Error?r.message:String(r);f.error("[agent:%s] installed.json \u89E3\u6790\u5931\u8D25: %s",t,i)}await this.syncSharedIntoState(e).catch(r=>{f.warn("[agent:%s] \u5171\u4EAB\u63D2\u4EF6\u540C\u6B65\u5931\u8D25: %s",t,r instanceof Error?r.message:String(r))}),e.hydrated=!0}installedFile(e){return m(this.rootDir,"agents",N(e),"installed.json")}persistInstalled(e){this.persistSecrets(e);const t=this.installedFile(e.agentId);D(J(t),{recursive:!0});const n=[...e.plugins.values()].map(r=>({name:r.name,source:r.source,installedAt:r.installedAt,enabled:r.enabled,config:this.stripSensitiveValues(r)}));U(t,`${JSON.stringify({version:1,plugins:n},null,2)}
|
|
9
|
+
`,"utf8")}sensitiveKeysOf(e){return(e.userConfig??[]).filter(t=>t?.sensitive===!0&&typeof t.key=="string").map(t=>t.key)}stripSensitiveValues(e){const t=new Set(this.sensitiveKeysOf(e)),n={};for(const[r,i]of Object.entries(e.configValues))t.has(r)||(n[r]=i);return n}secretsFile(e){return m(this.rootDir,"agents",N(e),"secrets.json")}readSecrets(e){try{const t=JSON.parse(k(this.secretsFile(e),"utf8"));if(!P(t)||!P(t.secrets))return{};const n={};for(const[r,i]of Object.entries(t.secrets)){if(!P(i))continue;const s={};for(const[o,a]of Object.entries(i))typeof a=="string"&&(s[o]=a);n[r]=s}return n}catch{return{}}}persistSecrets(e){const t={};for(const r of e.plugins.values()){const i={};for(const s of this.sensitiveKeysOf(r)){const o=r.configValues[s];typeof o=="string"&&o.length>0&&(i[s]=o)}Object.keys(i).length>0&&(t[r.name]=i)}const n=this.secretsFile(e.agentId);if(Object.keys(t).length===0){try{E(n,{force:!0})}catch{}return}D(J(n),{recursive:!0}),U(n,`${JSON.stringify({version:1,secrets:t},null,2)}
|
|
10
|
+
`,{encoding:"utf8",mode:384})}readJsonFile(e){if(!w(e))return{ok:!0,data:{}};try{const t=JSON.parse(k(e,"utf8"));return P(t)?{ok:!0,data:t}:{ok:!1,error:`${e}: \u6839\u8282\u70B9\u987B\u4E3A\u5BF9\u8C61`}}catch(t){const n=t instanceof Error?t.message:String(t);return{ok:!1,error:`${e}: JSON \u89E3\u6790\u5931\u8D25: ${n}`}}}loadManifestOnly(e){const t=this.readJsonFile(m(e,"plugin.json"));if(!t.ok)return t;const n=t.data,r=_e(n);return r?{ok:!1,error:r}:{ok:!0,manifest:n}}validateUserConfigValues(e,t){const n=Array.isArray(e.userConfig)?e.userConfig:[],r={...t};for(const i of n){if(!i||typeof i.key!="string"||!/^[A-Za-z_][A-Za-z0-9_]*$/.test(i.key))return"plugin.json: userConfig.key \u975E\u6CD5\uFF08\u987B\u4E3A\u73AF\u5883\u53D8\u91CF\u540D\uFF09";if(!(typeof r[i.key]=="string"&&r[i.key].length>0)&&i.required){const o=i.default!==void 0&&typeof i.default=="string"?i.default:"";if(!o)return`\u7F3A\u5C11\u5FC5\u9700\u914D\u7F6E ${i.key}${i.description?`\uFF08${i.description}\uFF09`:""}\uFF0C\u5B89\u88C5\u65F6\u8BF7\u5728 config \u4E2D\u63D0\u4F9B`;r[i.key]=o}}return null}loadPluginFromDir(e,t,n,r,i){const s=this.loadManifestOnly(t);if(!s.ok)return s;const o=s.manifest,a=m(t,o.tools??"tools/tools.json"),u=this.readJsonFile(a);if(!u.ok)return u;const c=[],d=Array.isArray(u.data.tools)?u.data.tools:[];for(const S of d){const T=Fe(S);if(T)return{ok:!1,error:`${o.tools??"tools/tools.json"}: ${T}`};c.push(S)}const y=m(t,o.listeners??"listeners/listeners.json"),h=this.readJsonFile(y);if(!h.ok)return h;const g=[],p=Array.isArray(h.data.listeners)?h.data.listeners:[];for(const S of p){const T=je(S);if(T)return{ok:!1,error:`${o.listeners??"listeners/listeners.json"}: ${T}`};g.push(S)}const v=Array.isArray(o.userConfig)?o.userConfig:[],L=this.validateUserConfigValues(o,i);if(L)return{ok:!1,error:L};const O={...i};for(const S of v){if(!S||typeof S.key!="string")continue;!(typeof O[S.key]=="string"&&O[S.key].length>0)&&S.required&&S.default!==void 0&&typeof S.default=="string"&&(O[S.key]=S.default)}const M=o.commands;let K;if(typeof M=="string"&&M.trim()){const S=m(t,M.trim());w(S)&&(K=S)}return{ok:!0,plugin:{name:o.name,version:typeof o.version=="string"?o.version:void 0,description:typeof o.description=="string"?o.description:void 0,source:n,installedAt:r,dir:t,enabled:!0,tools:c,listeners:g,commandDir:K,userConfig:v,configValues:O,status:"enabled",runtimes:g.map(S=>({def:S,stopping:!1,restarts:0,logs:[]})),moduleCache:new Map,importNonce:++this.moduleNonce}}}ensureListenersRunning(e){for(const t of e.plugins.values())if(t.enabled)for(const n of t.runtimes)!n.child&&!n.timer&&!n.backoffTimer&&!n.stopping&&this.startListener(e,t,n)}startAllListeners(e,t){for(const n of t.runtimes)this.stopListener(n),t.enabled&&this.startListener(e,t,n)}stopAllListeners(e){for(const t of e.runtimes)this.stopListener(t)}startListener(e,t,n){const r=n.def.transport??{type:"command-stream"};if(r.type==="http-callback"){n.stopping=!1;return}if(r.type==="poll-command"){const i=Math.max(5e3,r.intervalMs??3e4);n.stopping=!1,n.timer=setInterval(()=>{this.pollListenerOnce(e,t,n)},i),this.pollListenerOnce(e,t,n);return}if(!r.command){n.lastError="command-stream \u7F3A\u5C11 command",b(n,`ERROR ${n.lastError}`);return}n.stopping=!1,this.spawnListenerChild(e,t,n)}spawnListenerChild(e,t,n){const i=n.def.transport?.command??"",s=Y(i,{});try{b(n,`spawn: ${s.join(" ")}`);const o=_(s[0],s.slice(1),{cwd:t.dir,env:this.buildPluginEnv(t,e.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"]});n.child=o,n.lastError=void 0;let a="";o.stdout?.on("data",u=>{a+=u.toString("utf8");let c=a.indexOf(`
|
|
11
11
|
`);for(;c>=0;){const d=a.slice(0,c).trim();a=a.slice(c+1),d&&this.handleListenerLine(e,t,n,d),c=a.indexOf(`
|
|
12
|
-
`)}a.length>1024*1024&&(a=a.slice(-4096))}),o.stderr?.on("data",u=>{b(n,`stderr: ${A(u.toString("utf8").trimEnd(),400)}`)}),o.on("error",u=>{n.lastError=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${u.message}`,b(n,`ERROR ${n.lastError}`)}),o.on("close",u=>{n.child=void 0,!n.stopping&&(n.lastError=`\u76D1\u542C\u8FDB\u7A0B\u9000\u51FA\uFF08code=${u??"signal"}\uFF09`,b(n,`exit code=${u??"signal"}\uFF0C\u51C6\u5907\u91CD\u542F`),this.scheduleListenerRestart(e,t,n))})}catch(o){const a=o instanceof Error?o.message:String(o);n.lastError=a,b(n,`ERROR spawn: ${a}`),this.scheduleListenerRestart(e,t,n)}}scheduleListenerRestart(e,t,n){if(n.stopping)return;const r=Math.max(500,n.def.transport?.restartBackoffMs??2e3),i=Math.min(
|
|
13
|
-
`)){const c=u.trim();c&&this.handleListenerLine(e,t,n,c)}}catch(a){const u=a instanceof Error?a.message:String(a);n.lastError=u,b(n,`poll \u5931\u8D25: ${u}`)}finally{clearTimeout(o),n.polling=!1}}stopListener(e){if(e.stopping=!0,e.restarts=0,e.child){try{e.child.kill()}catch{}e.child=void 0}e.timer&&(clearInterval(e.timer),e.timer=void 0),e.backoffTimer&&(clearTimeout(e.backoffTimer),e.backoffTimer=void 0)}handleListenerLine(e,t,n,r){b(n,`event: ${A(r,300)}`);let i;try{i=JSON.parse(r)}catch{n.lastError="\u4E8B\u4EF6\u884C\u4E0D\u662F\u5408\u6CD5 JSON\uFF08\u8981\u6C42 JSONL\uFF09";return}if(!P(i))return;const s=typeof i.event=="string"?i.event:n.def.event,o=s===n.def.event?n.def:t.listeners.find(a=>a.event===s);o&&(o.delivery&&o.delivery!=="poll"&&f.debug("[plugin:%s] delivery=%s \u6682\u6309 poll \u4EA4\u4ED8",t.name,o.delivery),this.enqueueEvent(e,t,o,i))}enqueueEvent(e,t,n,r){for(const[y,h]of Object.entries(n.matcher??{})){const
|
|
12
|
+
`)}a.length>1024*1024&&(a=a.slice(-4096))}),o.stderr?.on("data",u=>{b(n,`stderr: ${A(u.toString("utf8").trimEnd(),400)}`)}),o.on("error",u=>{n.lastError=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${u.message}`,b(n,`ERROR ${n.lastError}`)}),o.on("close",u=>{n.child=void 0,!n.stopping&&(n.lastError=`\u76D1\u542C\u8FDB\u7A0B\u9000\u51FA\uFF08code=${u??"signal"}\uFF09`,b(n,`exit code=${u??"signal"}\uFF0C\u51C6\u5907\u91CD\u542F`),this.scheduleListenerRestart(e,t,n))})}catch(o){const a=o instanceof Error?o.message:String(o);n.lastError=a,b(n,`ERROR spawn: ${a}`),this.scheduleListenerRestart(e,t,n)}}scheduleListenerRestart(e,t,n){if(n.stopping)return;const r=Math.max(500,n.def.transport?.restartBackoffMs??2e3),i=Math.min(Ie,r*2**Math.min(n.restarts,6));n.restarts++,b(n,`restart #${n.restarts} in ${i}ms`),n.backoffTimer=setTimeout(()=>{n.backoffTimer=void 0,n.stopping||this.spawnListenerChild(e,t,n)},i)}async pollListenerOnce(e,t,n){if(n.polling)return;const r=n.def.transport?.command??"",i=Y(r,{});if(i.length===0)return;n.polling=!0;const s=new AbortController,o=setTimeout(()=>s.abort(),q);try{const a=await new Promise((u,c)=>{const d=_(i[0],i.slice(1),{cwd:t.dir,env:this.buildPluginEnv(t,e.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"],signal:s.signal});let y="",h="";d.stdout?.on("data",p=>{y.length<R&&(y+=p.toString("utf8"))}),d.stderr?.on("data",p=>{h.length<R&&(h+=p.toString("utf8"))});const g=()=>s.signal.aborted;d.on("error",p=>{c(g()?new Error(`poll \u8D85\u65F6(${q}ms)`):p)}),d.on("close",p=>{g()?c(new Error(`poll \u8D85\u65F6(${q}ms)`)):p===0?u(y):c(new Error(`exit ${p}: ${A(h||y,300)}`))})});n.lastError=void 0;for(const u of a.split(`
|
|
13
|
+
`)){const c=u.trim();c&&this.handleListenerLine(e,t,n,c)}}catch(a){const u=a instanceof Error?a.message:String(a);n.lastError=u,b(n,`poll \u5931\u8D25: ${u}`)}finally{clearTimeout(o),n.polling=!1}}stopListener(e){if(e.stopping=!0,e.restarts=0,e.child){try{e.child.kill()}catch{}e.child=void 0}e.timer&&(clearInterval(e.timer),e.timer=void 0),e.backoffTimer&&(clearTimeout(e.backoffTimer),e.backoffTimer=void 0)}handleListenerLine(e,t,n,r){b(n,`event: ${A(r,300)}`);let i;try{i=JSON.parse(r)}catch{n.lastError="\u4E8B\u4EF6\u884C\u4E0D\u662F\u5408\u6CD5 JSON\uFF08\u8981\u6C42 JSONL\uFF09";return}if(!P(i))return;const s=typeof i.event=="string"?i.event:n.def.event,o=s===n.def.event?n.def:t.listeners.find(a=>a.event===s);o&&(o.delivery&&o.delivery!=="poll"&&f.debug("[plugin:%s] delivery=%s \u6682\u6309 poll \u4EA4\u4ED8",t.name,o.delivery),this.enqueueEvent(e,t,o,i))}enqueueEvent(e,t,n,r){for(const[y,h]of Object.entries(n.matcher??{})){const g=I(r,y);if(!(Array.isArray(h)?h:[h]).some(v=>JSON.stringify(v)===JSON.stringify(g)))return}let i;if(n.dedupKey){const y=I(r,n.dedupKey);y!=null&&(i=A(String(y),256))}e.eventSeq++;const s=A(Ue(r.data??r),Ae),o=n.promptTemplate?He(n.promptTemplate,r):`\u3010\u63D2\u4EF6\u4E8B\u4EF6\u3011${t.name} \xB7 ${n.event}${n.description?`
|
|
14
14
|
${n.description}`:""}`,a=(n.toolHints??[]).join(","),u=`${o}
|
|
15
|
-
[plugin-event] plugin=${t.name} event=${n.event}`+(a?` toolHints=${a}`:"")+` payload=${s}`,c={msgId:A(i?`plugin-event-${t.name}-${i}`:`plugin-event-${t.name}-${n.event}-${e.eventSeq}`,512),channel:"plugin-event",senderId:`plugin:${t.name}`,senderName:`\u63D2\u4EF6[${t.name}]`,receiverId:e.agentId||void 0,content:u,requireReply:!1,role:"system",timestamp:new Date().toISOString()},d=n.priority??"normal";e.buffer.push({plugin:t.name,event:n.event,priority:d,dedupKey:i,receivedAt:Date.now(),message:c})}requiredParamsOf(e){const t=e.inputSchema;if(!(!t||!Array.isArray(t.required)))return t.required.filter(n=>typeof n=="string")}toSummary(e){return{name:e.name,version:e.version,description:e.description,status:e.status,enabled:e.enabled,source:e.source,installedAt:e.installedAt,toolCount:e.tools.length,tools:e.tools.map(t=>({name:t.name,title:t.title,description:t.description})),listeners:e.runtimes.map(t=>({event:t.def.event,delivery:t.def.delivery??"poll",running:!!(t.child||t.timer)||t.def.transport?.type==="http-callback",error:t.lastError})),running:e.runtimes.some(t=>!!(t.child||t.timer)||t.def.transport?.type==="http-callback"),error:e.error}}async getLogs(e,t){const n=await this.hydrate(e);if(t===$)return{ok:!0,logs:[`\u2500\u2500 ${$} \u4E3A\u7CFB\u7EDF\u5185\u7F6E\u63D2\u4EF6\uFF08\u65E0\u9700\u5B89\u88C5\uFF09\uFF0C\u65E0\u72EC\u7ACB\u76D1\u542C\u5668\u8FD0\u884C\u65E5\u5FD7\u3002`,"\u5176\u751F\u547D\u5468\u671F\u64CD\u4F5C\uFF08install/reload/disable/enable/list\uFF09\u7531 bridge plugin-manager \u5904\u7406\uFF0C\u53EF\u901A\u8FC7\u300C\u91CD\u8F7D/\u542F\u7528/\u505C\u7528\u300D\u6309\u94AE\u89C2\u5BDF\u72B6\u6001\u53D8\u5316\u3002"]};const r=n.plugins.get(t);if(!r)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5`,logs:[]};const i=[];for(const s of r.runtimes)i.push(`\u2500\u2500 listener ${s.def.event} (${s.def.transport?.type}) ${s.lastError?`[error: ${s.lastError}]`:""}`),i.push(...s.logs);return{ok:!0,logs:i}}async stopAgent(e){const t=this.agents.get(e);if(t){for(const n of t.plugins.values())this.stopAllListeners(n);this.agents.delete(e)}}async stopAll(){for(const e of[...this.agents.keys()])await this.stopAgent(e)}async listDeployed(){await this.migrateLegacySharedIfNeeded();const e=this.readSharedManifest(),t=[];for(const n of e){const r=this.deployedPluginDir(n.pluginName),i=this.deployedPluginHealthy(n.pluginName);let s;if(i)try{const o=JSON.parse(k(
|
|
15
|
+
[plugin-event] plugin=${t.name} event=${n.event}`+(a?` toolHints=${a}`:"")+` payload=${s}`,c={msgId:A(i?`plugin-event-${t.name}-${i}`:`plugin-event-${t.name}-${n.event}-${e.eventSeq}`,512),channel:"plugin-event",senderId:`plugin:${t.name}`,senderName:`\u63D2\u4EF6[${t.name}]`,receiverId:e.agentId||void 0,content:u,requireReply:!1,role:"system",timestamp:new Date().toISOString()},d=n.priority??"normal";e.buffer.push({plugin:t.name,event:n.event,priority:d,dedupKey:i,receivedAt:Date.now(),message:c})}requiredParamsOf(e){const t=e.inputSchema;if(!(!t||!Array.isArray(t.required)))return t.required.filter(n=>typeof n=="string")}toSummary(e){return{name:e.name,version:e.version,description:e.description,status:e.status,enabled:e.enabled,source:e.source,installedAt:e.installedAt,toolCount:e.tools.length,tools:e.tools.map(t=>({name:t.name,title:t.title,description:t.description})),listeners:e.runtimes.map(t=>({event:t.def.event,delivery:t.def.delivery??"poll",running:!!(t.child||t.timer)||t.def.transport?.type==="http-callback",error:t.lastError})),running:e.runtimes.some(t=>!!(t.child||t.timer)||t.def.transport?.type==="http-callback"),error:e.error}}async getLogs(e,t){const n=await this.hydrate(e);if(t===$)return{ok:!0,logs:[`\u2500\u2500 ${$} \u4E3A\u7CFB\u7EDF\u5185\u7F6E\u63D2\u4EF6\uFF08\u65E0\u9700\u5B89\u88C5\uFF09\uFF0C\u65E0\u72EC\u7ACB\u76D1\u542C\u5668\u8FD0\u884C\u65E5\u5FD7\u3002`,"\u5176\u751F\u547D\u5468\u671F\u64CD\u4F5C\uFF08install/reload/disable/enable/list\uFF09\u7531 bridge plugin-manager \u5904\u7406\uFF0C\u53EF\u901A\u8FC7\u300C\u91CD\u8F7D/\u542F\u7528/\u505C\u7528\u300D\u6309\u94AE\u89C2\u5BDF\u72B6\u6001\u53D8\u5316\u3002"]};const r=n.plugins.get(t);if(!r)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5`,logs:[]};const i=[];for(const s of r.runtimes)i.push(`\u2500\u2500 listener ${s.def.event} (${s.def.transport?.type}) ${s.lastError?`[error: ${s.lastError}]`:""}`),i.push(...s.logs);return{ok:!0,logs:i}}async stopAgent(e){const t=this.agents.get(e);if(t){for(const n of t.plugins.values())this.stopAllListeners(n);this.agents.delete(e)}}async stopAll(){for(const e of[...this.agents.keys()])await this.stopAgent(e)}async listDeployed(){await this.migrateLegacySharedIfNeeded();const e=this.readSharedManifest(),t=[];for(const n of e){const r=this.deployedPluginDir(n.pluginName),i=this.deployedPluginHealthy(n.pluginName);let s;if(i)try{const o=JSON.parse(k(m(r,"plugin.json"),"utf8"));typeof o.version=="string"&&(s=o.version)}catch{}t.push({pluginName:n.pluginName,version:s,fileName:n.fileName??`${n.pluginName}.zip`,defaultEnabled:n.defaultEnabled!==!1,sha256:n.sha256,deployed:i})}return t}deployedDefaultEnabled(){const e=this.readSharedManifest(),t={};for(const n of e)t[n.pluginName]=n.defaultEnabled!==!1;return t}async removeDeployedPlugin(e){if(!V(e))return{ok:!1,error:"pluginName \u975E\u6CD5\uFF08\u987B\u4E3A kebab-case\uFF0C1~64 \u5B57\u7B26\uFF09"};await this.migrateLegacySharedIfNeeded();for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const n=t.queue.then(async()=>{const r=t.plugins.get(e);r&&(this.stopAllListeners(r),t.plugins.delete(e)),this.removeRuntimeLink(t.agentId,e),this.persistInstalled(t)});t.queue=n.catch(()=>{}),await n}await W(this.deployedManifestFile(),async()=>{const t=this.readSharedManifest().filter(n=>n.pluginName!==e);this.writeSharedManifest(t)});try{E(this.deployedPluginDir(e),{recursive:!0,force:!0})}catch(t){return{ok:!1,error:`\u90E8\u7F72\u76EE\u5F55\u6E05\u7406\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`}}return f.info("[shared] \u63D2\u4EF6\u5DF2\u4ECE bridge \u79FB\u9664\u90E8\u7F72: %s",e),{ok:!0}}}function V(l){return typeof l=="string"&&l.length>0&&l.length<=64&&z.test(l)}function _e(l){const e=l.name;if(typeof e!="string"||!z.test(e))return`plugin.json: name \u975E\u6CD5\uFF08\u987B\u4E3A kebab-case\uFF09: ${String(e)}`;if(e.length>64)return"plugin.json: name \u8FC7\u957F\uFF08\u226464\uFF09";for(const t of De)if(e===t.replace(/\.$/,"")||e.startsWith(t))return`plugin.json: name \u4F7F\u7528\u4E86\u4FDD\u7559\u524D\u7F00 ${t}`;return Ne.test(e)?"plugin.json: name \u542B\u975E ASCII \u5B57\u7B26\uFF08\u540C\u5F62\u5B57\u9632\u62A4\uFF09":l.version!==void 0&&typeof l.version!="string"?"plugin.json: version \u987B\u4E3A\u5B57\u7B26\u4E32":l.userConfig!==void 0&&!Array.isArray(l.userConfig)?"plugin.json: userConfig \u987B\u4E3A\u6570\u7EC4":null}function Fe(l){if(!P(l))return"\u5DE5\u5177\u6761\u76EE\u987B\u4E3A\u5BF9\u8C61";const e=l.name;if(typeof e!="string"||!be.test(e))return`\u5DE5\u5177 name \u975E\u6CD5: ${String(e)}`;if(typeof l.description!="string"||!l.description.trim())return`\u5DE5\u5177 ${e} \u7F3A\u5C11 description`;const t=l.handler;if(!P(t))return`\u5DE5\u5177 ${e} \u7F3A\u5C11 handler`;const n=t.type;return n!=="process"&&n!=="module"&&n!=="mcp"?`\u5DE5\u5177 ${e} handler.type \u975E\u6CD5: ${String(n)}`:n==="process"&&typeof t.command!="string"?`\u5DE5\u5177 ${e} \u7684 process handler \u7F3A\u5C11 command`:n==="module"&&typeof t.module!="string"?`\u5DE5\u5177 ${e} \u7684 module handler \u7F3A\u5C11 module`:l.inputSchema!==void 0&&!P(l.inputSchema)?`\u5DE5\u5177 ${e} inputSchema \u987B\u4E3A\u5BF9\u8C61`:null}function je(l){if(!P(l))return"\u76D1\u542C\u5668\u6761\u76EE\u987B\u4E3A\u5BF9\u8C61";if(typeof l.event!="string"||!l.event.trim())return"\u76D1\u542C\u5668\u7F3A\u5C11 event";const e=l.transport;if(!P(e))return`\u76D1\u542C\u5668 ${String(l.event)} \u7F3A\u5C11 transport`;const t=e.type;if(t!=="command-stream"&&t!=="poll-command"&&t!=="http-callback")return`\u76D1\u542C\u5668 ${String(l.event)} transport.type \u975E\u6CD5: ${String(t)}`;if((t==="command-stream"||t==="poll-command")&&typeof e.command!="string")return`\u76D1\u542C\u5668 ${String(l.event)} \u7684 ${t} transport \u7F3A\u5C11 command`;const n=l.delivery;return n!==void 0&&n!=="poll"&&n!=="force"&&n!=="wake"?`\u76D1\u542C\u5668 ${String(l.event)} delivery \u975E\u6CD5: ${String(n)}`:null}function Y(l,e){return l.trim().split(/\s+/).map(t=>{const n=/^\{\{(.+)\}\}$/.exec(t);if(n){const r=I(e,n[1].trim());return r==null?"":typeof r=="string"?r:JSON.stringify(r)}return t.replace(/\{\{(.+?)\}\}/g,(r,i)=>{const s=I(e,i.trim());return s==null?"":typeof s=="string"?s:JSON.stringify(s)})}).filter(t=>t!=="")}function He(l,e){return l.replace(/\{\{(.+?)\}\}/g,(t,n)=>{let r=I(e,n.trim());return r===void 0&&!n.trim().startsWith("params.")&&(r=I(e,`data.${n.trim()}`)),r==null?"":typeof r=="string"?r:JSON.stringify(r)})}function Ue(l){try{return JSON.stringify(l)??"null"}catch{return"(\u4E0D\u53EF\u5E8F\u5217\u5316\u7684\u4E8B\u4EF6\u8D1F\u8F7D)"}}const Je=new Me;he("plugins",()=>Je.deployedDefaultEnabled());const tt=()=>ye("plugins");export{X as BUILTIN_PLUGIN_DESCRIPTION,Q as BUILTIN_PLUGIN_MANAGE_DESC,$ as BUILTIN_PLUGIN_NAME,Me as PluginManager,Ee as getBuiltinCommandDir,V as isValidPluginName,Je as pluginManager,tt as reconcilePluginsDefaultsFromDeployed,Y as renderCommandArgv,B as validateAgainstSchema,_e as validateManifest};
|
|
16
16
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{promises as g,cpSync as S,existsSync as
|
|
2
|
-
`,"utf8")}async saveSharedSkill(r,t,e=!0,
|
|
1
|
+
import{promises as g,cpSync as S,existsSync as f,mkdirSync as v,readFileSync as j,readdirSync as E,rmSync as m,writeFileSync as I}from"node:fs";import i from"node:path";import{getBridgeTemplateSkillsDir as b}from"../config.js";import{extractSkillZip as x,resolveSkillSourceDirFromExtractRoot as A}from"../utils/file-utils.js";import{createLogger as L}from"../utils/logger.js";import{getSkillFarmRoot as N,syncAgentSkillFarm as _}from"./agent-capability-sync.js";import{setDeployedDefaultsProvider as K,reconcileDefaultsFromDeployed as z}from"./capability-config.js";import{getAgentInitRoot as $}from"./instance-state.js";const h=L("skill-manager");function F(l){return typeof l=="string"&&l.length>0&&l.length<=128&&/^[a-zA-Z0-9_.-]+$/.test(l)}const O=1;class p{static getInstance(){return this._instance||(this._instance=new p(i.join(b(),"deployed"))),this._instance}constructor(r){this.rootDir=r}manifestFile(){return i.join(this.rootDir,"manifest.json")}skillDir(r){const t=i.join(this.rootDir,r),e=i.resolve(this.rootDir);if(i.resolve(t)!==i.join(e,r))throw new Error(`\u6280\u80FD\u76EE\u5F55\u8D8A\u51FA\u90E8\u7F72\u533A: ${r}`);return t}isHealthy(r){return f(i.join(this.skillDir(r),"SKILL.md"))}readManifest(){try{const r=JSON.parse(j(this.manifestFile(),"utf8"));return Array.isArray(r.skills)?r.skills.filter(t=>t&&t.skillName):[]}catch{return[]}}writeManifest(r){v(this.rootDir,{recursive:!0}),I(this.manifestFile(),`${JSON.stringify({version:O,skills:r},null,2)}
|
|
2
|
+
`,"utf8")}async saveSharedSkill(r,t,e=!0,o,D){if(!r||r.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};const y=i.join($("_tmp"),`skill-deploy-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{await R(r,y);const n=await A(y),a=i.basename(i.resolve(n)),M=String(t||"").replace(/\.zip$/i,"").trim(),s=D&&D.trim()||(a&&!a.startsWith("skill-deploy-")?a:"")||M;if(!F(s))return{ok:!1,error:`\u6280\u80FD\u540D\u975E\u6CD5: ${JSON.stringify(s)}`};if(!f(i.join(n,"SKILL.md")))return{ok:!1,error:`\u6280\u80FD\u5305\u7F3A\u5C11 SKILL.md: ${t}`};const k=this.readManifest().find(d=>d.skillName===s);if(k&&k.sha256===o&&this.isHealthy(s))return{ok:!0,skillName:s};v(this.rootDir,{recursive:!0});const c=this.skillDir(s),u=i.join(this.rootDir,`.old-${s}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);if(f(c))try{S(c,u,{recursive:!0})}catch{m(c,{recursive:!0,force:!0})}try{S(n,c,{recursive:!0})}catch(d){throw f(u)&&(m(c,{recursive:!0,force:!0}),S(u,c,{recursive:!0})),d}f(u)&&m(u,{recursive:!0,force:!0});const w=this.readManifest().filter(d=>d.skillName!==s);return w.push({skillName:s,zipFile:k?.zipFile??`${s}.zip`,fileName:t,defaultEnabled:e,sha256:o}),this.writeManifest(w),h.info("[shared] \u6280\u80FD\u5DF2\u90E8\u7F72\u5230 bridge: %s\uFF08\u6765\u6E90 %s%s\uFF09",s,t,o?`, sha256=${o.slice(0,12)}\u2026`:""),this.applyToKnownAgents(),{ok:!0,skillName:s}}catch(n){const a=n instanceof Error?n.message:String(n);return h.warn("[shared] \u6280\u80FD\u90E8\u7F72\u5931\u8D25\uFF08%s\uFF09: %s",t,a),{ok:!1,error:`\u6280\u80FD\u90E8\u7F72\u5931\u8D25: ${a}`}}finally{try{m(y,{recursive:!0,force:!0})}catch{}}}async removeDeployedSkill(r){if(!F(r))return{ok:!1,error:"skillName \u975E\u6CD5"};const t=this.readManifest().filter(e=>e.skillName!==r);this.writeManifest(t);try{m(this.skillDir(r),{recursive:!0,force:!0})}catch(e){return{ok:!1,error:`\u90E8\u7F72\u76EE\u5F55\u6E05\u7406\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`}}return this.applyToKnownAgents(),h.info("[shared] \u6280\u80FD\u5DF2\u4ECE bridge \u79FB\u9664\u90E8\u7F72: %s",r),{ok:!0}}listDeployed(){return this.readManifest().filter(r=>!/^skill-deploy-/.test(r.skillName)).map(r=>({...r,deployed:this.isHealthy(r.skillName)}))}deployedDefaultEnabled(){const r={};for(const t of this.readManifest())/^skill-deploy-/.test(t.skillName)||(r[t.skillName]=t.defaultEnabled);return r}applyToKnownAgents(){const r=new Set,t=N();try{if(f(t))for(const e of E(t))e.startsWith(".")||r.add(e)}catch{}for(const e of r)try{_(e)}catch(o){h.warn("[shared] \u540C\u6B65\u6280\u80FD\u519C\u573A\u5931\u8D25 agent=%s: %s",e,o instanceof Error?o.message:String(o))}}}p._instance=null;async function R(l,r){const t=i.join($("_tmp"),`skill-${Date.now()}-${Math.random().toString(36).slice(2,8)}.zip`);await g.mkdir(i.dirname(t),{recursive:!0}),await g.writeFile(t,l);try{await x(t,r)}finally{await g.rm(t,{force:!0}).catch(()=>{})}}const T=p.getInstance();K("skills",()=>T.deployedDefaultEnabled());const G=()=>z("skills");export{p as SkillManager,F as isValidSkillName,G as reconcileSkillsDefaultsFromDeployed,T as skillManager};
|
|
3
3
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{randomUUID as
|
|
3
|
-
`)}),await r.start(),await r.stop()}
|
|
2
|
+
import{randomUUID as a}from"node:crypto";import p from"node:os";import m from"node:path";import{ACodeRuntime as f}from"./runtime.js";function s(t,i){const o=t.indexOf(i);if(o>=0)return t[o+1];const n=t.find(e=>e.startsWith(`${i}=`));return n?n.slice(i.length+1):void 0}async function l(){const t=process.argv.slice(2),i=m.resolve(s(t,"--cwd")||process.cwd()),o=s(t,"--config"),n=s(t,"--skills-dir"),e=s(t,"--plugins-dir"),d=s(t,"--prompt")||t.filter(c=>!c.startsWith("--")).join(" "),r=new f({sessionId:s(t,"--session-id")||a(),agentId:s(t,"--agent-id")||p.hostname(),workingDirectory:i,configPath:o,skillsDir:n,pluginsDir:e,initialPrompt:d,model:s(t,"--model")});r.on("event",c=>{process.stdout.write(`${JSON.stringify(c)}
|
|
3
|
+
`)}),await r.start(),await r.stop()}l().catch(t=>{const i=t instanceof Error?t.message:String(t);process.stderr.write(`[acode] ${i}
|
|
4
4
|
`),process.exitCode=1});
|
|
5
5
|
|