aws-runtime-bridge 1.9.168 → 1.9.170

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/adapter/AcodeSdkAdapter.d.ts +46 -0
  3. package/dist/adapter/AcodeSdkAdapter.js +4 -4
  4. package/dist/adapter/ClaudeSdkAdapter.js +2 -2
  5. package/dist/adapter/types.d.ts +7 -0
  6. package/dist/config.d.ts +6 -0
  7. package/dist/config.js +2 -2
  8. package/dist/index.js +1 -1
  9. package/dist/routes/agent-state.d.ts +2 -0
  10. package/dist/routes/agent-state.js +2 -0
  11. package/dist/routes/capabilities.js +1 -1
  12. package/dist/routes/debug-mount.d.ts +2 -0
  13. package/dist/routes/debug-mount.js +2 -0
  14. package/dist/routes/mcp.js +1 -1
  15. package/dist/routes/plugins.js +1 -1
  16. package/dist/routes/skills.js +1 -1
  17. package/dist/routes/terminal.js +28 -32
  18. package/dist/services/acode-bg-manager.d.ts +2 -0
  19. package/dist/services/agent-capability-sync.js +1 -1
  20. package/dist/services/debug-mount.d.ts +122 -0
  21. package/dist/services/debug-mount.js +2 -0
  22. package/dist/services/desktop-mcp-manager.js +1 -1
  23. package/dist/services/instance-ai-config-service.js +1 -1
  24. package/dist/services/instance-features.d.ts +4 -0
  25. package/dist/services/instance-features.js +1 -1
  26. package/dist/services/instance-init-service.js +1 -1
  27. package/dist/services/mcp-deploy.d.ts +31 -0
  28. package/dist/services/mcp-deploy.js +4 -3
  29. package/dist/services/mcp-env-injector.d.ts +24 -0
  30. package/dist/services/mcp-env-injector.js +1 -1
  31. package/dist/services/mcp-package.d.ts +35 -0
  32. package/dist/services/mcp-package.js +2 -0
  33. package/dist/services/mcp-probe-client.d.ts +25 -0
  34. package/dist/services/mcp-probe-client.js +2 -0
  35. package/dist/services/panel-env.d.ts +5 -0
  36. package/dist/services/panel-env.js +1 -1
  37. package/dist/services/plugin-deployment.d.ts +36 -0
  38. package/dist/services/plugin-deployment.js +3 -0
  39. package/dist/services/plugin-event-buffer.js +2 -1
  40. package/dist/services/plugin-fs.d.ts +5 -0
  41. package/dist/services/plugin-fs.js +2 -0
  42. package/dist/services/plugin-handler-adapter.d.ts +7 -0
  43. package/dist/services/plugin-handler-adapter.js +3 -0
  44. package/dist/services/plugin-listener-runner.d.ts +18 -0
  45. package/dist/services/plugin-listener-runner.js +8 -0
  46. package/dist/services/plugin-loader.d.ts +32 -0
  47. package/dist/services/plugin-loader.js +2 -0
  48. package/dist/services/plugin-manager.d.ts +17 -136
  49. package/dist/services/plugin-manager.js +4 -15
  50. package/dist/services/plugin-manifest.d.ts +83 -0
  51. package/dist/services/plugin-manifest.js +2 -0
  52. package/dist/services/plugin-runtime.d.ts +67 -0
  53. package/dist/services/plugin-runtime.js +1 -0
  54. package/dist/services/skill-manager.d.ts +15 -0
  55. package/dist/services/skill-manager.js +3 -2
  56. package/dist/types.d.ts +6 -0
  57. package/dist/utils/mcp-utils.js +1 -1
  58. package/package/acode/dist/compaction.d.ts +35 -1
  59. package/package/acode/dist/compaction.js +6 -6
  60. package/package/acode/dist/plugin-types.d.ts +6 -27
  61. package/package/acode/dist/runtime.d.ts +37 -0
  62. package/package/acode/dist/runtime.js +31 -30
  63. package/package/acode/dist/tool-group-manager.d.ts +10 -0
  64. package/package/acode/dist/tool-group-manager.js +5 -10
  65. package/package/acode/dist/types.d.ts +2 -0
  66. package/package/aws-client-agent-mcp/dist/ability-market-tools.d.ts +18 -0
  67. package/package/aws-client-agent-mcp/dist/ability-market-tools.js +2 -0
  68. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +15 -4
  69. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  70. package/package/aws-client-agent-mcp/dist/http-client.d.ts +2 -0
  71. package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
  72. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +0 -7
  73. package/package/aws-client-agent-mcp/dist/mcp-server.js +12 -12
  74. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +3 -0
  75. package/package/aws-client-agent-mcp/dist/mcp-tools.js +20 -20
  76. package/package/aws-client-agent-mcp/dist/memory-store.d.ts +1 -1
  77. package/package/aws-client-agent-mcp/dist/memory-store.js +2 -2
  78. package/package/aws-client-agent-mcp/dist/memory-tools.js +7 -7
  79. package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
  80. package/package/aws-client-agent-mcp/dist/types.d.ts +2 -21
  81. package/package.json +3 -2
  82. package/dist/services/builtin-commands/create-plugin.md +0 -44
@@ -1,2 +1,2 @@
1
- import{access as P,constants as M}from"node:fs/promises";import{join as w,resolve as O}from"node:path";import{createBuiltInDesktopTools as k}from"../desktop/built-in-desktop-tools.js";import{DesktopMcpConnection as T}from"../desktop/desktop-mcp-client.js";import{logger as C}from"../utils/logger.js";import{DESKTOP_FEATURE_KEY as D,isFeatureEnabled as N}from"./instance-features.js";import{getPanelEnvVars as A}from"./panel-env.js";const d=C.child("desktop-mcp");let n=null,a=null,r=null,c,f="none";const g=process.platform==="win32"?"nuphus-mcp.exe":"nuphus-mcp",U=12e4,x=6e4;function I(){const e=process.env.AWS_DESKTOP_MCP_TIMEOUT_MS;if(e){const t=parseInt(e,10);if(Number.isFinite(t)&&t>0)return t}return U}function K(){const e=process.env.AWS_DESKTOP_MCP_RETRY_BACKOFF_MS;if(e){const t=parseInt(e,10);if(Number.isFinite(t)&&t>=0)return t}return x}async function $(){const e=process.env.AWS_DESKTOP_MCP_BIN;if(e){const o=O(e);return await h(o)?o:null}const t=w(process.cwd(),".desktop-mcp","bin",g);return await h(t)?t:null}async function h(e){try{return await P(e,M.F_OK),!0}catch{return!1}}function F(){const e={},t="AWS_DESKTOP_MCP_ENV_";for(const[o,s]of Object.entries(process.env))o.startsWith(t)&&s!==void 0&&(e[o.slice(t.length)]=s);return e}function S(e){const t={...F(),...A(e)},o=t.NUPHUS_MCP_VISION_API_KEY!==void 0||t.NUPHUS_MCP_VISION_MODEL!==void 0;return!o&&c?.apiKey&&c.supportsImage===!0?(f="agent-fallback",t.NUPHUS_MCP_VISION_API_KEY=c.apiKey,t.NUPHUS_MCP_VISION_MODEL=c.model,c.baseURL&&(t.NUPHUS_MCP_VISION_BASE_URL=c.baseURL),d.info(`vision model fallback: reusing agent model ${c.model} for desktop_vision`)):o?f="panel-env":f="none",t}function y(e){return Object.keys(e).sort().map(t=>`${t}=${e[t]}`).join("\0")}async function v(e){if(n){if(n.connection.isConnected())return n;await _(n.connection),n=null}if(a)return a;if(r){if(r.reason==="binary-missing"||Date.now()-r.at<K())return null;r=null}return a=(async()=>{const t=await $();if(!t)return r={reason:"binary-missing",message:`nuphus-mcp binary not found. Set AWS_DESKTOP_MCP_BIN or place it at ${w(process.cwd(),".desktop-mcp","bin",g)}`,at:Date.now()},u(`desktop tools unavailable: ${r.message}`),null;const o=S(e),s=new T({command:t,env:o,onUnexpectedClose:()=>{u("nuphus-mcp process exited unexpectedly; will restart on next use"),n?.connection===s&&(n=null)}});try{const i=await s.start(),l=I();r=null;const p={connection:s,tools:i,binaryPath:t,envSig:y(o),ownerAgentId:e,forwarder:(m,b)=>R(s,m,b,l,e)};return n=p,u(`nuphus-mcp started (${t}), ${i.filter(m=>m.name.startsWith("desktop_")).length} desktop tools available`),p}catch(i){return await _(s),r={reason:"start-failed",message:i.message,at:Date.now()},E(`nuphus-mcp start failed: ${r.message}`),null}finally{a=null}})(),a}async function R(e,t,o,s,i){try{return await e.callTool(t,o,s)}catch(l){if(e.isConnected())throw l;E(`nuphus-mcp connection lost during ${t}: ${l.message}; restarting`),n?.connection===e&&(n=null),await _(e);const p=await v(i);if(!p)throw new Error(`nuphus-mcp restart failed: ${r?.message??"unknown"}`);return p.connection.callTool(t,o,s)}}async function G(e,t){if(!e)return[];t?.model&&(c=t);const o=S(e),s=y(o);n&&n.connection.isConnected()&&n.envSig!==s&&(u("nuphus-mcp env changed; restarting to apply new env"),await B());const i=await v(e);return i?k({tools:i.tools,forwarder:(l,p)=>N(e,D)?i.forwarder(l,p):(d.warn(`tool ${l} blocked: desktop capability disabled for ${e}`),Promise.resolve("desktop capability is disabled for this agent (toggled off while tools were exposed); stop calling desktop_* tools"))}):[]}function J(){const e=n;return!e||!e.connection.isConnected()?L.map(t=>({kind:"builtin",toolName:t,exposedName:t,description:`${t}\uFF08\u684C\u9762\u81EA\u52A8\u5316\u5DE5\u5177\uFF0Cnuphus-mcp \u672A\u8FD0\u884C\uFF09\u3002\u5206\u914D desktop \u5206\u7C7B\u540E\u6309\u9700\u542F\u52A8\u540E\u7AEF\uFF0C\u5177\u4F53\u5DE5\u5177\u4EE5\u542F\u52A8\u540E\u76EE\u5F55\u4E3A\u51C6\u3002`,inputSchema:{type:"object",properties:{}},category:"desktop",async execute(){return`${t} is not ready: nuphus-mcp backend is not running. Allocate the desktop catalog to lazily start it, then retry.`}})):k({tools:e.tools,forwarder:(t,o)=>e.forwarder(t,o)})}const L=["desktop_screenshot","desktop_window_screenshot","desktop_perceive","desktop_vision","desktop_input","desktop_mouse","desktop_mouse_drag","desktop_screen_size","desktop_clipboard_write","desktop_clipboard_clean","desktop_config","desktop_uia_tree","desktop_uia_click","desktop_window_activate","desktop_window_info","desktop_window_move","desktop_window_resize","desktop_windows_list"];async function B(){const e=n;if(n=null,r=null,a){try{await a}catch{}a=null}e&&(await _(e.connection),u("nuphus-mcp stopped"))}function Q(){return{started:n!==null,binaryPath:n?.binaryPath??null,toolCount:n?n.tools.filter(e=>e.name.startsWith("desktop_")).length:0,failure:r,visionSource:f}}async function _(e){try{await e.close()}catch{}}function u(e){d.info(e)}function E(e){d.warn(e)}export{B as disposeDesktopMcpManager,Q as getDesktopMcpStatus,G as getDesktopTools,J as getDesktopToolsIfReady,$ as resolveDesktopMcpBinary,v as startDesktopMcpManager};
1
+ import{access as M,constants as P}from"node:fs/promises";import{join as w,resolve as O}from"node:path";import{createBuiltInDesktopTools as k}from"../desktop/built-in-desktop-tools.js";import{DesktopMcpConnection as T}from"../desktop/desktop-mcp-client.js";import{logger as C}from"../utils/logger.js";import{DESKTOP_FEATURE_KEY as D,isFeatureEnabled as A}from"./instance-features.js";import{getPanelEnvVars as N,getAgentMeta as U}from"./panel-env.js";import{buildAgentMetaEnv as x}from"./mcp-env-injector.js";const d=C.child("desktop-mcp");let n=null,a=null,r=null,c,f="none";const g=process.platform==="win32"?"nuphus-mcp.exe":"nuphus-mcp",I=12e4,K=6e4;function $(){const e=process.env.AWS_DESKTOP_MCP_TIMEOUT_MS;if(e){const t=parseInt(e,10);if(Number.isFinite(t)&&t>0)return t}return I}function F(){const e=process.env.AWS_DESKTOP_MCP_RETRY_BACKOFF_MS;if(e){const t=parseInt(e,10);if(Number.isFinite(t)&&t>=0)return t}return K}async function R(){const e=process.env.AWS_DESKTOP_MCP_BIN;if(e){const o=O(e);return await h(o)?o:null}const t=w(process.cwd(),".desktop-mcp","bin",g);return await h(t)?t:null}async function h(e){try{return await M(e,P.F_OK),!0}catch{return!1}}function L(){const e={},t="AWS_DESKTOP_MCP_ENV_";for(const[o,s]of Object.entries(process.env))o.startsWith(t)&&s!==void 0&&(e[o.slice(t.length)]=s);return e}function S(e){const t={...L(),...N(e),...x(U(e))},o=t.NUPHUS_MCP_VISION_API_KEY!==void 0||t.NUPHUS_MCP_VISION_MODEL!==void 0;return!o&&c?.apiKey&&c.supportsImage===!0?(f="agent-fallback",t.NUPHUS_MCP_VISION_API_KEY=c.apiKey,t.NUPHUS_MCP_VISION_MODEL=c.model,c.baseURL&&(t.NUPHUS_MCP_VISION_BASE_URL=c.baseURL),d.info(`vision model fallback: reusing agent model ${c.model} for desktop_vision`)):o?f="panel-env":f="none",t}function y(e){return Object.keys(e).sort().map(t=>`${t}=${e[t]}`).join("\0")}async function v(e){if(n){if(n.connection.isConnected())return n;await _(n.connection),n=null}if(a)return a;if(r){if(r.reason==="binary-missing"||Date.now()-r.at<F())return null;r=null}return a=(async()=>{const t=await R();if(!t)return r={reason:"binary-missing",message:`nuphus-mcp binary not found. Set AWS_DESKTOP_MCP_BIN or place it at ${w(process.cwd(),".desktop-mcp","bin",g)}`,at:Date.now()},u(`desktop tools unavailable: ${r.message}`),null;const o=S(e),s=new T({command:t,env:o,onUnexpectedClose:()=>{u("nuphus-mcp process exited unexpectedly; will restart on next use"),n?.connection===s&&(n=null)}});try{const i=await s.start(),l=$();r=null;const p={connection:s,tools:i,binaryPath:t,envSig:y(o),ownerAgentId:e,forwarder:(m,b)=>B(s,m,b,l,e)};return n=p,u(`nuphus-mcp started (${t}), ${i.filter(m=>m.name.startsWith("desktop_")).length} desktop tools available`),p}catch(i){return await _(s),r={reason:"start-failed",message:i.message,at:Date.now()},E(`nuphus-mcp start failed: ${r.message}`),null}finally{a=null}})(),a}async function B(e,t,o,s,i){try{return await e.callTool(t,o,s)}catch(l){if(e.isConnected())throw l;E(`nuphus-mcp connection lost during ${t}: ${l.message}; restarting`),n?.connection===e&&(n=null),await _(e);const p=await v(i);if(!p)throw new Error(`nuphus-mcp restart failed: ${r?.message??"unknown"}`);return p.connection.callTool(t,o,s)}}async function X(e,t){if(!e)return[];t?.model&&(c=t);const o=S(e),s=y(o);n&&n.connection.isConnected()&&n.envSig!==s&&(u("nuphus-mcp env changed; restarting to apply new env"),await V());const i=await v(e);return i?k({tools:i.tools,forwarder:(l,p)=>A(e,D)?i.forwarder(l,p):(d.warn(`tool ${l} blocked: desktop capability disabled for ${e}`),Promise.resolve("desktop capability is disabled for this agent (toggled off while tools were exposed); stop calling desktop_* tools"))}):[]}function Z(){const e=n;return!e||!e.connection.isConnected()?W.map(t=>({kind:"builtin",toolName:t,exposedName:t,description:`${t}\uFF08\u684C\u9762\u81EA\u52A8\u5316\u5DE5\u5177\uFF0Cnuphus-mcp \u672A\u8FD0\u884C\uFF09\u3002\u5206\u914D desktop \u5206\u7C7B\u540E\u6309\u9700\u542F\u52A8\u540E\u7AEF\uFF0C\u5177\u4F53\u5DE5\u5177\u4EE5\u542F\u52A8\u540E\u76EE\u5F55\u4E3A\u51C6\u3002`,inputSchema:{type:"object",properties:{}},category:"desktop",async execute(){return`${t} is not ready: nuphus-mcp backend is not running. Allocate the desktop catalog to lazily start it, then retry.`}})):k({tools:e.tools,forwarder:(t,o)=>e.forwarder(t,o)})}const W=["desktop_screenshot","desktop_window_screenshot","desktop_perceive","desktop_vision","desktop_input","desktop_mouse","desktop_mouse_drag","desktop_screen_size","desktop_clipboard_write","desktop_clipboard_clean","desktop_config","desktop_uia_tree","desktop_uia_click","desktop_window_activate","desktop_window_info","desktop_window_move","desktop_window_resize","desktop_windows_list"];async function V(){const e=n;if(n=null,r=null,a){try{await a}catch{}a=null}e&&(await _(e.connection),u("nuphus-mcp stopped"))}function ee(){return{started:n!==null,binaryPath:n?.binaryPath??null,toolCount:n?n.tools.filter(e=>e.name.startsWith("desktop_")).length:0,failure:r,visionSource:f}}async function _(e){try{await e.close()}catch{}}function u(e){d.info(e)}function E(e){d.warn(e)}export{V as disposeDesktopMcpManager,ee as getDesktopMcpStatus,X as getDesktopTools,Z as getDesktopToolsIfReady,R as resolveDesktopMcpBinary,v as startDesktopMcpManager};
2
2
 
@@ -1,2 +1,2 @@
1
- import p from"node:fs/promises";import S from"node:path";import{getBridgeInstanceConfigFile as U,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";import{injectEffectiveEnvIntoMcpServers as h,isBuiltinMcpName as D}from"./mcp-env-injector.js";import{getPanelEnvVars as M}from"./panel-env.js";const k=new Set(["apiKey","api_key","apikey","key","secret","token","password"]);function x(e){const t={...e};for(const r of Object.keys(t))if(k.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]=x(t[r]));return t}function N(){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 j(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 R(e){return A(e)}async function P(e){try{const t=await p.readFile(R(e),"utf-8"),r=JSON.parse(t);return r.servers&&typeof r.servers=="object"?r.servers:{}}catch{return{}}}function z(e){return R(e)}async function G(e){const t=F(),r=U(e.agentId),o=e.apiOverrides??{},a=N(),n=await j(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 I={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(S.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??{},L=w.resolveEnabledMcp(e.agentId,i),C=await P(e.agentId);for(const[O,K]of Object.entries(C))D(O)||(L[O]=K);h(L,M(e.agentId)),s.mcpServers=L}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:I}})}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:I},perInstanceConfigPath:r}}export{z as getAgentMcpExtraFilePath,G as prepareAcodeInstanceConfig,x as redactForLog};
1
+ import p from"node:fs/promises";import U from"node:path";import{getBridgeInstanceConfigFile as A,getBridgeInstanceMcpExtraFile as F,getBridgeTemplateConfigFile as _}from"../config.js";import{getInstanceAiConfigDebugLogger as D}from"../utils/instance-ai-config-debug-logger.js";import{mcpDeployManager as O}from"./mcp-deploy.js";import{injectEffectiveEnvIntoMcpServers as M,isBuiltinMcpName as h}from"./mcp-env-injector.js";import{getPanelEnvVars as w,getAgentMeta as k}from"./panel-env.js";const P=new Set(["apiKey","api_key","apikey","key","secret","token","password"]);function x(e){const t={...e};for(const r of Object.keys(t))if(P.has(r)){const a=t[r];typeof a=="string"&&a.length>0&&(t[r]=a.length>8?`${a.slice(0,4)}...${a.slice(-4)}`:"***")}else typeof t[r]=="object"&&t[r]!==null&&(t[r]=x(t[r]));return t}function N(){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 j(e){try{const t=await p.readFile(e,"utf-8"),o=JSON.parse(t).provider?.default,n=o?.options;return{...o?.model?{model:o.model}:{},...n?.baseURL||n?.baseUrl?{baseURL:n.baseURL||n.baseUrl}:{},...n?.apiKey?{apiKey:n.apiKey}:{}}}catch{return{}}}function v(e,t,r,a){return t!==void 0?"api":r!==void 0?"env":a!==void 0?"file":"default"}function C(e){return F(e)}async function B(e){try{const t=await p.readFile(C(e),"utf-8"),r=JSON.parse(t);return r.servers&&typeof r.servers=="object"?r.servers:{}}catch{return{}}}function z(e){return C(e)}async function G(e){const t=_(),r=A(e.agentId),a=e.apiOverrides??{},o=N(),n=await j(t),g=a.model??o.model??n.model,y=a.baseURL??o.baseURL??n.baseURL,u=a.apiKey??o.apiKey??n.apiKey,m=a.effort??o.effort,f={};g&&(f.model=g),y&&(f.baseURL=y),u&&(f.apiKey=u),m&&(f.effort=m);const R={model:v("model",a.model,o.model,n.model),baseURL:v("baseURL",a.baseURL,o.baseURL,n.baseURL),apiKey:v("apiKey",a.apiKey,o.apiKey,n.apiKey),effort:v("effort",a.effort,o.effort,void 0)},b=D();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)),E=s.provider??{},L=E.default??{},d=L.options??{};g&&(d.model=g),y&&(d.baseURL=y),u&&(d.apiKey=u),m&&(d.effort=m),L.options=d,E.default=L,s.provider=E;try{const i=s.mcpServers??{},I=O.resolveEnabledMcp(e.agentId,i),K=await B(e.agentId);for(const[l,S]of Object.entries(K))h(l)||(I[l]=S);M(I,w(e.agentId),{resolvePackageDir:l=>O.isPackageHealthy(l)?O.packageDir(l):void 0,agentMeta:k(e.agentId)}),s.mcpServers=I}catch(i){b.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"),b.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:R}})}catch(c){const s=c instanceof Error?c.message:String(c);b.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:R},perInstanceConfigPath:r}}export{z as getAgentMcpExtraFilePath,G as prepareAcodeInstanceConfig,x as redactForLog};
2
2
 
@@ -12,6 +12,10 @@ export declare const LAUNCH_ITEM_FEATURE_KEY = "agentSys.launchItem";
12
12
 
13
13
  export declare const HIRE_FEATURE_KEY = "agentSys.hire";
14
14
 
15
+ export declare const SKILL_INSTALL_FEATURE_KEY = "agentSys.skillInstall";
16
+
17
+ export declare const ABILITY_DEV_FEATURE_KEY = "agentSys.abilityDev";
18
+
15
19
  export declare const PENCIL_FEATURE_KEY = "pencil";
16
20
 
17
21
  export declare const DRAW_FEATURE_KEY = "draw";
@@ -1,2 +1,2 @@
1
- import{getEffective as P,hasAnyDefault as B}from"./capability-config.js";const Y=new Set(["disabled","collapsed","expanded"]);function N(e){if(e===!0)return"expanded";if(e===!1)return"disabled";if(typeof e=="string"&&Y.has(e))return e}const T={},ne="desktop",j="browser",O="agentSys.launchItem",x="agentSys.hire",D="pencil",v="draw",z="office",I="collaboration",S="collaboration.task",R="collaboration.meeting",h="collaboration.debug",m="collaboration.fileHistory",G="email",H=new Set,J=new Set([j,D,v,z,O,x,S,R,h,m,G]),k=[["agentSys","agentSys."],[I,"collaboration."]],V=new Map([["task",S],["meeting",R],["debug",h],["fileHistory",m],["launch",O],["hire",x]]);function oe(e){return V.get(e)??e}function W(e){for(const[t,n]of k)if(e.startsWith(n))return t}const X=new Set,d=new Map,y=new Map,a=new Map,q=["fileReadOutside","commandExecution","fileModification","fileModificationOutside"],Q=new Set(["allow","ask","deny"]);function Z(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;const t=e,n={};let r=!1;for(const o of q){const i=t[o];typeof i=="string"&&Q.has(i)?(n[o]=i,r=!0):n[o]="allow"}return r?n:null}function L(e){if(e==null)return{...T};let t=e;if(typeof e=="string")try{t=JSON.parse(e)}catch{t=null}if(typeof t!="object"||t===null||Array.isArray(t))return{...T};const n={};for(const[r,o]of Object.entries(t)){if(X.has(r))continue;const i=N(o);i!==void 0&&(n[r]=i)}return n}function re(e,t){if(!e)return;d.set(e,L(t));let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n=="object"&&n!==null&&!Array.isArray(n)){const r=Z(n.toolPermissions);r?a.set(e,r):a.delete(e)}else a.delete(e)}function $(e){return d.get(e)??{...T}}function ie(e,t){if(!e)return;if(t==null){y.delete(e);return}const n=L(t);if(Object.keys(n).length===0){y.delete(e);return}y.set(e,n)}function w(e){return y.get(e)??{}}function ee(e,t){const n=$(e),r=w(e),o=W(t);if(o&&(n[o]??r[o])==="disabled")return"disabled";const i=n[t]??r[t];return i!==void 0?i:H.has(t)?"expanded":J.has(t)?"collapsed":"disabled"}function se(e,t){return ee(e,t)!=="disabled"}function le(e){d.delete(e),a.delete(e),f.delete(e),_.delete(e)}function ue(e){return a.get(e)??null}function ce(e){return a.get(e)??{fileReadOutside:"allow",commandExecution:"allow",fileModification:"allow",fileModificationOutside:"allow"}}const U=["skills","mcp","plugins"],f=new Map,_=new Map;function K(e){if(typeof e!="object"||e===null||Array.isArray(e))return;const t={};for(const[n,r]of Object.entries(e))n.trim()&&typeof r=="boolean"&&(t[n.trim()]=r);return t}function fe(e,t){if(!e)return;if(t==null){f.delete(e);return}let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n!="object"||n===null||Array.isArray(n)){f.delete(e);return}const r=n,o={};let i=!1;for(const E of U){const l=K(r[E]);l&&(o[E]=l,i=!0)}i?f.set(e,o):f.delete(e);const s=r.plugins,u={};let b=!1;if(typeof s=="object"&&s!==null&&!Array.isArray(s))for(const[E,l]of Object.entries(s)){const A=E.trim();if(A){if(typeof l=="boolean"){const c=o.plugins??{};c[A]=l,o.plugins=c,i=!0;continue}if(l!==null&&typeof l=="object"&&!Array.isArray(l)){const c=l,M=c.enabled!==!1,g=typeof c.url=="string"?c.url:void 0,C=typeof c.sha256=="string"?c.sha256:void 0,F=o.plugins??{};F[A]=M,o.plugins=F,i=!0,g&&(u[A]={url:g,sha256:C},b=!0)}}}b?_.set(e,u):_.delete(e)}function ae(e){return f.get(e)??null}const p=new Map;function pe(e,t){if(!e)return;if(t==null){p.delete(e);return}let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n!="object"||n===null||Array.isArray(n)){p.delete(e);return}const r=n,o={};let i=!1;for(const s of U){const u=K(r[s]);u&&(o[s]=u,i=!0)}i?p.set(e,o):p.delete(e)}function Ee(e){return p.get(e)??null}function Ae(e){return _.get(e)??null}function de(e,t,n){if(B(t))return P(e,t,n);const o=p.get(e)?.[t]?.[n];if(o!==void 0)return o;const i=f.get(e);if(!i)return!0;const s=i[t];if(!s)return!0;const u=s[n];return u===void 0?!0:u}function ye(){return d.size}export{j as BROWSER_FEATURE_KEY,U as CAPABILITY_TYPES,h as COLLABORATION_DEBUG_FEATURE_KEY,I as COLLABORATION_FEATURE_KEY,m as COLLABORATION_FILE_HISTORY_FEATURE_KEY,R as COLLABORATION_MEETING_FEATURE_KEY,S as COLLABORATION_TASK_FEATURE_KEY,ne as DESKTOP_FEATURE_KEY,v as DRAW_FEATURE_KEY,G as EMAIL_FEATURE_KEY,V as GROUP_KEY_TO_FEATURE,x as HIRE_FEATURE_KEY,O as LAUNCH_ITEM_FEATURE_KEY,z as OFFICE_FEATURE_KEY,D as PENCIL_FEATURE_KEY,le as clearAgentFeatures,ae as getAgentCapabilities,Ee as getAgentCapabilitiesInherited,$ as getAgentFeatures,w as getAgentInheritedFeatures,Ae as getAgentPluginSources,ue as getAgentToolPermissions,ee as getFeatureState,ye as instanceFeaturesCacheSize,de as isCapabilityEnabled,se as isFeatureEnabled,N as normalizeFeatureState,ce as resolveAgentToolPermissions,oe as resolveGroupFeatureKey,fe as setAgentCapabilities,pe as setAgentCapabilitiesInherited,re as setAgentFeatures,ie as setAgentInheritedFeatures};
1
+ import{getEffective as P,hasAnyDefault as N}from"./capability-config.js";const D=new Set(["disabled","collapsed","expanded"]);function j(e){if(e===!0)return"expanded";if(e===!1)return"disabled";if(typeof e=="string"&&D.has(e))return e}const T={},re="desktop",v="browser",S="agentSys.launchItem",x="agentSys.hire",O="agentSys.skillInstall",R="agentSys.abilityDev",I="pencil",z="draw",G="office",H="collaboration",h="collaboration.task",L="collaboration.meeting",m="collaboration.debug",U="collaboration.fileHistory",k="email",J=new Set,V=new Set([v,I,z,G,S,x,O,R,h,L,m,U,k]),W=[["agentSys","agentSys."],[H,"collaboration."]],X=new Map([["task",h],["meeting",L],["debug",m],["fileHistory",U],["launch",S],["hire",x],["abilityMarket",O],["abilityDev",R]]);function ie(e){return X.get(e)??e}function q(e){for(const[t,n]of W)if(e.startsWith(n))return t}const Q=new Set,d=new Map,y=new Map,a=new Map,Z=["fileReadOutside","commandExecution","fileModification","fileModificationOutside"],$=new Set(["allow","ask","deny"]);function w(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;const t=e,n={};let r=!1;for(const o of Z){const i=t[o];typeof i=="string"&&$.has(i)?(n[o]=i,r=!0):n[o]="allow"}return r?n:null}function K(e){if(e==null)return{...T};let t=e;if(typeof e=="string")try{t=JSON.parse(e)}catch{t=null}if(typeof t!="object"||t===null||Array.isArray(t))return{...T};const n={};for(const[r,o]of Object.entries(t)){if(Q.has(r))continue;const i=j(o);i!==void 0&&(n[r]=i)}return n}function se(e,t){if(!e)return;d.set(e,K(t));let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n=="object"&&n!==null&&!Array.isArray(n)){const r=w(n.toolPermissions);r?a.set(e,r):a.delete(e)}else a.delete(e)}function ee(e){return d.get(e)??{...T}}function le(e,t){if(!e)return;if(t==null){y.delete(e);return}const n=K(t);if(Object.keys(n).length===0){y.delete(e);return}y.set(e,n)}function te(e){return y.get(e)??{}}function ne(e,t){const n=ee(e),r=te(e),o=q(t);if(o&&(n[o]??r[o])==="disabled")return"disabled";const i=n[t]??r[t];return i!==void 0?i:J.has(t)?"expanded":V.has(t)?"collapsed":"disabled"}function ue(e,t){return ne(e,t)!=="disabled"}function ce(e){d.delete(e),a.delete(e),f.delete(e),_.delete(e)}function fe(e){return a.get(e)??null}function ae(e){return a.get(e)??{fileReadOutside:"allow",commandExecution:"allow",fileModification:"allow",fileModificationOutside:"allow"}}const M=["skills","mcp","plugins"],f=new Map,_=new Map;function Y(e){if(typeof e!="object"||e===null||Array.isArray(e))return;const t={};for(const[n,r]of Object.entries(e))n.trim()&&typeof r=="boolean"&&(t[n.trim()]=r);return t}function pe(e,t){if(!e)return;if(t==null){f.delete(e);return}let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n!="object"||n===null||Array.isArray(n)){f.delete(e);return}const r=n,o={};let i=!1;for(const E of M){const l=Y(r[E]);l&&(o[E]=l,i=!0)}i?f.set(e,o):f.delete(e);const s=r.plugins,u={};let b=!1;if(typeof s=="object"&&s!==null&&!Array.isArray(s))for(const[E,l]of Object.entries(s)){const A=E.trim();if(A){if(typeof l=="boolean"){const c=o.plugins??{};c[A]=l,o.plugins=c,i=!0;continue}if(l!==null&&typeof l=="object"&&!Array.isArray(l)){const c=l,B=c.enabled!==!1,g=typeof c.url=="string"?c.url:void 0,C=typeof c.sha256=="string"?c.sha256:void 0,F=o.plugins??{};F[A]=B,o.plugins=F,i=!0,g&&(u[A]={url:g,sha256:C},b=!0)}}}b?_.set(e,u):_.delete(e)}function Ee(e){return f.get(e)??null}const p=new Map;function Ae(e,t){if(!e)return;if(t==null){p.delete(e);return}let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n!="object"||n===null||Array.isArray(n)){p.delete(e);return}const r=n,o={};let i=!1;for(const s of M){const u=Y(r[s]);u&&(o[s]=u,i=!0)}i?p.set(e,o):p.delete(e)}function de(e){return p.get(e)??null}function ye(e){return _.get(e)??null}function _e(e,t,n){if(N(t))return P(e,t,n);const o=p.get(e)?.[t]?.[n];if(o!==void 0)return o;const i=f.get(e);if(!i)return!0;const s=i[t];if(!s)return!0;const u=s[n];return u===void 0?!0:u}function Te(){return d.size}export{R as ABILITY_DEV_FEATURE_KEY,v as BROWSER_FEATURE_KEY,M as CAPABILITY_TYPES,m as COLLABORATION_DEBUG_FEATURE_KEY,H as COLLABORATION_FEATURE_KEY,U as COLLABORATION_FILE_HISTORY_FEATURE_KEY,L as COLLABORATION_MEETING_FEATURE_KEY,h as COLLABORATION_TASK_FEATURE_KEY,re as DESKTOP_FEATURE_KEY,z as DRAW_FEATURE_KEY,k as EMAIL_FEATURE_KEY,X as GROUP_KEY_TO_FEATURE,x as HIRE_FEATURE_KEY,S as LAUNCH_ITEM_FEATURE_KEY,G as OFFICE_FEATURE_KEY,I as PENCIL_FEATURE_KEY,O as SKILL_INSTALL_FEATURE_KEY,ce as clearAgentFeatures,Ee as getAgentCapabilities,de as getAgentCapabilitiesInherited,ee as getAgentFeatures,te as getAgentInheritedFeatures,ye as getAgentPluginSources,fe as getAgentToolPermissions,ne as getFeatureState,Te as instanceFeaturesCacheSize,_e as isCapabilityEnabled,ue as isFeatureEnabled,j as normalizeFeatureState,ae as resolveAgentToolPermissions,ie as resolveGroupFeatureKey,pe as setAgentCapabilities,Ae as setAgentCapabilitiesInherited,se as setAgentFeatures,le as setAgentInheritedFeatures};
2
2
 
@@ -1,2 +1,2 @@
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 B}from"../utils/logger.js";import{normalizeMcpPayload as j}from"../utils/mcp-utils.js";import{ensureEnabledTools as z,parseBoolean as A}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 D,reconcileMcpDefaultsFromDeployed as U}from"./mcp-deploy.js";import{isBuiltinMcpName as W}from"./mcp-env-injector.js";import{reconcilePluginsDefaultsFromDeployed as Z,pluginManager as q}from"./plugin-manager.js";import{reconcileSkillsDefaultsFromDeployed as x,skillManager as V}from"./skill-manager.js";import{detectToolStatuses as G}from"./tool-installer.js";const H=B("instance-init");function J(a,f){const s=new Set(Object.values(f).filter(r=>r.installed).map(r=>r.tool));return a.filter(r=>s.has(r))}async function K(a,f){try{const s=await O(a,f);if(!s)return null;const r=await P.readFile(s.outputPath),c=a.defaultEnabled!==!1,k=String(a.skillName||"").trim()||void 0,l=await V.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 H.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 de(a,f,s){const r=w.resolve(f),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=z(s.ccSwitchEnabledTools);l("detect-tools","running","\u5F00\u59CB\u68C0\u6D4B\u5DE5\u5177\u5B89\u88C5\u72B6\u6001",{tools:u});const d=await G(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=J(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:A(s.skillEnabled,!0),packagePresent:!1},mcp:{enabled:A(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 g=await K(n,t);g&&e.push(g)}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 g=await P.readFile(n.outputPath),T=e.defaultEnabled!==!1,h=await q.saveSharedPlugin(g,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=D.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=>j(e)).filter(e=>e!==null);for(const e of o){if(W(e.name))continue;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,collapsed:e.collapsed===!0,description:e.description||void 0};D.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=x(),E=U(),N=Z();return(M||E||N)&&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:N}),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{de as initInstance};
1
+ import{promises as P}from"node:fs";import w from"node:path";import{downloadPluginZip as $,downloadSkillZip as I,ensureDir as y}from"../utils/file-utils.js";import{createLogger as O}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 j,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 U,saveInstanceState as _}from"./instance-state.js";import{mcpDeployManager as M,reconcileMcpDefaultsFromDeployed as L}from"./mcp-deploy.js";import{isBuiltinMcpName as W}from"./mcp-env-injector.js";import{reconcilePluginsDefaultsFromDeployed as Z,pluginManager as q}from"./plugin-manager.js";import{reconcileSkillsDefaultsFromDeployed as x,skillManager as V}from"./skill-manager.js";import{detectToolStatuses as G}from"./tool-installer.js";const H=O("instance-init");function J(n,k){const s=new Set(Object.values(k).filter(r=>r.installed).map(r=>r.tool));return n.filter(r=>s.has(r))}async function K(n,k){try{const s=await I(n,k);if(!s)return null;const r=await P.readFile(s.outputPath),d=n.defaultEnabled!==!1,S=String(n.skillName||"").trim()||void 0,l=await V.saveSharedSkill(r,s.fileName,d,n.sha256,S);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 H.warn("\u6280\u80FD\u5305\u90E8\u7F72\u5230 bridge \u5931\u8D25\uFF08\u6309\u8DF3\u8FC7\u5904\u7406\uFF09: %s. %s",n.skillName||n.fileName||"(\u672A\u547D\u540D)",s instanceof Error?s.message:String(s)),null}}async function ue(n,k,s){const r=w.resolve(k),d=R(n),S=[];function l(t,o,e,a){S.push({step:t,status:o,message:e,timestamp:new Date().toISOString(),details:a})}l("prepare","running","\u5F00\u59CB\u521D\u59CB\u5316\u5B9E\u4F8B",{agentId:String(n),workspacePath:r}),await y(d),l("prepare","success","\u521D\u59CB\u5316\u76EE\u5F55\u5DF2\u5C31\u7EEA",{initRoot:d});const u=B(s.ccSwitchEnabledTools);l("detect-tools","running","\u5F00\u59CB\u68C0\u6D4B\u5DE5\u5177\u5B89\u88C5\u72B6\u6001",{tools:u});const p=await G(u);l("detect-tools","success","\u5DE5\u5177\u5B89\u88C5\u72B6\u6001\u68C0\u6D4B\u5B8C\u6210",{installedTools:Object.values(p).filter(t=>t.installed).map(t=>t.tool),missingTools:Object.values(p).filter(t=>!t.installed).map(t=>t.tool)});const T=J(u,p),b=Object.values(p).filter(t=>!t.installed),i={ok:!0,agentId:String(n),workspacePath:r,initRoot:d,enabledTools:u,toolStatus:p,logs:S,skill:{enabled:D(s.skillEnabled,!0),packagePresent:!1},mcp:{enabled:D(s.mcpEnabled,!0),configPath:null}},m=await U(n);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:T}),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(d,"skills")),o=Array.isArray(s.skillPackages)&&s.skillPackages.length>0?s.skillPackages:s.skillPackage?[s.skillPackage]:[],e=[];for(const a of o){const f=await K(a,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(a=>a.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 h=Array.isArray(s.pluginPackages)?s.pluginPackages:[];if(h.length>0){l("install-plugins","running","\u5F00\u59CB\u90E8\u7F72\u63D2\u4EF6\u6A21\u677F\u5305",{count:h.length});const t=await y(w.join(d,"plugins-tmp"));let o=0;for(const e of h)if(!(!e||!String(e.downloadUrl||"").trim()))try{const a=await $(e,t);if(!a)continue;const f=await P.readFile(a.outputPath),A=e.defaultEnabled!==!1,c=await q.saveSharedPlugin(f,a.fileName,A,e.sha256);c.ok?(o++,l("install-plugins","success",`\u63D2\u4EF6 ${c.pluginName||a.fileName} \u5DF2\u90E8\u7F72\u5230\u672C bridge`)):l("install-plugins","error",`\u63D2\u4EF6 ${a.fileName} \u90E8\u7F72\u5931\u8D25: ${c.error||"\u672A\u77E5\u9519\u8BEF"}`)}catch(a){l("install-plugins","error",`\u63D2\u4EF6 ${e.fileName||"(\u672A\u547D\u540D)"} \u90E8\u7F72\u5931\u8D25: ${a instanceof Error?a.message:String(a)}`)}i.plugin={enabled:!0,packagePresent:h.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 g=[];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=j();t=M.saveMcp(v,e,!0),t.ok&&(F("mcp",v,!0),g.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){if(W(e.name))continue;const a=String(e.packageUrl||"").trim();if(a)try{const c=await M.ensureMcpPackage(e.name,{packageUrl:a,packageSha256:e.packageSha256,fileName:`${e.name}.zip`});c.ok||l("install-mcp","error",`MCP \u5305 ${e.name} \u90E8\u7F72\u5931\u8D25: ${c.error||"\u672A\u77E5\u9519\u8BEF"}`)}catch(c){l("install-mcp","error",`MCP \u5305 ${e.name} \u90E8\u7F72\u5931\u8D25: ${c instanceof Error?c.message:String(c)}`)}const f={type:e.transport||"stdio",command:e.command||void 0,url:e.url||void 0,args:e.args||void 0,env:e.env||void 0,headers:e.headers||void 0,collapsed:e.collapsed===!0,description:e.description||void 0};M.saveMcp(e.name,f,e.enabled!==!1,e.packageSha256).ok&&g.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=g.length,l("install-mcp","success","MCP \u6A21\u677F\u90E8\u7F72\u5B8C\u6210",{installedCount:g.length,mcpServers:g.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"),m.initialized=!0,m.enabledTools=u,m.toolStatus=p,m.skillEnabled=i.skill.enabled,m.mcpEnabled=i.mcp.enabled,await _(n,m),l("persist-state","success","\u5B9E\u4F8B\u72B6\u6001\u4FDD\u5B58\u5B8C\u6210");const E=x(),N=L(),C=Z();return(E||N||C)&&l("sync-state","success","\u80FD\u529B\u9ED8\u8BA4\u5F00\u5173\u5DF2\u5BF9\u8D26\uFF08\u65B0\u589E\u9879\u9ED8\u8BA4\u5173\u95ED\uFF09",{reconciledSkills:E,reconciledMcp:N,reconciledPlugins:C}),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:g}}}export{ue as initInstance};
2
2
 
@@ -4,6 +4,15 @@ export interface DeployedMcpEntry {
4
4
  fileName: string;
5
5
  defaultEnabled: boolean;
6
6
  sha256?: string;
7
+
8
+ packageSha256?: string;
9
+ }
10
+
11
+ export interface DeployedMcpPackageEntry {
12
+ name: string;
13
+ fileName: string;
14
+ packageSha256?: string;
15
+ dependencies?: string;
7
16
  }
8
17
  export interface McpDeployResult {
9
18
  ok: boolean;
@@ -11,6 +20,12 @@ export interface McpDeployResult {
11
20
  name?: string;
12
21
  }
13
22
 
23
+ export interface McpPackageRef {
24
+ packageUrl: string;
25
+ packageSha256?: string;
26
+ fileName?: string;
27
+ }
28
+
14
29
  export interface McpDeploySpec {
15
30
  type: string;
16
31
  command?: string;
@@ -28,6 +43,8 @@ export declare class McpDeployManager {
28
43
  private static _instance;
29
44
  static getInstance(): McpDeployManager;
30
45
  private constructor();
46
+
47
+ private static isValidName;
31
48
  private manifestFile;
32
49
  private specFile;
33
50
  private isHealthy;
@@ -40,6 +57,20 @@ export declare class McpDeployManager {
40
57
  ok: boolean;
41
58
  error?: string;
42
59
  };
60
+ private packagesDir;
61
+ private packagesManifestFile;
62
+
63
+ packageDir(name: string): string;
64
+
65
+ isPackageHealthy(name: string): boolean;
66
+ private readPackagesManifest;
67
+ private writePackagesManifest;
68
+
69
+ private packageUpToDate;
70
+
71
+ ensureMcpPackage(name: string, ref: McpPackageRef): Promise<McpDeployResult>;
72
+
73
+ private removeMcpPackage;
43
74
 
44
75
  listDeployed(): DeployedMcpEntry[];
45
76
 
@@ -1,4 +1,5 @@
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
- `,"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{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};
1
+ import{existsSync as f,mkdirSync as p,readFileSync as d,renameSync as y,rmSync as h,writeFileSync as M}from"node:fs";import s from"node:path";import{getBridgeTemplateMcpDir as v,getBridgeTemplateMcpPackagesDir as $}from"../config.js";import{downloadPluginZip as N}from"../utils/file-utils.js";import{createLogger as j}from"../utils/logger.js";import{setDeployedDefaultsProvider as C,reconcileDefaultsFromDeployed as F}from"./capability-config.js";import{isCapabilityEnabled as P}from"./instance-features.js";import{extractMcpPackageZip as E,runMcpPackageInstall as b}from"./mcp-package.js";const g=j("mcp-deploy"),O=1;class c{static getInstance(){return this._instance||(this._instance=new c(s.join(v(),"deployed"))),this._instance}constructor(e){this.rootDir=e}static isValidName(e){return!e||e==="."||e===".."||e!==s.basename(e)?!1:/^[a-zA-Z0-9_.-]+$/.test(e)}manifestFile(){return s.join(this.rootDir,"manifest.json")}specFile(e){const r=s.join(this.rootDir,`${e}.json`),t=s.resolve(this.rootDir);if(s.resolve(r)!==s.join(t,`${e}.json`))throw new Error(`MCP \u6A21\u677F\u6587\u4EF6\u8D8A\u51FA\u90E8\u7F72\u533A: ${e}`);return r}isHealthy(e){return f(this.specFile(e))}readManifest(){try{const e=JSON.parse(d(this.manifestFile(),"utf8"));return Array.isArray(e.servers)?e.servers.filter(r=>r&&r.name):[]}catch{return[]}}writeManifest(e){p(this.rootDir,{recursive:!0}),M(this.manifestFile(),`${JSON.stringify({version:O,servers:e},null,2)}
2
+ `,"utf8")}saveMcp(e,r,t=!0,i){if(!c.isValidName(e))return{ok:!1,error:`MCP \u540D\u975E\u6CD5: ${JSON.stringify(e)}`};p(this.rootDir,{recursive:!0});try{M(this.specFile(e),`${JSON.stringify(r,null,2)}
3
+ `,"utf8")}catch(n){return{ok:!1,error:`MCP \u6A21\u677F\u5199\u5165\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`}}const a=this.readManifest().filter(n=>n.name!==e);return a.push({name:e,fileName:`${e}.json`,defaultEnabled:t,sha256:i}),this.writeManifest(a),g.info("[mcp] MCP \u6A21\u677F\u5DF2\u90E8\u7F72\u5230 bridge: %s",e),{ok:!0,name:e}}removeMcp(e){if(!c.isValidName(e))return{ok:!1,error:"name \u975E\u6CD5"};const r=this.readManifest().filter(t=>t.name!==e);this.writeManifest(r);try{h(this.specFile(e),{force:!0})}catch(t){return{ok:!1,error:`\u6A21\u677F\u6587\u4EF6\u6E05\u7406\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`}}return this.removeMcpPackage(e),g.info("[mcp] MCP \u6A21\u677F\u5DF2\u4ECE bridge \u79FB\u9664\u90E8\u7F72: %s",e),{ok:!0}}packagesDir(){return $()}packagesManifestFile(){return s.join(this.packagesDir(),"manifest.json")}packageDir(e){if(!c.isValidName(e))throw new Error(`\u975E\u6CD5 MCP \u540D: ${JSON.stringify(e)}`);const r=s.join(this.packagesDir(),e),t=s.resolve(this.packagesDir());if(s.resolve(r)!==s.join(t,e))throw new Error(`MCP \u5305\u76EE\u5F55\u8D8A\u51FA\u90E8\u7F72\u533A: ${e}`);return r}isPackageHealthy(e){try{return f(s.join(this.packageDir(e),"mcp.json"))}catch{return!1}}readPackagesManifest(){try{const e=JSON.parse(d(this.packagesManifestFile(),"utf8"));return Array.isArray(e.packages)?e.packages.filter(r=>r&&r.name):[]}catch{return[]}}writePackagesManifest(e){p(this.packagesDir(),{recursive:!0}),M(this.packagesManifestFile(),`${JSON.stringify({version:1,packages:e},null,2)}
4
+ `,"utf8")}packageUpToDate(e,r){return this.isPackageHealthy(e)?r?this.readPackagesManifest().find(i=>i.name===e)?.packageSha256===r:!0:!1}async ensureMcpPackage(e,r){if(!c.isValidName(e))return{ok:!1,error:`MCP \u540D\u975E\u6CD5: ${JSON.stringify(e)}`};const t=String(r?.packageUrl??"").trim();if(!t)return{ok:!1,error:"packageUrl \u4E3A\u7A7A"};if(this.packageUpToDate(e,r.packageSha256))return{ok:!0,name:e};const i=s.join(this.packagesDir(),"tmp",`pull-${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{p(i,{recursive:!0});const a=r.fileName?.trim()||`${e}.zip`,n=await N({downloadUrl:t,fileName:a,sha256:r.packageSha256},i);if(!n)return{ok:!1,error:`\u4E0B\u8F7D MCP \u5305\u65E0\u54CD\u5E94: ${t}`};const S=d(n.outputPath),w=s.join(i,"extract"),o=await E(S,w);await b(o.packageDir,o.manifest),p(this.packagesDir(),{recursive:!0});const l=this.packageDir(e),u=s.join(this.packagesDir(),`.old-${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);let k=!1;f(l)&&(y(l,u),k=!0);try{y(o.packageDir,l)}catch(m){throw k&&f(u)&&(h(l,{recursive:!0,force:!0}),y(u,l)),m}k&&f(u)&&h(u,{recursive:!0,force:!0});const D=this.readPackagesManifest().filter(m=>m.name!==e);return D.push({name:e,fileName:n.fileName,packageSha256:r.packageSha256,dependencies:o.manifest.dependencies}),this.writePackagesManifest(D),g.info("[mcp] \u5305\u578B MCP \u5DF2\u90E8\u7F72\u5230 bridge: %s\uFF08%d \u4E2A\u6587\u4EF6, dependencies=%s\uFF09",e,o.fileCount,o.manifest.dependencies),{ok:!0,name:e}}catch(a){const n=a instanceof Error?a.message:String(a);return g.warn("[mcp] \u5305\u578B MCP \u90E8\u7F72\u5931\u8D25\uFF08%s\uFF09: %s",e,n),{ok:!1,error:`MCP \u5305\u90E8\u7F72\u5931\u8D25: ${n}`}}finally{try{h(i,{recursive:!0,force:!0})}catch{}}}removeMcpPackage(e){try{const t=this.packageDir(e);f(t)&&h(t,{recursive:!0,force:!0})}catch(t){g.warn("[mcp] MCP \u5305\u76EE\u5F55\u6E05\u7406\u5931\u8D25\uFF08%s\uFF09: %s",e,t instanceof Error?t.message:String(t))}const r=this.readPackagesManifest().filter(t=>t.name!==e);try{this.writePackagesManifest(r)}catch{}}listDeployed(){return this.readManifest().map(e=>({...e,deployed:this.isHealthy(e.name)}))}getSpec(e){if(!this.isHealthy(e))return null;try{return JSON.parse(d(this.specFile(e),"utf8"))}catch{return null}}resolveEnabledMcp(e,r){const t={};for(const i of this.readManifest()){if(!P(e,"mcp",i.name)||!this.isHealthy(i.name))continue;const a=this.getSpec(i.name);a&&(t[i.name]={...a,type:a.type||"stdio"})}for(const[i,a]of Object.entries(r))P(e,"mcp",i)&&(t[i]||(t[i]=a));return t}deployedDefaultEnabled(){const e={};for(const r of this.readManifest())e[r.name]=r.defaultEnabled;return e}}c._instance=null;const J=c.getInstance();C("mcp",()=>J.deployedDefaultEnabled());const z=()=>F("mcp");export{c as McpDeployManager,J as mcpDeployManager,z as reconcileMcpDefaultsFromDeployed};
4
5
 
@@ -1,12 +1,36 @@
1
1
 
2
2
  export declare function isStdioMcpSpec(spec: unknown): boolean;
3
3
 
4
+ export declare const MCP_PACKAGE_DIR_PLACEHOLDER = "${MCP_PACKAGE_DIR}";
5
+ export declare const MCP_NODE_PLACEHOLDER = "${MCP_NODE}";
6
+
7
+ export declare function expandMcpPackagePlaceholders(record: Record<string, unknown>, packageDir?: string, nodePath?: string): boolean;
8
+
4
9
  export declare function isBuiltinMcpName(name: string): boolean;
5
10
 
11
+ export declare const AGENT_META_ENV_KEYS: {
12
+ readonly agentId: "AWS_AGENT_ID";
13
+ readonly roleId: "AWS_AGENT_ROLE_ID";
14
+ readonly projectId: "AWS_AGENT_PROJECT_ID";
15
+ };
16
+
17
+ export declare const RESERVED_ENV_KEY_PREFIX = "AWS_AGENT_";
18
+ export interface AgentMetaEnvInput {
19
+ agentId?: string;
20
+ roleId?: string;
21
+ projectId?: string;
22
+ }
23
+
24
+ export declare function buildAgentMetaEnv(meta: AgentMetaEnvInput | undefined): Record<string, string>;
25
+
6
26
  export declare function expandEnvPlaceholders(text: string, env: Record<string, string>): string;
7
27
  export interface InjectEnvOptions {
8
28
 
9
29
  overwriteExisting?: boolean;
30
+
31
+ resolvePackageDir?: (name: string) => string | undefined;
32
+
33
+ agentMeta?: AgentMetaEnvInput;
10
34
  }
11
35
 
12
36
  export declare function injectEffectiveEnvIntoMcpServers(servers: Record<string, unknown>, effectiveEnv: Record<string, string>, options?: InjectEnvOptions): string[];
@@ -1,2 +1,2 @@
1
- import{sanitizeEnvForChild as m}from"../utils/env-safety.js";import{createLogger as j}from"../utils/logger.js";const y=j("mcp-env-injector"),x=new Set(["agents-work-studio","aws-mcp","aws-mcp-dev"]);function b(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const t=e,r=typeof t.type=="string"?t.type.toLowerCase():"";return r==="sse"||r==="http"||r==="https"?!1:typeof t.command=="string"&&t.command.trim()!==""}function A(e){return x.has(e)}function g(e,t){return e.includes("${")?e.replace(/\$\{([^}]+)\}/g,(r,o)=>{const n=o.trim();if(t[n]!==void 0)return t[n];const i=n.toUpperCase();for(const[f,c]of Object.entries(t))if(f.toUpperCase()===i)return c;return r}):e}function h(e,t){let r=!1;for(const[o,n]of Object.entries(e)){if(typeof n!="string"||!n.includes("${"))continue;const i=g(n,t);i!==n&&(e[o]=i,r=!0)}return r}function E(e,t){let r=!1;if(typeof e.url=="string"&&e.url.includes("${")){const n=g(e.url,t);n!==e.url&&(e.url=n,r=!0)}const o=e.headers;return o&&typeof o=="object"&&!Array.isArray(o)&&(r=h(o,t)||r),r}function C(e,t,r){const o=m(t),n=[],i=[];for(const[f,c]of Object.entries(e)){if(A(f)||!c||typeof c!="object"||Array.isArray(c))continue;const s=c;if(!b(s)){Object.keys(o).length>0&&E(s,o)&&i.push(f);continue}if(Object.keys(o).length===0)continue;const p=s.env&&typeof s.env=="object"&&!Array.isArray(s.env)?s.env:{},a={...p},v=h(a,o);let l=!1;for(const[u,d]of Object.entries(o))!r?.overwriteExisting&&p[u]!==void 0||a[u]!==d&&(a[u]=d,l=!0);!l&&!v||(s.env=a,n.push(f))}return n.length>0&&y.info(`injected effective env vars into ${n.length} MCP server(s): ${n.join(", ")}`),i.length>0&&y.info(`expanded \${VAR} placeholders in ${i.length} remote MCP server(s): ${i.join(", ")}`),n}export{g as expandEnvPlaceholders,C as injectEffectiveEnvIntoMcpServers,A as isBuiltinMcpName,b as isStdioMcpSpec};
1
+ import{sanitizeEnvForChild as C}from"../utils/env-safety.js";import{createLogger as P}from"../utils/logger.js";const y=P("mcp-env-injector"),I=new Set(["agents-work-studio","aws-mcp","aws-mcp-dev"]);function M(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const o=e,n=typeof o.type=="string"?o.type.toLowerCase():"";return n==="sse"||n==="http"||n==="https"?!1:typeof o.command=="string"&&o.command.trim()!==""}const A="${MCP_PACKAGE_DIR}",x="${MCP_NODE}";function S(e,o,n=process.execPath){if(!o)return!1;let t=!1;const s=r=>!r.includes(A)&&!r.includes(x)?r:r.split(A).join(o).split(x).join(n);if(typeof e.command=="string"&&e.command.includes("${MCP_")){const r=s(e.command);r!==e.command&&(e.command=r,t=!0)}if(Array.isArray(e.args)){let r=!1;const c=e.args.map(a=>{if(typeof a!="string")return a;const i=s(a);return i!==a&&(r=!0),i});r&&(e.args=c,t=!0)}return t}function $(e){return I.has(e)}const g={agentId:"AWS_AGENT_ID",roleId:"AWS_AGENT_ROLE_ID",projectId:"AWS_AGENT_PROJECT_ID"},L="AWS_AGENT_";function O(e){if(!e)return{};const o={},n=[[g.agentId,e.agentId],[g.roleId,e.roleId],[g.projectId,e.projectId]];for(const[t,s]of n){const r=typeof s=="string"?s.trim():"";r&&(o[t]=r)}return o}function l(e,o){return e.includes("${")?e.replace(/\$\{([^}]+)\}/g,(n,t)=>{const s=t.trim();if(o[s]!==void 0)return o[s];const r=s.toUpperCase();for(const[c,a]of Object.entries(o))if(c.toUpperCase()===r)return a;return n}):e}function _(e,o){let n=!1;for(const[t,s]of Object.entries(e)){if(typeof s!="string"||!s.includes("${"))continue;const r=l(s,o);r!==s&&(e[t]=r,n=!0)}return n}function b(e,o){let n=!1;if(typeof e.url=="string"&&e.url.includes("${")){const s=l(e.url,o);s!==e.url&&(e.url=s,n=!0)}const t=e.headers;return t&&typeof t=="object"&&!Array.isArray(t)&&(n=_(t,o)||n),n}function k(e){const o={};for(const[n,t]of Object.entries(e))typeof t=="string"&&(o[n]=t);return o}function N(e,o){let n=!1;if(typeof e.command=="string"&&e.command.includes("${")){const t=l(e.command,o);t!==e.command&&(e.command=t,n=!0)}if(Array.isArray(e.args)){let t=!1;const s=e.args.map(r=>{if(typeof r!="string"||!r.includes("${"))return r;const c=l(r,o);return c!==r&&(t=!0),c});t&&(e.args=s,n=!0)}return n}function T(e,o,n){const t=C(o),s=[],r=[];for(const[c,a]of Object.entries(e)){if($(c)||!a||typeof a!="object"||Array.isArray(a))continue;const i=a;if(!M(i)){Object.keys(t).length>0&&b(i,t)&&r.push(c);continue}const m=i.env&&typeof i.env=="object"&&!Array.isArray(i.env)?i.env:{},f={...m},E=_(f,t);let d=!1;for(const[u,p]of Object.entries(t))!n?.overwriteExisting&&m[u]!==void 0||f[u]!==p&&(f[u]=p,d=!0);const v=n?.agentMeta?O(n.agentMeta):{};for(const[u,p]of Object.entries(v))f[u]!==p&&(f[u]=p,d=!0);const h=N(i,{...t,...k(f)}),j=n?.resolvePackageDir?S(i,n.resolvePackageDir(c)):!1;!d&&!E&&!h&&!j||((d||E)&&(i.env=f),s.push(c))}return s.length>0&&y.info(`injected effective env vars into ${s.length} MCP server(s): ${s.join(", ")}`),r.length>0&&y.info(`expanded \${VAR} placeholders in ${r.length} remote MCP server(s): ${r.join(", ")}`),s}export{g as AGENT_META_ENV_KEYS,x as MCP_NODE_PLACEHOLDER,A as MCP_PACKAGE_DIR_PLACEHOLDER,L as RESERVED_ENV_KEY_PREFIX,O as buildAgentMetaEnv,l as expandEnvPlaceholders,S as expandMcpPackagePlaceholders,T as injectEffectiveEnvIntoMcpServers,$ as isBuiltinMcpName,M as isStdioMcpSpec};
2
2
 
@@ -0,0 +1,35 @@
1
+
2
+ export interface McpPackageManifestEnvField {
3
+ key: string;
4
+ required?: boolean;
5
+ sensitive?: boolean;
6
+ description?: string;
7
+
8
+ example?: string;
9
+ }
10
+ export interface McpPackageManifest {
11
+ name?: string;
12
+ version?: string;
13
+ runtime: "node" | "python" | "binary";
14
+ entry: string;
15
+ args?: string[];
16
+ dependencies: "bundled" | "npm";
17
+ install?: string;
18
+ description?: string;
19
+
20
+ env?: McpPackageManifestEnvField[];
21
+ }
22
+
23
+ export declare function validateMcpPackageManifest(raw: unknown): McpPackageManifest;
24
+
25
+ export declare function readMcpPackageManifest(packageDir: string): McpPackageManifest;
26
+ export interface McpPackageExtractResult {
27
+
28
+ packageDir: string;
29
+ fileCount: number;
30
+ manifest: McpPackageManifest;
31
+ }
32
+
33
+ export declare function extractMcpPackageZip(zipBuffer: Buffer, stagingRoot: string): Promise<McpPackageExtractResult>;
34
+
35
+ export declare function runMcpPackageInstall(packageDir: string, manifest: McpPackageManifest): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import{spawn as l}from"node:child_process";import{existsSync as E,readFileSync as g}from"node:fs";import h from"node:path";import{createLogger as S}from"../utils/logger.js";import{BLOCKED_ENV_KEYS as w,ENV_KEY_PATTERN as y}from"../utils/env-safety.js";import{extractPluginZip as T}from"./plugin-package.js";const A=S("mcp-package"),$=new Set(["node","python","binary"]),M=new Set(["bundled","npm"]),d="mcp.json",N=/^[A-Za-z0-9_./@+-]+$/,a=/^(npm|pnpm|yarn)\s+(ci|install)(\s+[A-Za-z0-9@._/:=+-]+)*$/,u=5*60*1e3,P=64*1024;function f(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function _(n){if(n==null)return;if(!Array.isArray(n))throw new Error("mcp.json \u7684 env \u975E\u6CD5\uFF08\u987B\u4E3A\u6570\u7EC4\uFF09");if(n.length===0)return;if(n.length>64)throw new Error("mcp.json \u7684 env \u6700\u591A\u58F0\u660E 64 \u9879");const i=new Set,e=[];for(const r of n){if(!f(r))throw new Error("mcp.json \u7684 env \u5143\u7D20\u975E\u6CD5\uFF08\u987B\u4E3A\u5BF9\u8C61\uFF09");const t=String(r.key??"").trim();if(!t)throw new Error("mcp.json \u7684 env \u5143\u7D20\u7F3A\u5C11 key");if(!y.test(t))throw new Error(`mcp.json \u7684 env \u53D8\u91CF\u540D\u975E\u6CD5: ${t}`);if(w.has(t.toUpperCase()))throw new Error(`mcp.json \u58F0\u660E\u4E86\u7981\u6B62\u7684\u5371\u9669\u73AF\u5883\u53D8\u91CF: ${t}`);if(i.has(t))throw new Error(`mcp.json \u7684 env \u91CD\u590D\u58F0\u660E: ${t}`);i.add(t),e.push({key:t,required:r.required===!0,sensitive:r.sensitive===!0,description:r.description!==void 0?String(r.description):void 0,example:r.example!==void 0?String(r.example):void 0})}return e}function v(n){if(!f(n))throw new Error("mcp.json \u5FC5\u987B\u662F JSON \u5BF9\u8C61");const i=String(n.runtime??"").trim().toLowerCase();if(!$.has(i))throw new Error(`mcp.json \u7684 runtime \u975E\u6CD5\uFF08\u4EC5 node/python/binary\uFF09: ${String(n.runtime)}`);const e=String(n.entry??"").trim();if(!e||!N.test(e)||e.startsWith("/")||/^[A-Za-z]:/.test(e)||e.split(/[\\/]/).includes(".."))throw new Error(`mcp.json \u7684 entry \u975E\u6CD5\uFF08\u987B\u4E3A\u5305\u5185\u76F8\u5BF9\u8DEF\u5F84\uFF09: ${e}`);const r=String(n.dependencies??"bundled").trim().toLowerCase()||"bundled";if(!M.has(r))throw new Error(`mcp.json \u7684 dependencies \u975E\u6CD5\uFF08\u4EC5 bundled/npm\uFF09: ${r}`);let t;if(r==="npm"&&(t=String(n.install??"").trim(),!t||!a.test(t)))throw new Error(`dependencies=npm \u65F6\u5FC5\u987B\u58F0\u660E\u5408\u6CD5\u7684 install \u547D\u4EE4\uFF08\u4EC5 npm/pnpm/yarn \u7684 install/ci\uFF09: ${t}`);const o=Array.isArray(n.args)?n.args.filter(s=>s!=null).map(String):void 0;return{name:n.name!==void 0?String(n.name):void 0,version:n.version!==void 0?String(n.version):void 0,runtime:i,entry:e,args:o,dependencies:r,install:t,description:n.description!==void 0?String(n.description):void 0,env:_(n.env)}}function j(n){const i=h.join(n,d);if(!E(i))throw new Error(`MCP \u5305\u5185\u7F3A\u5C11 ${d}\uFF08\u5305\u578B MCP \u5FC5\u987B\u81EA\u63CF\u8FF0 runtime/entry\uFF09`);let e;try{e=JSON.parse(g(i,"utf8"))}catch(r){throw new Error(`MCP \u5305\u5185 ${d} \u89E3\u6790\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`)}return v(e)}async function O(n,i){const{pluginDir:e,fileCount:r}=await T(n,i),t=j(e);return{packageDir:e,fileCount:r,manifest:t}}async function R(n,i){if(i.dependencies!=="npm")return;const e=String(i.install??"").trim();if(!a.test(e))throw new Error(`\u62D2\u7EDD\u6267\u884C\u975E\u767D\u540D\u5355\u5B89\u88C5\u547D\u4EE4: ${e}`);await new Promise((r,t)=>{A.info("[mcp-package] \u6267\u884C\u4F9D\u8D56\u5B89\u88C5: %s (cwd=%s)",e,n);const o=l(e,{cwd:n,shell:!0,windowsHide:!0});let s="";const p=c=>{s.length<P&&(s+=c.toString("utf8"))};o.stdout?.on("data",p),o.stderr?.on("data",p);const m=setTimeout(()=>{o.kill(),t(new Error(`\u4F9D\u8D56\u5B89\u88C5\u8D85\u65F6\uFF08${u}ms\uFF09: ${e}`))},u);o.on("error",c=>{clearTimeout(m),t(new Error(`\u4F9D\u8D56\u5B89\u88C5\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${c.message}`))}),o.on("close",c=>{if(clearTimeout(m),c!==0){t(new Error(`\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25\uFF08\u9000\u51FA\u7801 ${c}\uFF09: ${s.trim().slice(0,600)||"(\u65E0\u8F93\u51FA)"}`));return}r()})})}export{O as extractMcpPackageZip,j as readMcpPackageManifest,R as runMcpPackageInstall,v as validateMcpPackageManifest};
2
+
@@ -0,0 +1,25 @@
1
+
2
+ import { type AgentMetaEnvInput } from "./mcp-env-injector.js";
3
+ export interface McpProbeTool {
4
+ name: string;
5
+ description?: string;
6
+ inputSchema?: unknown;
7
+ }
8
+ export interface McpProbeResult {
9
+ ok: boolean;
10
+ name: string;
11
+ tools: McpProbeTool[];
12
+ instructions?: string;
13
+
14
+ error?: string;
15
+ }
16
+ export interface McpProbeOptions {
17
+
18
+ effectiveEnv?: Record<string, string>;
19
+
20
+ agentMeta?: AgentMetaEnvInput;
21
+ connectTimeoutMs?: number;
22
+ listToolsTimeoutMs?: number;
23
+ }
24
+
25
+ export declare function probeDeployedMcp(name: string, options?: McpProbeOptions): Promise<McpProbeResult>;
@@ -0,0 +1,2 @@
1
+ import{Client as C}from"@modelcontextprotocol/sdk/client/index.js";import{StdioClientTransport as P}from"@modelcontextprotocol/sdk/client/stdio.js";import{SSEClientTransport as k}from"@modelcontextprotocol/sdk/client/sse.js";import{StreamableHTTPClientTransport as _}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{mcpDeployManager as f}from"./mcp-deploy.js";import{buildAgentMetaEnv as b,expandEnvPlaceholders as u,expandMcpPackagePlaceholders as v,isBuiltinMcpName as y}from"./mcp-env-injector.js";import{sanitizeEnvForChild as g}from"../utils/env-safety.js";import{createLogger as L}from"../utils/logger.js";const $=L("mcp-probe"),O=1e4,D=1e4;async function N(t,n={}){const e=String(t??"").trim();if(!e)return{ok:!1,name:e,tools:[],error:"name is required"};if(!/^[a-zA-Z0-9_.-]+$/.test(e))return{ok:!1,name:e,tools:[],error:`MCP \u540D\u975E\u6CD5: ${e}`};if(y(e))return{ok:!1,name:e,tools:[],error:`\u300C${e}\u300D\u662F\u5185\u7F6E\u901A\u8BAF MCP\uFF0C\u4E0D\u63A5\u53D7\u63A2\u6D4B`};const m=f.getSpec(e);if(!m)return{ok:!1,name:e,tools:[],error:`\u672A\u5728\u90E8\u7F72\u533A\u627E\u5230\u8BE5 MCP: ${e}\uFF08\u8BF7\u5148\u5B89\u88C5/\u90E8\u7F72\uFF09`};const i=n.connectTimeoutMs??O,s=n.listToolsTimeoutMs??D,r=new C({name:"aws-runtime-bridge-probe",version:"1.0.0"});try{const a=U(m,n.effectiveEnv??{},e,n.agentMeta);await M(r.connect(a),i,`MCP initialize timeout after ${i}ms`);const{tools:c}=await M(r.listTools(),s,`MCP listTools timeout after ${s}ms`),l=r.getInstructions();return{ok:!0,name:e,tools:(c??[]).map(o=>({name:o.name,...o.description?{description:o.description}:{},...o.inputSchema?{inputSchema:o.inputSchema}:{}})),...l?{instructions:l}:{}}}catch(a){const c=a instanceof Error?a.message:String(a);return $.warn(`[mcp] \u63A2\u6D4B\u5931\u8D25: ${e}: ${c}`),{ok:!1,name:e,tools:[],error:c}}finally{try{await r.close()}catch{}}}function U(t,n,e,m){const i=String(t.type??"stdio").toLowerCase();if(i==="stdio"||t.command){if(!t.command)throw new Error("stdio MCP server requires command");const l=g(n),o=g(t.env??{}),d={...l,...o,...b(m)},w=e&&f.isPackageHealthy(e)?f.packageDir(e):void 0,p={command:t.command,args:t.args??[]};v(p,w);const S=u(String(p.command),d),E=p.args.map(h=>u(String(h),d)),T=new P({command:S,args:E,env:d,stderr:"pipe"});return T.stderr?.on("data",()=>{}),T}if(!t.url)throw new Error("remote MCP server requires url");const s=g(n),r=u(t.url,s),a=t.headers?Object.fromEntries(Object.entries(t.headers).map(([l,o])=>[l,u(String(o),s)])):void 0,c=a?{headers:a}:void 0;return i==="sse"?new k(new URL(r),{requestInit:c}):new _(new URL(r),{requestInit:c})}function M(t,n,e){return new Promise((m,i)=>{const s=setTimeout(()=>i(new Error(e)),n);t.then(r=>{clearTimeout(s),m(r)},r=>{clearTimeout(s),i(r instanceof Error?r:new Error(String(r)))})})}export{N as probeDeployedMcp};
2
+
@@ -1,9 +1,14 @@
1
1
 
2
+ import type { AgentMetaEnvInput } from "./mcp-env-injector.js";
2
3
 
3
4
  export declare function setPanelEnvVars(agentId: string | undefined, env: unknown): void;
4
5
 
5
6
  export declare function getPanelEnvVars(agentId?: string): Record<string, string>;
6
7
 
8
+ export declare function setAgentMeta(agentId: string | undefined, meta: unknown): void;
9
+
10
+ export declare function getAgentMeta(agentId?: string): AgentMetaEnvInput | undefined;
11
+
7
12
  export declare function clearPanelEnvVars(agentId: string | undefined): void;
8
13
 
9
14
  export declare function resetPanelEnvVars(): void;
@@ -1,2 +1,2 @@
1
- import{sanitizeEnvForChild as i}from"../utils/env-safety.js";const o="",r=new Map;function t(n){return(n==null?"":String(n).trim())||o}function a(n){return i(n)}function c(n,e){r.set(t(n),a(e))}function l(n){const e=r.get(t(n));return e||(r.get(o)??{})}function u(n){r.delete(t(n))}function f(){r.clear()}export{u as clearPanelEnvVars,l as getPanelEnvVars,f as resetPanelEnvVars,c as setPanelEnvVars};
1
+ import{sanitizeEnvForChild as u}from"../utils/env-safety.js";const i="",r=new Map,o=new Map;function t(e){return(e==null?"":String(e).trim())||i}function p(e){return u(e)}function g(e,n){r.set(t(e),p(n))}function E(e){const n=r.get(t(e));return n||(r.get(i)??{})}function m(e,n){const a=n&&typeof n=="object"&&!Array.isArray(n)?n:{},c=l=>{const s=a[l];return(typeof s=="string"?s.trim():"")||void 0};o.set(t(e),{agentId:c("agentId"),roleId:c("roleId"),projectId:c("projectId")})}function v(e){return o.get(t(e))??o.get(i)}function A(e){r.delete(t(e)),o.delete(t(e))}function x(){r.clear(),o.clear()}export{A as clearPanelEnvVars,v as getAgentMeta,E as getPanelEnvVars,x as resetPanelEnvVars,m as setAgentMeta,g as setPanelEnvVars};
2
2
 
@@ -0,0 +1,36 @@
1
+
2
+ import type { PluginLoader } from "./plugin-loader.js";
3
+ import type { SharedPluginEntry } from "./plugin-runtime.js";
4
+ export declare class PluginDeploymentStore {
5
+ private readonly rootDir;
6
+ private readonly runtimeRootDir;
7
+ private readonly loader;
8
+ constructor(rootDir: string, runtimeRootDir: string | undefined, loader: PluginLoader);
9
+ deployedDir(): string;
10
+ deployedManifestFile(): string;
11
+
12
+ deployedPluginDir(name: string): string;
13
+
14
+ private legacySharedDir;
15
+
16
+ deployedPluginHealthy(name: string): boolean;
17
+ readSharedManifest(): SharedPluginEntry[];
18
+ writeSharedManifest(entries: SharedPluginEntry[]): void;
19
+
20
+ migrateLegacySharedIfNeeded(): Promise<void>;
21
+
22
+ deployPluginZipToPersistentDir(zipBuffer: Buffer, expectedName?: string): Promise<SharedPluginEntry | null>;
23
+
24
+ replaceDeployedDir(pluginName: string, sourceDir: string): void;
25
+
26
+ removeDeployedDir(pluginName: string): void;
27
+
28
+ updateSharedManifest(mutator: (entries: SharedPluginEntry[]) => SharedPluginEntry[]): Promise<void>;
29
+
30
+ runtimeDirFor(agentId: string): string;
31
+ runtimeLinkPath(agentId: string, name: string): string;
32
+
33
+ ensureRuntimeLink(agentId: string, name: string): boolean;
34
+
35
+ removeRuntimeLink(agentId: string, name: string): void;
36
+ }
@@ -0,0 +1,3 @@
1
+ import{cpSync as S,existsSync as a,lstatSync as P,mkdirSync as h,readFileSync as f,readdirSync as w,renameSync as g,rmSync as u,symlinkSync as M,writeFileSync as v}from"node:fs";import{join as s,resolve as m}from"node:path";import{getBridgeInstancePluginsDir as N}from"../config.js";import{sanitizeAgentId as F,sanitizeArchiveFileName as k,withFileLock as $}from"../utils/file-utils.js";import{createLogger as L}from"../utils/logger.js";import{extractPluginZip as E}from"./plugin-package.js";import{isValidPluginName as D,PLUGIN_NAME_PATTERN as R}from"./plugin-manifest.js";const l=L("plugin-manager"),A=process.platform==="win32"?"junction":"dir";class Z{constructor(r,e,i){this.rootDir=r,this.runtimeRootDir=e,this.loader=i}deployedDir(){return s(this.rootDir,"deployed")}deployedManifestFile(){return s(this.deployedDir(),"manifest.json")}deployedPluginDir(r){if(!D(r))throw new Error(`\u975E\u6CD5\u63D2\u4EF6\u540D\uFF08\u4EC5\u5141\u8BB8 ${R}\uFF09: ${JSON.stringify(r)}`);const e=s(this.deployedDir(),r),i=m(this.deployedDir());if(m(e)!==s(i,r))throw new Error(`\u63D2\u4EF6\u76EE\u5F55\u8D8A\u51FA\u90E8\u7F72\u533A: ${r}`);return e}legacySharedDir(){return s(this.rootDir,"shared")}deployedPluginHealthy(r){return a(s(this.deployedPluginDir(r),"plugin.json"))}readSharedManifest(){try{const r=JSON.parse(f(this.deployedManifestFile(),"utf8"));return Array.isArray(r.plugins)?r.plugins.filter(e=>e&&D(e.pluginName)):[]}catch{return[]}}writeSharedManifest(r){h(this.deployedDir(),{recursive:!0}),v(this.deployedManifestFile(),`${JSON.stringify({version:2,plugins:r},null,2)}
2
+ `,"utf8")}async migrateLegacySharedIfNeeded(){try{if(a(this.deployedManifestFile()))return;const r=s(this.legacySharedDir(),"manifest.json");if(!a(r))return;const e=JSON.parse(f(r,"utf8")),i=Array.isArray(e.plugins)?e.plugins:[];if(i.length===0)return;const t=[];let n=0,o=0;for(const d of i){const y=k(d.zipFile,"");if(!d.pluginName||!y)continue;const p=s(this.legacySharedDir(),y);if(a(p)){n+=1;try{const c=await this.deployPluginZipToPersistentDir(f(p),d.pluginName);if(!c){o+=1;continue}t.push(c),l.info("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u5230\u90E8\u7F72\u533A: %s",d.pluginName)}catch(c){o+=1,l.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6 %s \u8FC1\u79FB\u5931\u8D25: %s",d.pluginName,c instanceof Error?c.message:String(c))}}}t.length>0&&this.writeSharedManifest(t),o===0?u(this.legacySharedDir(),{recursive:!0,force:!0}):l.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u90E8\u5206\u5931\u8D25\uFF08%d/%d\uFF09\uFF0C\u4FDD\u7559 shared/ \u76EE\u5F55\u4EE5\u514D\u6570\u636E\u4E22\u5931",o,n)}catch(r){l.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u672A\u6267\u884C\uFF08\u4E0B\u6B21\u91CD\u8BD5\uFF09: %s",r instanceof Error?r.message:String(r))}}async deployPluginZipToPersistentDir(r,e){if(!r||r.length===0)return null;const i=s(this.rootDir,"tmp",`migrate-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const t=await E(r,i),n=this.loader.loadManifestOnly(t.pluginDir);if(!n.ok)return null;const o=n.manifest.name;return e&&o!==e?null:(this.replaceDeployedDir(o,t.pluginDir),{pluginName:o,zipFile:`${o}.zip`,fileName:`${o}.zip`,defaultEnabled:!0})}finally{u(i,{recursive:!0,force:!0})}}replaceDeployedDir(r,e){h(this.deployedDir(),{recursive:!0});const i=this.deployedPluginDir(r),t=s(this.deployedDir(),`.old-${r}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);a(i)&&g(i,t);try{S(e,i,{recursive:!0,filter:n=>!/[\\/]\.git([\\/]|$)/.test(n)&&!/[\\/]node_modules([\\/]|$)/.test(n)})}catch(n){throw a(t)&&(u(i,{recursive:!0,force:!0}),g(t,i)),n}a(t)&&u(t,{recursive:!0,force:!0})}removeDeployedDir(r){u(this.deployedPluginDir(r),{recursive:!0,force:!0})}async updateSharedManifest(r){await $(this.deployedManifestFile(),async()=>{this.writeSharedManifest(r(this.readSharedManifest()))})}runtimeDirFor(r){return this.runtimeRootDir?s(this.runtimeRootDir,F(r)):N(r)}runtimeLinkPath(r,e){return s(this.runtimeDirFor(r),e)}ensureRuntimeLink(r,e){const i=this.runtimeLinkPath(r,e),t=this.deployedPluginDir(e);if(!a(s(t,"plugin.json")))return!1;h(this.runtimeDirFor(r),{recursive:!0});try{if(a(i)){let n=!1;try{n=P(i).isSymbolicLink()}catch{n=!1}if(n)try{return w(i),!0}catch{}u(i,{recursive:!0,force:!0})}return M(t,i,A),l.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u5EFA\u7ACB: %s \u2192 %s",r,i,t),!0}catch(n){return l.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5931\u8D25\uFF08%s \u2192 %s\uFF09: %s",r,e,t,n instanceof Error?n.message:String(n)),!1}}removeRuntimeLink(r,e){const i=this.runtimeLinkPath(r,e);try{a(i)&&(u(i,{recursive:!0,force:!0}),l.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u79FB\u9664: %s",r,e))}catch(t){l.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u79FB\u9664\u5931\u8D25\uFF08%s\uFF09: %s",r,e,t instanceof Error?t.message:String(t))}}}export{Z as PluginDeploymentStore};
3
+
@@ -1,2 +1,3 @@
1
- const D=6e4,_=2e3,m=500,u={urgent:0,normal:1,low:2};class v{constructor(i){this.agentId=i,this.revision=0,this.records=[],this.dedup=new Map,this.nextSeq=1}get currentRevision(){return this.revision}push(i){const n=i.dedupKey||i.message.msgId,t=Date.now();if(n){const e=this.dedup.get(n);if(e!==void 0&&t-e<6e4)return!1;this.dedup.set(n,t)}for(this.pruneDedup(t),this.records.push({seq:this.nextSeq++,record:i});this.records.length>500;)this.dropOldestLowestPriority();return this.revision++,!0}drain(i={}){const n=Math.max(1,i.maxPerKey??10),t=this.revision;if(this.records.length===0)return{revision:t,events:[]};const e=[...this.records].sort((s,o)=>{const r=u[s.record.priority]-u[o.record.priority];return r!==0?r:s.seq-o.seq}),d=[],p=new Map,c=new Map;for(const s of e){const o=s.record,r=`${o.plugin}:${o.event}`,l=p.get(r)??0;if(l<n)p.set(r,l+1),d.push(s);else{const a=c.get(r);a?a.count++:c.set(r,{count:1,sample:o})}}const f=new Set(d.map(s=>s.seq));this.records=this.records.filter(s=>!f.has(s.seq));const h=d.map(s=>s.record.message);for(const[s,{count:o,sample:r}]of c)h.push({msgId:`plugin-collapse-${s}-${t}`,channel:"plugin-event",senderId:`plugin:${r.plugin}`,senderName:`\u63D2\u4EF6[${r.plugin}]`,receiverId:this.agentId||void 0,content:`\u3010\u63D2\u4EF6\u4E8B\u4EF6\u6298\u53E0\u3011\u63D2\u4EF6 ${r.plugin} \u7684 ${r.event} \u4E8B\u4EF6\u8FD8\u6709 ${o} \u6761\u5F85\u5904\u7406\uFF08\u672C\u6279\u6B21\u6BCF\u4E2A\u4E8B\u4EF6\u952E\u6700\u591A\u4EA4\u4ED8 ${n} \u6761\uFF0C\u5176\u4F59\u5DF2\u6298\u53E0\uFF1B\u7EE7\u7EED\u8C03\u7528\u63D2\u4EF6\u5DE5\u5177\u6216\u7B49\u5F85\u4E0B\u6279 poll \u4EA4\u4ED8\uFF09\u3002`,requireReply:!1,role:"system",timestamp:new Date(r.receivedAt).toISOString()});return{revision:t,events:h}}dropOldestLowestPriority(){if(this.records.length===0)return;let i=0,n=-1;for(let t=0;t<this.records.length;t++){const e=u[this.records[t].record.priority];if(e>n&&(n=e,i=t,e===2))break}this.records.splice(i,1)}pruneDedup(i){if(this.dedup.size<=2e3)return;for(const[e,d]of this.dedup)i-d>=6e4&&this.dedup.delete(e);if(this.dedup.size<=2e3)return;const n=[...this.dedup.entries()].sort((e,d)=>e[1]-d[1]),t=this.dedup.size-2e3;for(let e=0;e<t;e++)this.dedup.delete(n[e][0])}}export{v as PluginEventBuffer};
1
+ const D=6e4,v=2e3,_=500,u={urgent:0,normal:1,low:2};class m{constructor(n){this.agentId=n,this.revision=0,this.records=[],this.dedup=new Map,this.nextSeq=1}get currentRevision(){return this.revision}push(n){const i=n.dedupKey||n.message.msgId,s=Date.now();if(i){const e=this.dedup.get(i);if(e!==void 0&&s-e<6e4)return!1;this.dedup.set(i,s)}for(this.pruneDedup(s),this.records.push({seq:this.nextSeq++,record:n});this.records.length>500;)this.dropOldestLowestPriority();return this.revision++,!0}drain(n={}){const i=Math.max(1,n.maxPerKey??10),s=this.revision;if(this.records.length===0)return{revision:s,events:[]};const e=[...this.records].sort((r,o)=>{const t=u[r.record.priority]-u[o.record.priority];return t!==0?t:r.seq-o.seq}),d=[],p=new Map,c=new Map;for(const r of e){const o=r.record,t=`${o.plugin}:${o.event}`,h=p.get(t)??0;if(h<i)p.set(t,h+1),d.push(r);else{const a=c.get(t);a?a.count++:c.set(t,{count:1,sample:o})}}const f=new Set(d.map(r=>r.seq));this.records=this.records.filter(r=>!f.has(r.seq));const l=d.map(r=>r.record.message);for(const[r,{count:o,sample:t}]of c)l.push({msgId:`plugin-collapse-${r}-${s}`,channel:"plugin-event",senderId:`plugin:${t.plugin}`,senderName:`\u63D2\u4EF6[${t.plugin}]`,receiverId:this.agentId||void 0,content:`[plugin:${t.plugin}] ${t.event}
2
+ \u3010\u63D2\u4EF6\u4E8B\u4EF6\u6298\u53E0\u3011\u63D2\u4EF6 ${t.plugin} \u7684 ${t.event} \u4E8B\u4EF6\u8FD8\u6709 ${o} \u6761\u5F85\u5904\u7406\uFF08\u672C\u6279\u6B21\u6BCF\u4E2A\u4E8B\u4EF6\u952E\u6700\u591A\u4EA4\u4ED8 ${i} \u6761\uFF0C\u5176\u4F59\u5DF2\u6298\u53E0\uFF1B\u7EE7\u7EED\u8C03\u7528\u63D2\u4EF6\u5DE5\u5177\u6216\u7B49\u5F85\u4E0B\u6279 poll \u4EA4\u4ED8\uFF09\u3002`,requireReply:!1,role:"system",timestamp:new Date(t.receivedAt).toISOString()});return{revision:s,events:l}}dropOldestLowestPriority(){if(this.records.length===0)return;let n=0,i=-1;for(let s=0;s<this.records.length;s++){const e=u[this.records[s].record.priority];if(e>i&&(i=e,n=s,e===2))break}this.records.splice(n,1)}pruneDedup(n){if(this.dedup.size<=2e3)return;for(const[e,d]of this.dedup)n-d>=6e4&&this.dedup.delete(e);if(this.dedup.size<=2e3)return;const i=[...this.dedup.entries()].sort((e,d)=>e[1]-d[1]),s=this.dedup.size-2e3;for(let e=0;e<s;e++)this.dedup.delete(i[e][0])}}export{m as PluginEventBuffer};
2
3
 
@@ -0,0 +1,5 @@
1
+
2
+
3
+ export declare function rmWithRetry(dir: string, attempts?: number, delayMs?: number): Promise<void>;
4
+
5
+ export declare function movePluginDir(sourceDir: string, targetDir: string): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import{cpSync as o,mkdirSync as m,renameSync as u,rmSync as f}from"node:fs";import{dirname as s}from"node:path";async function y(r,t=8,e=200){for(let n=0;;n++)try{f(r,{recursive:!0,force:!0});return}catch(c){if(n>=t-1)throw c;await new Promise(i=>setTimeout(i,e))}}async function d(r,t){m(s(t),{recursive:!0});try{u(r,t);return}catch(e){const n=e?.code;if(!n||!["EXDEV","EPERM","EACCES","EBUSY","EINVAL"].includes(n))throw e}o(r,t,{recursive:!0,filter:e=>!/[\\/]\.git([\\/]|$)/.test(e)&&!/[\\/]node_modules([\\/]|$)/.test(e)}),await y(r)}export{d as movePluginDir,y as rmWithRetry};
2
+
@@ -0,0 +1,7 @@
1
+
2
+ import type { PluginInvokeContext, PluginToolInvocationResult, JsonObject } from "@agentswork/acode";
3
+ import type { PluginToolDef } from "./plugin-manifest.js";
4
+ import type { LoadedPlugin } from "./plugin-runtime.js";
5
+ export declare function executeHandler(agentId: string, plugin: LoadedPlugin, tool: PluginToolDef, params: JsonObject, ctx?: PluginInvokeContext): Promise<PluginToolInvocationResult>;
6
+
7
+ export declare function buildPluginEnv(plugin: LoadedPlugin, agentId: string): NodeJS.ProcessEnv;
@@ -0,0 +1,3 @@
1
+ import{spawn as T}from"node:child_process";import{join as _}from"node:path";import{pathToFileURL as O}from"node:url";import{BLOCKED_ENV_KEYS as P}from"../utils/env-safety.js";import{createLogger as A}from"../utils/logger.js";import{renderCommandArgv as v,truncate as C}from"./plugin-manifest.js";const N=A("plugin-manager"),g=256*1024,h=6e4,S=/^[A-Za-z_][A-Za-z0-9_]*$/;async function G(t,e,s,a,o){const n=Date.now(),r=s.handler??{type:"process"};try{return r.type==="mcp"?{ok:!1,error:"handler.type=mcp \u5C06\u5728\u540E\u7EED\u7248\u672C\u652F\u6301\uFF0C\u8BF7\u6539\u7528 process/module handler"}:r.type==="module"?{ok:!0,result:await b(e,r,a,t,o),durationMs:Date.now()-n}:!r.command||!r.command.trim()?{ok:!1,error:`\u5DE5\u5177 ${s.name} \u7684 process handler \u7F3A\u5C11 command`}:{ok:!0,result:await $(e,r,a,t,o),durationMs:Date.now()-n}}catch(i){return{ok:!1,error:i instanceof Error?i.message:String(i),durationMs:Date.now()-n}}}async function $(t,e,s,a,o){const n=e.command??"";if(e.shell===!0&&/\{\{.+?\}\}/.test(n))throw new Error('shell:true \u7684 handler \u4E0D\u652F\u6301 {{params.*}} \u63D2\u503C\uFF08\u547D\u4EE4\u6CE8\u5165\u98CE\u9669\uFF09\uFF1B\u8BF7\u6539\u7528 shell:false \u7684 argv \u6A21\u5F0F\u6216 stdin:"params"');const r=v(n,{params:s});if(r.length===0)throw new Error("process handler command \u4E3A\u7A7A");const i=typeof e.timeoutMs=="number"&&e.timeoutMs>0?e.timeoutMs:h,u=new AbortController,d=()=>u.abort();o?.signal?.addEventListener("abort",d,{once:!0});const E=setTimeout(()=>u.abort(),i);try{return await new Promise((l,w)=>{N.info("[plugin:%s] spawn: %s",t.name,r.join(" "));const c=T(r[0],r.slice(1),{cwd:t.dir,env:k(t,a),shell:e.shell===!0,windowsHide:!0,signal:u.signal});let f="",y="";c.stdin?.on("error",()=>{}),c.stdout?.on("data",m=>{f.length<g&&(f+=m.toString("utf8"))}),c.stderr?.on("data",m=>{y.length<g&&(y+=m.toString("utf8"))}),c.on("error",m=>{w(new Error(`\u63D2\u4EF6\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${m.message}`))}),c.on("close",m=>{const p=f.trim();if(m!==0){const M=C(y.trim()||p||"(\u65E0\u8F93\u51FA)",600);w(new Error(u.signal.aborted?`\u63D2\u4EF6\u8FDB\u7A0B\u8D85\u65F6(${i}ms)\u6216\u88AB\u4E2D\u6B62`:`\u63D2\u4EF6\u8FDB\u7A0B\u9000\u51FA\u7801 ${m}: ${M}`));return}if(!p){l({ok:!0});return}try{l(JSON.parse(p))}catch{l(p)}});try{e.stdin==="params"?c.stdin?.end(`${JSON.stringify(s)}
2
+ `):c.stdin?.end()}catch{}})}finally{clearTimeout(E),o?.signal?.removeEventListener("abort",d)}}async function b(t,e,s,a,o){if(!e.module)throw new Error("module handler \u7F3A\u5C11 module \u8DEF\u5F84");const n=_(t.dir,e.module);let r=t.moduleCache.get(n);r||(r=await import(`${O(n).href}?acode_nonce=${t.importNonce}`),t.moduleCache.set(n,r));const i=e.export||"default",d=r[i];if(typeof d!="function")throw new Error(`\u6A21\u5757 ${e.module} \u672A\u5BFC\u51FA\u51FD\u6570 ${i}`);const E=typeof e.timeoutMs=="number"&&e.timeoutMs>0?e.timeoutMs:h;let l;const w=Promise.resolve().then(()=>d(s,{agentId:a,signal:o?.signal,pluginRoot:t.dir}));try{return await Promise.race([w,new Promise((c,f)=>{l=setTimeout(()=>f(new Error(`\u63D2\u4EF6\u6A21\u5757\u6267\u884C\u8D85\u65F6(${E}ms)`)),E)})])}finally{clearTimeout(l)}}function k(t,e){const s={};for(const o of["PATH","HOME","USERPROFILE","SystemRoot","COMSPEC","TEMP","TMP","LANG","TZ"]){const n=process.env[o];n!==void 0&&(s[o]=n)}s.ACODE_PLUGIN_ROOT=t.dir,s.ACODE_AGENT_ID=e,s.ACODE_PLUGIN_NAME=t.name;const a=new Set((t.userConfig??[]).map(o=>o.key));for(const[o,n]of Object.entries(t.configValues))a.has(o)&&(!S.test(o)||P.has(o.toUpperCase())||(s[o]=n));return s}export{k as buildPluginEnv,G as executeHandler};
3
+
@@ -0,0 +1,18 @@
1
+
2
+ import type { PluginListenerDef } from "./plugin-manifest.js";
3
+ import type { AgentState, LoadedPlugin } from "./plugin-runtime.js";
4
+ export declare class ListenerRunner {
5
+
6
+ ensureRunning(state: AgentState): void;
7
+ startAll(state: AgentState, plugin: LoadedPlugin): void;
8
+ stopAll(plugin: LoadedPlugin): void;
9
+ private start;
10
+ private spawnChild;
11
+ private scheduleRestart;
12
+
13
+ private pollOnce;
14
+ private stop;
15
+ private handleLine;
16
+
17
+ enqueue(state: AgentState, plugin: LoadedPlugin, listener: PluginListenerDef, eventObj: Record<string, unknown>): void;
18
+ }
@@ -0,0 +1,8 @@
1
+ import{spawn as $}from"node:child_process";import{createLogger as R}from"../utils/logger.js";import{buildPluginEnv as S}from"./plugin-handler-adapter.js";import{getPath as E,isRecord as _,renderCommandArgv as w,renderTemplate as A,safeStableStringify as b,truncate as h}from"./plugin-manifest.js";const I=R("plugin-manager"),L=200,T=256*1024,M=4*1024,y=6e4,x=6e4;function p(g,n){g.logs.push(`${new Date().toISOString()} ${n}`),g.logs.length>L&&g.logs.shift()}class J{ensureRunning(n){for(const t of n.plugins.values())if(t.enabled)for(const e of t.runtimes)!e.child&&!e.timer&&!e.backoffTimer&&!e.stopping&&this.start(n,t,e)}startAll(n,t){for(const e of t.runtimes)this.stop(e),t.enabled&&this.start(n,t,e)}stopAll(n){for(const t of n.runtimes)this.stop(t)}start(n,t,e){const r=e.def.transport??{type:"command-stream"};if(r.type==="http-callback"){e.stopping=!1;return}if(r.type==="poll-command"){const s=Math.max(5e3,r.intervalMs??3e4);e.stopping=!1,e.timer=setInterval(()=>{this.pollOnce(n,t,e)},s),this.pollOnce(n,t,e);return}if(!r.command){e.lastError="command-stream \u7F3A\u5C11 command",p(e,`ERROR ${e.lastError}`);return}e.stopping=!1,this.spawnChild(n,t,e)}spawnChild(n,t,e){const s=e.def.transport?.command??"",d=w(s,{});try{p(e,`spawn: ${d.join(" ")}`);const i=$(d[0],d.slice(1),{cwd:t.dir,env:S(t,n.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"]});e.child=i,e.lastError=void 0;let o="";i.stdout?.on("data",a=>{o+=a.toString("utf8");let l=o.indexOf(`
2
+ `);for(;l>=0;){const f=o.slice(0,l).trim();o=o.slice(l+1),f&&this.handleLine(n,t,e,f),l=o.indexOf(`
3
+ `)}o.length>1024*1024&&(o=o.slice(-4096))}),i.stderr?.on("data",a=>{p(e,`stderr: ${h(a.toString("utf8").trimEnd(),400)}`)}),i.on("error",a=>{e.lastError=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${a.message}`,p(e,`ERROR ${e.lastError}`)}),i.on("close",a=>{e.child=void 0,!e.stopping&&(e.lastError=`\u76D1\u542C\u8FDB\u7A0B\u9000\u51FA\uFF08code=${a??"signal"}\uFF09`,p(e,`exit code=${a??"signal"}\uFF0C\u51C6\u5907\u91CD\u542F`),this.scheduleRestart(n,t,e))})}catch(i){const o=i instanceof Error?i.message:String(i);e.lastError=o,p(e,`ERROR spawn: ${o}`),this.scheduleRestart(n,t,e)}}scheduleRestart(n,t,e){if(e.stopping)return;const r=Math.max(500,e.def.transport?.restartBackoffMs??2e3),s=Math.min(x,r*2**Math.min(e.restarts,6));e.restarts++,p(e,`restart #${e.restarts} in ${s}ms`),e.backoffTimer=setTimeout(()=>{e.backoffTimer=void 0,e.stopping||this.spawnChild(n,t,e)},s)}async pollOnce(n,t,e){if(e.polling)return;const r=e.def.transport?.command??"",s=w(r,{});if(s.length===0)return;e.polling=!0;const d=new AbortController,i=setTimeout(()=>d.abort(),y);try{const o=await new Promise((a,l)=>{const f=$(s[0],s.slice(1),{cwd:t.dir,env:S(t,n.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"],signal:d.signal});let c="",u="";f.stdout?.on("data",m=>{c.length<T&&(c+=m.toString("utf8"))}),f.stderr?.on("data",m=>{u.length<T&&(u+=m.toString("utf8"))});const v=()=>d.signal.aborted;f.on("error",m=>{l(v()?new Error(`poll \u8D85\u65F6(${y}ms)`):m)}),f.on("close",m=>{v()?l(new Error(`poll \u8D85\u65F6(${y}ms)`)):m===0?a(c):l(new Error(`exit ${m}: ${h(u||c,300)}`))})});e.lastError=void 0;for(const a of o.split(`
4
+ `)){const l=a.trim();l&&this.handleLine(n,t,e,l)}}catch(o){const a=o instanceof Error?o.message:String(o);e.lastError=a,p(e,`poll \u5931\u8D25: ${a}`)}finally{clearTimeout(i),e.polling=!1}}stop(n){if(n.stopping=!0,n.restarts=0,n.child){try{n.child.kill()}catch{}n.child=void 0}n.timer&&(clearInterval(n.timer),n.timer=void 0),n.backoffTimer&&(clearTimeout(n.backoffTimer),n.backoffTimer=void 0)}handleLine(n,t,e,r){p(e,`event: ${h(r,300)}`);let s;try{s=JSON.parse(r)}catch{e.lastError="\u4E8B\u4EF6\u884C\u4E0D\u662F\u5408\u6CD5 JSON\uFF08\u8981\u6C42 JSONL\uFF09";return}if(!_(s))return;const d=typeof s.event=="string"?s.event:e.def.event,i=d===e.def.event?e.def:t.listeners.find(o=>o.event===d);i&&(i.delivery&&i.delivery!=="poll"&&I.debug("[plugin:%s] delivery=%s \u6682\u6309 poll \u4EA4\u4ED8",t.name,i.delivery),this.enqueue(n,t,i,s))}enqueue(n,t,e,r){for(const[c,u]of Object.entries(e.matcher??{})){const v=E(r,c);if(!(Array.isArray(u)?u:[u]).some(O=>JSON.stringify(O)===JSON.stringify(v)))return}let s;if(e.dedupKey){const c=E(r,e.dedupKey);c!=null&&(s=h(String(c),256))}n.eventSeq++;const d=h(b(r.data??r),M),i=e.summary?A(e.summary,r):e.description??"",o=(e.toolHints??[]).join(","),a=`[plugin:${t.name}] ${e.event}`+(i?`
5
+ ${i}`:"")+(o?`
6
+ toolHints=${o}`:"")+`
7
+ payload=${d}`,l={msgId:h(s?`plugin-event-${t.name}-${s}`:`plugin-event-${t.name}-${e.event}-${n.eventSeq}`,512),channel:"plugin-event",senderId:`plugin:${t.name}`,senderName:`\u63D2\u4EF6[${t.name}]`,receiverId:n.agentId||void 0,content:a,requireReply:!1,role:"system",timestamp:new Date().toISOString()},f=e.priority??"normal";n.buffer.push({plugin:t.name,event:e.event,priority:f,dedupKey:s,receivedAt:Date.now(),message:l})}}export{J as ListenerRunner};
8
+
@@ -0,0 +1,32 @@
1
+
2
+ import type { PluginSummary } from "@agentswork/acode";
3
+ import { type PluginManifest, type PluginToolDef } from "./plugin-manifest.js";
4
+ import type { LoadedPlugin } from "./plugin-runtime.js";
5
+ export type ManifestReadResult = {
6
+ ok: true;
7
+ manifest: PluginManifest;
8
+ } | {
9
+ ok: false;
10
+ error: string;
11
+ };
12
+ export declare class PluginLoader {
13
+
14
+ private importNonce;
15
+ private readJsonFile;
16
+
17
+ loadManifestOnly(dir: string): ManifestReadResult;
18
+
19
+ validateUserConfigValues(manifest: PluginManifest, configValues: Record<string, string>): string | null;
20
+
21
+ loadPluginFromDir(dir: string, source: string, installedAt: string, configValues: Record<string, string>): {
22
+ ok: true;
23
+ plugin: LoadedPlugin;
24
+ } | {
25
+ ok: false;
26
+ error: string;
27
+ };
28
+ }
29
+
30
+ export declare function requiredParamsOf(tool: PluginToolDef): string[] | undefined;
31
+
32
+ export declare function toSummary(plugin: LoadedPlugin): PluginSummary;