aws-runtime-bridge 1.9.162 → 1.9.169

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 (123) hide show
  1. package/CHANGELOG.md +324 -0
  2. package/dist/adapter/AcodeSdkAdapter.d.ts +31 -3
  3. package/dist/adapter/AcodeSdkAdapter.js +4 -9
  4. package/dist/adapter/ClaudeSdkAdapter.d.ts +2 -0
  5. package/dist/adapter/ClaudeSdkAdapter.js +3 -3
  6. package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
  7. package/dist/adapter/CodexSdkAdapter.js +3 -3
  8. package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
  9. package/dist/adapter/OpencodeSdkAdapter.js +3 -3
  10. package/dist/adapter/prompts.d.ts +1 -1
  11. package/dist/adapter/prompts.js +1 -1
  12. package/dist/adapter/types.d.ts +41 -4
  13. package/dist/adapter/types.js +1 -1
  14. package/dist/browser/frame-encode.d.ts +25 -0
  15. package/dist/browser/frame-encode.js +2 -0
  16. package/dist/browser/screencast-differ.d.ts +2 -3
  17. package/dist/browser/screencast-differ.js +1 -1
  18. package/dist/browser/screencast-manager.js +1 -1
  19. package/dist/browser/types.d.ts +5 -1
  20. package/dist/browser/types.js +1 -1
  21. package/dist/desktop/desktop-mcp-client.js +2 -2
  22. package/dist/routes/background-tasks.js +3 -3
  23. package/dist/routes/capabilities.js +1 -1
  24. package/dist/routes/dashboard.d.ts +2 -0
  25. package/dist/routes/dashboard.js +4 -4
  26. package/dist/routes/git.js +22 -22
  27. package/dist/routes/instance.js +1 -1
  28. package/dist/routes/launch.js +10 -10
  29. package/dist/routes/mcp-extra.js +2 -2
  30. package/dist/routes/mcp.d.ts +4 -0
  31. package/dist/routes/mcp.js +1 -1
  32. package/dist/routes/plugins.js +1 -1
  33. package/dist/routes/pty.d.ts +11 -3
  34. package/dist/routes/pty.js +3 -3
  35. package/dist/routes/runtime-binding.js +1 -1
  36. package/dist/routes/sessions.js +1 -1
  37. package/dist/routes/skills.js +1 -1
  38. package/dist/routes/sub-agents.js +8 -8
  39. package/dist/routes/terminal.d.ts +16 -2
  40. package/dist/routes/terminal.js +34 -36
  41. package/dist/services/agent-process-manager.js +1 -1
  42. package/dist/services/agent-pty-manager.js +4 -4
  43. package/dist/services/aws-client-agent-mcp.js +2 -2
  44. package/dist/services/capability-config.d.ts +8 -0
  45. package/dist/services/capability-config.js +2 -2
  46. package/dist/services/desktop-mcp-manager.d.ts +3 -1
  47. package/dist/services/desktop-mcp-manager.js +1 -1
  48. package/dist/services/instance-ai-config-service.js +1 -1
  49. package/dist/services/instance-features.d.ts +10 -0
  50. package/dist/services/instance-features.js +1 -1
  51. package/dist/services/instance-init-service.js +1 -1
  52. package/dist/services/launch-manager.d.ts +9 -1
  53. package/dist/services/launch-manager.js +6 -6
  54. package/dist/services/launch-metrics.d.ts +1 -1
  55. package/dist/services/launch-metrics.js +4 -3
  56. package/dist/services/mcp-deploy.d.ts +4 -0
  57. package/dist/services/mcp-env-injector.d.ts +12 -0
  58. package/dist/services/mcp-env-injector.js +2 -0
  59. package/dist/services/mcp-launch-binding-queue.d.ts +8 -0
  60. package/dist/services/mcp-launch-binding-queue.js +1 -1
  61. package/dist/services/orphan-monitor.js +1 -1
  62. package/dist/services/panel-env.d.ts +6 -2
  63. package/dist/services/panel-env.js +1 -1
  64. package/dist/services/plugin-manager.js +9 -9
  65. package/dist/services/process-detector.d.ts +23 -3
  66. package/dist/services/process-detector.js +13 -13
  67. package/dist/services/runtime-resources-snapshot.d.ts +3 -0
  68. package/dist/services/runtime-resources-snapshot.js +3 -0
  69. package/dist/services/session-output.d.ts +13 -0
  70. package/dist/services/session-output.js +4 -4
  71. package/dist/services/tunnel-client.js +1 -1
  72. package/dist/services/workspace-files.js +1 -1
  73. package/dist/types.d.ts +4 -0
  74. package/dist/utils/env-safety.d.ts +15 -0
  75. package/dist/utils/env-safety.js +2 -0
  76. package/dist/utils/lifecycle-log.d.ts +2 -0
  77. package/dist/utils/lifecycle-log.js +3 -0
  78. package/dist/utils/mcp-utils.js +1 -1
  79. package/package/acode/dist/background-command-manager.js +4 -4
  80. package/package/acode/dist/built-in-file-tools.d.ts +13 -0
  81. package/package/acode/dist/built-in-file-tools.js +2 -2
  82. package/package/acode/dist/builtins/shellCommandPreparation.d.ts +2 -0
  83. package/package/acode/dist/builtins/shellCommandPreparation.js +2 -2
  84. package/package/acode/dist/compaction.d.ts +10 -0
  85. package/package/acode/dist/compaction.js +6 -6
  86. package/package/acode/dist/context-overflow.js +1 -1
  87. package/package/acode/dist/index.d.ts +1 -0
  88. package/package/acode/dist/index.js +1 -1
  89. package/package/acode/dist/mcpToolNames.d.ts +4 -0
  90. package/package/acode/dist/mcpToolNames.js +1 -1
  91. package/package/acode/dist/runtime-environment.d.ts +2 -0
  92. package/package/acode/dist/runtime-environment.js +3 -2
  93. package/package/acode/dist/runtime.d.ts +68 -8
  94. package/package/acode/dist/runtime.js +28 -27
  95. package/package/acode/dist/sub-agent-manager.js +1 -1
  96. package/package/acode/dist/tool-allocation.js +1 -1
  97. package/package/acode/dist/tool-group-manager.d.ts +12 -0
  98. package/package/acode/dist/tool-group-manager.js +8 -4
  99. package/package/acode/dist/types.d.ts +8 -0
  100. package/package/acode/package.json +1 -1
  101. package/package/aws-client-agent-mcp/README.md +1 -0
  102. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +22 -8
  103. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  104. package/package/aws-client-agent-mcp/dist/http-client.d.ts +10 -0
  105. package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
  106. package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -1
  107. package/package/aws-client-agent-mcp/dist/logger.js +2 -2
  108. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +19 -2
  109. package/package/aws-client-agent-mcp/dist/mcp-server.js +18 -18
  110. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +15 -4
  111. package/package/aws-client-agent-mcp/dist/mcp-tools.js +79 -29
  112. package/package/aws-client-agent-mcp/dist/memory-store.d.ts +2 -0
  113. package/package/aws-client-agent-mcp/dist/memory-store.js +3 -3
  114. package/package/aws-client-agent-mcp/dist/message-buffer.js +1 -1
  115. package/package/aws-client-agent-mcp/dist/office/office-workspace.d.ts +15 -0
  116. package/package/aws-client-agent-mcp/dist/office/office-workspace.js +1 -1
  117. package/package/aws-client-agent-mcp/dist/status-reporter.js +1 -1
  118. package/package/aws-client-agent-mcp/dist/tool-groups.d.ts +4 -0
  119. package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
  120. package/package/aws-client-agent-mcp/dist/types.d.ts +52 -1
  121. package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
  122. package/package/aws-client-agent-mcp/package.json +1 -1
  123. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- import{access as b,constants as P}from"node:fs/promises";import{join as m,resolve as M}from"node:path";import{createBuiltInDesktopTools as w}from"../desktop/built-in-desktop-tools.js";import{DesktopMcpConnection as O}from"../desktop/desktop-mcp-client.js";import{logger as T}from"../utils/logger.js";import{DESKTOP_FEATURE_KEY as C,isFeatureEnabled as D}from"./instance-features.js";import{getPanelEnvVars as I}from"./panel-env.js";const d=T.child("desktop-mcp");let n=null,c=null,r=null,l,f="none";const k=process.platform==="win32"?"nuphus-mcp.exe":"nuphus-mcp",N=12e4,U=6e4;function x(){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 N}function A(){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 U}async function K(){const e=process.env.AWS_DESKTOP_MCP_BIN;if(e){const o=M(e);return await g(o)?o:null}const t=m(process.cwd(),".desktop-mcp","bin",k);return await g(t)?t:null}async function g(e){try{return await b(e,P.F_OK),!0}catch{return!1}}function $(){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 h(){const e={...$(),...I()},t=e.NUPHUS_MCP_VISION_API_KEY!==void 0||e.NUPHUS_MCP_VISION_MODEL!==void 0;return!t&&l?.apiKey&&l.supportsImage===!0?(f="agent-fallback",e.NUPHUS_MCP_VISION_API_KEY=l.apiKey,e.NUPHUS_MCP_VISION_MODEL=l.model,l.baseURL&&(e.NUPHUS_MCP_VISION_BASE_URL=l.baseURL),d.info(`vision model fallback: reusing agent model ${l.model} for desktop_vision`)):t?f="panel-env":f="none",e}function S(e){return Object.keys(e).sort().map(t=>`${t}=${e[t]}`).join("\0")}async function y(){if(n){if(n.connection.isConnected())return n;await _(n.connection),n=null}if(c)return c;if(r){if(r.reason==="binary-missing"||Date.now()-r.at<A())return null;r=null}return c=(async()=>{const e=await K();if(!e)return r={reason:"binary-missing",message:`nuphus-mcp binary not found. Set AWS_DESKTOP_MCP_BIN or place it at ${m(process.cwd(),".desktop-mcp","bin",k)}`,at:Date.now()},u(`desktop tools unavailable: ${r.message}`),null;const t=h(),o=new O({command:e,env:t,onUnexpectedClose:()=>{u("nuphus-mcp process exited unexpectedly; will restart on next use"),n?.connection===o&&(n=null)}});try{const s=await o.start(),i=x();r=null;const a={connection:o,tools:s,binaryPath:e,envSig:S(t),forwarder:(p,E)=>F(o,p,E,i)};return n=a,u(`nuphus-mcp started (${e}), ${s.filter(p=>p.name.startsWith("desktop_")).length} desktop tools available`),a}catch(s){return await _(o),r={reason:"start-failed",message:s.message,at:Date.now()},v(`nuphus-mcp start failed: ${r.message}`),null}finally{c=null}})(),c}async function F(e,t,o,s){try{return await e.callTool(t,o,s)}catch(i){if(e.isConnected())throw i;v(`nuphus-mcp connection lost during ${t}: ${i.message}; restarting`),n?.connection===e&&(n=null),await _(e);const a=await y();if(!a)throw new Error(`nuphus-mcp restart failed: ${r?.message??"unknown"}`);return a.connection.callTool(t,o,s)}}async function q(e,t){if(!e)return[];t?.model&&(l=t);const o=h(),s=S(o);n&&n.connection.isConnected()&&n.envSig!==s&&(u("nuphus-mcp env changed; restarting to apply new env"),await L());const i=await y();return i?w({tools:i.tools,forwarder:(a,p)=>D(e,C)?i.forwarder(a,p):(d.warn(`tool ${a} 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 G(){const e=n;return!e||!e.connection.isConnected()?R.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.`}})):w({tools:e.tools,forwarder:(t,o)=>e.forwarder(t,o)})}const R=["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 L(){const e=n;if(n=null,r=null,c){try{await c}catch{}c=null}e&&(await _(e.connection),u("nuphus-mcp stopped"))}function J(){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 v(e){d.warn(e)}export{L as disposeDesktopMcpManager,J as getDesktopMcpStatus,q as getDesktopTools,G as getDesktopToolsIfReady,K as resolveDesktopMcpBinary,y as startDesktopMcpManager};
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};
2
2
 
@@ -1,2 +1,2 @@
1
- import p from"node:fs/promises";import U from"node:path";import{getBridgeInstanceConfigFile as S,getBridgeInstanceMcpExtraFile as A,getBridgeTemplateConfigFile as F}from"../config.js";import{getInstanceAiConfigDebugLogger as _}from"../utils/instance-ai-config-debug-logger.js";import{mcpDeployManager as w}from"./mcp-deploy.js";const h=new Set(["apiKey","api_key","apikey","key","secret","token","password"]);function D(e){const t={...e};for(const r of Object.keys(t))if(h.has(r)){const o=t[r];typeof o=="string"&&o.length>0&&(t[r]=o.length>8?`${o.slice(0,4)}...${o.slice(-4)}`:"***")}else typeof t[r]=="object"&&t[r]!==null&&(t[r]=D(t[r]));return t}function M(){return{...process.env.ACODE_MODEL?{model:process.env.ACODE_MODEL}:{},...process.env.ACODE_BASE_URL?{baseURL:process.env.ACODE_BASE_URL}:{},...process.env.ACODE_API_KEY?{apiKey:process.env.ACODE_API_KEY}:{},...process.env.ACODE_EFFORT?{effort:process.env.ACODE_EFFORT}:{}}}async function k(e){try{const t=await p.readFile(e,"utf-8"),a=JSON.parse(t).provider?.default,n=a?.options;return{...a?.model?{model:a.model}:{},...n?.baseURL||n?.baseUrl?{baseURL:n.baseURL||n.baseUrl}:{},...n?.apiKey?{apiKey:n.apiKey}:{}}}catch{return{}}}function m(e,t,r,o){return t!==void 0?"api":r!==void 0?"env":o!==void 0?"file":"default"}function O(e){return A(e)}async function x(e){try{const t=await p.readFile(O(e),"utf-8"),r=JSON.parse(t);return r.servers&&typeof r.servers=="object"?r.servers:{}}catch{return{}}}function T(e){return O(e)}async function $(e){const t=F(),r=S(e.agentId),o=e.apiOverrides??{},a=M(),n=await k(t),l=o.model??a.model??n.model,g=o.baseURL??a.baseURL??n.baseURL,y=o.apiKey??a.apiKey??n.apiKey,u=o.effort??a.effort,f={};l&&(f.model=l),g&&(f.baseURL=g),y&&(f.apiKey=y),u&&(f.effort=u);const L={model:m("model",o.model,a.model,n.model),baseURL:m("baseURL",o.baseURL,a.baseURL,n.baseURL),apiKey:m("apiKey",o.apiKey,a.apiKey,n.apiKey),effort:m("effort",o.effort,a.effort,void 0)},v=_();try{await p.mkdir(U.dirname(r),{recursive:!0});let c={};try{const i=await p.readFile(t,"utf-8");c=JSON.parse(i)}catch{}const s=JSON.parse(JSON.stringify(c)),b=s.provider??{},E=b.default??{},d=E.options??{};l&&(d.model=l),g&&(d.baseURL=g),y&&(d.apiKey=y),u&&(d.effort=u),E.options=d,b.default=E,s.provider=b;try{const i=s.mcpServers??{},I=w.resolveEnabledMcp(e.agentId,i),R=await x(e.agentId);for(const[C,K]of Object.entries(R))I[C]=K;s.mcpServers=I}catch(i){v.log({level:"error",category:"apply",message:`MCP \u80FD\u529B\u8FC7\u6EE4/\u79C1\u6709\u5408\u5E76\u5931\u8D25\uFF08fail-open\uFF0C\u4FDD\u6301\u539F\u914D\u7F6E\uFF09: ${i instanceof Error?i.message:String(i)}`,source:"bridge",agentId:e.agentId,sessionId:e.sessionId})}await p.writeFile(r,JSON.stringify(s,null,2),"utf-8"),v.log({level:"info",category:"apply",message:"per-instance acode.json \u5DF2\u5199\u5165",source:"bridge",agentId:e.agentId,sessionId:e.sessionId,details:{perInstanceConfigPath:r,source:L}})}catch(c){const s=c instanceof Error?c.message:String(c);v.log({level:"error",category:"apply",message:`per-instance acode.json \u5199\u5165\u5931\u8D25: ${s}`,source:"bridge",agentId:e.agentId})}return{instanceConfig:{config:f,source:L},perInstanceConfigPath:r}}export{T as getAgentMcpExtraFilePath,$ as prepareAcodeInstanceConfig,D as redactForLog};
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};
2
2
 
@@ -28,6 +28,8 @@ export declare const COLLABORATION_DEBUG_FEATURE_KEY = "collaboration.debug";
28
28
 
29
29
  export declare const COLLABORATION_FILE_HISTORY_FEATURE_KEY = "collaboration.fileHistory";
30
30
 
31
+ export declare const EMAIL_FEATURE_KEY = "email";
32
+
31
33
  export declare const GROUP_KEY_TO_FEATURE: ReadonlyMap<string, string>;
32
34
 
33
35
  export declare function resolveGroupFeatureKey(key: string): string;
@@ -36,6 +38,10 @@ export declare function setAgentFeatures(agentId: string, features: unknown): vo
36
38
 
37
39
  export declare function getAgentFeatures(agentId: string): Record<string, FeatureState>;
38
40
 
41
+ export declare function setAgentInheritedFeatures(agentId: string, features: unknown): void;
42
+
43
+ export declare function getAgentInheritedFeatures(agentId: string): Record<string, FeatureState>;
44
+
39
45
  export declare function getFeatureState(agentId: string, key: string): FeatureState;
40
46
 
41
47
  export declare function isFeatureEnabled(agentId: string, key: string): boolean;
@@ -63,6 +69,10 @@ export declare function setAgentCapabilities(agentId: string, raw: unknown): voi
63
69
 
64
70
  export declare function getAgentCapabilities(agentId: string): AgentCapabilities | null;
65
71
 
72
+ export declare function setAgentCapabilitiesInherited(agentId: string, raw: unknown): void;
73
+
74
+ export declare function getAgentCapabilitiesInherited(agentId: string): AgentCapabilities | null;
75
+
66
76
  export declare function getAgentPluginSources(agentId: string): Record<string, AgentPluginSource> | null;
67
77
 
68
78
  export declare function isCapabilityEnabled(agentId: string, type: CapabilityType, name: string): boolean;
@@ -1,2 +1,2 @@
1
- import{getEffective as U,hasAnyDefault as h}from"./capability-config.js";const K=new Set(["disabled","collapsed","expanded"]);function P(e){if(e===!0)return"expanded";if(e===!1)return"disabled";if(typeof e=="string"&&K.has(e))return e}const d={},Z="desktop",C="browser",b="agentSys.launchItem",g="agentSys.hire",M="pencil",Y="draw",B="office",N="collaboration",S="collaboration.task",F="collaboration.meeting",R="collaboration.debug",x="collaboration.fileHistory",D=new Set,j=new Set([C,M,Y,B,b,g,S,F,R,x]),v=[["agentSys","agentSys."],[N,"collaboration."]],I=new Map([["task",S],["meeting",F],["debug",R],["fileHistory",x],["launch",b],["hire",g]]);function $(e){return I.get(e)??e}function z(e){for(const[t,n]of v)if(e.startsWith(n))return t}const G=new Set,E=new Map,c=new Map,H=["fileReadOutside","commandExecution","fileModification","fileModificationOutside"],k=new Set(["allow","ask","deny"]);function J(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;const t=e,n={};let o=!1;for(const r of H){const i=t[r];typeof i=="string"&&k.has(i)?(n[r]=i,o=!0):n[r]="allow"}return o?n:null}function W(e){if(e==null)return{...d};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{...d};const n={};for(const[o,r]of Object.entries(t)){if(G.has(o))continue;const i=P(r);i!==void 0&&(n[o]=i)}return n}function ee(e,t){if(!e)return;E.set(e,W(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 o=J(n.toolPermissions);o?c.set(e,o):c.delete(e)}else c.delete(e)}function w(e){return E.get(e)??{...d}}function V(e,t){const n=w(e),o=z(t);if(o&&n[o]==="disabled")return"disabled";const r=n[t];return r!==void 0?r:D.has(t)?"expanded":j.has(t)?"collapsed":"disabled"}function te(e,t){return V(e,t)!=="disabled"}function ne(e){E.delete(e),c.delete(e),u.delete(e),A.delete(e)}function oe(e){return c.get(e)??null}function re(e){return c.get(e)??{fileReadOutside:"allow",commandExecution:"allow",fileModification:"allow",fileModificationOutside:"allow"}}const X=["skills","mcp","plugins"],u=new Map,A=new Map;function q(e){if(typeof e!="object"||e===null||Array.isArray(e))return;const t={};for(const[n,o]of Object.entries(e))n.trim()&&typeof o=="boolean"&&(t[n.trim()]=o);return t}function ie(e,t){if(!e)return;if(t==null){u.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)){u.delete(e);return}const o=n,r={};let i=!1;for(const a of X){const s=q(o[a]);s&&(r[a]=s,i=!0)}i?u.set(e,r):u.delete(e);const f=o.plugins,y={};let _=!1;if(typeof f=="object"&&f!==null&&!Array.isArray(f))for(const[a,s]of Object.entries(f)){const p=a.trim();if(p){if(typeof s=="boolean"){const l=r.plugins??{};l[p]=s,r.plugins=l,i=!0;continue}if(s!==null&&typeof s=="object"&&!Array.isArray(s)){const l=s,m=l.enabled!==!1,T=typeof l.url=="string"?l.url:void 0,L=typeof l.sha256=="string"?l.sha256:void 0,O=r.plugins??{};O[p]=m,r.plugins=O,i=!0,T&&(y[p]={url:T,sha256:L},_=!0)}}}_?A.set(e,y):A.delete(e)}function se(e){return u.get(e)??null}function le(e){return A.get(e)??null}function ue(e,t,n){if(h(t))return U(e,t,n);const o=u.get(e);if(!o)return!0;const r=o[t];if(!r)return!0;const i=r[n];return i===void 0?!0:i}function ce(){return E.size}export{C as BROWSER_FEATURE_KEY,X as CAPABILITY_TYPES,R as COLLABORATION_DEBUG_FEATURE_KEY,N as COLLABORATION_FEATURE_KEY,x as COLLABORATION_FILE_HISTORY_FEATURE_KEY,F as COLLABORATION_MEETING_FEATURE_KEY,S as COLLABORATION_TASK_FEATURE_KEY,Z as DESKTOP_FEATURE_KEY,Y as DRAW_FEATURE_KEY,I as GROUP_KEY_TO_FEATURE,g as HIRE_FEATURE_KEY,b as LAUNCH_ITEM_FEATURE_KEY,B as OFFICE_FEATURE_KEY,M as PENCIL_FEATURE_KEY,ne as clearAgentFeatures,se as getAgentCapabilities,w as getAgentFeatures,le as getAgentPluginSources,oe as getAgentToolPermissions,V as getFeatureState,ce as instanceFeaturesCacheSize,ue as isCapabilityEnabled,te as isFeatureEnabled,P as normalizeFeatureState,re as resolveAgentToolPermissions,$ as resolveGroupFeatureKey,ie as setAgentCapabilities,ee as setAgentFeatures};
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};
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 j}from"../utils/logger.js";import{normalizeMcpPayload as z}from"../utils/mcp-utils.js";import{ensureEnabledTools as B,parseBoolean as D}from"../utils/validation.js";import{buildBuiltinAwsMcpDeploySpec as $,BUILTIN_AWS_MCP_SERVER_NAME as v}from"./aws-client-agent-mcp.js";import{setDefault as F}from"./capability-config.js";import{getAgentInitRoot as R,loadInstanceState as _,saveInstanceState as L}from"./instance-state.js";import{mcpDeployManager as N,reconcileMcpDefaultsFromDeployed as U}from"./mcp-deploy.js";import{reconcilePluginsDefaultsFromDeployed as W,pluginManager as Z}from"./plugin-manager.js";import{reconcileSkillsDefaultsFromDeployed as q,skillManager as x}from"./skill-manager.js";import{detectToolStatuses as V}from"./tool-installer.js";const G=j("instance-init");function H(a,g){const s=new Set(Object.values(g).filter(r=>r.installed).map(r=>r.tool));return a.filter(r=>s.has(r))}async function J(a,g){try{const s=await O(a,g);if(!s)return null;const r=await P.readFile(s.outputPath),c=a.defaultEnabled!==!1,k=String(a.skillName||"").trim()||void 0,l=await x.saveSharedSkill(r,s.fileName,c,a.sha256,k);return!l.ok||!l.skillName?null:{id:l.skillName,name:l.skillName,fileName:s.fileName,filePath:"",bytes:s.bytes,installedAt:new Date().toISOString()}}catch(s){return G.warn("\u6280\u80FD\u5305\u90E8\u7F72\u5230 bridge \u5931\u8D25\uFF08\u6309\u8DF3\u8FC7\u5904\u7406\uFF09: %s. %s",a.skillName||a.fileName||"(\u672A\u547D\u540D)",s instanceof Error?s.message:String(s)),null}}async function ce(a,g,s){const r=w.resolve(g),c=R(a),k=[];function l(t,o,e,n){k.push({step:t,status:o,message:e,timestamp:new Date().toISOString(),details:n})}l("prepare","running","\u5F00\u59CB\u521D\u59CB\u5316\u5B9E\u4F8B",{agentId:String(a),workspacePath:r}),await y(c),l("prepare","success","\u521D\u59CB\u5316\u76EE\u5F55\u5DF2\u5C31\u7EEA",{initRoot:c});const u=B(s.ccSwitchEnabledTools);l("detect-tools","running","\u5F00\u59CB\u68C0\u6D4B\u5DE5\u5177\u5B89\u88C5\u72B6\u6001",{tools:u});const d=await V(u);l("detect-tools","success","\u5DE5\u5177\u5B89\u88C5\u72B6\u6001\u68C0\u6D4B\u5B8C\u6210",{installedTools:Object.values(d).filter(t=>t.installed).map(t=>t.tool),missingTools:Object.values(d).filter(t=>!t.installed).map(t=>t.tool)});const C=H(u,d),b=Object.values(d).filter(t=>!t.installed),i={ok:!0,agentId:String(a),workspacePath:r,initRoot:c,enabledTools:u,toolStatus:d,logs:k,skill:{enabled:D(s.skillEnabled,!0),packagePresent:!1},mcp:{enabled:D(s.mcpEnabled,!0),configPath:null}},p=await _(a);if(b.length>0&&l("skip-uninstalled-tools","skipped","\u5DF2\u8DF3\u8FC7\u672A\u5B89\u88C5\u5DE5\u5177",{skippedTools:b.map(t=>({tool:t.tool,error:t.error}))}),l("select-installed-tools","success","\u5DF2\u9009\u62E9\u53EF\u521D\u59CB\u5316\u5DE5\u5177",{enabledTools:u,installedTools:C}),l("load-sdk","running","\u5F00\u59CB\u90E8\u7F72\u6280\u80FD/MCP \u6A21\u677F\u5230\u672C bridge"),l("load-sdk","success","\u6280\u80FD/MCP \u6A21\u677F\u90E8\u7F72\u51C6\u5907\u5B8C\u6210",{tools:u}),i.skill.enabled){l("install-skills","running","\u5F00\u59CB\u90E8\u7F72\u6280\u80FD\u5305",{count:Array.isArray(s.skillPackages)?s.skillPackages.length:s.skillPackage?1:0});const t=await y(w.join(c,"skills")),o=Array.isArray(s.skillPackages)&&s.skillPackages.length>0?s.skillPackages:s.skillPackage?[s.skillPackage]:[],e=[];for(const n of o){const f=await J(n,t);f&&e.push(f)}e.length>0?(i.skill.packagePresent=!0,i.skill.installedCount=e.length,i.skill.installed=e,l("install-skills","success","\u6280\u80FD\u5305\u90E8\u7F72\u5B8C\u6210",{installedCount:e.length,skills:e.map(n=>n.name)})):l("install-skills","skipped","\u6CA1\u6709\u53EF\u90E8\u7F72\u7684\u6280\u80FD\u5305")}else l("install-skills","skipped","\u5DF2\u8DF3\u8FC7\u6280\u80FD\u5305\u90E8\u7F72\uFF08skillEnabled=false\uFF09");const S=Array.isArray(s.pluginPackages)?s.pluginPackages:[];if(S.length>0){l("install-plugins","running","\u5F00\u59CB\u90E8\u7F72\u63D2\u4EF6\u6A21\u677F\u5305",{count:S.length});const t=await y(w.join(c,"plugins-tmp"));let o=0;for(const e of S)if(!(!e||!String(e.downloadUrl||"").trim()))try{const n=await I(e,t);if(!n)continue;const f=await P.readFile(n.outputPath),T=e.defaultEnabled!==!1,h=await Z.saveSharedPlugin(f,n.fileName,T,e.sha256);h.ok?(o++,l("install-plugins","success",`\u63D2\u4EF6 ${h.pluginName||n.fileName} \u5DF2\u90E8\u7F72\u5230\u672C bridge`)):l("install-plugins","error",`\u63D2\u4EF6 ${n.fileName} \u90E8\u7F72\u5931\u8D25: ${h.error||"\u672A\u77E5\u9519\u8BEF"}`)}catch(n){l("install-plugins","error",`\u63D2\u4EF6 ${e.fileName||"(\u672A\u547D\u540D)"} \u90E8\u7F72\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}i.plugin={enabled:!0,packagePresent:S.length>0,installedCount:o},o>0?l("install-plugins","success","\u63D2\u4EF6\u6A21\u677F\u5305\u90E8\u7F72\u5B8C\u6210",{installedCount:o}):l("install-plugins","skipped","\u6CA1\u6709\u53EF\u90E8\u7F72\u7684\u63D2\u4EF6\u5305"),await P.rm(t,{recursive:!0,force:!0}).catch(()=>{})}const m=[];if(i.mcp.enabled){l("install-mcp","running","\u5F00\u59CB\u90E8\u7F72 MCP \u6A21\u677F",{count:(Array.isArray(s.mcpServers)?s.mcpServers.length:0)+1});let t;try{const e=$();t=N.saveMcp(v,e,!0),t.ok&&(F("mcp",v,!0),m.push({id:"",name:v,transport:"stdio",command:e.command||"",url:e.url||"",args:e.args||[],env:e.env||{},enabled:!0,installedAt:new Date().toISOString()}))}catch(e){t={ok:!1,error:e instanceof Error?e.message:String(e)}}t.ok||l("install-mcp","error",`\u5185\u7F6E\u901A\u8BAF MCP \u90E8\u7F72\u5931\u8D25: ${t.error||"\u672A\u77E5\u9519\u8BEF"}`);const o=(Array.isArray(s.mcpServers)?s.mcpServers:[]).map(e=>z(e)).filter(e=>e!==null);for(const e of o){const n={type:e.transport||"stdio",command:e.command||void 0,url:e.url||void 0,args:e.args||void 0,env:e.env||void 0};N.saveMcp(e.name,n,e.enabled!==!1).ok&&m.push({id:e.id||"",name:e.name,transport:e.transport||"stdio",command:e.command||"",url:e.url||"",args:e.args||[],env:e.env||{},enabled:e.enabled!==!1,installedAt:new Date().toISOString()})}i.mcp.installedCount=m.length,l("install-mcp","success","MCP \u6A21\u677F\u90E8\u7F72\u5B8C\u6210",{installedCount:m.length,mcpServers:m.map(e=>e.name)})}else l("install-mcp","skipped","\u5DF2\u8DF3\u8FC7 MCP \u6A21\u677F\uFF08mcpEnabled=false\uFF09");l("persist-state","running","\u5F00\u59CB\u4FDD\u5B58\u5B9E\u4F8B\u72B6\u6001"),p.initialized=!0,p.enabledTools=u,p.toolStatus=d,p.skillEnabled=i.skill.enabled,p.mcpEnabled=i.mcp.enabled,await L(a,p),l("persist-state","success","\u5B9E\u4F8B\u72B6\u6001\u4FDD\u5B58\u5B8C\u6210");const M=q(),E=U(),A=W();return(M||E||A)&&l("sync-state","success","\u80FD\u529B\u9ED8\u8BA4\u5F00\u5173\u5DF2\u5BF9\u8D26\uFF08\u65B0\u589E\u9879\u9ED8\u8BA4\u5173\u95ED\uFF09",{reconciledSkills:M,reconciledMcp:E,reconciledPlugins:A}),l("sync-state","success","\u6280\u80FD/MCP \u6A21\u677F\u90E8\u7F72\u72B6\u6001\u5DF2\u5C31\u7EEA"),l("complete","success",b.length>0?"\u5B9E\u4F8B\u521D\u59CB\u5316\u5B8C\u6210\uFF0C\u672A\u5B89\u88C5\u5DE5\u5177\u5DF2\u8DF3\u8FC7":"\u5B9E\u4F8B\u521D\u59CB\u5316\u5B8C\u6210"),{...i,installed:{skills:i.skill.installed||[],mcpServers:m}}}export{ce as initInstance};
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};
2
2
 
@@ -145,6 +145,8 @@ export declare class LaunchManager {
145
145
  private readonly metricsMonitor;
146
146
 
147
147
  private restored;
148
+
149
+ private readonly portsProbeInflight;
148
150
  private constructor();
149
151
  static getInstance(): LaunchManager;
150
152
 
@@ -173,7 +175,13 @@ export declare class LaunchManager {
173
175
 
174
176
  private resolveStartupWaiters;
175
177
 
176
- listRuns(): Promise<LaunchRunSummary[]>;
178
+ listRuns(options?: {
179
+ withPorts?: boolean;
180
+ }): Promise<LaunchRunSummary[]>;
181
+
182
+ private probePorts;
183
+
184
+ publishRunningPorts(): Promise<void>;
177
185
 
178
186
  getLogs(configId: string, sinceIndex: number): Promise<LaunchLogsResult | null>;
179
187
 
@@ -1,12 +1,12 @@
1
- import{exec as j,spawn as z}from"node:child_process";import{promises as F}from"node:fs";import A from"node:os";import M from"node:path";import{promisify as J}from"node:util";import{atomicWriteJsonFile as U,withFileLock as G}from"../utils/file-utils.js";import{createLogger as V}from"../utils/logger.js";import{LaunchMetricsMonitor as X}from"./launch-metrics.js";import{getLaunchStreamHub as x}from"./launch-streams.js";import{getListeningPortsForProcessTrees as k}from"./port-detector.js";import{isProcessRunning as L,terminateProcessTree as E}from"./process-detector.js";import{RingBuffer as O}from"./ring-buffer.js";const C=J(j),g=V("launch-manager"),D=5e3,B=4096,K=1500,Y=20;class H extends Error{constructor(t){super(`\u542F\u52A8\u9879\u5DF2\u5728\u8FD0\u884C: pid=${t.pid}`),this.name="LaunchAlreadyRunningError",this.existing=t}}function N(){return M.join(A.tmpdir(),"agentswork-runtime-bridge","launch-runs.json")}function Z(l,t){return l.replace(/\$\{([^}]+)\}/g,(e,r)=>{const s=r.trim(),n=s.toUpperCase();if(n==="WORKSPACE")return t.workspacePath||"";if(n==="JAVA_HOME")return t.jdkPath||process.env.JAVA_HOME||"";if(n==="HOME")return A.homedir();if(t.env&&t.env[s]!==void 0)return t.env[s];if(t.env){for(const[i,a]of Object.entries(t.env))if(i.toUpperCase()===n)return a}return e})}function Q(l){const t={...process.env};l.env&&Object.assign(t,l.env);for(const e of Object.keys(t))if(e.toUpperCase()==="PATH"&&e!=="PATH"){const r=t[e];delete t[e],t.PATH===void 0&&typeof r=="string"&&(t.PATH=r)}if(l.jdkPath){t.JAVA_HOME=l.jdkPath;const e=M.join(l.jdkPath,"bin"),r=M.delimiter;t.PATH=t.PATH?`${e}${r}${t.PATH}`:e}return t}const q=256,tt=120;class W{constructor(t=()=>{}){this.utf8Probe=new TextDecoder("utf-8",{fatal:!0}),this.utf8=new TextDecoder("utf-8"),this.gbk=new TextDecoder("gbk"),this.mode=null,this.buffered=[],this.bufferedSize=0,this.flushTimer=null,this.onFlush=t}decode(t){return this.mode!==null?(this.mode==="gbk"?this.gbk:this.utf8).decode(t,{stream:!0}):(this.buffered.push(t),this.bufferedSize+=t.length,this.bufferedSize>=q?this.commit():(this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.onFlush(this.commit())},tt)),""))}finalize(){return this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.mode===null?this.commit():(this.mode==="gbk"?this.gbk:this.utf8).decode()}commit(){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.mode!==null)return"";const t=Buffer.concat(this.buffered,this.bufferedSize);this.buffered=[],this.bufferedSize=0;try{return this.utf8Probe.decode(t),this.mode="utf8",this.utf8.decode(t)}catch{return this.mode="gbk",this.gbk.decode(t)}}}function et(l){const t=l.length>0&&!l.endsWith(`
1
+ import{exec as _,spawn as z}from"node:child_process";import{promises as F}from"node:fs";import A from"node:os";import M from"node:path";import{promisify as J}from"node:util";import{atomicWriteJsonFile as U,withFileLock as G}from"../utils/file-utils.js";import{createLogger as V}from"../utils/logger.js";import{LaunchMetricsMonitor as X}from"./launch-metrics.js";import{getLaunchStreamHub as P}from"./launch-streams.js";import{getListeningPortsForProcessTrees as k}from"./port-detector.js";import{isProcessRunning as L,terminateProcessTree as E}from"./process-detector.js";import{RingBuffer as O}from"./ring-buffer.js";const C=J(_),m=V("launch-manager"),D=5e3,B=4096,K=1500,Y=20;class H extends Error{constructor(t){super(`\u542F\u52A8\u9879\u5DF2\u5728\u8FD0\u884C: pid=${t.pid}`),this.name="LaunchAlreadyRunningError",this.existing=t}}function N(){return M.join(A.tmpdir(),"agentswork-runtime-bridge","launch-runs.json")}function Z(l,t){return l.replace(/\$\{([^}]+)\}/g,(e,s)=>{const r=s.trim(),i=r.toUpperCase();if(i==="WORKSPACE")return t.workspacePath||"";if(i==="JAVA_HOME")return t.jdkPath||process.env.JAVA_HOME||"";if(i==="HOME")return A.homedir();if(t.env&&t.env[r]!==void 0)return t.env[r];if(t.env){for(const[n,a]of Object.entries(t.env))if(n.toUpperCase()===i)return a}return e})}function Q(l){const t={...process.env};l.env&&Object.assign(t,l.env);for(const e of Object.keys(t))if(e.toUpperCase()==="PATH"&&e!=="PATH"){const s=t[e];delete t[e],t.PATH===void 0&&typeof s=="string"&&(t.PATH=s)}if(l.jdkPath){t.JAVA_HOME=l.jdkPath;const e=M.join(l.jdkPath,"bin"),s=M.delimiter;t.PATH=t.PATH?`${e}${s}${t.PATH}`:e}return t}const q=256,tt=120;class W{constructor(t=()=>{}){this.utf8Probe=new TextDecoder("utf-8",{fatal:!0}),this.utf8=new TextDecoder("utf-8"),this.gbk=new TextDecoder("gbk"),this.mode=null,this.buffered=[],this.bufferedSize=0,this.flushTimer=null,this.onFlush=t}decode(t){return this.mode!==null?(this.mode==="gbk"?this.gbk:this.utf8).decode(t,{stream:!0}):(this.buffered.push(t),this.bufferedSize+=t.length,this.bufferedSize>=q?this.commit():(this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.onFlush(this.commit())},tt)),""))}finalize(){return this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.mode===null?this.commit():(this.mode==="gbk"?this.gbk:this.utf8).decode()}commit(){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.mode!==null)return"";const t=Buffer.concat(this.buffered,this.bufferedSize);this.buffered=[],this.bufferedSize=0;try{return this.utf8Probe.decode(t),this.mode="utf8",this.utf8.decode(t)}catch{return this.mode="gbk",this.gbk.decode(t)}}}function et(l){const t=l.length>0&&!l.endsWith(`
2
2
  `)?l+`
3
- `:l;return t.length>B?t.slice(-B):t}async function st(l){const t=A.platform();for(let e=0;e<6;e+=1){try{if(t==="win32"){const r=`Get-CimInstance Win32_Process -Filter "ParentProcessId = ${l} AND Name <> 'conhost.exe'" | Select-Object -First 1 ProcessId | ConvertTo-Json -Compress`,s=Buffer.from(r,"utf16le").toString("base64"),{stdout:n}=await C(`powershell -NoProfile -NonInteractive -EncodedCommand ${s}`,{encoding:"utf8",timeout:5e3,windowsHide:!0}),i=n.replace(/#\s*<\s*CLIXML[\s\S]*?(?=\{|\[|$)/g,"").trim(),a=JSON.parse(i||"null"),h=Number(a?.ProcessId);if(Number.isFinite(h)&&h>0)return h}else{const{stdout:r}=await C(`pgrep -P ${l} | head -n 1`,{encoding:"utf8",timeout:3e3}),s=Number(r.trim());if(Number.isFinite(s)&&s>0)return s}}catch{}await new Promise(r=>setTimeout(r,300))}return null}class S{constructor(){this.runs=new Map,this.logs=new Map,this.startupWaiters=new Map,this.readinessMatchers=new Map,this.logListeners=new Map,this.metricsMonitor=new X(()=>this.runningRefs()),this.restored=!1}static getInstance(){return S.instance===null&&(S.instance=new S),S.instance}runningRefs(){const t=[];for(const e of this.runs.values())e.state==="running"&&e.pid>0&&t.push({configId:e.configId,pid:e.pid});return t}async start(t){const e=t.configId;if(!e||!e.trim())throw new Error("configId is required");if(!t.command||!t.command.trim())throw new Error("command is required");let r=null;if(t.readinessPattern&&t.readinessPattern.trim())try{r=new RegExp(t.readinessPattern.trim())}catch(o){throw new Error(`readinessPattern \u6B63\u5219\u8BED\u6CD5\u65E0\u6548: ${o.message}`)}const s=t.startedBy?.trim()||void 0;await this.ensureRestored();const n=this.runs.get(e);if(n&&n.state==="running"&&L(n.pid))throw new H(n);const i=Z(t.command,{workspacePath:t.workspacePath,jdkPath:t.jdkPath,env:t.env}),a=t.cwd||t.workspacePath||process.cwd(),h=Q(t);g.info(`[start] \u542F\u52A8\u547D\u4EE4: configId=${e}, cwd=${a}, command=${i}`);let m;try{m=z(i,{cwd:a,env:h,shell:!0,windowsHide:!0})}catch(o){const c=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${o.message}`;throw g.error(`[start] spawn \u5931\u8D25: configId=${e}, error=${c}`),new Error(c)}const w=m.pid??0,T={configId:e,pid:w,state:"running",startedAt:new Date().toISOString(),command:i,cwd:a,...s?{startedBy:s}:{}};this.runs.set(e,T),this.publishRunStatus(e,!0),this.metricsMonitor.clear(e),this.metricsMonitor.ensureRunning();let p=this.logs.get(e);p||(p=new O(D),this.logs.set(e,p));const I=p.getSinceIndex(-1).nextIndex;r?this.readinessMatchers.set(e,{pattern:r,fromIndex:I+1}):this.readinessMatchers.delete(e);const y=p.append({stream:"stdout",text:`> ${i}
4
- `});x().publish(e,"logs",y.index,y.data);let R=null;(async()=>{const o=await st(w),c=this.runs.get(e);o&&c?.pid===w&&(R=o,this.runs.set(e,{...c,pid:o}),await this.persist(),this.publishRunStatus(e))})();const P=o=>o!==void 0&&(o.pid===w||o.pid===R),u=new W(o=>{f("stdout",o)}),d=new W(o=>{f("stderr",o)}),f=(o,c)=>{const b=et(c);if(b){const $=p.append({stream:o,text:b});x().publish(e,"logs",$.index,$.data);const v=this.logListeners.get(e);if(v&&v.size>0)for(const _ of v)try{_($)}catch{}}};return m.stdout.on("data",o=>{f("stdout",u.decode(o))}),m.stderr.on("data",o=>{f("stderr",d.decode(o))}),m.on("error",o=>{f("stderr",`[\u542F\u52A8\u5931\u8D25] ${o.message}
5
- `);const c=this.runs.get(e);c&&P(c)&&c.state==="running"&&(this.runs.set(e,{...c,state:"exited",exitedAt:new Date().toISOString(),exitCode:-1}),x().publishState(e,{configId:e,state:"exited",exitCode:-1}),this.publishRunStatus(e),this.persist(),this.resolveStartupWaiters(e,"exited",-1))}),m.on("exit",(o,c)=>{f("stdout",u.finalize()),f("stderr",d.finalize()),f("stderr",`
3
+ `:l;return t.length>B?t.slice(-B):t}async function st(l){const t=A.platform();for(let e=0;e<6;e+=1){try{if(t==="win32"){const s=`Get-CimInstance Win32_Process -Filter "ParentProcessId = ${l} AND Name <> 'conhost.exe'" | Select-Object -First 1 ProcessId | ConvertTo-Json -Compress`,r=Buffer.from(s,"utf16le").toString("base64"),{stdout:i}=await C(`powershell -NoProfile -NonInteractive -EncodedCommand ${r}`,{encoding:"utf8",timeout:5e3,windowsHide:!0}),n=i.replace(/#\s*<\s*CLIXML[\s\S]*?(?=\{|\[|$)/g,"").trim(),a=JSON.parse(n||"null"),h=Number(a?.ProcessId);if(Number.isFinite(h)&&h>0)return h}else{const{stdout:s}=await C(`pgrep -P ${l} | head -n 1`,{encoding:"utf8",timeout:3e3}),r=Number(s.trim());if(Number.isFinite(r)&&r>0)return r}}catch{}await new Promise(s=>setTimeout(s,300))}return null}class S{constructor(){this.runs=new Map,this.logs=new Map,this.startupWaiters=new Map,this.readinessMatchers=new Map,this.logListeners=new Map,this.metricsMonitor=new X(()=>this.runningRefs()),this.restored=!1,this.portsProbeInflight=new Map}static getInstance(){return S.instance===null&&(S.instance=new S),S.instance}runningRefs(){const t=[];for(const e of this.runs.values())e.state==="running"&&e.pid>0&&t.push({configId:e.configId,pid:e.pid});return t}async start(t){const e=t.configId;if(!e||!e.trim())throw new Error("configId is required");if(!t.command||!t.command.trim())throw new Error("command is required");let s=null;if(t.readinessPattern&&t.readinessPattern.trim())try{s=new RegExp(t.readinessPattern.trim())}catch(o){throw new Error(`readinessPattern \u6B63\u5219\u8BED\u6CD5\u65E0\u6548: ${o.message}`)}const r=t.startedBy?.trim()||void 0;await this.ensureRestored();const i=this.runs.get(e);if(i&&i.state==="running"&&await L(i.pid))throw new H(i);const n=Z(t.command,{workspacePath:t.workspacePath,jdkPath:t.jdkPath,env:t.env}),a=t.cwd||t.workspacePath||process.cwd(),h=Q(t);m.info(`[start] \u542F\u52A8\u547D\u4EE4: configId=${e}, cwd=${a}, command=${n}`);let g;try{g=z(n,{cwd:a,env:h,shell:!0,windowsHide:!0})}catch(o){const c=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${o.message}`;throw m.error(`[start] spawn \u5931\u8D25: configId=${e}, error=${c}`),new Error(c)}const w=g.pid??0,T={configId:e,pid:w,state:"running",startedAt:new Date().toISOString(),command:n,cwd:a,...r?{startedBy:r}:{}};this.runs.set(e,T),this.publishRunStatus(e,!0),this.metricsMonitor.clear(e),this.metricsMonitor.ensureRunning();let p=this.logs.get(e);p||(p=new O(D),this.logs.set(e,p));const I=p.getSinceIndex(-1).nextIndex;s?this.readinessMatchers.set(e,{pattern:s,fromIndex:I+1}):this.readinessMatchers.delete(e);const b=p.append({stream:"stdout",text:`> ${n}
4
+ `});P().publish(e,"logs",b.index,b.data);let R=null;(async()=>{const o=await st(w),c=this.runs.get(e);o&&c?.pid===w&&(R=o,this.runs.set(e,{...c,pid:o}),await this.persist(),this.publishRunStatus(e))})();const y=o=>o!==void 0&&(o.pid===w||o.pid===R),u=new W(o=>{f("stdout",o)}),d=new W(o=>{f("stderr",o)}),f=(o,c)=>{const x=et(c);if(x){const $=p.append({stream:o,text:x});P().publish(e,"logs",$.index,$.data);const v=this.logListeners.get(e);if(v&&v.size>0)for(const j of v)try{j($)}catch{}}};return g.stdout.on("data",o=>{f("stdout",u.decode(o))}),g.stderr.on("data",o=>{f("stderr",d.decode(o))}),g.on("error",o=>{f("stderr",`[\u542F\u52A8\u5931\u8D25] ${o.message}
5
+ `);const c=this.runs.get(e);c&&y(c)&&c.state==="running"&&(this.runs.set(e,{...c,state:"exited",exitedAt:new Date().toISOString(),exitCode:-1}),P().publishState(e,{configId:e,state:"exited",exitCode:-1}),this.publishRunStatus(e),this.persist(),this.resolveStartupWaiters(e,"exited",-1))}),g.on("exit",(o,c)=>{f("stdout",u.finalize()),f("stderr",d.finalize()),f("stderr",`
6
6
  [\u8FDB\u7A0B\u9000\u51FA] code=${o??"-"}${c?` signal=${c}`:""}
7
- `);const b=this.runs.get(e);b&&P(b)&&b.state==="running"&&(this.runs.set(e,{...b,state:"exited",exitedAt:new Date().toISOString(),exitCode:o}),x().publishState(e,{configId:e,state:"exited",exitCode:o}),this.publishRunStatus(e),this.persist(),this.resolveStartupWaiters(e,"exited",o))}),await this.persist(),T}async stop(t,e="manual",r){await this.ensureRestored();const s=this.runs.get(t);if(!s||s.state!=="running")return{success:!1,message:"\u542F\u52A8\u9879\u672A\u5728\u8FD0\u884C",pid:s?.pid};const n=r?.trim()||void 0;g.info(`[stop] \u7EC8\u6B62\u8FDB\u7A0B\u6811: configId=${t}, pid=${s.pid}, reason=${e}${n?`, actor=${n}`:""}`),this.runs.set(t,{...s,state:"stopped",exitedAt:new Date().toISOString(),...n?{stoppedBy:n}:{}});const i=await E(s.pid),a=e==="shutdown"?`
7
+ `);const x=this.runs.get(e);x&&y(x)&&x.state==="running"&&(this.runs.set(e,{...x,state:"exited",exitedAt:new Date().toISOString(),exitCode:o}),P().publishState(e,{configId:e,state:"exited",exitCode:o}),this.publishRunStatus(e),this.persist(),this.resolveStartupWaiters(e,"exited",o))}),await this.persist(),T}async stop(t,e="manual",s){await this.ensureRestored();const r=this.runs.get(t);if(!r||r.state!=="running")return{success:!1,message:"\u542F\u52A8\u9879\u672A\u5728\u8FD0\u884C",pid:r?.pid};const i=s?.trim()||void 0;m.info(`[stop] \u7EC8\u6B62\u8FDB\u7A0B\u6811: configId=${t}, pid=${r.pid}, reason=${e}${i?`, actor=${i}`:""}`),this.runs.set(t,{...r,state:"stopped",exitedAt:new Date().toISOString(),...i?{stoppedBy:i}:{}});const n=await E(r.pid),a=e==="shutdown"?`
8
8
  [bridge \u505C\u6B62\uFF0C\u8FDB\u7A0B\u5DF2\u8054\u52A8\u7EC8\u6B62]
9
9
  `:`
10
10
  [\u5DF2\u624B\u52A8\u505C\u6B62]
11
- `,h=this.logs.get(t)?.append({stream:"stderr",text:a});return h&&x().publish(t,"logs",h.index,h.data),x().publishState(t,{configId:t,state:"stopped"}),this.publishRunStatus(t),await this.persist(),this.resolveStartupWaiters(t,"stopped",void 0),{success:i.failed===0,message:i.failed===0?"\u8FDB\u7A0B\u5DF2\u505C\u6B62":`\u90E8\u5206\u8FDB\u7A0B\u672A\u80FD\u7EC8\u6B62\uFF08terminated=${i.terminated}, failed=${i.failed}\uFF09`,pid:s.pid}}async restart(t){await this.ensureRestored();const e=this.runs.get(t.configId);return e&&e.state==="running"&&await this.stop(t.configId,"manual",t.startedBy),await this.start(t)}async startBatch(t,e){await this.ensureRestored();const r=await Promise.all(t.map(async n=>{try{const i=await this.start(n);return{configId:n.configId,ok:!0,run:i}}catch(i){return i instanceof H?{configId:n.configId,ok:!0,skipped:!0,message:"\u5F53\u524D\u5DF2\u5904\u4E8E\u542F\u52A8/\u6B63\u5728\u542F\u52A8\u72B6\u6001\uFF0C\u8DF3\u8FC7",run:i.existing}:{configId:n.configId,ok:!1,error:i.message}}}));if(e>0){const n=await Promise.all(r.map(async i=>{if(!i.ok||i.skipped)return i;try{const a=await this.waitStartupResult(i.configId,e);return{...i,wait:a}}catch(a){return{...i,error:a.message}}}));r.splice(0,r.length,...n)}const s={total:r.length,started:0,skipped:0,failed:0,ready:0,exited:0,stopped:0,timeout:0};for(const n of r){if(!n.ok){s.failed+=1;continue}if(n.skipped){s.skipped+=1;continue}s.started+=1,n.wait&&(s[n.wait.outcome]+=1)}return{items:r,summary:s}}async stopAll(){await this.ensureRestored();const t=Array.from(this.runs.values()).filter(r=>r.state==="running");let e=0;for(const r of t)try{const s=await this.stop(r.configId,"shutdown");s.success?e++:g.warn(`[stopAll] \u542F\u52A8\u9879\u672A\u80FD\u5B8C\u5168\u7EC8\u6B62: configId=${r.configId}, message=${s.message}`)}catch(s){g.warn(`[stopAll] \u505C\u6B62\u542F\u52A8\u9879\u5931\u8D25: configId=${r.configId}, error=${s.message}`)}return{running:t.length,stopped:e}}async waitStartupResult(t,e){const r=this.runs.get(t);if(!r)throw new Error("launch run not found");const s=Date.now(),n=()=>(this.logs.get(t)?.getLastN(Y)??[]).map(a=>a.data);if(r.state!=="running")return{outcome:r.state==="stopped"?"stopped":"exited",waitedMs:0,...r.state==="exited"?{exitCode:r.exitCode??null}:{},logTail:n()};const i=this.readinessMatchers.get(t);if(i){const a=this.scanReadinessMatch(t,i);if(a!==null)return{outcome:"ready",waitedMs:0,matchedLine:a,logTail:n()}}return await new Promise(a=>{let h=!1,m=null,w=null,T=!1,p=null;const I=()=>{m!==null&&(clearInterval(m),m=null),w!==null&&(clearTimeout(w),w=null);const u=this.startupWaiters.get(t);if(u&&(u.delete(R),u.size===0&&this.startupWaiters.delete(t)),p!==null){const d=this.logListeners.get(t);d&&(d.delete(p),d.size===0&&this.logListeners.delete(t)),p=null}},y=u=>{h||(h=!0,I(),a(u))},R=(u,d)=>{y({outcome:u==="stopped"?"stopped":"exited",waitedMs:Date.now()-s,...u==="exited"?{exitCode:d??null}:{},logTail:n()})};let P=this.startupWaiters.get(t);if(P||(P=new Set,this.startupWaiters.set(t,P)),P.add(R),i){p=d=>{if(!(h||d.index<i.fromIndex)){for(const f of d.data.text.split(/\r?\n/))if(f&&i.pattern.test(f)){y({outcome:"ready",waitedMs:Date.now()-s,matchedLine:f.trim(),logTail:n()});return}}};let u=this.logListeners.get(t);u||(u=new Set,this.logListeners.set(t,u)),u.add(p)}else{const u=async()=>{if(h||T)return;const d=this.runs.get(t);if(!(!d||d.state!=="running"||d.pid<=0)){T=!0;try{const o=(await k([d.pid])).get(d.pid)??[];if(o.length>0&&!h){const c=this.runs.get(t);c?.state==="running"&&c.pid===d.pid&&y({outcome:"ready",waitedMs:Date.now()-s,ports:o,logTail:n()})}}catch{}finally{T=!1}}};m=setInterval(()=>{u()},K),u()}w=setTimeout(()=>{y({outcome:"timeout",waitedMs:Date.now()-s,logTail:n()})},e)})}scanReadinessMatch(t,e){const r=this.logs.get(t);if(!r)return null;for(const s of r.getSinceIndex(e.fromIndex-1).entries)for(const n of s.data.text.split(/\r?\n/))if(n&&e.pattern.test(n))return n.trim();return null}resolveStartupWaiters(t,e,r){const s=this.startupWaiters.get(t);if(!(!s||s.size===0)){this.startupWaiters.delete(t);for(const n of s)try{n(e,r)}catch{}}}async listRuns(){await this.ensureRestored();const t=Array.from(this.runs.values()).filter(s=>s.state==="running"&&s.pid>0).map(s=>s.pid);let e=new Map;if(t.length>0)try{e=await k(t)}catch(s){g.debug(`[listRuns] \u7AEF\u53E3\u63A2\u6D4B\u5931\u8D25: ${s.message}`)}const r=[];for(const s of this.runs.values()){const n=this.logs.get(s.configId);r.push({...s,logTail:n?n.getLastN(20).map(i=>i.data):[],nextLogIndex:n?n.getSinceIndex(-1).nextIndex:0,ports:s.state==="running"?e.get(s.pid)??[]:[],metrics:this.metricsMonitor.getLatest(s.configId)??void 0})}return r}async getLogs(t,e){await this.ensureRestored();const r=this.runs.get(t);if(!r)return null;const s=this.logs.get(t);if(!s)return{configId:t,state:r.state,entries:[],nextIndex:0,oldestIndex:0};const{entries:n,nextIndex:i,oldestIndex:a}=s.getSinceIndex(e);return{configId:t,state:r.state,entries:n,nextIndex:i,oldestIndex:a}}getRun(t){return this.runs.get(t)}getMetrics(t,e){return this.metricsMonitor.getHistory(t,e)}getMetricsSince(t,e,r){return this.metricsMonitor.getHistoryEntriesSince(t,e,r)}async ensureRestored(){if(!this.restored){this.restored=!0;try{const t=await F.readFile(N(),"utf-8"),e=JSON.parse(t);for(const r of e){const s=r.pid>0&&L(r.pid);if(s){g.warn(`[restore] \u68C0\u6D4B\u5230\u4E0A\u6B21 bridge \u975E\u4F18\u96C5\u9000\u51FA\u540E\u7684\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u8054\u52A8\u7EC8\u6B62: configId=${r.configId}, pid=${r.pid}`);try{await E(r.pid)}catch(n){g.warn(`[restore] \u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B\u5931\u8D25: configId=${r.configId}, pid=${r.pid}, error=${n.message}`)}}this.runs.set(r.configId,{...r,state:"exited",...s?{exitedAt:new Date().toISOString()}:{}}),this.logs.set(r.configId,new O(D))}g.info(`[restore] \u5DF2\u6062\u590D ${e.length} \u6761\u542F\u52A8\u9879\u8FD0\u884C\u8BB0\u5F55`)}catch{}}}publishRunStatus(t,e=!1){const r=this.runs.get(t);r&&(x().publishStatusRun({...r}),!(!e||r.state!=="running"||r.pid<=0)&&setTimeout(()=>{const s=this.runs.get(t);!s||s.state!=="running"||s.pid<=0||(async()=>{let n=[];try{n=(await k([s.pid])).get(s.pid)??[]}catch{}const i=this.runs.get(t);i&&i.state==="running"&&i.pid===s.pid&&x().publishStatusRun({...i,ports:n})})()},2e3))}async persist(){const t=N();try{const e=Array.from(this.runs.values());await G(t,async()=>{await U(t,e)})}catch(e){g.warn(`[persist] \u6301\u4E45\u5316\u5931\u8D25: ${e.message}`)}}}S.instance=null;function mt(){return S.getInstance()}export{H as LaunchAlreadyRunningError,S as LaunchManager,W as StreamDecoder,mt as getLaunchManager,Z as resolvePlaceholders};
11
+ `,h=this.logs.get(t)?.append({stream:"stderr",text:a});return h&&P().publish(t,"logs",h.index,h.data),P().publishState(t,{configId:t,state:"stopped"}),this.publishRunStatus(t),await this.persist(),this.resolveStartupWaiters(t,"stopped",void 0),{success:n.failed===0,message:n.failed===0?"\u8FDB\u7A0B\u5DF2\u505C\u6B62":`\u90E8\u5206\u8FDB\u7A0B\u672A\u80FD\u7EC8\u6B62\uFF08terminated=${n.terminated}, failed=${n.failed}\uFF09`,pid:r.pid}}async restart(t){await this.ensureRestored();const e=this.runs.get(t.configId);return e&&e.state==="running"&&await this.stop(t.configId,"manual",t.startedBy),await this.start(t)}async startBatch(t,e){await this.ensureRestored();const s=await Promise.all(t.map(async i=>{try{const n=await this.start(i);return{configId:i.configId,ok:!0,run:n}}catch(n){return n instanceof H?{configId:i.configId,ok:!0,skipped:!0,message:"\u5F53\u524D\u5DF2\u5904\u4E8E\u542F\u52A8/\u6B63\u5728\u542F\u52A8\u72B6\u6001\uFF0C\u8DF3\u8FC7",run:n.existing}:{configId:i.configId,ok:!1,error:n.message}}}));if(e>0){const i=await Promise.all(s.map(async n=>{if(!n.ok||n.skipped)return n;try{const a=await this.waitStartupResult(n.configId,e);return{...n,wait:a}}catch(a){return{...n,error:a.message}}}));s.splice(0,s.length,...i)}const r={total:s.length,started:0,skipped:0,failed:0,ready:0,exited:0,stopped:0,timeout:0};for(const i of s){if(!i.ok){r.failed+=1;continue}if(i.skipped){r.skipped+=1;continue}r.started+=1,i.wait&&(r[i.wait.outcome]+=1)}return{items:s,summary:r}}async stopAll(){await this.ensureRestored();const t=Array.from(this.runs.values()).filter(s=>s.state==="running");let e=0;for(const s of t)try{const r=await this.stop(s.configId,"shutdown");r.success?e++:m.warn(`[stopAll] \u542F\u52A8\u9879\u672A\u80FD\u5B8C\u5168\u7EC8\u6B62: configId=${s.configId}, message=${r.message}`)}catch(r){m.warn(`[stopAll] \u505C\u6B62\u542F\u52A8\u9879\u5931\u8D25: configId=${s.configId}, error=${r.message}`)}return{running:t.length,stopped:e}}async waitStartupResult(t,e){const s=this.runs.get(t);if(!s)throw new Error("launch run not found");const r=Date.now(),i=()=>(this.logs.get(t)?.getLastN(Y)??[]).map(a=>a.data);if(s.state!=="running")return{outcome:s.state==="stopped"?"stopped":"exited",waitedMs:0,...s.state==="exited"?{exitCode:s.exitCode??null}:{},logTail:i()};const n=this.readinessMatchers.get(t);if(n){const a=this.scanReadinessMatch(t,n);if(a!==null)return{outcome:"ready",waitedMs:0,matchedLine:a,logTail:i()}}return await new Promise(a=>{let h=!1,g=null,w=null,T=!1,p=null;const I=()=>{g!==null&&(clearInterval(g),g=null),w!==null&&(clearTimeout(w),w=null);const u=this.startupWaiters.get(t);if(u&&(u.delete(R),u.size===0&&this.startupWaiters.delete(t)),p!==null){const d=this.logListeners.get(t);d&&(d.delete(p),d.size===0&&this.logListeners.delete(t)),p=null}},b=u=>{h||(h=!0,I(),a(u))},R=(u,d)=>{b({outcome:u==="stopped"?"stopped":"exited",waitedMs:Date.now()-r,...u==="exited"?{exitCode:d??null}:{},logTail:i()})};let y=this.startupWaiters.get(t);if(y||(y=new Set,this.startupWaiters.set(t,y)),y.add(R),n){p=d=>{if(!(h||d.index<n.fromIndex)){for(const f of d.data.text.split(/\r?\n/))if(f&&n.pattern.test(f)){b({outcome:"ready",waitedMs:Date.now()-r,matchedLine:f.trim(),logTail:i()});return}}};let u=this.logListeners.get(t);u||(u=new Set,this.logListeners.set(t,u)),u.add(p)}else{const u=async()=>{if(h||T)return;const d=this.runs.get(t);if(!(!d||d.state!=="running"||d.pid<=0)){T=!0;try{const o=(await k([d.pid])).get(d.pid)??[];if(o.length>0&&!h){const c=this.runs.get(t);c?.state==="running"&&c.pid===d.pid&&b({outcome:"ready",waitedMs:Date.now()-r,ports:o,logTail:i()})}}catch{}finally{T=!1}}};g=setInterval(()=>{u()},K),u()}w=setTimeout(()=>{b({outcome:"timeout",waitedMs:Date.now()-r,logTail:i()})},e)})}scanReadinessMatch(t,e){const s=this.logs.get(t);if(!s)return null;for(const r of s.getSinceIndex(e.fromIndex-1).entries)for(const i of r.data.text.split(/\r?\n/))if(i&&e.pattern.test(i))return i.trim();return null}resolveStartupWaiters(t,e,s){const r=this.startupWaiters.get(t);if(!(!r||r.size===0)){this.startupWaiters.delete(t);for(const i of r)try{i(e,s)}catch{}}}async listRuns(t){await this.ensureRestored();const s=t?.withPorts??!0?Array.from(this.runs.values()).filter(n=>n.state==="running"&&n.pid>0).map(n=>n.pid):[];let r=new Map;if(s.length>0)try{r=await this.probePorts(s)}catch(n){m.debug(`[listRuns] \u7AEF\u53E3\u63A2\u6D4B\u5931\u8D25: ${n.message}`)}const i=[];for(const n of this.runs.values()){const a=this.logs.get(n.configId);i.push({...n,logTail:a?a.getLastN(20).map(h=>h.data):[],nextLogIndex:a?a.getSinceIndex(-1).nextIndex:0,ports:n.state==="running"?r.get(n.pid)??[]:[],metrics:this.metricsMonitor.getLatest(n.configId)??void 0})}return i}async probePorts(t){const e=[...t].sort((i,n)=>i-n).join(","),s=this.portsProbeInflight.get(e);if(s)return s;const r=k(t).finally(()=>{this.portsProbeInflight.get(e)===r&&this.portsProbeInflight.delete(e)});return this.portsProbeInflight.set(e,r),r}async publishRunningPorts(){const t=this.runningRefs();if(t.length===0)return;let e=new Map;try{e=await this.probePorts(t.map(s=>s.pid))}catch(s){m.debug(`[publishRunningPorts] \u7AEF\u53E3\u63A2\u6D4B\u5931\u8D25: ${s.message}`);return}for(const s of t){const r=this.runs.get(s.configId);!r||r.state!=="running"||r.pid!==s.pid||P().publishStatusRun({...r,ports:e.get(s.pid)??[]})}}async getLogs(t,e){await this.ensureRestored();const s=this.runs.get(t);if(!s)return null;const r=this.logs.get(t);if(!r)return{configId:t,state:s.state,entries:[],nextIndex:0,oldestIndex:0};const{entries:i,nextIndex:n,oldestIndex:a}=r.getSinceIndex(e);return{configId:t,state:s.state,entries:i,nextIndex:n,oldestIndex:a}}getRun(t){return this.runs.get(t)}getMetrics(t,e){return this.metricsMonitor.getHistory(t,e)}getMetricsSince(t,e,s){return this.metricsMonitor.getHistoryEntriesSince(t,e,s)}async ensureRestored(){if(!this.restored){this.restored=!0;try{const t=await F.readFile(N(),"utf-8"),e=JSON.parse(t);for(const s of e){const r=s.pid>0&&await L(s.pid);if(r){m.warn(`[restore] \u68C0\u6D4B\u5230\u4E0A\u6B21 bridge \u975E\u4F18\u96C5\u9000\u51FA\u540E\u7684\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u8054\u52A8\u7EC8\u6B62: configId=${s.configId}, pid=${s.pid}`);try{await E(s.pid)}catch(i){m.warn(`[restore] \u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B\u5931\u8D25: configId=${s.configId}, pid=${s.pid}, error=${i.message}`)}}this.runs.set(s.configId,{...s,state:"exited",...r?{exitedAt:new Date().toISOString()}:{}}),this.logs.set(s.configId,new O(D))}m.info(`[restore] \u5DF2\u6062\u590D ${e.length} \u6761\u542F\u52A8\u9879\u8FD0\u884C\u8BB0\u5F55`)}catch{}}}publishRunStatus(t,e=!1){const s=this.runs.get(t);s&&(P().publishStatusRun({...s}),!(!e||s.state!=="running"||s.pid<=0)&&setTimeout(()=>{const r=this.runs.get(t);!r||r.state!=="running"||r.pid<=0||(async()=>{let i=[];try{i=(await this.probePorts([r.pid])).get(r.pid)??[]}catch{}const n=this.runs.get(t);n&&n.state==="running"&&n.pid===r.pid&&P().publishStatusRun({...n,ports:i})})()},2e3))}async persist(){const t=N();try{const e=Array.from(this.runs.values());await G(t,async()=>{await U(t,e)})}catch(e){m.warn(`[persist] \u6301\u4E45\u5316\u5931\u8D25: ${e.message}`)}}}S.instance=null;function gt(){return S.getInstance()}export{H as LaunchAlreadyRunningError,S as LaunchManager,W as StreamDecoder,gt as getLaunchManager,Z as resolvePlaceholders};
12
12
 
@@ -1,6 +1,6 @@
1
1
 
2
2
 
3
- export declare const METRICS_SAMPLE_INTERVAL_MS = 2000;
3
+ export declare const METRICS_SAMPLE_INTERVAL_MS = 5000;
4
4
 
5
5
  export declare const METRICS_HISTORY_CAPACITY = 900;
6
6
 
@@ -1,4 +1,5 @@
1
- import{exec as m}from"node:child_process";import h from"node:os";import{promisify as g}from"node:util";import{createLogger as M}from"../utils/logger.js";import{getLaunchStreamHub as b}from"./launch-streams.js";import{RingBuffer as y}from"./ring-buffer.js";const l=g(m),w=M("launch-metrics"),N=2e3,d=900;function x(r){return r.replace(/#\s*<\s*CLIXML[\s\S]*?(?=#<\s*CLIXML|$)/g,"").trim()}function I(r){return r==null?[]:Array.isArray(r)?r:[r]}function S(r){const t=x(r),e=t.search(/[[{]/);if(e<0)return[];const n=JSON.parse(t.slice(e)),s=[];for(const i of I(n)){const o=Number(i?.ProcessId),c=Number(i?.ParentProcessId);if(!Number.isFinite(o)||!Number.isFinite(c))continue;const a=Number(i?.UserModeTime??0)/1e4,u=Number(i?.KernelModeTime??0)/1e4;s.push({pid:o,ppid:c,cpuMs:(Number.isFinite(a)?a:0)+(Number.isFinite(u)?u:0),rssBytes:Math.max(0,Number(i?.WorkingSetSize)||0),threads:Math.max(0,Number(i?.ThreadCount)||0)})}return s}function C(r){const t=r.trim();if(!t)return 0;const[e,...n]=t.split("-");let s=0,i;n.length>0?(s=Number(e)||0,i=n.join("-")):i=e;const o=i.split(":").map(p=>Number(p)||0),c=o[o.length-1]??0,a=o[o.length-2]??0,u=o[o.length-3]??0;return(((s*24+u)*60+a)*60+c)*1e3}function P(r,t){const e=[];for(const n of r.split(`
2
- `)){const s=n.trim().split(/\s+/),i=t?5:4;if(s.length<i)continue;const o=Number.parseInt(s[0],10),c=Number.parseInt(s[1],10),a=Number.parseInt(s[2],10),u=t?Number.parseInt(s[3],10):0,p=C(s[t?4:3]);!Number.isFinite(o)||!Number.isFinite(c)||e.push({pid:o,ppid:c,cpuMs:p,rssBytes:Number.isFinite(a)&&a>0?a*1024:0,threads:Number.isFinite(u)&&u>0?u:0})}return e}async function T(r){const t=new Map;for(const e of r)try{const{stdout:n}=await l(`ps -M -p ${e}`,{encoding:"utf8",timeout:5e3}),s=n.split(`
3
- `).filter(i=>i.trim().length>0);t.set(e,Math.max(0,s.length-1))}catch{}return t}async function B(){const e=Buffer.from("Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId, WorkingSetSize, UserModeTime, KernelModeTime, ThreadCount | ConvertTo-Json -Compress","utf16le").toString("base64"),{stdout:n}=await l(`powershell -NoProfile -NonInteractive -EncodedCommand ${e}`,{encoding:"utf8",timeout:1e4,windowsHide:!0,maxBuffer:10*1024*1024});return S(n)}async function L(r){const t=h.platform();if(t==="win32")return B();const e=t==="darwin",n=e?"pid=,ppid=,rss=,time=":"pid=,ppid=,rss=,nlwp=,time=",{stdout:s}=await l(`ps -axo ${n}`,{encoding:"utf8",timeout:5e3}),i=P(s,!e);if(e&&r.length>0){const o=await T(r);for(const c of i){const a=o.get(c.pid);a!==void 0&&(c.threads=a)}}return i}function k(r){const t=new Map;for(const e of r){const n=t.get(e.ppid);n?n.push(e.pid):t.set(e.ppid,[e.pid])}return t}function A(r,t){const e=new Map(r.map(u=>[u.pid,u]));if(!e.has(t))return{cpuMs:0,rssBytes:0,threads:0,found:!1};const n=k(r),s=[t],i=new Set;let o=0,c=0,a=0;for(;s.length>0;){const u=s.shift();if(i.has(u))continue;i.add(u);const p=e.get(u);p&&(o+=p.cpuMs,c+=p.rssBytes,a+=p.threads);for(const f of n.get(u)??[])s.push(f)}return{cpuMs:o,rssBytes:c,threads:a,found:!0}}function F(r,t){const e=t.at-r.at,n=t.totalCpuMs-r.totalCpuMs;return e<=0||n<=0?0:n/e*100}class j{constructor(t){this.getRuns=t,this.histories=new Map,this.cpuBaselines=new Map,this.timer=null,this.ticking=!1}ensureRunning(){if(this.timer===null){const t=setInterval(()=>void this.tick(),N);t.unref?.(),this.timer=t,this.tick()}}stop(){this.timer!==null&&(clearInterval(this.timer),this.timer=null)}clear(t){this.histories.delete(t),this.cpuBaselines.delete(t)}getLatest(t){const e=this.histories.get(t);if(!e)return null;const n=e.getLastN(1)[0];return n?n.data:null}getHistory(t,e=d){const n=this.histories.get(t);if(!n)return[];const s=Math.max(0,Math.min(e,d));return n.getLastN(s).map(i=>({at:i.timestamp,...i.data}))}getHistoryEntriesSince(t,e,n=d){const s=this.histories.get(t);if(!s)return[];const{entries:i}=s.getSinceIndex(e),o=Math.max(0,Math.min(n,d));return i.slice(-o).map(c=>({index:c.index,at:c.timestamp,sample:c.data}))}async tick(){if(!this.ticking){this.ticking=!0;try{const t=this.getRuns();if(t.length===0){this.stop();return}let e=[];try{e=await L(t.map(s=>s.pid))}catch(s){w.debug(`[launch-metrics] \u8FDB\u7A0B\u8868\u91C7\u96C6\u5931\u8D25: ${s.message}`);return}const n=Date.now();for(const s of t){const i=A(e,s.pid);if(!i.found)continue;const o=this.cpuBaselines.get(s.configId),c=o?F(o,{at:n,totalCpuMs:i.cpuMs}):0;this.cpuBaselines.set(s.configId,{at:n,totalCpuMs:i.cpuMs});let a=this.histories.get(s.configId);a||(a=new y(d),this.histories.set(s.configId,a));const u=a.append({cpuPercent:c,memoryBytes:i.rssBytes,threadCount:i.threads});b().publish(s.configId,"metrics",u.index,u.data)}}finally{this.ticking=!1}}}}export{j as LaunchMetricsMonitor,d as METRICS_HISTORY_CAPACITY,N as METRICS_SAMPLE_INTERVAL_MS,A as aggregateProcessTree,F as computeCpuPercent,C as parsePsCpuTime,P as parseUnixProcessTable,S as parseWindowsProcessTable};
1
+ import{exec as h}from"node:child_process";import g from"node:os";import{promisify as b}from"node:util";import{createLogger as M}from"../utils/logger.js";import{getLaunchStreamHub as $}from"./launch-streams.js";import{RingBuffer as w}from"./ring-buffer.js";const l=b(h),f=M("launch-metrics"),I=5e3,d=900;function y(n){return n.replace(/#\s*<\s*CLIXML[\s\S]*?(?=#<\s*CLIXML|$)/g,"").trim()}function P(n){return n==null?[]:Array.isArray(n)?n:[n]}function N(n){const t=y(n),s=t.search(/[[{]/);if(s<0)return[];const i=JSON.parse(t.slice(s)),e=[];for(const r of P(i)){const o=Number(r?.ProcessId),c=Number(r?.ParentProcessId);if(!Number.isFinite(o)||!Number.isFinite(c))continue;const a=Number(r?.UserModeTime??0)/1e4,u=Number(r?.KernelModeTime??0)/1e4;e.push({pid:o,ppid:c,cpuMs:(Number.isFinite(a)?a:0)+(Number.isFinite(u)?u:0),rssBytes:Math.max(0,Number(r?.WorkingSetSize)||0),threads:Math.max(0,Number(r?.ThreadCount)||0)})}return e}function C(n){const t=n.trim();if(!t)return 0;const[s,...i]=t.split("-");let e=0,r;i.length>0?(e=Number(s)||0,r=i.join("-")):r=s;const o=r.split(":").map(p=>Number(p)||0),c=o[o.length-1]??0,a=o[o.length-2]??0,u=o[o.length-3]??0;return(((e*24+u)*60+a)*60+c)*1e3}function S(n,t){const s=[];for(const i of n.split(`
2
+ `)){const e=i.trim().split(/\s+/),r=t?5:4;if(e.length<r)continue;const o=Number.parseInt(e[0],10),c=Number.parseInt(e[1],10),a=Number.parseInt(e[2],10),u=t?Number.parseInt(e[3],10):0,p=C(e[t?4:3]);!Number.isFinite(o)||!Number.isFinite(c)||s.push({pid:o,ppid:c,cpuMs:p,rssBytes:Number.isFinite(a)&&a>0?a*1024:0,threads:Number.isFinite(u)&&u>0?u:0})}return s}async function x(n){const t=new Map;for(const s of n)try{const{stdout:i}=await l(`ps -M -p ${s}`,{encoding:"utf8",timeout:5e3}),e=i.split(`
3
+ `).filter(r=>r.trim().length>0);t.set(s,Math.max(0,e.length-1))}catch{}return t}function T(n){return["$ErrorActionPreference = 'Stop'",`$roots = @(${n.filter(s=>Number.isInteger(s)&&s>0).join(", ")})`,"$seen = @{}","$rows = [System.Collections.Generic.List[object]]::new()","$field = 'ProcessId'","$frontier = $roots","while ($true) {",` $conds = ($frontier | ForEach-Object { "$field = $_" }) -join ' OR '`," $batch = @(Get-CimInstance Win32_Process -Filter $conds | Select-Object ProcessId, ParentProcessId, WorkingSetSize, UserModeTime, KernelModeTime, ThreadCount)"," $newIds = @()"," foreach ($p in $batch) {"," if ($seen.ContainsKey([int]$p.ProcessId)) { continue }"," $seen[[int]$p.ProcessId] = $true"," $rows.Add($p)"," $newIds += $p.ProcessId"," }"," if ($newIds.Count -eq 0) { break }"," $frontier = $newIds"," $field = 'ParentProcessId'","}","if ($rows.Count -eq 0) { '[]' } else { $rows | ConvertTo-Json -Compress }"].join(`
4
+ `)}async function B(n=[]){const t=async e=>{const o=Buffer.from(e,"utf16le").toString("base64"),{stdout:c}=await l(`powershell -NoProfile -NonInteractive -EncodedCommand ${o}`,{encoding:"utf8",timeout:1e4,windowsHide:!0,maxBuffer:10*1024*1024});return N(c)},s=n.filter(e=>Number.isInteger(e)&&e>0);if(s.length>0)try{return await t(T(s))}catch(e){f.debug(`[launch-metrics] \u5B9A\u5411\u8FDB\u7A0B\u6811\u67E5\u8BE2\u5931\u8D25\uFF0C\u56DE\u9000\u5168\u91CF\u67E5\u8BE2: ${e.message}`)}return t("Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId, WorkingSetSize, UserModeTime, KernelModeTime, ThreadCount | ConvertTo-Json -Compress")}async function L(n){const t=g.platform();if(t==="win32")return B(n);const s=t==="darwin",i=s?"pid=,ppid=,rss=,time=":"pid=,ppid=,rss=,nlwp=,time=",{stdout:e}=await l(`ps -axo ${i}`,{encoding:"utf8",timeout:5e3}),r=S(e,!s);if(s&&n.length>0){const o=await x(n);for(const c of r){const a=o.get(c.pid);a!==void 0&&(c.threads=a)}}return r}function k(n){const t=new Map;for(const s of n){const i=t.get(s.ppid);i?i.push(s.pid):t.set(s.ppid,[s.pid])}return t}function A(n,t){const s=new Map(n.map(u=>[u.pid,u]));if(!s.has(t))return{cpuMs:0,rssBytes:0,threads:0,found:!1};const i=k(n),e=[t],r=new Set;let o=0,c=0,a=0;for(;e.length>0;){const u=e.shift();if(r.has(u))continue;r.add(u);const p=s.get(u);p&&(o+=p.cpuMs,c+=p.rssBytes,a+=p.threads);for(const m of i.get(u)??[])e.push(m)}return{cpuMs:o,rssBytes:c,threads:a,found:!0}}function F(n,t){const s=t.at-n.at,i=t.totalCpuMs-n.totalCpuMs;return s<=0||i<=0?0:i/s*100}class H{constructor(t){this.getRuns=t,this.histories=new Map,this.cpuBaselines=new Map,this.timer=null,this.ticking=!1}ensureRunning(){if(this.timer===null){const t=setInterval(()=>void this.tick(),I);t.unref?.(),this.timer=t,this.tick()}}stop(){this.timer!==null&&(clearInterval(this.timer),this.timer=null)}clear(t){this.histories.delete(t),this.cpuBaselines.delete(t)}getLatest(t){const s=this.histories.get(t);if(!s)return null;const i=s.getLastN(1)[0];return i?i.data:null}getHistory(t,s=d){const i=this.histories.get(t);if(!i)return[];const e=Math.max(0,Math.min(s,d));return i.getLastN(e).map(r=>({at:r.timestamp,...r.data}))}getHistoryEntriesSince(t,s,i=d){const e=this.histories.get(t);if(!e)return[];const{entries:r}=e.getSinceIndex(s),o=Math.max(0,Math.min(i,d));return r.slice(-o).map(c=>({index:c.index,at:c.timestamp,sample:c.data}))}async tick(){if(!this.ticking){this.ticking=!0;try{const t=this.getRuns();if(t.length===0){this.stop();return}let s=[];try{s=await L(t.map(e=>e.pid))}catch(e){f.debug(`[launch-metrics] \u8FDB\u7A0B\u8868\u91C7\u96C6\u5931\u8D25: ${e.message}`);return}const i=Date.now();for(const e of t){const r=A(s,e.pid);if(!r.found)continue;const o=this.cpuBaselines.get(e.configId),c=o?F(o,{at:i,totalCpuMs:r.cpuMs}):0;this.cpuBaselines.set(e.configId,{at:i,totalCpuMs:r.cpuMs});let a=this.histories.get(e.configId);a||(a=new w(d),this.histories.set(e.configId,a));const u=a.append({cpuPercent:c,memoryBytes:r.rssBytes,threadCount:r.threads});$().publish(e.configId,"metrics",u.index,u.data)}}finally{this.ticking=!1}}}}export{H as LaunchMetricsMonitor,d as METRICS_HISTORY_CAPACITY,I as METRICS_SAMPLE_INTERVAL_MS,A as aggregateProcessTree,F as computeCpuPercent,C as parsePsCpuTime,S as parseUnixProcessTable,N as parseWindowsProcessTable};
4
5
 
@@ -18,6 +18,10 @@ export interface McpDeploySpec {
18
18
  args?: string[];
19
19
  env?: Record<string, string>;
20
20
  headers?: Record<string, string>;
21
+
22
+ collapsed?: boolean;
23
+
24
+ description?: string;
21
25
  }
22
26
  export declare class McpDeployManager {
23
27
  private readonly rootDir;
@@ -0,0 +1,12 @@
1
+
2
+ export declare function isStdioMcpSpec(spec: unknown): boolean;
3
+
4
+ export declare function isBuiltinMcpName(name: string): boolean;
5
+
6
+ export declare function expandEnvPlaceholders(text: string, env: Record<string, string>): string;
7
+ export interface InjectEnvOptions {
8
+
9
+ overwriteExisting?: boolean;
10
+ }
11
+
12
+ export declare function injectEffectiveEnvIntoMcpServers(servers: Record<string, unknown>, effectiveEnv: Record<string, string>, options?: InjectEnvOptions): string[];
@@ -0,0 +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};
2
+
@@ -38,3 +38,11 @@ export declare function clearMcpLaunchBindingQueues(): void;
38
38
  export declare function getLatestAgentToken(agentId: string): {
39
39
  runtimeAccessToken: string;
40
40
  } | null;
41
+
42
+ export declare function getLatestAgentTokenEntry(agentId: string): {
43
+ runtimeAccessToken: string;
44
+ schedulerBaseUrl?: string;
45
+ updatedAt: number;
46
+ } | null;
47
+
48
+ export declare function updateLatestAgentToken(agentId: string, runtimeAccessToken: string, schedulerBaseUrl?: string): void;
@@ -1,2 +1,2 @@
1
- import B from"node:path";import{schedulerBaseUrl as f}from"../config.js";import{getRuntimeAccessToken as x,loadRuntimeBinding as U,normalizeSchedulerBaseUrl as g}from"./runtime-binding.js";const L=5*60*1e3,w=new Map,s=[];function u(e){const r=String(e||"").trim();return r?B.resolve(r).toLowerCase():""}function h(e){return String(e||"").trim()}function v(e){const r=e.toLowerCase();return r==="localhost"||r==="::1"||r==="[::1]"?"127.0.0.1":r}function k(e){const r=g(e)||String(e||"").trim();if(!r)return"";try{const t=new URL(r);return t.protocol==="ws:"?t.protocol="http:":t.protocol==="wss:"?t.protocol="https:":t.protocol=t.protocol.toLowerCase(),t.hostname=v(t.hostname),t.origin}catch{return r.replace(/\/+$/,"").toLowerCase()}}function p(e=Date.now()){for(let r=s.length-1;r>=0;r-=1){const t=Date.parse(s[r]?.enqueuedAt||"");(!Number.isFinite(t)||e-t>L)&&s.splice(r,1)}}function M(e){return`${e}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}function q(e){p();const r=String(e.agentId||"").trim(),t=u(e.workspacePath);if(!r||!t)return null;const n=U(),i=g(e.serverUrl||e.schedulerBaseUrl||n.schedulerBaseUrl||f)||h(e.serverUrl||e.schedulerBaseUrl||n.schedulerBaseUrl||f),o=g(e.schedulerBaseUrl||n.schedulerBaseUrl||f)||h(e.schedulerBaseUrl||n.schedulerBaseUrl||f),c={id:M(r),agentId:r,workspacePath:B.resolve(String(e.workspacePath)),serverUrl:i,mcpHttpUrl:h(e.mcpHttpUrl),runtimeAccessToken:h(e.runtimeAccessToken),userId:h(e.userId),schedulerBaseUrl:o,enqueuedAt:new Date().toISOString()};s.push(c);const d=c.runtimeAccessToken;return d&&w.set(r,{runtimeAccessToken:d,updatedAt:Date.now()}),c}function A(e){if(e.length===0||new Set(e.map(({binding:i})=>i.agentId)).size>1)return-1;let t=e[0],n=Date.parse(t.binding.enqueuedAt||"");for(const i of e.slice(1)){const o=Date.parse(i.binding.enqueuedAt||"");o>n&&(t=i,n=o)}return t.index}function C(e){p();const r=String(e.agentId||"").trim(),t=u(e.workspacePath),n=k(e.serverUrl);if(!t)return null;const i=s.map((l,a)=>({binding:l,index:a})).filter(({binding:l})=>(!r||l.agentId===r)&&u(l.workspacePath)===t&&n&&k(l.serverUrl||l.schedulerBaseUrl)===n);let o=A(i);if(o<0){const l=s.map((a,T)=>({binding:a,index:T})).filter(({binding:a})=>(!r||a.agentId===r)&&u(a.workspacePath)===t);o=A(l)}if(o<0)return null;const[c]=s.splice(o,1);if(!c)return null;const d=U(),I=c.userId||d.userId,m=c.schedulerBaseUrl||d.schedulerBaseUrl,S=c.runtimeAccessToken||x(m);return{...c,runtimeAccessToken:S,userId:I,schedulerBaseUrl:m}}function y(e){p();const r=u(e);return r?s.filter(t=>u(t.workspacePath)===r).length:0}function H(e){p();const r=String(e||"").trim();if(!r)return!1;const t=s.findIndex(n=>n.id===r);return t<0?!1:(s.splice(t,1),!0)}function K(){s.splice(0,s.length)}function N(e){const r=w.get(e);return!r||!r.runtimeAccessToken?null:{runtimeAccessToken:r.runtimeAccessToken}}export{C as claimMcpLaunchBinding,K as clearMcpLaunchBindingQueues,q as enqueueMcpLaunchBinding,N as getLatestAgentToken,y as getMcpLaunchQueueSize,H as removeMcpLaunchBinding};
1
+ import U from"node:path";import{schedulerBaseUrl as f}from"../config.js";import{getRuntimeAccessToken as x,loadRuntimeBinding as k,normalizeSchedulerBaseUrl as p}from"./runtime-binding.js";const L=5*60*1e3,h=new Map,s=[];function a(e){const t=String(e||"").trim();return t?U.resolve(t).toLowerCase():""}function g(e){return String(e||"").trim()}function z(e){const t=e.toLowerCase();return t==="localhost"||t==="::1"||t==="[::1]"?"127.0.0.1":t}function A(e){const t=p(e)||String(e||"").trim();if(!t)return"";try{const r=new URL(t);return r.protocol==="ws:"?r.protocol="http:":r.protocol==="wss:"?r.protocol="https:":r.protocol=r.protocol.toLowerCase(),r.hostname=z(r.hostname),r.origin}catch{return t.replace(/\/+$/,"").toLowerCase()}}function m(e=Date.now()){for(let t=s.length-1;t>=0;t-=1){const r=Date.parse(s[t]?.enqueuedAt||"");(!Number.isFinite(r)||e-r>L)&&s.splice(t,1)}}function v(e){return`${e}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}function q(e){m();const t=String(e.agentId||"").trim(),r=a(e.workspacePath);if(!t||!r)return null;const n=k(),o=p(e.serverUrl||e.schedulerBaseUrl||n.schedulerBaseUrl||f)||g(e.serverUrl||e.schedulerBaseUrl||n.schedulerBaseUrl||f),c=p(e.schedulerBaseUrl||n.schedulerBaseUrl||f)||g(e.schedulerBaseUrl||n.schedulerBaseUrl||f),i={id:v(t),agentId:t,workspacePath:U.resolve(String(e.workspacePath)),serverUrl:o,mcpHttpUrl:g(e.mcpHttpUrl),runtimeAccessToken:g(e.runtimeAccessToken),userId:g(e.userId),schedulerBaseUrl:c,enqueuedAt:new Date().toISOString()};s.push(i);const d=i.runtimeAccessToken;return d&&h.set(t,{runtimeAccessToken:d,schedulerBaseUrl:i.schedulerBaseUrl||c||void 0,updatedAt:Date.now()}),i}function w(e){if(e.length===0||new Set(e.map(({binding:o})=>o.agentId)).size>1)return-1;let r=e[0],n=Date.parse(r.binding.enqueuedAt||"");for(const o of e.slice(1)){const c=Date.parse(o.binding.enqueuedAt||"");c>n&&(r=o,n=c)}return r.index}function y(e){m();const t=String(e.agentId||"").trim(),r=a(e.workspacePath),n=A(e.serverUrl);if(!r)return null;const o=s.map((l,u)=>({binding:l,index:u})).filter(({binding:l})=>(!t||l.agentId===t)&&a(l.workspacePath)===r&&n&&A(l.serverUrl||l.schedulerBaseUrl)===n);let c=w(o);if(c<0){const l=s.map((u,T)=>({binding:u,index:T})).filter(({binding:u})=>(!t||u.agentId===t)&&a(u.workspacePath)===r);c=w(l)}if(c<0)return null;const[i]=s.splice(c,1);if(!i)return null;const d=k(),I=i.userId||d.userId,B=i.schedulerBaseUrl||d.schedulerBaseUrl,S=i.runtimeAccessToken||x(B);return{...i,runtimeAccessToken:S,userId:I,schedulerBaseUrl:B}}function C(e){m();const t=a(e);return t?s.filter(r=>a(r.workspacePath)===t).length:0}function H(e){m();const t=String(e||"").trim();if(!t)return!1;const r=s.findIndex(n=>n.id===t);return r<0?!1:(s.splice(r,1),!0)}function K(){s.splice(0,s.length)}function N(e){const t=h.get(e);return!t||!t.runtimeAccessToken?null:{runtimeAccessToken:t.runtimeAccessToken}}function $(e){const t=h.get(String(e||"").trim());return!t||!t.runtimeAccessToken?null:t}function E(e,t,r){const n=String(e||"").trim(),o=String(t||"").trim();!n||!o||h.set(n,{runtimeAccessToken:o,schedulerBaseUrl:r||h.get(n)?.schedulerBaseUrl,updatedAt:Date.now()})}export{y as claimMcpLaunchBinding,K as clearMcpLaunchBindingQueues,q as enqueueMcpLaunchBinding,N as getLatestAgentToken,$ as getLatestAgentTokenEntry,C as getMcpLaunchQueueSize,H as removeMcpLaunchBinding,E as updateLatestAgentToken};
2
2
 
@@ -1,2 +1,2 @@
1
- import{ORPHAN_SCAN_INTERVAL as d,ORPHAN_AUTO_CLEAN_MODE as r,ORPHAN_SCAN_ENABLED as m,schedulerBaseUrl as o}from"../config.js";import{createLogger as f}from"../utils/logger.js";import{detectOrphanProcesses as g,checkAllSessionsHealth as w,terminateProcessTree as S,waitForProcessExit as $}from"./process-detector.js";import{getRuntimeAccessToken as c}from"./runtime-binding.js";import{shouldAutoCleanOrphanProcesses as l}from"./runtime-lifecycle-policy.js";import{loadPersistedSessions as y,savePersistedSessions as v}from"./terminal-persistence.js";const n=f("orphan-monitor");class O{constructor(){this.intervalId=null,this.lastScanTime=null,this.eventListeners=[],this.stopped=!1}async start(){if(!m){n.info("\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5DF2\u7981\u7528 (AWS_ORPHAN_SCAN_ENABLED=false)");return}this.stopped=!1,n.info(`\u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\uFF0C\u626B\u63CF\u95F4\u9694: ${d}ms, \u81EA\u52A8\u6E05\u7406\u6A21\u5F0F: ${r}`),await this.scan(),this.intervalId=setInterval(async()=>{await this.scan()},d),n.info("\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5DF2\u542F\u52A8")}stop(){this.stopped=!0,this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,n.info("\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5DF2\u505C\u6B62"))}async scan(){if(this.stopped){n.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u8DF3\u8FC7\u626B\u63CF");return}this.lastScanTime=new Date,n.debug("\u5F00\u59CB\u626B\u63CF\u5B64\u513F\u8FDB\u7A0B...");try{const e=await y();if(this.stopped){n.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u4E2D\u65AD\u626B\u63CF");return}if(e.length===0){n.debug("\u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u8DF3\u8FC7\u626B\u63CF");return}const t=await g(e.map(s=>({agentId:s.agentId,pid:s.pid,workspacePath:s.workspacePath,command:s.command})));if(this.stopped){n.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u4E2D\u65AD\u626B\u63CF");return}const a=await w(e.filter(s=>s.pid).map(s=>({agentId:s.agentId,pid:s.pid})));if(this.stopped){n.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u4E2D\u65AD\u626B\u63CF");return}for(const s of t){if(this.stopped)break;await this.handleOrphanDetected(s.agentId,s.process.pid)}for(const[s,i]of a){if(this.stopped)break;i.status!=="healthy"&&i.alive&&await this.handleHealthIssue(s,i)}this.stopped||await this.cleanupDeadSessions(e,a)}catch(e){n.warn("\u626B\u63CF\u5B64\u513F\u8FDB\u7A0B\u5931\u8D25:",e)}}async handleOrphanDetected(e,t){const a={type:"orphan_detected",agentId:e,pid:t,message:`\u68C0\u6D4B\u5230\u5B64\u513F\u8FDB\u7A0B: agentId=${e}, pid=${t}`,timestamp:new Date};if(this.emit(a),n.warn(`\u68C0\u6D4B\u5230\u5B64\u513F\u8FDB\u7A0B: agentId=${e}, pid=${t}`),await this.checkAgentExistsOnServer(e)===!1){n.info(`agent ${e} \u5DF2\u4ECE\u670D\u52A1\u7AEF\u5220\u9664\uFF0C\u81EA\u52A8\u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B pid=${t}`),await this.autoCleanOrphan(e,t);return}switch(r){case"auto":l()?await this.autoCleanOrphan(e,t):(n.warn("auto \u6A21\u5F0F\u672A\u542F\u7528\u7834\u574F\u6027\u6E05\u7406\u5F00\u5173\uFF0C\u6539\u4E3A\u544A\u8B66\u5E76\u4FDD\u7559\u5B64\u513F\u8FDB\u7A0B"),await this.reportToScheduler(e,"orphan_detected",{pid:t}));break;case"alert":await this.reportToScheduler(e,"orphan_detected",{pid:t});break;case"manual":n.info("manual \u6A21\u5F0F\uFF0C\u4EC5\u8BB0\u5F55\u65E5\u5FD7\uFF0C\u4E0D\u81EA\u52A8\u5904\u7406");break}}async handleHealthIssue(e,t){const a=t.status==="unresponsive"?"process_unresponsive":t.status==="high_cpu"?"process_high_cpu":"process_high_memory",s={type:a,agentId:e,pid:t.pid,message:`\u8FDB\u7A0B\u5065\u5EB7\u5F02\u5E38: ${t.status}, CPU=${t.cpu}%, Memory=${t.memoryMB}MB`,timestamp:new Date,details:{cpu:t.cpu,memoryMB:t.memoryMB}};this.emit(s),await this.reportToScheduler(e,a,{pid:t.pid,cpu:t.cpu,memoryMB:t.memoryMB}),r==="auto"&&t.status!=="healthy"&&l()?(n.warn(`auto \u6A21\u5F0F: \u7EC8\u6B62\u5F02\u5E38\u8FDB\u7A0B ${t.pid} (${t.status})`),await this.autoCleanOrphan(e,t.pid)):r==="auto"&&t.status!=="healthy"&&n.warn(`auto \u6A21\u5F0F\u672A\u542F\u7528\u7834\u574F\u6027\u6E05\u7406\u5F00\u5173\uFF0C\u4FDD\u7559\u5F02\u5E38\u8FDB\u7A0B ${t.pid} (${t.status})`)}async autoCleanOrphan(e,t){n.info(`\u81EA\u52A8\u6E05\u7406\u5B64\u513F\u8FDB\u7A0B\uFF1AagentId=${e}, pid=${t}`);const a=await S(t),s=await $(t,5e3);if(a.terminated>0&&s){const i={type:"orphan_cleaned",agentId:e,pid:t,message:`\u81EA\u52A8\u6E05\u7406\u6210\u529F\uFF1AagentId=${e}, pid=${t}, \u7EC8\u6B62\u4E86 ${a.terminated} \u4E2A\u8FDB\u7A0B`,timestamp:new Date,details:{terminated:a.terminated,failed:a.failed}};this.emit(i),await this.reportToScheduler(e,"orphan_cleaned",{pid:t,terminated:a.terminated,failed:a.failed})}else n.warn(`\u81EA\u52A8\u6E05\u7406\u5931\u8D25\uFF1AagentId=${e}, pid=${t}, terminated=${a.terminated}, exited=${s}`),await this.reportToScheduler(e,"orphan_clean_failed",{pid:t,terminated:a.terminated,failed:a.failed})}async cleanupDeadSessions(e,t){const a=e.filter(s=>s.pid?!t.get(s.agentId)?.alive:!1);if(a.length>0){n.info(`\u6E05\u7406 ${a.length} \u4E2A\u5DF2\u6B7B\u4EA1\u4F1A\u8BDD\u8BB0\u5F55`);const s=e.filter(i=>t.get(i.agentId)?.alive!==!1);await v(s)}}async checkAgentExistsOnServer(e){if(this.stopped)return null;try{const t=c(o)||c();if(!t)return n.debug("\u7F3A\u5C11 runtimeAccessToken\uFF0C\u65E0\u6CD5\u67E5\u8BE2 agent \u5B58\u5728\u6027"),null;const a=await fetch(`${o}/api/runtime/callback/agent-exists`,{method:"POST",headers:{"Content-Type":"application/json","X-Runtime-Token":t},body:JSON.stringify({agentId:e}),signal:AbortSignal.timeout(5e3)});return a.ok?(await a.json()).exists===!0:(n.debug(`\u67E5\u8BE2 agent \u5B58\u5728\u6027\u5931\u8D25: ${a.status}`),null)}catch(t){return n.debug("\u67E5\u8BE2 agent \u5B58\u5728\u6027\u5F02\u5E38:",t),null}}async reportToScheduler(e,t,a){if(this.stopped){n.debug(`\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u8DF3\u8FC7\u4E0A\u62A5: ${t}`);return}try{const s=c(o)||c();if(!s){n.debug(`\u7F3A\u5C11 runtimeAccessToken\uFF0C\u8DF3\u8FC7\u4E0A\u62A5: ${t}`);return}const i=await fetch(`${o}/api/runtime/callback/orphan-event`,{method:"POST",headers:{"Content-Type":"application/json","X-Runtime-Token":s},body:JSON.stringify({agentId:e,eventType:t,details:a,timestamp:new Date().toISOString()})});i.ok||(i.status===404?n.debug(`\u4E0A\u62A5\u5931\u8D25: \u8C03\u5EA6\u4E2D\u5FC3\u4E0D\u53EF\u8FBE (404)\uFF0C\u4E8B\u4EF6: ${t}`):n.warn(`\u4E0A\u62A5\u5931\u8D25: ${i.status}`))}catch(s){n.debug("\u4E0A\u62A5\u5230\u8C03\u5EA6\u4E2D\u5FC3\u5931\u8D25:",s)}}onEvent(e){this.eventListeners.push(e)}offEvent(e){const t=this.eventListeners.indexOf(e);t>-1&&this.eventListeners.splice(t,1)}emit(e){for(const t of this.eventListeners)try{t(e)}catch(a){n.warn("\u4E8B\u4EF6\u76D1\u542C\u5668\u6267\u884C\u5931\u8D25:",a)}}getStatus(){return{running:this.intervalId!==null,lastScanTime:this.lastScanTime,mode:r}}}let p=null;function h(){return p||(p=new O),p}async function E(){await h().start()}function M(){h().stop()}export{O as OrphanMonitor,h as getOrphanMonitor,E as startOrphanMonitor,M as stopOrphanMonitor};
1
+ import{ORPHAN_SCAN_INTERVAL as l,ORPHAN_AUTO_CLEAN_MODE as r,ORPHAN_SCAN_ENABLED as f,schedulerBaseUrl as c}from"../config.js";import{createLogger as g}from"../utils/logger.js";import{captureProcessSnapshot as w,detectOrphanProcesses as S,checkAllSessionsHealth as y,terminateProcessTree as $,waitForProcessExit as v}from"./process-detector.js";import{getRuntimeAccessToken as p}from"./runtime-binding.js";import{shouldAutoCleanOrphanProcesses as h}from"./runtime-lifecycle-policy.js";import{loadPersistedSessions as O,savePersistedSessions as b}from"./terminal-persistence.js";const s=g("orphan-monitor");class A{constructor(){this.intervalId=null,this.lastScanTime=null,this.eventListeners=[],this.stopped=!1}async start(){if(!f){s.info("\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5DF2\u7981\u7528 (AWS_ORPHAN_SCAN_ENABLED=false)");return}this.stopped=!1,s.info(`\u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\uFF0C\u626B\u63CF\u95F4\u9694: ${l}ms, \u81EA\u52A8\u6E05\u7406\u6A21\u5F0F: ${r}`),await this.scan(),this.intervalId=setInterval(async()=>{await this.scan()},l),s.info("\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5DF2\u542F\u52A8")}stop(){this.stopped=!0,this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,s.info("\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5DF2\u505C\u6B62"))}async scan(){if(this.stopped){s.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u8DF3\u8FC7\u626B\u63CF");return}this.lastScanTime=new Date,s.debug("\u5F00\u59CB\u626B\u63CF\u5B64\u513F\u8FDB\u7A0B...");try{const e=await O();if(this.stopped){s.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u4E2D\u65AD\u626B\u63CF");return}if(e.length===0){s.debug("\u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u8DF3\u8FC7\u626B\u63CF");return}let t;try{t=await w()}catch(a){s.debug("\u91C7\u96C6\u8FDB\u7A0B\u5FEB\u7167\u5931\u8D25\uFF0C\u672C\u8F6E\u56DE\u9000\u9010\u8FDB\u7A0B\u68C0\u6D4B:",a)}if(this.stopped){s.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u4E2D\u65AD\u626B\u63CF");return}const n=await S(e.map(a=>({agentId:a.agentId,pid:a.pid,workspacePath:a.workspacePath,command:a.command})),t);if(this.stopped){s.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u4E2D\u65AD\u626B\u63CF");return}const i=await y(e.filter(a=>a.pid).map(a=>({agentId:a.agentId,pid:a.pid})),t);if(this.stopped){s.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u4E2D\u65AD\u626B\u63CF");return}for(const a of n){if(this.stopped)break;await this.handleOrphanDetected(a.agentId,a.process.pid)}for(const[a,o]of i){if(this.stopped)break;o.status!=="healthy"&&o.alive&&await this.handleHealthIssue(a,o)}this.stopped||await this.cleanupDeadSessions(e,i)}catch(e){s.warn("\u626B\u63CF\u5B64\u513F\u8FDB\u7A0B\u5931\u8D25:",e)}}async handleOrphanDetected(e,t){const n={type:"orphan_detected",agentId:e,pid:t,message:`\u68C0\u6D4B\u5230\u5B64\u513F\u8FDB\u7A0B: agentId=${e}, pid=${t}`,timestamp:new Date};if(this.emit(n),s.warn(`\u68C0\u6D4B\u5230\u5B64\u513F\u8FDB\u7A0B: agentId=${e}, pid=${t}`),await this.checkAgentExistsOnServer(e)===!1){s.info(`agent ${e} \u5DF2\u4ECE\u670D\u52A1\u7AEF\u5220\u9664\uFF0C\u81EA\u52A8\u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B pid=${t}`),await this.autoCleanOrphan(e,t);return}switch(r){case"auto":h()?await this.autoCleanOrphan(e,t):(s.warn("auto \u6A21\u5F0F\u672A\u542F\u7528\u7834\u574F\u6027\u6E05\u7406\u5F00\u5173\uFF0C\u6539\u4E3A\u544A\u8B66\u5E76\u4FDD\u7559\u5B64\u513F\u8FDB\u7A0B"),await this.reportToScheduler(e,"orphan_detected",{pid:t}));break;case"alert":await this.reportToScheduler(e,"orphan_detected",{pid:t});break;case"manual":s.info("manual \u6A21\u5F0F\uFF0C\u4EC5\u8BB0\u5F55\u65E5\u5FD7\uFF0C\u4E0D\u81EA\u52A8\u5904\u7406");break}}async handleHealthIssue(e,t){const n=t.status==="unresponsive"?"process_unresponsive":t.status==="high_cpu"?"process_high_cpu":"process_high_memory",i={type:n,agentId:e,pid:t.pid,message:`\u8FDB\u7A0B\u5065\u5EB7\u5F02\u5E38: ${t.status}, CPU=${t.cpu}%, Memory=${t.memoryMB}MB`,timestamp:new Date,details:{cpu:t.cpu,memoryMB:t.memoryMB}};this.emit(i),await this.reportToScheduler(e,n,{pid:t.pid,cpu:t.cpu,memoryMB:t.memoryMB}),r==="auto"&&t.status!=="healthy"&&h()?(s.warn(`auto \u6A21\u5F0F: \u7EC8\u6B62\u5F02\u5E38\u8FDB\u7A0B ${t.pid} (${t.status})`),await this.autoCleanOrphan(e,t.pid)):r==="auto"&&t.status!=="healthy"&&s.warn(`auto \u6A21\u5F0F\u672A\u542F\u7528\u7834\u574F\u6027\u6E05\u7406\u5F00\u5173\uFF0C\u4FDD\u7559\u5F02\u5E38\u8FDB\u7A0B ${t.pid} (${t.status})`)}async autoCleanOrphan(e,t){s.info(`\u81EA\u52A8\u6E05\u7406\u5B64\u513F\u8FDB\u7A0B\uFF1AagentId=${e}, pid=${t}`);const n=await $(t),i=await v(t,5e3);if(n.terminated>0&&i){const a={type:"orphan_cleaned",agentId:e,pid:t,message:`\u81EA\u52A8\u6E05\u7406\u6210\u529F\uFF1AagentId=${e}, pid=${t}, \u7EC8\u6B62\u4E86 ${n.terminated} \u4E2A\u8FDB\u7A0B`,timestamp:new Date,details:{terminated:n.terminated,failed:n.failed}};this.emit(a),await this.reportToScheduler(e,"orphan_cleaned",{pid:t,terminated:n.terminated,failed:n.failed})}else s.warn(`\u81EA\u52A8\u6E05\u7406\u5931\u8D25\uFF1AagentId=${e}, pid=${t}, terminated=${n.terminated}, exited=${i}`),await this.reportToScheduler(e,"orphan_clean_failed",{pid:t,terminated:n.terminated,failed:n.failed})}async cleanupDeadSessions(e,t){const n=e.filter(i=>i.pid?!t.get(i.agentId)?.alive:!1);if(n.length>0){s.info(`\u6E05\u7406 ${n.length} \u4E2A\u5DF2\u6B7B\u4EA1\u4F1A\u8BDD\u8BB0\u5F55`);const i=e.filter(a=>t.get(a.agentId)?.alive!==!1);await b(i)}}async checkAgentExistsOnServer(e){if(this.stopped)return null;try{const t=p(c)||p();if(!t)return s.debug("\u7F3A\u5C11 runtimeAccessToken\uFF0C\u65E0\u6CD5\u67E5\u8BE2 agent \u5B58\u5728\u6027"),null;const n=await fetch(`${c}/api/runtime/callback/agent-exists`,{method:"POST",headers:{"Content-Type":"application/json","X-Runtime-Token":t},body:JSON.stringify({agentId:e}),signal:AbortSignal.timeout(5e3)});return n.ok?(await n.json()).exists===!0:(s.debug(`\u67E5\u8BE2 agent \u5B58\u5728\u6027\u5931\u8D25: ${n.status}`),null)}catch(t){return s.debug("\u67E5\u8BE2 agent \u5B58\u5728\u6027\u5F02\u5E38:",t),null}}async reportToScheduler(e,t,n){if(this.stopped){s.debug(`\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u8DF3\u8FC7\u4E0A\u62A5: ${t}`);return}try{const i=p(c)||p();if(!i){s.debug(`\u7F3A\u5C11 runtimeAccessToken\uFF0C\u8DF3\u8FC7\u4E0A\u62A5: ${t}`);return}const a=await fetch(`${c}/api/runtime/callback/orphan-event`,{method:"POST",headers:{"Content-Type":"application/json","X-Runtime-Token":i},body:JSON.stringify({agentId:e,eventType:t,details:n,timestamp:new Date().toISOString()})});a.ok||(a.status===404?s.debug(`\u4E0A\u62A5\u5931\u8D25: \u8C03\u5EA6\u4E2D\u5FC3\u4E0D\u53EF\u8FBE (404)\uFF0C\u4E8B\u4EF6: ${t}`):s.warn(`\u4E0A\u62A5\u5931\u8D25: ${a.status}`))}catch(i){s.debug("\u4E0A\u62A5\u5230\u8C03\u5EA6\u4E2D\u5FC3\u5931\u8D25:",i)}}onEvent(e){this.eventListeners.push(e)}offEvent(e){const t=this.eventListeners.indexOf(e);t>-1&&this.eventListeners.splice(t,1)}emit(e){for(const t of this.eventListeners)try{t(e)}catch(n){s.warn("\u4E8B\u4EF6\u76D1\u542C\u5668\u6267\u884C\u5931\u8D25:",n)}}getStatus(){return{running:this.intervalId!==null,lastScanTime:this.lastScanTime,mode:r}}}let u=null;function m(){return u||(u=new A),u}async function M(){await m().start()}function N(){m().stop()}export{A as OrphanMonitor,m as getOrphanMonitor,M as startOrphanMonitor,N as stopOrphanMonitor};
2
2
 
@@ -1,5 +1,9 @@
1
1
 
2
2
 
3
- export declare function setPanelEnvVars(env: unknown): void;
3
+ export declare function setPanelEnvVars(agentId: string | undefined, env: unknown): void;
4
4
 
5
- export declare function getPanelEnvVars(): Record<string, string>;
5
+ export declare function getPanelEnvVars(agentId?: string): Record<string, string>;
6
+
7
+ export declare function clearPanelEnvVars(agentId: string | undefined): void;
8
+
9
+ export declare function resetPanelEnvVars(): void;
@@ -1,2 +1,2 @@
1
- let o={};function c(n){const t={};if(n&&typeof n=="object")for(const[a,e]of Object.entries(n)){const r=a.trim();!r||e===void 0||e===null||(t[r]=String(e))}o=t}function i(){return o}export{i as getPanelEnvVars,c as setPanelEnvVars};
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};
2
2