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.
- package/CHANGELOG.md +324 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts +31 -3
- package/dist/adapter/AcodeSdkAdapter.js +4 -9
- package/dist/adapter/ClaudeSdkAdapter.d.ts +2 -0
- package/dist/adapter/ClaudeSdkAdapter.js +3 -3
- package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
- package/dist/adapter/CodexSdkAdapter.js +3 -3
- package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/OpencodeSdkAdapter.js +3 -3
- package/dist/adapter/prompts.d.ts +1 -1
- package/dist/adapter/prompts.js +1 -1
- package/dist/adapter/types.d.ts +41 -4
- package/dist/adapter/types.js +1 -1
- package/dist/browser/frame-encode.d.ts +25 -0
- package/dist/browser/frame-encode.js +2 -0
- package/dist/browser/screencast-differ.d.ts +2 -3
- package/dist/browser/screencast-differ.js +1 -1
- package/dist/browser/screencast-manager.js +1 -1
- package/dist/browser/types.d.ts +5 -1
- package/dist/browser/types.js +1 -1
- package/dist/desktop/desktop-mcp-client.js +2 -2
- package/dist/routes/background-tasks.js +3 -3
- package/dist/routes/capabilities.js +1 -1
- package/dist/routes/dashboard.d.ts +2 -0
- package/dist/routes/dashboard.js +4 -4
- package/dist/routes/git.js +22 -22
- package/dist/routes/instance.js +1 -1
- package/dist/routes/launch.js +10 -10
- package/dist/routes/mcp-extra.js +2 -2
- package/dist/routes/mcp.d.ts +4 -0
- package/dist/routes/mcp.js +1 -1
- package/dist/routes/plugins.js +1 -1
- package/dist/routes/pty.d.ts +11 -3
- package/dist/routes/pty.js +3 -3
- package/dist/routes/runtime-binding.js +1 -1
- package/dist/routes/sessions.js +1 -1
- package/dist/routes/skills.js +1 -1
- package/dist/routes/sub-agents.js +8 -8
- package/dist/routes/terminal.d.ts +16 -2
- package/dist/routes/terminal.js +34 -36
- package/dist/services/agent-process-manager.js +1 -1
- package/dist/services/agent-pty-manager.js +4 -4
- package/dist/services/aws-client-agent-mcp.js +2 -2
- package/dist/services/capability-config.d.ts +8 -0
- package/dist/services/capability-config.js +2 -2
- package/dist/services/desktop-mcp-manager.d.ts +3 -1
- package/dist/services/desktop-mcp-manager.js +1 -1
- package/dist/services/instance-ai-config-service.js +1 -1
- package/dist/services/instance-features.d.ts +10 -0
- package/dist/services/instance-features.js +1 -1
- package/dist/services/instance-init-service.js +1 -1
- package/dist/services/launch-manager.d.ts +9 -1
- package/dist/services/launch-manager.js +6 -6
- package/dist/services/launch-metrics.d.ts +1 -1
- package/dist/services/launch-metrics.js +4 -3
- package/dist/services/mcp-deploy.d.ts +4 -0
- package/dist/services/mcp-env-injector.d.ts +12 -0
- package/dist/services/mcp-env-injector.js +2 -0
- package/dist/services/mcp-launch-binding-queue.d.ts +8 -0
- package/dist/services/mcp-launch-binding-queue.js +1 -1
- package/dist/services/orphan-monitor.js +1 -1
- package/dist/services/panel-env.d.ts +6 -2
- package/dist/services/panel-env.js +1 -1
- package/dist/services/plugin-manager.js +9 -9
- package/dist/services/process-detector.d.ts +23 -3
- package/dist/services/process-detector.js +13 -13
- package/dist/services/runtime-resources-snapshot.d.ts +3 -0
- package/dist/services/runtime-resources-snapshot.js +3 -0
- package/dist/services/session-output.d.ts +13 -0
- package/dist/services/session-output.js +4 -4
- package/dist/services/tunnel-client.js +1 -1
- package/dist/services/workspace-files.js +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/utils/env-safety.d.ts +15 -0
- package/dist/utils/env-safety.js +2 -0
- package/dist/utils/lifecycle-log.d.ts +2 -0
- package/dist/utils/lifecycle-log.js +3 -0
- package/dist/utils/mcp-utils.js +1 -1
- package/package/acode/dist/background-command-manager.js +4 -4
- package/package/acode/dist/built-in-file-tools.d.ts +13 -0
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/builtins/shellCommandPreparation.d.ts +2 -0
- package/package/acode/dist/builtins/shellCommandPreparation.js +2 -2
- package/package/acode/dist/compaction.d.ts +10 -0
- package/package/acode/dist/compaction.js +6 -6
- package/package/acode/dist/context-overflow.js +1 -1
- package/package/acode/dist/index.d.ts +1 -0
- package/package/acode/dist/index.js +1 -1
- package/package/acode/dist/mcpToolNames.d.ts +4 -0
- package/package/acode/dist/mcpToolNames.js +1 -1
- package/package/acode/dist/runtime-environment.d.ts +2 -0
- package/package/acode/dist/runtime-environment.js +3 -2
- package/package/acode/dist/runtime.d.ts +68 -8
- package/package/acode/dist/runtime.js +28 -27
- package/package/acode/dist/sub-agent-manager.js +1 -1
- package/package/acode/dist/tool-allocation.js +1 -1
- package/package/acode/dist/tool-group-manager.d.ts +12 -0
- package/package/acode/dist/tool-group-manager.js +8 -4
- package/package/acode/dist/types.d.ts +8 -0
- package/package/acode/package.json +1 -1
- package/package/aws-client-agent-mcp/README.md +1 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +22 -8
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +10 -0
- package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -1
- package/package/aws-client-agent-mcp/dist/logger.js +2 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +19 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.js +18 -18
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +15 -4
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +79 -29
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/memory-store.js +3 -3
- package/package/aws-client-agent-mcp/dist/message-buffer.js +1 -1
- package/package/aws-client-agent-mcp/dist/office/office-workspace.d.ts +15 -0
- package/package/aws-client-agent-mcp/dist/office/office-workspace.js +1 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.js +1 -1
- package/package/aws-client-agent-mcp/dist/tool-groups.d.ts +4 -0
- package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
- package/package/aws-client-agent-mcp/dist/types.d.ts +52 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
- package/package/aws-client-agent-mcp/package.json +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{access as
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
4
|
-
`});
|
|
5
|
-
`);const c=this.runs.get(e);c&&
|
|
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
|
|
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&&
|
|
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,4 +1,5 @@
|
|
|
1
|
-
import{exec as
|
|
2
|
-
`)){const
|
|
3
|
-
`).filter(
|
|
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
|
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
|