aws-runtime-bridge 1.9.137 → 1.9.139

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 (96) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +2 -0
  2. package/dist/adapter/AcodeSdkAdapter.js +2 -2
  3. package/dist/adapter/ClaudeSdkAdapter.js +3 -3
  4. package/dist/adapter/CodexSdkAdapter.js +3 -3
  5. package/dist/adapter/OpencodeSdkAdapter.js +3 -3
  6. package/dist/browser/browser-pool.js +1 -1
  7. package/dist/browser/built-in-browser-tools.d.ts +1 -2
  8. package/dist/browser/built-in-browser-tools.js +1 -1
  9. package/dist/browser/ws-server.js +1 -1
  10. package/dist/config.js +2 -2
  11. package/dist/index.js +1 -1
  12. package/dist/middleware/auth.js +1 -1
  13. package/dist/remote-desktop/computer-control.d.ts +1 -1
  14. package/dist/remote-desktop/index.d.ts +1 -1
  15. package/dist/remote-desktop/index.js +2 -2
  16. package/dist/remote-desktop/session-manager.d.ts +2 -2
  17. package/dist/remote-desktop/session-manager.js +1 -1
  18. package/dist/remote-desktop/system-backend.js +3 -3
  19. package/dist/routes/ai-sources.js +1 -1
  20. package/dist/routes/background-tasks.js +1 -1
  21. package/dist/routes/browser-listeners.js +1 -1
  22. package/dist/routes/capabilities.js +1 -1
  23. package/dist/routes/dashboard.js +1 -1
  24. package/dist/routes/file-change-diff.js +3 -3
  25. package/dist/routes/file-diff-rollback.js +1 -1
  26. package/dist/routes/file-snapshot.js +1 -1
  27. package/dist/routes/git.js +1 -1
  28. package/dist/routes/instance.js +1 -1
  29. package/dist/routes/launch.js +1 -1
  30. package/dist/routes/mcp.js +1 -1
  31. package/dist/routes/plugins.js +1 -1
  32. package/dist/routes/properties.js +1 -1
  33. package/dist/routes/pty.d.ts +1 -1
  34. package/dist/routes/pty.js +1 -1
  35. package/dist/routes/runtime-binding.js +1 -1
  36. package/dist/routes/skills.js +1 -1
  37. package/dist/routes/sub-agents.js +1 -1
  38. package/dist/routes/task-context.js +1 -1
  39. package/dist/routes/terminal.js +5 -5
  40. package/dist/routes/yml.js +1 -1
  41. package/dist/services/access-control.js +1 -1
  42. package/dist/services/acode-bg-manager.js +1 -1
  43. package/dist/services/agent-capability-sync.js +1 -1
  44. package/dist/services/agent-process-manager.d.ts +1 -1
  45. package/dist/services/agent-process-manager.js +1 -1
  46. package/dist/services/ai-config-service.js +1 -1
  47. package/dist/services/ai-source-apply.d.ts +1 -1
  48. package/dist/services/auto-register.js +1 -1
  49. package/dist/services/bridge-package-publish-hooks.js +1 -1
  50. package/dist/services/browser-session-manager.d.ts +3 -3
  51. package/dist/services/browser-session-manager.js +1 -1
  52. package/dist/services/cli-commands.js +2 -2
  53. package/dist/services/desktop-mcp-manager.js +1 -1
  54. package/dist/services/fileSnapshotStore.js +1 -1
  55. package/dist/services/instance-ai-config-service.js +1 -1
  56. package/dist/services/instance-init-service.js +1 -1
  57. package/dist/services/jdk-scanner.js +1 -1
  58. package/dist/services/launch-manager.js +1 -1
  59. package/dist/services/lifecycle-state.js +2 -2
  60. package/dist/services/mcp-deploy.js +1 -1
  61. package/dist/services/orphan-monitor.js +1 -1
  62. package/dist/services/plugin-manager.d.ts +26 -4
  63. package/dist/services/plugin-manager.js +15 -9
  64. package/dist/services/process-detail.js +2 -2
  65. package/dist/services/process-detector.js +10 -10
  66. package/dist/services/process-registry.js +1 -1
  67. package/dist/services/process-top.js +2 -2
  68. package/dist/services/runtime-binding.js +4 -4
  69. package/dist/services/sdk-tool-file-change-recorder.js +1 -1
  70. package/dist/services/skill-manager.js +2 -2
  71. package/dist/services/startup-config-wizard.js +6 -6
  72. package/dist/services/system-metrics.js +1 -1
  73. package/dist/services/tunnel-client.js +1 -1
  74. package/dist/services/update-notifier.js +2 -2
  75. package/dist/services/windows-service-manager.js +1 -1
  76. package/dist/services/workspace-files.js +1 -1
  77. package/dist/services/workspaceTaskChangeWatcher.js +3 -3
  78. package/dist/utils/file-utils.js +2 -2
  79. package/dist/utils/instance-ai-config-debug-logger.js +1 -1
  80. package/dist/utils/mcp-utils.js +1 -1
  81. package/dist/utils/yaml-utils.js +1 -1
  82. package/package/acode/dist/plugin-tools.js +3 -8
  83. package/package/acode/dist/plugin-types.d.ts +10 -0
  84. package/package/acode/dist/runtime.d.ts +2 -0
  85. package/package/acode/dist/runtime.js +17 -17
  86. package/package/acode/dist/types.d.ts +2 -0
  87. package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
  88. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +0 -1
  89. package/package/aws-client-agent-mcp/dist/mcp-server.js +10 -10
  90. package/package/aws-client-agent-mcp/dist/memory-tools.js +6 -6
  91. package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts +1 -1
  92. package/package/aws-client-agent-mcp/dist/server-memory-store.js +1 -1
  93. package/package/aws-client-agent-mcp/dist/status-reporter.d.ts +2 -0
  94. package/package/aws-client-agent-mcp/dist/status-reporter.js +3 -2
  95. package/package/aws-client-agent-mcp/dist/types.d.ts +1 -0
  96. package/package.json +1 -1
@@ -1,6 +1,13 @@
1
1
 
2
2
  import { type ACodeCommandSpec, type ACodePluginBridge, type PluginCatalogSnapshot, type PluginInvokeContext, type PluginManageRequest, type PluginManageResult, type PluginSummary, type PluginToolInvocationResult, type PluginToolSchema, type JsonObject } from "@agentswork/acode";
3
3
  import { type PluginEventMessage, type PluginEventPriority } from "./plugin-event-buffer.js";
4
+
5
+ export declare const BUILTIN_PLUGIN_NAME = "plugin-manager";
6
+ export declare const BUILTIN_PLUGIN_DESCRIPTION = "\u7CFB\u7EDF\u5185\u7F6E\uFF1A\u7BA1\u7406\u63D2\u4EF6\u7684\u751F\u547D\u5468\u671F\uFF08\u5B89\u88C5/\u5378\u8F7D/\u542F\u505C/\u91CD\u8F7D\uFF09\uFF1B\u5F00\u53D1\u63D2\u4EF6\u7528\u5185\u7F6E /create-plugin \u547D\u4EE4";
7
+
8
+ export declare const BUILTIN_PLUGIN_MANAGE_DESC = "\u300C\u63D2\u4EF6\u7BA1\u7406\u63D2\u4EF6\u300D\u7684\u751F\u547D\u5468\u671F\u5DE5\u5177\uFF1A\u7BA1\u7406\u63D2\u4EF6\uFF08\u5B89\u88C5/\u5378\u8F7D/\u91CD\u8F7D/\u542F\u505C/\u5217\u8868\uFF09\u3002\u4EC5\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u5B89\u88C5\u3001\u79FB\u9664\u6216\u4FEE\u590D\u63D2\u4EF6\u65F6\u4F7F\u7528\u3002\n- action=list\uFF1A\u5217\u51FA\u5DF2\u5B89\u88C5\u63D2\u4EF6\uFF08\u72B6\u6001\u3001\u76D1\u542C\u5668\u5065\u5EB7\u3001\u5DE5\u5177\u6570\uFF09\u3002\n- action=install\uFF1Asource \u4E3A\u63D2\u4EF6\u6765\u6E90\uFF0C\u5F53\u524D\u652F\u6301 \"local:<\u4EFB\u610F\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>\"\uFF08\u4E0D\u505A\u76EE\u5F55\u4F4D\u7F6E\u9650\u5236\uFF09\uFF1Bconfig \u4F20\u63D2\u4EF6 manifest \u91CC userConfig \u58F0\u660E\u7684\u914D\u7F6E\u503C\u3002\u5B89\u88C5\u65F6\u4F1A\u5148\u628A\u8BE5\u76EE\u5F55\u79FB\u52A8\u5230\u672C agent \u52A0\u8F7D\u63D2\u4EF6\u7684\u4F4D\u7F6E\uFF0C\u518D\u52A0\u8F7D\u79FB\u52A8\u540E\u7684\u526F\u672C\uFF08\u79FB\u52A8\u540E\u6E90\u76EE\u5F55\u4E0D\u518D\u4FDD\u7559\uFF09\uFF0C\u5B89\u88C5\u540E\u7ACB\u5373\u751F\u6548\uFF1A\u4E0B\u4E00\u6B21 poll_message \u7684 pluginCatalog \u5373\u53EF\u89C1\u3002\n- action=reload\uFF1A\u91CD\u8F7D\u6307\u5B9A\u63D2\u4EF6\uFF08\u6539\u8FC7\u63D2\u4EF6\u6587\u4EF6\u540E\u4F7F\u7528\uFF09\uFF0C\u539F\u5B50\u6362\u88C5\uFF0C\u76D1\u542C\u5668\u91CD\u542F\u3002\n- action=enable / disable\uFF1A\u505C\u7528/\u542F\u7528\uFF08disable \u4FDD\u7559\u5B89\u88C5\u4E0E\u914D\u7F6E\uFF0C\u4EC5\u505C\u6B62\u76D1\u542C\u4E0E\u5DE5\u5177\u8C03\u7528\uFF09\u3002\n- action=uninstall\uFF1A\u5378\u8F7D\u5E76\u5220\u9664\u63D2\u4EF6\u76EE\u5F55\uFF08\u4E0D\u53EF\u9006\uFF0C\u9700\u7528\u6237\u660E\u786E\u8981\u6C42\uFF09\u3002";
9
+
10
+ export declare function getBuiltinCommandDir(): string;
4
11
  export interface PluginUserConfigField {
5
12
  key: string;
6
13
  type?: "string" | "number" | "boolean";
@@ -78,6 +85,8 @@ export declare class PluginManager {
78
85
  private agents;
79
86
  private readonly rootDir;
80
87
  private readonly runtimeRootDir;
88
+
89
+ private moduleNonce;
81
90
  constructor(options?: PluginManagerOptions);
82
91
  forAgent(agentId: string): ACodePluginBridge;
83
92
 
@@ -89,12 +98,15 @@ export declare class PluginManager {
89
98
 
90
99
  getPluginCommands(agentId: string): Promise<ACodeCommandSpec[]>;
91
100
  private parsePluginCommandDir;
101
+ private parseCommandDir;
92
102
  list(agentId: string): Promise<PluginSummary[]>;
93
103
 
94
104
  private deployedPluginVersion;
95
105
  getCatalog(agentId: string): Promise<PluginCatalogSnapshot>;
96
106
  getToolSchema(agentId: string, qualifiedName: string): Promise<PluginToolSchema | null>;
97
107
  invokeTool(agentId: string, pluginName: string, toolName: string, params: JsonObject, ctx?: PluginInvokeContext): Promise<PluginToolInvocationResult>;
108
+
109
+ private buildManageRequest;
98
110
  private executeHandler;
99
111
  private invokeProcessHandler;
100
112
  private invokeModuleHandler;
@@ -178,13 +190,27 @@ export declare class PluginManager {
178
190
  ok: boolean;
179
191
  error?: string;
180
192
  }>;
193
+
194
+ private bumpCatalogRevision;
181
195
  private agentState;
182
196
 
183
197
  private hydrate;
198
+ private doHydrate;
184
199
  private installedFile;
185
200
  private persistInstalled;
201
+
202
+ private sensitiveKeysOf;
203
+
204
+ private stripSensitiveValues;
205
+ private secretsFile;
206
+
207
+ private readSecrets;
208
+
209
+ private persistSecrets;
186
210
  private readJsonFile;
187
211
  private loadManifestOnly;
212
+
213
+ private validateUserConfigValues;
188
214
  private loadPluginFromDir;
189
215
 
190
216
  private ensureListenersRunning;
@@ -226,10 +252,6 @@ export declare class PluginManager {
226
252
  error?: string;
227
253
  }>;
228
254
  }
229
- export declare function splitQualifiedName(qualifiedName: string): {
230
- plugin: string;
231
- tool: string;
232
- } | null;
233
255
 
234
256
  export declare function isValidPluginName(name: unknown): name is string;
235
257
  export declare function validateManifest(manifest: Record<string, unknown>): string | null;
@@ -1,10 +1,16 @@
1
- import{spawn as C}from"node:child_process";import{cpSync as F,existsSync as S,lstatSync as X,mkdirSync as L,readFileSync as E,readdirSync as H,renameSync as V,rmSync as v,symlinkSync as Q,writeFileSync as B}from"node:fs";import{dirname as Z,join as g,resolve as R,sep as ee}from"node:path";import{pathToFileURL as te}from"node:url";import{parseAcodeCommandMarkdown as ne}from"@agentswork/acode";import{getAcodePluginDataHome as K}from"../config.js";import{createLogger as re}from"../utils/logger.js";import{sanitizeAgentId as M,withFileLock as W}from"../utils/file-utils.js";import{isCapabilityEnabled as se,getAgentPluginSources as ie}from"./instance-features.js";import{setDeployedDefaultsProvider as oe,reconcileDefaultsFromDeployed as ae}from"./capability-config.js";import{downloadPluginZip as le,sanitizeArchiveFileName as ue}from"../utils/file-utils.js";import{PluginEventBuffer as ce}from"./plugin-event-buffer.js";import{extractPluginZip as j}from"./plugin-package.js";const d=re("plugin-manager"),de=200,_=256*1024,fe=4*1024,ge=6e4,J=6e4,pe=/^[a-zA-Z0-9_][a-zA-Z0-9_-]*$/,I=/^[a-z0-9][a-z0-9-]*$/,he=["system.","aws-","acode-"],me=new Set(["NODE_OPTIONS","NODE_PATH","NODE_EXTRA_CA_CERTS","NODE_REPL_HISTORY","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","PYTHONPATH","PYTHONSTARTUP","PYTHONHOME","PERL5LIB","PERL5OPT","RUBYOPT","RUBYLIB","BASH_ENV","ENV","SHELLOPTS","BASHOPTS","IFS","PS1","PS4","GIT_SSH","GIT_SSH_COMMAND","GIT_CONFIG","GIT_CONFIG_GLOBAL","PATH","HOME","USERPROFILE","SYSTEMROOT","COMSPEC","TEMP","TMP","LANG","TZ"]),ye=/^[A-Za-z_][A-Za-z0-9_]*$/,Se=process.platform==="win32"?"junction":"dir",we=/[^\x20-\x7E]/,$e=6e4,x=20,Pe=80;function P(l){return typeof l=="object"&&l!==null&&!Array.isArray(l)}function O(l,e){let t=l;for(const n of e.split(".")){if(!P(t))return;t=t[n]}return t}function A(l,e){return l.length<=e?l:`${l.slice(0,e)}\u2026(\u622A\u65AD,\u5171 ${l.length} \u5B57\u7B26)`}async function b(l,e=8,t=200){for(let n=0;;n++)try{v(l,{recursive:!0,force:!0});return}catch(r){if(n>=e-1)throw r;await new Promise(s=>setTimeout(s,t))}}function k(l,e){l.logs.push(`${new Date().toISOString()} ${e}`),l.logs.length>de&&l.logs.shift()}function q(l,e,t="params"){if(!P(l))return[];const n=[],r=l.type;if(typeof r=="string"&&!ve(r,e))return[`${t}: \u671F\u671B ${r}\uFF0C\u5B9E\u9645 ${De(e)}`];if(Array.isArray(l.enum)&&l.enum.length>0&&(l.enum.some(o=>JSON.stringify(o)===JSON.stringify(e))||n.push(`${t}: \u503C ${JSON.stringify(e)} \u4E0D\u5728\u679A\u4E3E ${JSON.stringify(l.enum)} \u5185`)),r==="object"&&P(e)){const s=P(l.properties)?l.properties:{},o=Array.isArray(l.required)?l.required:[];for(const i of o)(!(i in e)||e[i]===void 0)&&n.push(`${t}.${i}: \u5FC5\u586B\u53C2\u6570\u7F3A\u5931`);for(const[i,a]of Object.entries(s))i in e&&e[i]!==void 0&&n.push(...q(a,e[i],`${t}.${i}`));if(l.additionalProperties===!1)for(const i of Object.keys(e))i in s||n.push(`${t}.${i}: \u4E0D\u5141\u8BB8\u7684\u672A\u77E5\u53C2\u6570\uFF08schema additionalProperties=false\uFF09`)}return r==="array"&&Array.isArray(e)&&P(l.items)&&e.forEach((s,o)=>{n.push(...q(l.items,s,`${t}[${o}]`))}),n}function ve(l,e){switch(l){case"string":return typeof e=="string";case"number":return typeof e=="number"&&Number.isFinite(e);case"boolean":return typeof e=="boolean";case"object":return P(e);case"array":return Array.isArray(e);case"null":return e===null;default:return!0}}function De(l){return l===null?"null":Array.isArray(l)?"array":typeof l}class Ee{constructor(e={}){this.agents=new Map,this.templatePullInFlight=new Set,this.backgroundTemplatePulls=new Set,this.rootDir=e.rootDir??g(K(),"plugins"),this.runtimeRootDir=e.runtimeRootDir??g(K(),"plugins-runtime")}forAgent(e){return{listPlugins:()=>this.list(e),getCatalog:()=>this.getCatalog(e),getToolSchema:t=>this.getToolSchema(e,t),invokeTool:(t,n,r,s)=>this.invokeTool(e,t,n,r,s),manage:t=>this.manage(e,t),getCommandDirs:()=>this.getCommandDirs(e)}}setOnPluginsChanged(e){this.onPluginsChanged=e}notifyPluginsChanged(e){try{this.onPluginsChanged?.(e)}catch(t){d.warn("[agent:%s] onPluginsChanged \u56DE\u8C03\u5931\u8D25: %s",e,t instanceof Error?t.message:String(t))}}async getCommandDirs(e){return[...(await this.hydrate(e)).plugins.values()].filter(n=>n.enabled&&n.commandDir).map(n=>n.commandDir)}async getPluginCommands(e){const t=await this.hydrate(e),n=[];for(const r of t.plugins.values())!r.enabled||!r.commandDir||n.push(...this.parsePluginCommandDir(r));return n}parsePluginCommandDir(e){const t=[];try{for(const n of H(e.commandDir)){if(!n.endsWith(".md"))continue;const r=g(e.commandDir,n);try{t.push(ne(r,E(r,"utf8")))}catch(s){d.warn("[plugin:%s] \u547D\u4EE4\u89E3\u6790\u5931\u8D25 %s: %s",e.name,n,s instanceof Error?s.message:String(s))}}}catch{}return t}async list(e){const t=await this.hydrate(e),n=new Map;for(const r of t.plugins.values()){const s=this.toSummary(r);n.set(s.name,s)}for(const r of this.readSharedManifest()){const s=r.pluginName;if(!this.deployedPluginHealthy(s))continue;const i=n.get(s);if(i){String(i.source||"").startsWith("shared:")&&(i.enabled=this.effectiveSharedEnabled(e,r));continue}n.set(s,{name:s,version:this.deployedPluginVersion(s),status:"enabled",enabled:this.effectiveSharedEnabled(e,r),source:`shared:${r.fileName??`${s}.zip`}`,installedAt:new Date().toISOString(),toolCount:0,listeners:[]})}return[...n.values()].sort((r,s)=>r.name.localeCompare(s.name))}deployedPluginVersion(e){try{const t=JSON.parse(E(g(this.deployedPluginDir(e),"plugin.json"),"utf8"));return typeof t.version=="string"?t.version:void 0}catch{return}}async getCatalog(e){const t=await this.hydrate(e),n=[];for(const r of t.plugins.values()){if(!r.enabled||r.status==="error")continue;const s=r.tools.slice(0,x).map(o=>({name:o.name,description:A(o.title||o.description,Pe),requiredParams:this.requiredParamsOf(o)}));r.tools.length>x&&s.push({name:`(\u53E6\u6709 ${r.tools.length-x} \u4E2A\u5DE5\u5177\u672A\u5217\u51FA)`,description:'\u7528 function_call {action:"catalog"} \u67E5\u770B\u5168\u91CF',requiredParams:void 0}),n.push({plugin:r.name,version:r.version,description:r.description,status:r.status,tools:s})}return{revision:t.buffer.currentRevision,plugins:n}}async getToolSchema(e,t){const n=ke(t);if(!n)return null;const s=(await this.hydrate(e)).plugins.get(n.plugin);if(!s||!s.enabled)return null;const o=s.tools.find(i=>i.name===n.tool);return o?{plugin:s.name,name:o.name,title:o.title,description:o.description,inputSchema:o.inputSchema??{type:"object",properties:{}}}:null}async invokeTool(e,t,n,r,s){const o=await this.hydrate(e),i=o.plugins.get(t);if(!i)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\uFF08\u53EF\u7528\u63D2\u4EF6: ${[...o.plugins.keys()].join(", ")||"\u65E0"}\uFF09`};if(!i.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u5DF2\u505C\u7528\uFF0C\u53EF\u8BA9\u7528\u6237\u5728\u9762\u677F\u6216\u7528 plugin_manage enable \u542F\u7528`};const a=i.tools.find(u=>u.name===n);if(!a)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5DE5\u5177 ${n}\uFF08\u53EF\u7528: ${i.tools.map(u=>u.name).join(", ")||"\u65E0"}\uFF09`};if(a.inputSchema){const u=q(a.inputSchema,r);if(u.length>0)return{ok:!1,error:`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${u.join("; ")}`,inputSchema:a.inputSchema}}return this.executeHandler(e,i,a,r,s)}async executeHandler(e,t,n,r,s){const o=Date.now(),i=n.handler??{type:"process"};try{return i.type==="mcp"?{ok:!1,error:"handler.type=mcp \u5C06\u5728\u540E\u7EED\u7248\u672C\u652F\u6301\uFF0C\u8BF7\u6539\u7528 process/module handler"}:i.type==="module"?{ok:!0,result:await this.invokeModuleHandler(t,i,r,e,s),durationMs:Date.now()-o}:!i.command||!i.command.trim()?{ok:!1,error:`\u5DE5\u5177 ${n.name} \u7684 process handler \u7F3A\u5C11 command`}:{ok:!0,result:await this.invokeProcessHandler(t,i,r,e,s),durationMs:Date.now()-o}}catch(a){return{ok:!1,error:a instanceof Error?a.message:String(a),durationMs:Date.now()-o}}}async invokeProcessHandler(e,t,n,r,s){const o=U(t.command??"",{params:n});if(o.length===0)throw new Error("process handler command \u4E3A\u7A7A");const i=typeof t.timeoutMs=="number"&&t.timeoutMs>0?t.timeoutMs:ge,a=new AbortController,u=()=>a.abort();s?.signal?.addEventListener("abort",u,{once:!0});const c=setTimeout(()=>a.abort(),i);try{return await new Promise((f,y)=>{d.info("[plugin:%s] spawn: %s",e.name,o.join(" "));const m=C(o[0],o.slice(1),{cwd:e.dir,env:this.buildPluginEnv(e,r),shell:t.shell===!0,windowsHide:!0,signal:a.signal});let p="",w="";m.stdin?.on("error",()=>{}),m.stdout?.on("data",$=>{p.length<_&&(p+=$.toString("utf8"))}),m.stderr?.on("data",$=>{w.length<_&&(w+=$.toString("utf8"))}),m.on("error",$=>{y(new Error(`\u63D2\u4EF6\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${$.message}`))}),m.on("close",$=>{const D=p.trim();if($!==0){const N=A(w.trim()||D||"(\u65E0\u8F93\u51FA)",600);y(new Error(a.signal.aborted?`\u63D2\u4EF6\u8FDB\u7A0B\u8D85\u65F6(${i}ms)\u6216\u88AB\u4E2D\u6B62`:`\u63D2\u4EF6\u8FDB\u7A0B\u9000\u51FA\u7801 ${$}: ${N}`));return}if(!D){f({ok:!0});return}try{f(JSON.parse(D))}catch{f(D)}});try{t.stdin==="params"?m.stdin?.end(`${JSON.stringify(n)}
2
- `):m.stdin?.end()}catch{}})}finally{clearTimeout(c),s?.signal?.removeEventListener("abort",u)}}async invokeModuleHandler(e,t,n,r,s){if(!t.module)throw new Error("module handler \u7F3A\u5C11 module \u8DEF\u5F84");const o=g(e.dir,t.module);let i=e.moduleCache.get(o);i||(i=await import(te(o).href),e.moduleCache.set(o,i));const a=t.export||"default",c=i[a];if(typeof c!="function")throw new Error(`\u6A21\u5757 ${t.module} \u672A\u5BFC\u51FA\u51FD\u6570 ${a}`);return await c(n,{agentId:r,signal:s?.signal,pluginRoot:e.dir})}buildPluginEnv(e,t){const n={};for(const s of["PATH","HOME","USERPROFILE","SystemRoot","COMSPEC","TEMP","TMP","LANG","TZ"]){const o=process.env[s];o!==void 0&&(n[s]=o)}n.ACODE_PLUGIN_ROOT=e.dir,n.ACODE_AGENT_ID=t,n.ACODE_PLUGIN_NAME=e.name;const r=new Set((e.userConfig??[]).map(s=>s.key));for(const[s,o]of Object.entries(e.configValues))r.has(s)&&(!ye.test(s)||me.has(s.toUpperCase())||(n[s]=o));return n}async manage(e,t){const n=this.agentState(e),r=n.queue.then(async()=>{const s=await this.hydrate(e);return this.doManage(s,t)});return n.queue=r.catch(()=>{}),r}async doManage(e,t){switch(t.action){case"list":return{ok:!0,plugins:[...e.plugins.values()].map(n=>this.toSummary(n))};case"install":return this.installPlugin(e,t);case"uninstall":return this.uninstallPlugin(e,t);case"reload":return this.reloadPlugin(e,t);case"enable":case"disable":return this.setEnabled(e,t,t.action==="enable");default:return{ok:!1,error:`\u672A\u77E5 action: ${String(t.action)}`}}}async installPlugin(e,t){const n=(t.source??"").trim();if(!n)return{ok:!1,error:"install \u9700\u8981 source\uFF08\u5F53\u524D\u652F\u6301 local:<\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>\uFF09"};const r=n.split(":",1)[0];if(r!=="local")return{ok:!1,error:`\u6682\u4E0D\u652F\u6301\u63D2\u4EF6\u6765\u6E90 "${r}:"\uFF08npm:/git: \u5728\u8DEF\u7EBF\u56FE\u4E2D\uFF1Bzip \u5305\u8BF7\u7528\u9762\u677F\u5BFC\u5165\u6216 POST /runtime/plugins/:agentId/upload\uFF09`};const s=n.slice(6).trim();if(!s||!S(g(s,"plugin.json")))return{ok:!1,error:`\u63D2\u4EF6\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u7F3A\u5C11 plugin.json: ${s}`};const o=R(this.rootDir),i=R(s);return i!==o&&!i.startsWith(o+ee)?{ok:!1,error:`local \u6765\u6E90\u5FC5\u987B\u5728\u63D2\u4EF6\u76EE\u5F55\uFF08${this.rootDir}\uFF09\u5185\u52A0\u8F7D\uFF0C\u4E0D\u5141\u8BB8\u4EFB\u610F\u8DEF\u5F84: ${s}`}:this.installFromDirectory(e,s,n,t.config)}async installFromZip(e,t,n,r){if(!t||t.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};const s=await this.hydrate(e),o=s.queue.then(async()=>{const i=g(this.rootDir,"tmp",`upload-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const a=await j(t,i);return S(g(a.pluginDir,"plugin.json"))?(d.info("[agent:%s] zip \u5BFC\u5165: %s\uFF08%d \u4E2A\u6587\u4EF6\uFF09",e,n,a.fileCount),await this.installFromDirectory(s,a.pluginDir,`upload:${n}`,r)):{ok:!1,error:"zip \u5185\u672A\u627E\u5230 plugin.json\uFF08\u8BF7\u6253\u5305\u63D2\u4EF6\u76EE\u5F55\uFF0C\u4E14 zip \u5185\u8DEF\u5F84\u4F7F\u7528\u82F1\u6587\uFF09"}}catch(a){const u=a instanceof Error?a.message:String(a);return d.warn("[agent:%s] zip \u5BFC\u5165\u5931\u8D25: %s",e,u),{ok:!1,error:`zip \u5BFC\u5165\u5931\u8D25: ${u}`}}finally{await b(i,3,100).catch(()=>{})}});return s.queue=o.catch(()=>{}),o}async installFromDirectory(e,t,n,r){const s=this.loadManifestOnly(t);if(!s.ok)return s;const o=s.manifest.name,i=g(this.rootDir,"cache",M(e.agentId),o),a=e.plugins.get(o);a&&this.stopAllListeners(a);try{await b(i),L(Z(i),{recursive:!0}),F(t,i,{recursive:!0,filter:f=>!/[\\/]\.git([\\/]|$)/.test(f)&&!/[\\/]node_modules([\\/]|$)/.test(f)})}catch(f){const y=f instanceof Error?f.message:String(f);return d.warn("[agent:%s] \u63D2\u4EF6\u7269\u5316\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,y),a&&this.startAllListeners(e,a),{ok:!1,error:`\u63D2\u4EF6\u7269\u5316\u5931\u8D25: ${y}`}}const u=this.loadPluginFromDir(e,i,n,new Date().toISOString(),r??{});if(!u.ok)return d.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,u.error),await b(i),u;const c=u.plugin;return e.plugins.set(c.name,c),this.persistInstalled(e),this.startAllListeners(e,c),d.info("[agent:%s] \u63D2\u4EF6\u5DF2\u5B89\u88C5: %s@%s",e.agentId,c.name,c.version??"?"),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(c)}}async uninstallPlugin(e,t){const n=(t.name??"").trim(),r=e.plugins.get(n);return r?(this.stopAllListeners(r),e.plugins.delete(n),this.readSharedManifest().some(o=>o.pluginName===n)&&this.removeRuntimeLink(e.agentId,n),this.persistInstalled(e),await b(r.dir),d.info("[agent:%s] \u63D2\u4EF6\u5DF2\u5378\u8F7D: %s",e.agentId,n),this.notifyPluginsChanged(e.agentId),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${n} \u672A\u5B89\u88C5`}}async reloadPlugin(e,t){const n=(t.name??"").trim(),r=e.plugins.get(n);if(!r)return{ok:!1,error:`\u63D2\u4EF6 ${n} \u672A\u5B89\u88C5`};const s=this.loadPluginFromDir(e,r.dir,r.source,r.installedAt,r.configValues);if(!s.ok)return{ok:!1,error:`\u91CD\u8F7D\u5931\u8D25\uFF08\u4FDD\u7559\u65E7\u7248\u672C\u8FD0\u884C\uFF09: ${s.error}`};const o=s.plugin;return this.stopAllListeners(r),e.plugins.set(n,o),this.persistInstalled(e),this.startAllListeners(e,o),d.info("[agent:%s] \u63D2\u4EF6\u5DF2\u91CD\u8F7D: %s",e.agentId,n),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(o)}}async setEnabled(e,t,n){const r=(t.name??"").trim(),s=e.plugins.get(r);return s?(s.enabled=n,n?this.startAllListeners(e,s):this.stopAllListeners(s),this.persistInstalled(e),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(s)}):{ok:!1,error:`\u63D2\u4EF6 ${r} \u672A\u5B89\u88C5`}}deployedDir(){return g(this.rootDir,"deployed")}deployedManifestFile(){return g(this.deployedDir(),"manifest.json")}deployedPluginDir(e){if(!z(e))throw new Error(`\u975E\u6CD5\u63D2\u4EF6\u540D\uFF08\u4EC5\u5141\u8BB8 ${I}\uFF09: ${JSON.stringify(e)}`);const t=g(this.deployedDir(),e),n=R(this.deployedDir());if(R(t)!==g(n,e))throw new Error(`\u63D2\u4EF6\u76EE\u5F55\u8D8A\u51FA\u90E8\u7F72\u533A: ${e}`);return t}legacySharedDir(){return g(this.rootDir,"shared")}readSharedManifest(){try{const e=JSON.parse(E(this.deployedManifestFile(),"utf8"));return Array.isArray(e.plugins)?e.plugins.filter(t=>t&&z(t.pluginName)):[]}catch{return[]}}writeSharedManifest(e){L(this.deployedDir(),{recursive:!0}),B(this.deployedManifestFile(),`${JSON.stringify({version:2,plugins:e},null,2)}
3
- `,"utf8")}async migrateLegacySharedIfNeeded(){try{if(S(this.deployedManifestFile()))return;const e=g(this.legacySharedDir(),"manifest.json");if(!S(e))return;const t=JSON.parse(E(e,"utf8")),n=Array.isArray(t.plugins)?t.plugins:[];if(n.length===0)return;const r=[];for(const s of n){const o=g(this.legacySharedDir(),s.zipFile);if(!(!s.pluginName||!S(o)))try{const i=await this.deployPluginZipToPersistentDir(E(o),s.pluginName);if(!i)continue;r.push(i),d.info("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u5230\u90E8\u7F72\u533A: %s",s.pluginName)}catch(i){d.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6 %s \u8FC1\u79FB\u5931\u8D25: %s",s.pluginName,i instanceof Error?i.message:String(i))}}r.length>0&&this.writeSharedManifest(r),v(this.legacySharedDir(),{recursive:!0,force:!0})}catch(e){d.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u672A\u6267\u884C\uFF08\u4E0B\u6B21\u91CD\u8BD5\uFF09: %s",e instanceof Error?e.message:String(e))}}deployedPluginHealthy(e){return S(g(this.deployedPluginDir(e),"plugin.json"))}runtimeDirFor(e){return g(this.runtimeRootDir,M(e))}runtimeLinkPath(e,t){return g(this.runtimeDirFor(e),t)}ensureRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t),r=this.deployedPluginDir(t);if(!S(g(r,"plugin.json")))return!1;L(this.runtimeDirFor(e),{recursive:!0});try{if(S(n)){let s=!1;try{s=X(n).isSymbolicLink()}catch{s=!1}if(s)try{return H(n),!0}catch{}v(n,{recursive:!0,force:!0})}return Q(r,n,Se),d.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u5EFA\u7ACB: %s \u2192 %s",e,n,r),!0}catch(s){return d.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5931\u8D25\uFF08%s \u2192 %s\uFF09: %s",e,t,r,s instanceof Error?s.message:String(s)),!1}}removeRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t);try{S(n)&&(v(n,{recursive:!0,force:!0}),d.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u79FB\u9664: %s",e,t))}catch(r){d.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u79FB\u9664\u5931\u8D25\uFF08%s\uFF09: %s",e,t,r instanceof Error?r.message:String(r))}}async saveSharedPlugin(e,t,n=!0,r){if(!e||e.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};await this.migrateLegacySharedIfNeeded();const s=g(this.rootDir,"tmp",`deploy-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const o=await j(e,s),i=this.loadManifestOnly(o.pluginDir);if(!i.ok)return i;const a=i.manifest.name,u=this.readSharedManifest().find(p=>p.pluginName===a);if(u&&u.sha256===r&&this.deployedPluginHealthy(a))return{ok:!0,pluginName:a};await this.suspendDeployedPluginAcrossAgents(a),L(this.deployedDir(),{recursive:!0});const c=this.deployedPluginDir(a),f=g(this.deployedDir(),`.old-${a}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);if(S(c))try{V(c,f)}catch{v(c,{recursive:!0,force:!0})}try{F(o.pluginDir,c,{recursive:!0,filter:p=>!/[\\/]\.git([\\/]|$)/.test(p)&&!/[\\/]node_modules([\\/]|$)/.test(p)})}catch(p){throw S(f)&&(v(c,{recursive:!0,force:!0}),V(f,c)),p}S(f)&&v(f,{recursive:!0,force:!0}),await W(this.deployedManifestFile(),async()=>{const p=this.readSharedManifest().filter(w=>w.pluginName!==a);p.push({pluginName:a,zipFile:u?.zipFile??`${a}.zip`,fileName:t,defaultEnabled:n,sha256:r}),this.writeSharedManifest(p)}),d.info("[shared] \u63D2\u4EF6\u5DF2\u90E8\u7F72\u5230 bridge: %s\uFF08\u6765\u6E90 %s%s\uFF09",a,t,r?`, sha256=${r.slice(0,12)}\u2026`:"");const m=(await this.applySharedToKnownAgents()).find(p=>p.installed.includes(a));return m&&d.info("[shared] \u5DF2\u540C\u6B65\u5230\u8FD0\u884C\u4E2D agent: %s",m.agentId),{ok:!0,pluginName:a}}catch(o){const i=o instanceof Error?o.message:String(o);return d.warn("[shared] \u63D2\u4EF6\u90E8\u7F72\u5931\u8D25\uFF08%s\uFF09: %s",t,i),{ok:!1,error:`\u63D2\u4EF6\u90E8\u7F72\u5931\u8D25: ${i}`}}finally{await b(s,3,100).catch(()=>{})}}async deployPluginZipToPersistentDir(e,t){if(!e||e.length===0)return null;const n=g(this.rootDir,"tmp",`migrate-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const r=await j(e,n),s=this.loadManifestOnly(r.pluginDir);if(!s.ok)return null;const o=s.manifest.name;if(t&&o!==t)return null;L(this.deployedDir(),{recursive:!0});const i=this.deployedPluginDir(o);return S(i)&&v(i,{recursive:!0,force:!0}),F(r.pluginDir,i,{recursive:!0,filter:a=>!/[\\/]\.git([\\/]|$)/.test(a)&&!/[\\/]node_modules([\\/]|$)/.test(a)}),{pluginName:o,zipFile:`${o}.zip`,fileName:`${o}.zip`,defaultEnabled:!0}}finally{v(n,{recursive:!0,force:!0})}}async suspendDeployedPluginAcrossAgents(e){for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const n=t.queue.then(async()=>{const r=t.plugins.get(e);r&&(this.stopAllListeners(r),t.plugins.delete(e),d.info("[agent:%s] \u5DF2\u6458\u9664\u63D2\u4EF6\u7B49\u5F85\u90E8\u7F72\u533A\u66F4\u65B0: %s",t.agentId,e))});t.queue=n.catch(()=>{}),await n}}async applySharedToKnownAgents(){const e=[];for(const t of this.agents.values()){if(!t.hydrated)continue;const n=await this.syncSharedIntoStateQueued(t);n.length>0&&e.push({agentId:t.agentId,installed:n})}return e}async syncSharedIntoStateQueued(e){const t=e.queue.then(()=>this.syncSharedIntoState(e));return e.queue=t.catch(()=>[]),t}effectiveSharedEnabled(e,t){return se(e,"plugins",t.pluginName)&&(t.defaultEnabled??!0)}async pullTemplatePluginsFromCapabilities(e){const t=ie(e.agentId);if(!t)return;const n=this.readSharedManifest();for(const[r,s]of Object.entries(t)){if(!s.url)continue;const o=n.find(a=>a.pluginName===r);if(!o||!o.sha256||o.sha256===s.sha256&&this.deployedPluginHealthy(r)||this.templatePullInFlight.has(r))continue;this.templatePullInFlight.add(r);const i=g(this.rootDir,"tmp",`pull-${M(e.agentId)}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{L(i,{recursive:!0});let a=`${r}.zip`;try{const y=decodeURIComponent(s.url.split("/").pop()||"");y.toLowerCase().endsWith(".zip")&&(a=ue(y,`${r}.zip`))}catch{}const u=await le({downloadUrl:s.url,fileName:a,sha256:s.sha256},i);if(!u)continue;const c=E(u.outputPath),f=await this.saveSharedPlugin(c,u.fileName,o.defaultEnabled??!0,s.sha256);f.ok?d.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u81EA\u52A8\u5BF9\u8D26\u66F4\u65B0\u6210\u529F: %s",e.agentId,f.pluginName??r):d.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u66F4\u65B0\u5931\u8D25: %s: %s",e.agentId,r,f.error)}catch(a){d.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6 %s \u66F4\u65B0\u5931\u8D25: %s",e.agentId,r,a instanceof Error?a.message:String(a))}finally{this.templatePullInFlight.delete(r),await b(i,3,100).catch(()=>{})}}}queueTemplatePull(e){this.backgroundTemplatePulls.has(e.agentId)||(this.backgroundTemplatePulls.add(e.agentId),this.pullTemplatePluginsFromCapabilities(e).catch(t=>{d.warn("[agent:%s] \u540E\u53F0\u63D2\u4EF6\u5BF9\u8D26\u66F4\u65B0\u5931\u8D25: %s",e.agentId,t instanceof Error?t.message:String(t))}).finally(()=>{this.backgroundTemplatePulls.delete(e.agentId)}))}async syncSharedIntoState(e){this.queueTemplatePull(e);const t=this.readSharedManifest(),n=new Set,r=[];for(const s of t)if(n.add(s.pluginName),this.effectiveSharedEnabled(e.agentId,s)){const i=e.plugins.get(s.pluginName);if(!this.ensureRuntimeLink(e.agentId,s.pluginName))continue;const a=this.runtimeLinkPath(e.agentId,s.pluginName);if(!i){const u=this.loadPluginFromDir(e,a,`shared:${s.fileName}`,new Date().toISOString(),{});u.ok?(e.plugins.set(u.plugin.name,u.plugin),r.push(u.plugin.name),d.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u5DF2\u6309\u5F00\u542F\u6001\u52A0\u8F7D: %s",e.agentId,s.pluginName)):d.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25: %s: %s",e.agentId,s.pluginName,u.error)}}else{const i=e.plugins.get(s.pluginName);i&&(this.stopAllListeners(i),e.plugins.delete(s.pluginName)),this.removeRuntimeLink(e.agentId,s.pluginName)}return this.cleanupRuntimeDir(e,n),this.persistInstalled(e),r}cleanupRuntimeDir(e,t){const n=this.runtimeDirFor(e.agentId);try{if(!S(n))return;const r=new Set(t);for(const s of H(n))!r.has(s)&&!e.plugins.has(s)&&this.removeRuntimeLink(e.agentId,s)}catch{}}async applyCapabilities(e){const t=await this.hydrate(e);await this.pullTemplatePluginsFromCapabilities(t),await this.syncSharedIntoState(t)}async drainEvents(e,t={}){const n=await this.hydrate(e);this.ensureListenersRunning(n);const r=n.buffer.drain(t),s=await this.getCatalog(e);return{revision:r.revision,events:r.events,catalog:s,compactionSeq:n.compactionSeq}}markAgentCompacted(e){const t=this.agentState(e);t.compactionSeq++,d.debug("[agent:%s] \u4E0A\u4E0B\u6587\u538B\u7F29\u6807\u8BB0: compactionSeq=%d",e,t.compactionSeq)}async enqueueExternalEvent(e,t,n){const r=await this.hydrate(e),s=r.plugins.get(t);if(!s||!s.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\u6216\u5DF2\u505C\u7528`};const o=typeof n.event=="string"?n.event:"",i=s.listeners.find(a=>a.transport.type==="http-callback"&&(!o||a.event===o));return i?(this.enqueueEvent(r,s,i,n),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5339\u914D\u7684 http-callback \u76D1\u542C\u5668\uFF08event=${o||"(\u7A7A)"}\uFF09`}}agentState(e){let t=this.agents.get(e);return t||(t={agentId:e,plugins:new Map,buffer:new ce(e),hydrated:!1,queue:Promise.resolve(),eventSeq:0,compactionSeq:0},this.agents.set(e,t)),t}async hydrate(e){await this.migrateLegacySharedIfNeeded();const t=this.agentState(e);if(t.hydrated)return t;t.hydrated=!0;const n=this.installedFile(e);if(!S(n))return await this.syncSharedIntoState(t).catch(()=>{}),t;try{const r=JSON.parse(E(n,"utf8"));for(const s of r.plugins??[]){if(String(s.source||"").startsWith("shared:"))continue;const i=g(this.rootDir,"cache",M(e),s.name);if(!S(g(i,"plugin.json"))){d.warn("[agent:%s] \u5DF2\u5B89\u88C5\u63D2\u4EF6\u76EE\u5F55\u7F3A\u5931\uFF0C\u8DF3\u8FC7: %s",e,s.name);continue}const a=this.loadPluginFromDir(t,i,s.source,s.installedAt,s.config??{});if(a.ok){const u=a.plugin;u.enabled=s.enabled,t.plugins.set(u.name,u)}else d.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25: %s: %s",e,s.name,a.error)}}catch(r){const s=r instanceof Error?r.message:String(r);d.error("[agent:%s] installed.json \u89E3\u6790\u5931\u8D25: %s",e,s)}return await this.syncSharedIntoState(t).catch(r=>{d.warn("[agent:%s] \u5171\u4EAB\u63D2\u4EF6\u540C\u6B65\u5931\u8D25: %s",e,r instanceof Error?r.message:String(r))}),t}installedFile(e){return g(this.rootDir,"agents",M(e),"installed.json")}persistInstalled(e){const t=this.installedFile(e.agentId);L(Z(t),{recursive:!0});const n=[...e.plugins.values()].map(r=>({name:r.name,source:r.source,installedAt:r.installedAt,enabled:r.enabled,config:r.configValues}));B(t,`${JSON.stringify({version:1,plugins:n},null,2)}
4
- `,"utf8")}readJsonFile(e){if(!S(e))return{ok:!0,data:{}};try{const t=JSON.parse(E(e,"utf8"));return P(t)?{ok:!0,data:t}:{ok:!1,error:`${e}: \u6839\u8282\u70B9\u987B\u4E3A\u5BF9\u8C61`}}catch(t){const n=t instanceof Error?t.message:String(t);return{ok:!1,error:`${e}: JSON \u89E3\u6790\u5931\u8D25: ${n}`}}}loadManifestOnly(e){const t=this.readJsonFile(g(e,"plugin.json"));if(!t.ok)return t;const n=t.data,r=Ae(n);return r?{ok:!1,error:r}:{ok:!0,manifest:n}}loadPluginFromDir(e,t,n,r,s){const o=this.loadManifestOnly(t);if(!o.ok)return o;const i=o.manifest,a=g(t,i.tools??"tools/tools.json"),u=this.readJsonFile(a);if(!u.ok)return u;const c=[],f=Array.isArray(u.data.tools)?u.data.tools:[];for(const h of f){const T=Le(h);if(T)return{ok:!1,error:`${i.tools??"tools/tools.json"}: ${T}`};c.push(h)}const y=g(t,i.listeners??"listeners/listeners.json"),m=this.readJsonFile(y);if(!m.ok)return m;const p=[],w=Array.isArray(m.data.listeners)?m.data.listeners:[];for(const h of w){const T=Te(h);if(T)return{ok:!1,error:`${i.listeners??"listeners/listeners.json"}: ${T}`};p.push(h)}const $=Array.isArray(i.userConfig)?i.userConfig:[],D={...s};for(const h of $){if(!h||typeof h.key!="string"||!/^[A-Za-z_][A-Za-z0-9_]*$/.test(h.key))return{ok:!1,error:"plugin.json: userConfig.key \u975E\u6CD5\uFF08\u987B\u4E3A\u73AF\u5883\u53D8\u91CF\u540D\uFF09"};if(!(typeof D[h.key]=="string"&&D[h.key].length>0)&&h.required){const G=h.default!==void 0&&typeof h.default=="string"?h.default:"";if(G)D[h.key]=G;else return{ok:!1,error:`\u7F3A\u5C11\u5FC5\u9700\u914D\u7F6E ${h.key}${h.description?`\uFF08${h.description}\uFF09`:""}\uFF0C\u5B89\u88C5\u65F6\u8BF7\u5728 config \u4E2D\u63D0\u4F9B`}}}const N=i.commands;let Y;if(typeof N=="string"&&N.trim()){const h=g(t,N.trim());S(h)&&(Y=h)}return{ok:!0,plugin:{name:i.name,version:typeof i.version=="string"?i.version:void 0,description:typeof i.description=="string"?i.description:void 0,source:n,installedAt:r,dir:t,enabled:!0,tools:c,listeners:p,commandDir:Y,userConfig:$,configValues:D,status:"enabled",runtimes:p.map(h=>({def:h,stopping:!1,restarts:0,logs:[]})),moduleCache:new Map}}}ensureListenersRunning(e){for(const t of e.plugins.values())if(t.enabled)for(const n of t.runtimes)!n.child&&!n.timer&&!n.backoffTimer&&!n.stopping&&this.startListener(e,t,n)}startAllListeners(e,t){for(const n of t.runtimes)this.stopListener(n),t.enabled&&this.startListener(e,t,n)}stopAllListeners(e){for(const t of e.runtimes)this.stopListener(t)}startListener(e,t,n){const r=n.def.transport??{type:"command-stream"};if(r.type==="http-callback"){n.stopping=!1;return}if(r.type==="poll-command"){const s=Math.max(5e3,r.intervalMs??3e4);n.stopping=!1,n.timer=setInterval(()=>{this.pollListenerOnce(e,t,n)},s),this.pollListenerOnce(e,t,n);return}if(!r.command){n.lastError="command-stream \u7F3A\u5C11 command",k(n,`ERROR ${n.lastError}`);return}n.stopping=!1,this.spawnListenerChild(e,t,n)}spawnListenerChild(e,t,n){const s=n.def.transport?.command??"",o=U(s,{});try{k(n,`spawn: ${o.join(" ")}`);const i=C(o[0],o.slice(1),{cwd:t.dir,env:this.buildPluginEnv(t,e.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"]});n.child=i,n.lastError=void 0;let a="";i.stdout?.on("data",u=>{a+=u.toString("utf8");let c=a.indexOf(`
5
- `);for(;c>=0;){const f=a.slice(0,c).trim();a=a.slice(c+1),f&&this.handleListenerLine(e,t,n,f),c=a.indexOf(`
6
- `)}a.length>1024*1024&&(a=a.slice(-4096))}),i.stderr?.on("data",u=>{k(n,`stderr: ${A(u.toString("utf8").trimEnd(),400)}`)}),i.on("error",u=>{n.lastError=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${u.message}`,k(n,`ERROR ${n.lastError}`)}),i.on("close",u=>{n.child=void 0,!n.stopping&&(n.lastError=`\u76D1\u542C\u8FDB\u7A0B\u9000\u51FA\uFF08code=${u??"signal"}\uFF09`,k(n,`exit code=${u??"signal"}\uFF0C\u51C6\u5907\u91CD\u542F`),this.scheduleListenerRestart(e,t,n))})}catch(i){const a=i instanceof Error?i.message:String(i);n.lastError=a,k(n,`ERROR spawn: ${a}`),this.scheduleListenerRestart(e,t,n)}}scheduleListenerRestart(e,t,n){if(n.stopping)return;const r=Math.max(500,n.def.transport?.restartBackoffMs??2e3),s=Math.min($e,r*2**Math.min(n.restarts,6));n.restarts++,k(n,`restart #${n.restarts} in ${s}ms`),n.backoffTimer=setTimeout(()=>{n.backoffTimer=void 0,n.stopping||this.spawnListenerChild(e,t,n)},s)}async pollListenerOnce(e,t,n){if(n.polling)return;const r=n.def.transport?.command??"",s=U(r,{});if(s.length===0)return;n.polling=!0;const o=new AbortController,i=setTimeout(()=>o.abort(),J);try{const a=await new Promise((u,c)=>{const f=C(s[0],s.slice(1),{cwd:t.dir,env:this.buildPluginEnv(t,e.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"],signal:o.signal});let y="",m="";f.stdout?.on("data",w=>{y.length<_&&(y+=w.toString("utf8"))}),f.stderr?.on("data",w=>{m.length<_&&(m+=w.toString("utf8"))});const p=()=>o.signal.aborted;f.on("error",w=>{c(p()?new Error(`poll \u8D85\u65F6(${J}ms)`):w)}),f.on("close",w=>{p()?c(new Error(`poll \u8D85\u65F6(${J}ms)`)):w===0?u(y):c(new Error(`exit ${w}: ${A(m||y,300)}`))})});n.lastError=void 0;for(const u of a.split(`
7
- `)){const c=u.trim();c&&this.handleListenerLine(e,t,n,c)}}catch(a){const u=a instanceof Error?a.message:String(a);n.lastError=u,k(n,`poll \u5931\u8D25: ${u}`)}finally{clearTimeout(i),n.polling=!1}}stopListener(e){if(e.stopping=!0,e.restarts=0,e.child){try{e.child.kill()}catch{}e.child=void 0}e.timer&&(clearInterval(e.timer),e.timer=void 0),e.backoffTimer&&(clearTimeout(e.backoffTimer),e.backoffTimer=void 0)}handleListenerLine(e,t,n,r){k(n,`event: ${A(r,300)}`);let s;try{s=JSON.parse(r)}catch{n.lastError="\u4E8B\u4EF6\u884C\u4E0D\u662F\u5408\u6CD5 JSON\uFF08\u8981\u6C42 JSONL\uFF09";return}if(!P(s))return;const o=typeof s.event=="string"?s.event:n.def.event,i=o===n.def.event?n.def:t.listeners.find(a=>a.event===o);i&&(i.delivery&&i.delivery!=="poll"&&d.debug("[plugin:%s] delivery=%s \u6682\u6309 poll \u4EA4\u4ED8",t.name,i.delivery),this.enqueueEvent(e,t,i,s))}enqueueEvent(e,t,n,r){for(const[y,m]of Object.entries(n.matcher??{})){const p=O(r,y);if(!(Array.isArray(m)?m:[m]).some($=>JSON.stringify($)===JSON.stringify(p)))return}let s;if(n.dedupKey){const y=O(r,n.dedupKey);y!=null&&(s=A(String(y),256))}e.eventSeq++;const o=A(be(r.data??r),fe),i=n.promptTemplate?Oe(n.promptTemplate,r):`\u3010\u63D2\u4EF6\u4E8B\u4EF6\u3011${t.name} \xB7 ${n.event}${n.description?`
8
- ${n.description}`:""}`,a=(n.toolHints??[]).join(","),u=`${i}
9
- [plugin-event] plugin=${t.name} event=${n.event}`+(a?` toolHints=${a}`:"")+` payload=${o}`,c={msgId:A(s?`plugin-event-${t.name}-${s}`:`plugin-event-${t.name}-${n.event}-${e.eventSeq}`,512),channel:"plugin-event",senderId:`plugin:${t.name}`,senderName:`\u63D2\u4EF6[${t.name}]`,receiverId:e.agentId||void 0,content:u,requireReply:!1,role:"system",timestamp:new Date().toISOString()},f=n.priority??"normal";e.buffer.push({plugin:t.name,event:n.event,priority:f,dedupKey:s,receivedAt:Date.now(),message:c})}requiredParamsOf(e){const t=e.inputSchema;if(!(!t||!Array.isArray(t.required)))return t.required.filter(n=>typeof n=="string")}toSummary(e){return{name:e.name,version:e.version,description:e.description,status:e.status,enabled:e.enabled,source:e.source,installedAt:e.installedAt,toolCount:e.tools.length,listeners:e.runtimes.map(t=>({event:t.def.event,delivery:t.def.delivery??"poll",running:!!(t.child||t.timer)||t.def.transport?.type==="http-callback",error:t.lastError})),error:e.error}}async getLogs(e,t){const r=(await this.hydrate(e)).plugins.get(t);if(!r)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5`,logs:[]};const s=[];for(const o of r.runtimes)s.push(`\u2500\u2500 listener ${o.def.event} (${o.def.transport?.type}) ${o.lastError?`[error: ${o.lastError}]`:""}`),s.push(...o.logs);return{ok:!0,logs:s}}async stopAgent(e){const t=this.agents.get(e);if(t){for(const n of t.plugins.values())this.stopAllListeners(n);this.agents.delete(e)}}async stopAll(){for(const e of[...this.agents.keys()])await this.stopAgent(e)}async listDeployed(){await this.migrateLegacySharedIfNeeded();const e=this.readSharedManifest(),t=[];for(const n of e){const r=this.deployedPluginDir(n.pluginName),s=this.deployedPluginHealthy(n.pluginName);let o;if(s)try{const i=JSON.parse(E(g(r,"plugin.json"),"utf8"));typeof i.version=="string"&&(o=i.version)}catch{}t.push({pluginName:n.pluginName,version:o,fileName:n.fileName??`${n.pluginName}.zip`,defaultEnabled:n.defaultEnabled!==!1,sha256:n.sha256,deployed:s})}return t}deployedDefaultEnabled(){const e=this.readSharedManifest(),t={};for(const n of e)t[n.pluginName]=n.defaultEnabled!==!1;return t}async removeDeployedPlugin(e){if(!z(e))return{ok:!1,error:"pluginName \u975E\u6CD5\uFF08\u987B\u4E3A kebab-case\uFF0C1~64 \u5B57\u7B26\uFF09"};await this.migrateLegacySharedIfNeeded();for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const n=t.queue.then(async()=>{const r=t.plugins.get(e);r&&(this.stopAllListeners(r),t.plugins.delete(e)),this.removeRuntimeLink(t.agentId,e),this.persistInstalled(t)});t.queue=n.catch(()=>{}),await n}await W(this.deployedManifestFile(),async()=>{const t=this.readSharedManifest().filter(n=>n.pluginName!==e);this.writeSharedManifest(t)});try{v(this.deployedPluginDir(e),{recursive:!0,force:!0})}catch(t){return{ok:!1,error:`\u90E8\u7F72\u76EE\u5F55\u6E05\u7406\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`}}return d.info("[shared] \u63D2\u4EF6\u5DF2\u4ECE bridge \u79FB\u9664\u90E8\u7F72: %s",e),{ok:!0}}}function ke(l){const e=l.indexOf(".");if(e<=0||e>=l.length-1)return null;const t=l.slice(0,e),n=l.slice(e+1);return!I.test(t)||!n.trim()?null:{plugin:t,tool:n.trim()}}function z(l){return typeof l=="string"&&l.length>0&&l.length<=64&&I.test(l)}function Ae(l){const e=l.name;if(typeof e!="string"||!I.test(e))return`plugin.json: name \u975E\u6CD5\uFF08\u987B\u4E3A kebab-case\uFF09: ${String(e)}`;if(e.length>64)return"plugin.json: name \u8FC7\u957F\uFF08\u226464\uFF09";for(const t of he)if(e===t.replace(/\.$/,"")||e.startsWith(t))return`plugin.json: name \u4F7F\u7528\u4E86\u4FDD\u7559\u524D\u7F00 ${t}`;return we.test(e)?"plugin.json: name \u542B\u975E ASCII \u5B57\u7B26\uFF08\u540C\u5F62\u5B57\u9632\u62A4\uFF09":l.version!==void 0&&typeof l.version!="string"?"plugin.json: version \u987B\u4E3A\u5B57\u7B26\u4E32":l.userConfig!==void 0&&!Array.isArray(l.userConfig)?"plugin.json: userConfig \u987B\u4E3A\u6570\u7EC4":null}function Le(l){if(!P(l))return"\u5DE5\u5177\u6761\u76EE\u987B\u4E3A\u5BF9\u8C61";const e=l.name;if(typeof e!="string"||!pe.test(e))return`\u5DE5\u5177 name \u975E\u6CD5: ${String(e)}`;if(typeof l.description!="string"||!l.description.trim())return`\u5DE5\u5177 ${e} \u7F3A\u5C11 description`;const t=l.handler;if(!P(t))return`\u5DE5\u5177 ${e} \u7F3A\u5C11 handler`;const n=t.type;return n!=="process"&&n!=="module"&&n!=="mcp"?`\u5DE5\u5177 ${e} handler.type \u975E\u6CD5: ${String(n)}`:n==="process"&&typeof t.command!="string"?`\u5DE5\u5177 ${e} \u7684 process handler \u7F3A\u5C11 command`:n==="module"&&typeof t.module!="string"?`\u5DE5\u5177 ${e} \u7684 module handler \u7F3A\u5C11 module`:l.inputSchema!==void 0&&!P(l.inputSchema)?`\u5DE5\u5177 ${e} inputSchema \u987B\u4E3A\u5BF9\u8C61`:null}function Te(l){if(!P(l))return"\u76D1\u542C\u5668\u6761\u76EE\u987B\u4E3A\u5BF9\u8C61";if(typeof l.event!="string"||!l.event.trim())return"\u76D1\u542C\u5668\u7F3A\u5C11 event";const e=l.transport;if(!P(e))return`\u76D1\u542C\u5668 ${String(l.event)} \u7F3A\u5C11 transport`;const t=e.type;if(t!=="command-stream"&&t!=="poll-command"&&t!=="http-callback")return`\u76D1\u542C\u5668 ${String(l.event)} transport.type \u975E\u6CD5: ${String(t)}`;if((t==="command-stream"||t==="poll-command")&&typeof e.command!="string")return`\u76D1\u542C\u5668 ${String(l.event)} \u7684 ${t} transport \u7F3A\u5C11 command`;const n=l.delivery;return n!==void 0&&n!=="poll"&&n!=="force"&&n!=="wake"?`\u76D1\u542C\u5668 ${String(l.event)} delivery \u975E\u6CD5: ${String(n)}`:null}function U(l,e){return l.trim().split(/\s+/).map(t=>{const n=/^\{\{(.+)\}\}$/.exec(t);if(n){const r=O(e,n[1].trim());return r==null?"":typeof r=="string"?r:JSON.stringify(r)}return t.replace(/\{\{(.+?)\}\}/g,(r,s)=>{const o=O(e,s.trim());return o==null?"":typeof o=="string"?o:JSON.stringify(o)})}).filter(t=>t!=="")}function Oe(l,e){return l.replace(/\{\{(.+?)\}\}/g,(t,n)=>{let r=O(e,n.trim());return r===void 0&&!n.trim().startsWith("params.")&&(r=O(e,`data.${n.trim()}`)),r==null?"":typeof r=="string"?r:JSON.stringify(r)})}function be(l){try{return JSON.stringify(l)??"null"}catch{return"(\u4E0D\u53EF\u5E8F\u5217\u5316\u7684\u4E8B\u4EF6\u8D1F\u8F7D)"}}const Ne=new Ee;oe("plugins",()=>Ne.deployedDefaultEnabled());const Ge=()=>ae("plugins");export{Ee as PluginManager,z as isValidPluginName,Ne as pluginManager,Ge as reconcilePluginsDefaultsFromDeployed,U as renderCommandArgv,ke as splitQualifiedName,q as validateAgainstSchema,Ae as validateManifest};
1
+ import{spawn as _}from"node:child_process";import{cpSync as F,existsSync as w,lstatSync as se,mkdirSync as D,readFileSync as k,readdirSync as j,renameSync as H,rmSync as E,symlinkSync as oe,writeFileSync as U}from"node:fs";import{dirname as J,join as g,resolve as Z}from"node:path";import{fileURLToPath as ae,pathToFileURL as le}from"node:url";import{parseAcodeCommandMarkdown as ue,splitQualifiedToolName as ce}from"@agentswork/acode";import{getAcodePluginDataHome as W,getBridgeVersion as de}from"../config.js";import{sanitizeAgentId as N,withFileLock as X,downloadPluginZip as fe,sanitizeArchiveFileName as ge}from"../utils/file-utils.js";import{createLogger as pe}from"../utils/logger.js";import{setDeployedDefaultsProvider as me,reconcileDefaultsFromDeployed as he}from"./capability-config.js";import{isCapabilityEnabled as ye,getAgentPluginSources as Se}from"./instance-features.js";import{PluginEventBuffer as we}from"./plugin-event-buffer.js";import{extractPluginZip as x}from"./plugin-package.js";const f=pe("plugin-manager"),$="plugin-manager",Q="\u7CFB\u7EDF\u5185\u7F6E\uFF1A\u7BA1\u7406\u63D2\u4EF6\u7684\u751F\u547D\u5468\u671F\uFF08\u5B89\u88C5/\u5378\u8F7D/\u542F\u505C/\u91CD\u8F7D\uFF09\uFF1B\u5F00\u53D1\u63D2\u4EF6\u7528\u5185\u7F6E /create-plugin \u547D\u4EE4",ee=`\u300C\u63D2\u4EF6\u7BA1\u7406\u63D2\u4EF6\u300D\u7684\u751F\u547D\u5468\u671F\u5DE5\u5177\uFF1A\u7BA1\u7406\u63D2\u4EF6\uFF08\u5B89\u88C5/\u5378\u8F7D/\u91CD\u8F7D/\u542F\u505C/\u5217\u8868\uFF09\u3002\u4EC5\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u5B89\u88C5\u3001\u79FB\u9664\u6216\u4FEE\u590D\u63D2\u4EF6\u65F6\u4F7F\u7528\u3002
2
+ - action=list\uFF1A\u5217\u51FA\u5DF2\u5B89\u88C5\u63D2\u4EF6\uFF08\u72B6\u6001\u3001\u76D1\u542C\u5668\u5065\u5EB7\u3001\u5DE5\u5177\u6570\uFF09\u3002
3
+ - action=install\uFF1Asource \u4E3A\u63D2\u4EF6\u6765\u6E90\uFF0C\u5F53\u524D\u652F\u6301 "local:<\u4EFB\u610F\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>"\uFF08\u4E0D\u505A\u76EE\u5F55\u4F4D\u7F6E\u9650\u5236\uFF09\uFF1Bconfig \u4F20\u63D2\u4EF6 manifest \u91CC userConfig \u58F0\u660E\u7684\u914D\u7F6E\u503C\u3002\u5B89\u88C5\u65F6\u4F1A\u5148\u628A\u8BE5\u76EE\u5F55\u79FB\u52A8\u5230\u672C agent \u52A0\u8F7D\u63D2\u4EF6\u7684\u4F4D\u7F6E\uFF0C\u518D\u52A0\u8F7D\u79FB\u52A8\u540E\u7684\u526F\u672C\uFF08\u79FB\u52A8\u540E\u6E90\u76EE\u5F55\u4E0D\u518D\u4FDD\u7559\uFF09\uFF0C\u5B89\u88C5\u540E\u7ACB\u5373\u751F\u6548\uFF1A\u4E0B\u4E00\u6B21 poll_message \u7684 pluginCatalog \u5373\u53EF\u89C1\u3002
4
+ - action=reload\uFF1A\u91CD\u8F7D\u6307\u5B9A\u63D2\u4EF6\uFF08\u6539\u8FC7\u63D2\u4EF6\u6587\u4EF6\u540E\u4F7F\u7528\uFF09\uFF0C\u539F\u5B50\u6362\u88C5\uFF0C\u76D1\u542C\u5668\u91CD\u542F\u3002
5
+ - action=enable / disable\uFF1A\u505C\u7528/\u542F\u7528\uFF08disable \u4FDD\u7559\u5B89\u88C5\u4E0E\u914D\u7F6E\uFF0C\u4EC5\u505C\u6B62\u76D1\u542C\u4E0E\u5DE5\u5177\u8C03\u7528\uFF09\u3002
6
+ - action=uninstall\uFF1A\u5378\u8F7D\u5E76\u5220\u9664\u63D2\u4EF6\u76EE\u5F55\uFF08\u4E0D\u53EF\u9006\uFF0C\u9700\u7528\u6237\u660E\u786E\u8981\u6C42\uFF09\u3002`,ve={type:"object",properties:{action:{type:"string",enum:["install","uninstall","reload","enable","disable","list"],description:"\u751F\u547D\u5468\u671F\u52A8\u4F5C"},name:{type:"string",description:"\u63D2\u4EF6\u540D\uFF08uninstall/reload/enable/disable \u5FC5\u586B\uFF09"},source:{type:"string",description:'install \u6765\u6E90\uFF0C\u5F53\u524D\u652F\u6301 "local:<\u4EFB\u610F\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>"\uFF08\u5B89\u88C5\u65F6\u81EA\u52A8\u79FB\u52A8\u5230\u672C agent \u63D2\u4EF6\u4F4D\u7F6E\u540E\u52A0\u8F7D\uFF09'},config:{type:"object",description:"install \u65F6\u63D2\u4EF6 userConfig \u58F0\u660E\u7684\u914D\u7F6E\u503C\uFF08\u952E\u503C\u5BF9\uFF09",additionalProperties:{type:"string"}}},required:["action"],additionalProperties:!1},Pe=new Set(["install","uninstall","reload","enable","disable","list"]);function te(){const l=de();return l&&l!=="unknown"?l:void 0}function $e(){return ae(new URL("./builtin-commands/",import.meta.url))}const Ee=200,R=256*1024,ke=4*1024,ne=6e4,q=6e4,Ae=/^[a-zA-Z0-9_][a-zA-Z0-9_-]*$/,z=/^[a-z0-9][a-z0-9-]*$/,be=["system.","aws-","acode-"],De=new Set(["NODE_OPTIONS","NODE_PATH","NODE_EXTRA_CA_CERTS","NODE_REPL_HISTORY","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","PYTHONPATH","PYTHONSTARTUP","PYTHONHOME","PERL5LIB","PERL5OPT","RUBYOPT","RUBYLIB","BASH_ENV","ENV","SHELLOPTS","BASHOPTS","IFS","PS1","PS4","GIT_SSH","GIT_SSH_COMMAND","GIT_CONFIG","GIT_CONFIG_GLOBAL","PATH","HOME","USERPROFILE","SYSTEMROOT","COMSPEC","TEMP","TMP","LANG","TZ"]),Le=/^[A-Za-z_][A-Za-z0-9_]*$/,Oe=process.platform==="win32"?"junction":"dir",Te=/[^\x20-\x7E]/,Ne=6e4,G=20,re=80;function P(l){return typeof l=="object"&&l!==null&&!Array.isArray(l)}function I(l,e){let t=l;for(const n of e.split(".")){if(!P(t))return;t=t[n]}return t}function A(l,e){return l.length<=e?l:`${l.slice(0,e)}\u2026(\u622A\u65AD,\u5171 ${l.length} \u5B57\u7B26)`}async function C(l,e=8,t=200){for(let n=0;;n++)try{E(l,{recursive:!0,force:!0});return}catch(r){if(n>=e-1)throw r;await new Promise(i=>setTimeout(i,t))}}async function ie(l,e){D(J(e),{recursive:!0});try{H(l,e);return}catch(t){const n=t?.code;if(!n||!["EXDEV","EPERM","EACCES","EBUSY","EINVAL"].includes(n))throw t}F(l,e,{recursive:!0,filter:t=>!/[\\/]\.git([\\/]|$)/.test(t)&&!/[\\/]node_modules([\\/]|$)/.test(t)}),await C(l)}function b(l,e){l.logs.push(`${new Date().toISOString()} ${e}`),l.logs.length>Ee&&l.logs.shift()}function V(l,e,t="params"){if(!P(l))return[];const n=[],r=l.type;if(typeof r=="string"&&!Ie(r,e))return[`${t}: \u671F\u671B ${r}\uFF0C\u5B9E\u9645 ${Ce(e)}`];if(Array.isArray(l.enum)&&l.enum.length>0&&(l.enum.some(s=>JSON.stringify(s)===JSON.stringify(e))||n.push(`${t}: \u503C ${JSON.stringify(e)} \u4E0D\u5728\u679A\u4E3E ${JSON.stringify(l.enum)} \u5185`)),r==="object"&&P(e)){const i=P(l.properties)?l.properties:{},s=Array.isArray(l.required)?l.required:[];for(const o of s)(!(o in e)||e[o]===void 0)&&n.push(`${t}.${o}: \u5FC5\u586B\u53C2\u6570\u7F3A\u5931`);for(const[o,a]of Object.entries(i))o in e&&e[o]!==void 0&&n.push(...V(a,e[o],`${t}.${o}`));if(l.additionalProperties===!1)for(const o of Object.keys(e))o in i||n.push(`${t}.${o}: \u4E0D\u5141\u8BB8\u7684\u672A\u77E5\u53C2\u6570\uFF08schema additionalProperties=false\uFF09`)}return r==="array"&&Array.isArray(e)&&P(l.items)&&e.forEach((i,s)=>{n.push(...V(l.items,i,`${t}[${s}]`))}),n}function Ie(l,e){switch(l){case"string":return typeof e=="string";case"number":return typeof e=="number"&&Number.isFinite(e);case"boolean":return typeof e=="boolean";case"object":return P(e);case"array":return Array.isArray(e);case"null":return e===null;default:return!0}}function Ce(l){return l===null?"null":Array.isArray(l)?"array":typeof l}class Re{constructor(e={}){this.agents=new Map,this.moduleNonce=0,this.templatePullInFlight=new Set,this.backgroundTemplatePulls=new Set,this.rootDir=e.rootDir??g(W(),"plugins"),this.runtimeRootDir=e.runtimeRootDir??g(W(),"plugins-runtime")}forAgent(e){return{listPlugins:()=>this.list(e),getCatalog:()=>this.getCatalog(e),getToolSchema:t=>this.getToolSchema(e,t),invokeTool:(t,n,r,i)=>this.invokeTool(e,t,n,r,i),manage:t=>this.manage(e,t),getCommandDirs:()=>this.getCommandDirs(e)}}setOnPluginsChanged(e){this.onPluginsChanged=e}notifyPluginsChanged(e){try{this.onPluginsChanged?.(e)}catch(t){f.warn("[agent:%s] onPluginsChanged \u56DE\u8C03\u5931\u8D25: %s",e,t instanceof Error?t.message:String(t))}}async getCommandDirs(e){return[...(await this.hydrate(e)).plugins.values()].filter(n=>n.enabled&&n.commandDir).map(n=>n.commandDir)}async getPluginCommands(e){const t=await this.hydrate(e),n=[];n.push(...this.parseCommandDir($,$e()));for(const r of t.plugins.values())!r.enabled||!r.commandDir||n.push(...this.parsePluginCommandDir(r));return n}parsePluginCommandDir(e){return this.parseCommandDir(e.name,e.commandDir)}parseCommandDir(e,t){const n=[];if(!t)return n;try{for(const r of j(t)){if(!r.endsWith(".md"))continue;const i=g(t,r);try{const s=ue(i,k(i,"utf8"));s.plugin=e,n.push(s)}catch(s){f.warn("[plugin:%s] \u547D\u4EE4\u89E3\u6790\u5931\u8D25 %s: %s",e,r,s instanceof Error?s.message:String(s))}}}catch{}return n}async list(e){const t=await this.hydrate(e),n=new Map;for(const r of t.plugins.values()){const i=this.toSummary(r);n.set(i.name,i)}n.has($)||n.set($,{name:$,version:te(),description:Q,status:"enabled",enabled:!0,source:"builtin",installedAt:new Date().toISOString(),toolCount:1,tools:[{name:"plugin-manager.manage",description:"\u63D2\u4EF6\u751F\u547D\u5468\u671F\u7BA1\u7406\uFF08install/uninstall/reload/disable/enable/list\uFF09"}],listeners:[],builtin:!0});for(const r of this.readSharedManifest()){const i=r.pluginName;if(!this.deployedPluginHealthy(i))continue;const o=n.get(i);if(o){String(o.source||"").startsWith("shared:")&&(o.enabled=this.effectiveSharedEnabled(e,r));continue}n.set(i,{name:i,version:this.deployedPluginVersion(i),status:"enabled",enabled:this.effectiveSharedEnabled(e,r),source:`shared:${r.fileName??`${i}.zip`}`,installedAt:new Date().toISOString(),toolCount:0,listeners:[]})}return[...n.values()].sort((r,i)=>r.name.localeCompare(i.name))}deployedPluginVersion(e){try{const t=JSON.parse(k(g(this.deployedPluginDir(e),"plugin.json"),"utf8"));return typeof t.version=="string"?t.version:void 0}catch{return}}async getCatalog(e){const t=await this.hydrate(e),n=[];for(const r of t.plugins.values()){if(!r.enabled||r.status==="error")continue;const i=r.tools.slice(0,G).map(s=>({name:s.name,description:A(s.title||s.description,re),requiredParams:this.requiredParamsOf(s)}));r.tools.length>G&&i.push({name:`(\u53E6\u6709 ${r.tools.length-G} \u4E2A\u5DE5\u5177\u672A\u5217\u51FA)`,description:'\u7528 function_call {action:"catalog"} \u67E5\u770B\u5168\u91CF',requiredParams:void 0}),n.push({plugin:r.name,version:r.version,description:r.description,status:r.status,tools:i})}return n.push({plugin:$,version:te(),description:Q,status:"enabled",tools:[{name:"manage",description:A(ee,re),requiredParams:["action"]}]}),{revision:t.catalogRevision,plugins:n}}async getToolSchema(e,t){const n=ce(t);if(!n)return null;if(n.plugin===$&&n.tool==="manage")return{plugin:$,name:"manage",description:ee,inputSchema:ve};const i=(await this.hydrate(e)).plugins.get(n.plugin);if(!i||!i.enabled)return null;const s=i.tools.find(o=>o.name===n.tool);return s?{plugin:i.name,name:s.name,title:s.title,description:s.description,inputSchema:s.inputSchema??{type:"object",properties:{}}}:null}async invokeTool(e,t,n,r,i){if(t===$&&n==="manage"){const u=this.buildManageRequest(r);if(!u)return{ok:!1,error:"plugin-manager.manage \u7F3A\u5C11 action"};const c=await this.manage(e,u);if(!c.ok)return{ok:!1,error:c.error??"\u63D2\u4EF6\u7BA1\u7406\u64CD\u4F5C\u5931\u8D25"};const d={ok:!0};return c.plugins&&(d.plugins=c.plugins),c.summary&&(d.summary=c.summary),{ok:!0,result:d}}const s=await this.hydrate(e),o=s.plugins.get(t);if(!o)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\uFF08\u53EF\u7528\u63D2\u4EF6: ${[...s.plugins.keys()].join(", ")||"\u65E0"}\uFF09`};if(!o.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u5DF2\u505C\u7528\uFF0C\u53EF\u8BA9\u7528\u6237\u5728\u9762\u677F\u6216\u7528 plugin-manager.manage enable \u542F\u7528`};const a=o.tools.find(u=>u.name===n);if(!a)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5DE5\u5177 ${n}\uFF08\u53EF\u7528: ${o.tools.map(u=>u.name).join(", ")||"\u65E0"}\uFF09`};if(a.inputSchema){const u=V(a.inputSchema,r);if(u.length>0)return{ok:!1,error:`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${u.join("; ")}`,inputSchema:a.inputSchema}}return this.executeHandler(e,o,a,r,i)}buildManageRequest(e){const t=e.action;if(typeof t!="string"||!Pe.has(t))return null;const n={action:t};if(typeof e.name=="string"&&e.name.trim()&&(n.name=e.name.trim()),typeof e.source=="string"&&e.source.trim()&&(n.source=e.source.trim()),e.config&&typeof e.config=="object"&&!Array.isArray(e.config)){const r={};for(const[i,s]of Object.entries(e.config))typeof s=="string"&&(r[i]=s);n.config=r}return n}async executeHandler(e,t,n,r,i){const s=Date.now(),o=n.handler??{type:"process"};try{return o.type==="mcp"?{ok:!1,error:"handler.type=mcp \u5C06\u5728\u540E\u7EED\u7248\u672C\u652F\u6301\uFF0C\u8BF7\u6539\u7528 process/module handler"}:o.type==="module"?{ok:!0,result:await this.invokeModuleHandler(t,o,r,e,i),durationMs:Date.now()-s}:!o.command||!o.command.trim()?{ok:!1,error:`\u5DE5\u5177 ${n.name} \u7684 process handler \u7F3A\u5C11 command`}:{ok:!0,result:await this.invokeProcessHandler(t,o,r,e,i),durationMs:Date.now()-s}}catch(a){return{ok:!1,error:a instanceof Error?a.message:String(a),durationMs:Date.now()-s}}}async invokeProcessHandler(e,t,n,r,i){const s=Y(t.command??"",{params:n});if(s.length===0)throw new Error("process handler command \u4E3A\u7A7A");const o=typeof t.timeoutMs=="number"&&t.timeoutMs>0?t.timeoutMs:ne,a=new AbortController,u=()=>a.abort();i?.signal?.addEventListener("abort",u,{once:!0});const c=setTimeout(()=>a.abort(),o);try{return await new Promise((d,y)=>{f.info("[plugin:%s] spawn: %s",e.name,s.join(" "));const h=_(s[0],s.slice(1),{cwd:e.dir,env:this.buildPluginEnv(e,r),shell:t.shell===!0,windowsHide:!0,signal:a.signal});let p="",m="";h.stdin?.on("error",()=>{}),h.stdout?.on("data",v=>{p.length<R&&(p+=v.toString("utf8"))}),h.stderr?.on("data",v=>{m.length<R&&(m+=v.toString("utf8"))}),h.on("error",v=>{y(new Error(`\u63D2\u4EF6\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${v.message}`))}),h.on("close",v=>{const L=p.trim();if(v!==0){const O=A(m.trim()||L||"(\u65E0\u8F93\u51FA)",600);y(new Error(a.signal.aborted?`\u63D2\u4EF6\u8FDB\u7A0B\u8D85\u65F6(${o}ms)\u6216\u88AB\u4E2D\u6B62`:`\u63D2\u4EF6\u8FDB\u7A0B\u9000\u51FA\u7801 ${v}: ${O}`));return}if(!L){d({ok:!0});return}try{d(JSON.parse(L))}catch{d(L)}});try{t.stdin==="params"?h.stdin?.end(`${JSON.stringify(n)}
7
+ `):h.stdin?.end()}catch{}})}finally{clearTimeout(c),i?.signal?.removeEventListener("abort",u)}}async invokeModuleHandler(e,t,n,r,i){if(!t.module)throw new Error("module handler \u7F3A\u5C11 module \u8DEF\u5F84");const s=g(e.dir,t.module);let o=e.moduleCache.get(s);o||(o=await import(`${le(s).href}?acode_nonce=${e.importNonce}`),e.moduleCache.set(s,o));const a=t.export||"default",c=o[a];if(typeof c!="function")throw new Error(`\u6A21\u5757 ${t.module} \u672A\u5BFC\u51FA\u51FD\u6570 ${a}`);const d=typeof t.timeoutMs=="number"&&t.timeoutMs>0?t.timeoutMs:ne;let y;const h=Promise.resolve().then(()=>c(n,{agentId:r,signal:i?.signal,pluginRoot:e.dir}));try{return await Promise.race([h,new Promise((p,m)=>{y=setTimeout(()=>m(new Error(`\u63D2\u4EF6\u6A21\u5757\u6267\u884C\u8D85\u65F6(${d}ms)`)),d)})])}finally{clearTimeout(y)}}buildPluginEnv(e,t){const n={};for(const i of["PATH","HOME","USERPROFILE","SystemRoot","COMSPEC","TEMP","TMP","LANG","TZ"]){const s=process.env[i];s!==void 0&&(n[i]=s)}n.ACODE_PLUGIN_ROOT=e.dir,n.ACODE_AGENT_ID=t,n.ACODE_PLUGIN_NAME=e.name;const r=new Set((e.userConfig??[]).map(i=>i.key));for(const[i,s]of Object.entries(e.configValues))r.has(i)&&(!Le.test(i)||De.has(i.toUpperCase())||(n[i]=s));return n}async manage(e,t){const n=this.agentState(e),r=n.queue.then(async()=>{const i=await this.hydrate(e);return this.doManage(i,t)});return n.queue=r.catch(()=>{}),r}async doManage(e,t){if(t.name===$&&(t.action==="uninstall"||t.action==="disable"||t.action==="enable"||t.action==="reload"))return{ok:!1,error:`\u5185\u7F6E\u7CFB\u7EDF\u63D2\u4EF6 ${$} \u4E0D\u53EF${t.action==="uninstall"?"\u5378\u8F7D":t.action==="reload"?"\u91CD\u8F7D":"\u505C\u7528/\u542F\u7528"}`};switch(t.action){case"list":return{ok:!0,plugins:await this.list(e.agentId)};case"install":return this.installPlugin(e,t);case"uninstall":return this.uninstallPlugin(e,t);case"reload":return this.reloadPlugin(e,t);case"enable":case"disable":return this.setEnabled(e,t,t.action==="enable");default:return{ok:!1,error:`\u672A\u77E5 action: ${String(t.action)}`}}}async installPlugin(e,t){const n=(t.source??"").trim();if(!n)return{ok:!1,error:"install \u9700\u8981 source\uFF08\u5F53\u524D\u652F\u6301 local:<\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>\uFF09"};const r=n.split(":",1)[0];if(r!=="local")return{ok:!1,error:`\u6682\u4E0D\u652F\u6301\u63D2\u4EF6\u6765\u6E90 "${r}:"\uFF08npm:/git: \u5728\u8DEF\u7EBF\u56FE\u4E2D\uFF1Bzip \u5305\u8BF7\u7528\u9762\u677F\u5BFC\u5165\u6216 POST /runtime/plugins/:agentId/upload\uFF09`};const i=n.slice(6).trim();return!i||!w(g(i,"plugin.json"))?{ok:!1,error:`\u63D2\u4EF6\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u7F3A\u5C11 plugin.json: ${i}`}:this.installFromDirectory(e,i,n,t.config)}async installFromZip(e,t,n,r){if(!t||t.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};const i=this.agentState(e),s=i.queue.then(async()=>{await this.hydrate(e);const o=g(this.rootDir,"tmp",`upload-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const a=await x(t,o);return w(g(a.pluginDir,"plugin.json"))?(f.info("[agent:%s] zip \u5BFC\u5165: %s\uFF08%d \u4E2A\u6587\u4EF6\uFF09",e,n,a.fileCount),await this.installFromDirectory(i,a.pluginDir,`upload:${n}`,r)):{ok:!1,error:"zip \u5185\u672A\u627E\u5230 plugin.json\uFF08\u8BF7\u6253\u5305\u63D2\u4EF6\u76EE\u5F55\uFF0C\u4E14 zip \u5185\u8DEF\u5F84\u4F7F\u7528\u82F1\u6587\uFF09"}}catch(a){const u=a instanceof Error?a.message:String(a);return f.warn("[agent:%s] zip \u5BFC\u5165\u5931\u8D25: %s",e,u),{ok:!1,error:`zip \u5BFC\u5165\u5931\u8D25: ${u}`}}finally{await C(o,3,100).catch(()=>{})}});return i.queue=s.catch(()=>{}),s}async installFromDirectory(e,t,n,r){const i=this.loadManifestOnly(t);if(!i.ok)return i;const s=i.manifest,o=s.name;if(o===$)return{ok:!1,error:`\u63D2\u4EF6\u540D ${o} \u4E3A\u7CFB\u7EDF\u4FDD\u7559\u540D\u79F0\uFF0C\u4E0D\u5141\u8BB8\u5B89\u88C5\u540C\u540D\u63D2\u4EF6`};const a=this.validateUserConfigValues(s,r??{});if(a)return{ok:!1,error:a};const u=this.loadPluginFromDir(e,t,n,new Date().toISOString(),r??{});if(!u.ok)return f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u6821\u9A8C\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,u.error),u;const c=g(this.rootDir,"cache",N(e.agentId),o),d=t===c,y=e.plugins.get(o);if(y&&this.stopAllListeners(y),!d)try{await C(c),await ie(t,c)}catch(m){const v=m instanceof Error?m.message:String(m);return f.warn("[agent:%s] \u63D2\u4EF6\u79FB\u52A8\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,v),y&&this.startAllListeners(e,y),{ok:!1,error:`\u63D2\u4EF6\u79FB\u52A8\u5931\u8D25: ${v}`}}const h=this.loadPluginFromDir(e,c,n,new Date().toISOString(),r??{});if(!h.ok){if(f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,h.error),!d)try{await ie(c,t)}catch(m){f.warn("[agent:%s] \u88C5\u8F7D\u5931\u8D25\u540E\u65E0\u6CD5\u79FB\u56DE\u6E90\u76EE\u5F55\uFF08%s\uFF09\uFF0C\u5DF2\u4FDD\u7559\u7F13\u5B58\u526F\u672C",e.agentId,m instanceof Error?m.message:String(m))}if(y)try{this.startAllListeners(e,y)}catch(m){f.warn("[agent:%s] \u6062\u590D\u65E7\u5B9E\u4F8B\u76D1\u542C\u5931\u8D25: %s",e.agentId,m instanceof Error?m.message:String(m))}return h}const p=h.plugin;return e.plugins.set(p.name,p),this.bumpCatalogRevision(e),this.persistInstalled(e),this.startAllListeners(e,p),f.info("[agent:%s] \u63D2\u4EF6\u5DF2\u5B89\u88C5: %s@%s",e.agentId,p.name,p.version??"?"),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(p)}}async uninstallPlugin(e,t){const n=(t.name??"").trim(),r=e.plugins.get(n);return r?(this.stopAllListeners(r),e.plugins.delete(n),this.bumpCatalogRevision(e),this.readSharedManifest().some(s=>s.pluginName===n)&&this.removeRuntimeLink(e.agentId,n),this.persistInstalled(e),await C(r.dir),f.info("[agent:%s] \u63D2\u4EF6\u5DF2\u5378\u8F7D: %s",e.agentId,n),this.notifyPluginsChanged(e.agentId),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${n} \u672A\u5B89\u88C5`}}async reloadPlugin(e,t){const n=(t.name??"").trim(),r=e.plugins.get(n);if(!r)return{ok:!1,error:`\u63D2\u4EF6 ${n} \u672A\u5B89\u88C5`};const i=this.loadPluginFromDir(e,r.dir,r.source,r.installedAt,r.configValues);if(!i.ok)return{ok:!1,error:`\u91CD\u8F7D\u5931\u8D25\uFF08\u4FDD\u7559\u65E7\u7248\u672C\u8FD0\u884C\uFF09: ${i.error}`};const s=i.plugin;return this.stopAllListeners(r),e.plugins.set(n,s),this.bumpCatalogRevision(e),this.persistInstalled(e),this.startAllListeners(e,s),f.info("[agent:%s] \u63D2\u4EF6\u5DF2\u91CD\u8F7D: %s",e.agentId,n),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(s)}}async setEnabled(e,t,n){const r=(t.name??"").trim(),i=e.plugins.get(r);return i?(i.enabled=n,this.bumpCatalogRevision(e),n?this.startAllListeners(e,i):this.stopAllListeners(i),this.persistInstalled(e),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(i)}):{ok:!1,error:`\u63D2\u4EF6 ${r} \u672A\u5B89\u88C5`}}deployedDir(){return g(this.rootDir,"deployed")}deployedManifestFile(){return g(this.deployedDir(),"manifest.json")}deployedPluginDir(e){if(!B(e))throw new Error(`\u975E\u6CD5\u63D2\u4EF6\u540D\uFF08\u4EC5\u5141\u8BB8 ${z}\uFF09: ${JSON.stringify(e)}`);const t=g(this.deployedDir(),e),n=Z(this.deployedDir());if(Z(t)!==g(n,e))throw new Error(`\u63D2\u4EF6\u76EE\u5F55\u8D8A\u51FA\u90E8\u7F72\u533A: ${e}`);return t}legacySharedDir(){return g(this.rootDir,"shared")}readSharedManifest(){try{const e=JSON.parse(k(this.deployedManifestFile(),"utf8"));return Array.isArray(e.plugins)?e.plugins.filter(t=>t&&B(t.pluginName)):[]}catch{return[]}}writeSharedManifest(e){D(this.deployedDir(),{recursive:!0}),U(this.deployedManifestFile(),`${JSON.stringify({version:2,plugins:e},null,2)}
8
+ `,"utf8")}async migrateLegacySharedIfNeeded(){try{if(w(this.deployedManifestFile()))return;const e=g(this.legacySharedDir(),"manifest.json");if(!w(e))return;const t=JSON.parse(k(e,"utf8")),n=Array.isArray(t.plugins)?t.plugins:[];if(n.length===0)return;const r=[];for(const i of n){const s=g(this.legacySharedDir(),i.zipFile);if(!(!i.pluginName||!w(s)))try{const o=await this.deployPluginZipToPersistentDir(k(s),i.pluginName);if(!o)continue;r.push(o),f.info("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u5230\u90E8\u7F72\u533A: %s",i.pluginName)}catch(o){f.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6 %s \u8FC1\u79FB\u5931\u8D25: %s",i.pluginName,o instanceof Error?o.message:String(o))}}r.length>0&&this.writeSharedManifest(r),E(this.legacySharedDir(),{recursive:!0,force:!0})}catch(e){f.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u672A\u6267\u884C\uFF08\u4E0B\u6B21\u91CD\u8BD5\uFF09: %s",e instanceof Error?e.message:String(e))}}deployedPluginHealthy(e){return w(g(this.deployedPluginDir(e),"plugin.json"))}runtimeDirFor(e){return g(this.runtimeRootDir,N(e))}runtimeLinkPath(e,t){return g(this.runtimeDirFor(e),t)}ensureRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t),r=this.deployedPluginDir(t);if(!w(g(r,"plugin.json")))return!1;D(this.runtimeDirFor(e),{recursive:!0});try{if(w(n)){let i=!1;try{i=se(n).isSymbolicLink()}catch{i=!1}if(i)try{return j(n),!0}catch{}E(n,{recursive:!0,force:!0})}return oe(r,n,Oe),f.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u5EFA\u7ACB: %s \u2192 %s",e,n,r),!0}catch(i){return f.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5931\u8D25\uFF08%s \u2192 %s\uFF09: %s",e,t,r,i instanceof Error?i.message:String(i)),!1}}removeRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t);try{w(n)&&(E(n,{recursive:!0,force:!0}),f.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u79FB\u9664: %s",e,t))}catch(r){f.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u79FB\u9664\u5931\u8D25\uFF08%s\uFF09: %s",e,t,r instanceof Error?r.message:String(r))}}async saveSharedPlugin(e,t,n=!0,r){if(!e||e.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};await this.migrateLegacySharedIfNeeded();const i=g(this.rootDir,"tmp",`deploy-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const s=await x(e,i),o=this.loadManifestOnly(s.pluginDir);if(!o.ok)return o;const a=o.manifest.name,u=this.readSharedManifest().find(p=>p.pluginName===a);if(u&&u.sha256===r&&this.deployedPluginHealthy(a))return{ok:!0,pluginName:a};await this.suspendDeployedPluginAcrossAgents(a),D(this.deployedDir(),{recursive:!0});const c=this.deployedPluginDir(a),d=g(this.deployedDir(),`.old-${a}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);if(w(c))try{H(c,d)}catch{E(c,{recursive:!0,force:!0})}try{F(s.pluginDir,c,{recursive:!0,filter:p=>!/[\\/]\.git([\\/]|$)/.test(p)&&!/[\\/]node_modules([\\/]|$)/.test(p)})}catch(p){throw w(d)&&(E(c,{recursive:!0,force:!0}),H(d,c)),p}w(d)&&E(d,{recursive:!0,force:!0}),await X(this.deployedManifestFile(),async()=>{const p=this.readSharedManifest().filter(m=>m.pluginName!==a);p.push({pluginName:a,zipFile:u?.zipFile??`${a}.zip`,fileName:t,defaultEnabled:n,sha256:r}),this.writeSharedManifest(p)}),f.info("[shared] \u63D2\u4EF6\u5DF2\u90E8\u7F72\u5230 bridge: %s\uFF08\u6765\u6E90 %s%s\uFF09",a,t,r?`, sha256=${r.slice(0,12)}\u2026`:"");const h=(await this.applySharedToKnownAgents()).find(p=>p.installed.includes(a));return h&&f.info("[shared] \u5DF2\u540C\u6B65\u5230\u8FD0\u884C\u4E2D agent: %s",h.agentId),{ok:!0,pluginName:a}}catch(s){const o=s instanceof Error?s.message:String(s);return f.warn("[shared] \u63D2\u4EF6\u90E8\u7F72\u5931\u8D25\uFF08%s\uFF09: %s",t,o),{ok:!1,error:`\u63D2\u4EF6\u90E8\u7F72\u5931\u8D25: ${o}`}}finally{await C(i,3,100).catch(()=>{})}}async deployPluginZipToPersistentDir(e,t){if(!e||e.length===0)return null;const n=g(this.rootDir,"tmp",`migrate-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const r=await x(e,n),i=this.loadManifestOnly(r.pluginDir);if(!i.ok)return null;const s=i.manifest.name;if(t&&s!==t)return null;D(this.deployedDir(),{recursive:!0});const o=this.deployedPluginDir(s);return w(o)&&E(o,{recursive:!0,force:!0}),F(r.pluginDir,o,{recursive:!0,filter:a=>!/[\\/]\.git([\\/]|$)/.test(a)&&!/[\\/]node_modules([\\/]|$)/.test(a)}),{pluginName:s,zipFile:`${s}.zip`,fileName:`${s}.zip`,defaultEnabled:!0}}finally{E(n,{recursive:!0,force:!0})}}async suspendDeployedPluginAcrossAgents(e){for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const n=t.queue.then(async()=>{const r=t.plugins.get(e);r&&(this.stopAllListeners(r),t.plugins.delete(e),this.bumpCatalogRevision(t),f.info("[agent:%s] \u5DF2\u6458\u9664\u63D2\u4EF6\u7B49\u5F85\u90E8\u7F72\u533A\u66F4\u65B0: %s",t.agentId,e))});t.queue=n.catch(()=>{}),await n}}async applySharedToKnownAgents(){const e=[];for(const t of this.agents.values()){if(!t.hydrated)continue;const n=await this.syncSharedIntoStateQueued(t);n.length>0&&e.push({agentId:t.agentId,installed:n})}return e}async syncSharedIntoStateQueued(e){const t=e.queue.then(()=>this.syncSharedIntoState(e));return e.queue=t.catch(()=>[]),t}effectiveSharedEnabled(e,t){return ye(e,"plugins",t.pluginName)&&(t.defaultEnabled??!0)}async pullTemplatePluginsFromCapabilities(e){const t=Se(e.agentId);if(!t)return;const n=this.readSharedManifest();for(const[r,i]of Object.entries(t)){if(!i.url)continue;const s=n.find(a=>a.pluginName===r);if(!s||!s.sha256||s.sha256===i.sha256&&this.deployedPluginHealthy(r)||this.templatePullInFlight.has(r))continue;this.templatePullInFlight.add(r);const o=g(this.rootDir,"tmp",`pull-${N(e.agentId)}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{D(o,{recursive:!0});let a=`${r}.zip`;try{const y=decodeURIComponent(i.url.split("/").pop()||"");y.toLowerCase().endsWith(".zip")&&(a=ge(y,`${r}.zip`))}catch{}const u=await fe({downloadUrl:i.url,fileName:a,sha256:i.sha256},o);if(!u)continue;const c=k(u.outputPath),d=await this.saveSharedPlugin(c,u.fileName,s.defaultEnabled??!0,i.sha256);d.ok?f.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u81EA\u52A8\u5BF9\u8D26\u66F4\u65B0\u6210\u529F: %s",e.agentId,d.pluginName??r):f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u66F4\u65B0\u5931\u8D25: %s: %s",e.agentId,r,d.error)}catch(a){f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6 %s \u66F4\u65B0\u5931\u8D25: %s",e.agentId,r,a instanceof Error?a.message:String(a))}finally{this.templatePullInFlight.delete(r),await C(o,3,100).catch(()=>{})}}}queueTemplatePull(e){this.backgroundTemplatePulls.has(e.agentId)||(this.backgroundTemplatePulls.add(e.agentId),this.pullTemplatePluginsFromCapabilities(e).catch(t=>{f.warn("[agent:%s] \u540E\u53F0\u63D2\u4EF6\u5BF9\u8D26\u66F4\u65B0\u5931\u8D25: %s",e.agentId,t instanceof Error?t.message:String(t))}).finally(()=>{this.backgroundTemplatePulls.delete(e.agentId)}))}async syncSharedIntoState(e){this.queueTemplatePull(e);const t=this.readSharedManifest(),n=new Set,r=[];let i=0;for(const s of t)if(n.add(s.pluginName),this.effectiveSharedEnabled(e.agentId,s)){const a=e.plugins.get(s.pluginName);if(!this.ensureRuntimeLink(e.agentId,s.pluginName))continue;const u=this.runtimeLinkPath(e.agentId,s.pluginName);if(!a){const c=this.loadPluginFromDir(e,u,`shared:${s.fileName}`,new Date().toISOString(),{});c.ok?(e.plugins.set(c.plugin.name,c.plugin),r.push(c.plugin.name),f.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u5DF2\u6309\u5F00\u542F\u6001\u52A0\u8F7D: %s",e.agentId,s.pluginName)):f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25: %s: %s",e.agentId,s.pluginName,c.error)}}else{const a=e.plugins.get(s.pluginName);a&&(this.stopAllListeners(a),e.plugins.delete(s.pluginName),i++),this.removeRuntimeLink(e.agentId,s.pluginName)}return this.cleanupRuntimeDir(e,n),(r.length>0||i>0)&&this.bumpCatalogRevision(e),this.persistInstalled(e),r}cleanupRuntimeDir(e,t){const n=this.runtimeDirFor(e.agentId);try{if(!w(n))return;const r=new Set(t);for(const i of j(n))!r.has(i)&&!e.plugins.has(i)&&this.removeRuntimeLink(e.agentId,i)}catch{}}async applyCapabilities(e){const t=await this.hydrate(e);await this.pullTemplatePluginsFromCapabilities(t),await this.syncSharedIntoState(t)}async drainEvents(e,t={}){const n=await this.hydrate(e);this.ensureListenersRunning(n);const r=n.buffer.drain(t),i=await this.getCatalog(e);return{revision:r.revision,events:r.events,catalog:i,compactionSeq:n.compactionSeq}}markAgentCompacted(e){const t=this.agentState(e);t.compactionSeq++,f.debug("[agent:%s] \u4E0A\u4E0B\u6587\u538B\u7F29\u6807\u8BB0: compactionSeq=%d",e,t.compactionSeq)}async enqueueExternalEvent(e,t,n){const r=await this.hydrate(e),i=r.plugins.get(t);if(!i||!i.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\u6216\u5DF2\u505C\u7528`};const s=typeof n.event=="string"?n.event:"",o=i.listeners.find(a=>a.transport.type==="http-callback"&&(!s||a.event===s));return o?(this.enqueueEvent(r,i,o,n),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5339\u914D\u7684 http-callback \u76D1\u542C\u5668\uFF08event=${s||"(\u7A7A)"}\uFF09`}}bumpCatalogRevision(e){e.catalogRevision++}agentState(e){let t=this.agents.get(e);return t||(t={agentId:e,plugins:new Map,buffer:new we(e),hydrated:!1,queue:Promise.resolve(),catalogRevision:0,eventSeq:0,compactionSeq:0},this.agents.set(e,t)),t}async hydrate(e){const t=this.agentState(e);return t.hydratePromise||(t.hydratePromise=this.doHydrate(t).catch(n=>{throw t.hydratePromise=void 0,n})),await t.hydratePromise,t}async doHydrate(e){const t=e.agentId;await this.migrateLegacySharedIfNeeded();const n=this.installedFile(t);if(!w(n)){await this.syncSharedIntoState(e).catch(()=>{}),e.hydrated=!0;return}try{const r=JSON.parse(k(n,"utf8")),i=this.readSecrets(t);for(const s of r.plugins??[]){if(String(s.source||"").startsWith("shared:"))continue;const a=g(this.rootDir,"cache",N(t),s.name);if(!w(g(a,"plugin.json"))){f.warn("[agent:%s] \u5DF2\u5B89\u88C5\u63D2\u4EF6\u76EE\u5F55\u7F3A\u5931\uFF0C\u8DF3\u8FC7: %s",t,s.name);continue}const u={...s.config,...i[s.name]??{}},c=this.loadPluginFromDir(e,a,s.source,s.installedAt,u);if(c.ok){const d=c.plugin;d.enabled=s.enabled,e.plugins.set(d.name,d)}else f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25: %s: %s",t,s.name,c.error)}}catch(r){const i=r instanceof Error?r.message:String(r);f.error("[agent:%s] installed.json \u89E3\u6790\u5931\u8D25: %s",t,i)}await this.syncSharedIntoState(e).catch(r=>{f.warn("[agent:%s] \u5171\u4EAB\u63D2\u4EF6\u540C\u6B65\u5931\u8D25: %s",t,r instanceof Error?r.message:String(r))}),e.hydrated=!0}installedFile(e){return g(this.rootDir,"agents",N(e),"installed.json")}persistInstalled(e){this.persistSecrets(e);const t=this.installedFile(e.agentId);D(J(t),{recursive:!0});const n=[...e.plugins.values()].map(r=>({name:r.name,source:r.source,installedAt:r.installedAt,enabled:r.enabled,config:this.stripSensitiveValues(r)}));U(t,`${JSON.stringify({version:1,plugins:n},null,2)}
9
+ `,"utf8")}sensitiveKeysOf(e){return(e.userConfig??[]).filter(t=>t?.sensitive===!0&&typeof t.key=="string").map(t=>t.key)}stripSensitiveValues(e){const t=new Set(this.sensitiveKeysOf(e)),n={};for(const[r,i]of Object.entries(e.configValues))t.has(r)||(n[r]=i);return n}secretsFile(e){return g(this.rootDir,"agents",N(e),"secrets.json")}readSecrets(e){try{const t=JSON.parse(k(this.secretsFile(e),"utf8"));if(!P(t)||!P(t.secrets))return{};const n={};for(const[r,i]of Object.entries(t.secrets)){if(!P(i))continue;const s={};for(const[o,a]of Object.entries(i))typeof a=="string"&&(s[o]=a);n[r]=s}return n}catch{return{}}}persistSecrets(e){const t={};for(const r of e.plugins.values()){const i={};for(const s of this.sensitiveKeysOf(r)){const o=r.configValues[s];typeof o=="string"&&o.length>0&&(i[s]=o)}Object.keys(i).length>0&&(t[r.name]=i)}const n=this.secretsFile(e.agentId);if(Object.keys(t).length===0){try{E(n,{force:!0})}catch{}return}D(J(n),{recursive:!0}),U(n,`${JSON.stringify({version:1,secrets:t},null,2)}
10
+ `,{encoding:"utf8",mode:384})}readJsonFile(e){if(!w(e))return{ok:!0,data:{}};try{const t=JSON.parse(k(e,"utf8"));return P(t)?{ok:!0,data:t}:{ok:!1,error:`${e}: \u6839\u8282\u70B9\u987B\u4E3A\u5BF9\u8C61`}}catch(t){const n=t instanceof Error?t.message:String(t);return{ok:!1,error:`${e}: JSON \u89E3\u6790\u5931\u8D25: ${n}`}}}loadManifestOnly(e){const t=this.readJsonFile(g(e,"plugin.json"));if(!t.ok)return t;const n=t.data,r=Me(n);return r?{ok:!1,error:r}:{ok:!0,manifest:n}}validateUserConfigValues(e,t){const n=Array.isArray(e.userConfig)?e.userConfig:[],r={...t};for(const i of n){if(!i||typeof i.key!="string"||!/^[A-Za-z_][A-Za-z0-9_]*$/.test(i.key))return"plugin.json: userConfig.key \u975E\u6CD5\uFF08\u987B\u4E3A\u73AF\u5883\u53D8\u91CF\u540D\uFF09";if(!(typeof r[i.key]=="string"&&r[i.key].length>0)&&i.required){const o=i.default!==void 0&&typeof i.default=="string"?i.default:"";if(!o)return`\u7F3A\u5C11\u5FC5\u9700\u914D\u7F6E ${i.key}${i.description?`\uFF08${i.description}\uFF09`:""}\uFF0C\u5B89\u88C5\u65F6\u8BF7\u5728 config \u4E2D\u63D0\u4F9B`;r[i.key]=o}}return null}loadPluginFromDir(e,t,n,r,i){const s=this.loadManifestOnly(t);if(!s.ok)return s;const o=s.manifest,a=g(t,o.tools??"tools/tools.json"),u=this.readJsonFile(a);if(!u.ok)return u;const c=[],d=Array.isArray(u.data.tools)?u.data.tools:[];for(const S of d){const T=_e(S);if(T)return{ok:!1,error:`${o.tools??"tools/tools.json"}: ${T}`};c.push(S)}const y=g(t,o.listeners??"listeners/listeners.json"),h=this.readJsonFile(y);if(!h.ok)return h;const p=[],m=Array.isArray(h.data.listeners)?h.data.listeners:[];for(const S of m){const T=Fe(S);if(T)return{ok:!1,error:`${o.listeners??"listeners/listeners.json"}: ${T}`};p.push(S)}const v=Array.isArray(o.userConfig)?o.userConfig:[],L=this.validateUserConfigValues(o,i);if(L)return{ok:!1,error:L};const O={...i};for(const S of v){if(!S||typeof S.key!="string")continue;!(typeof O[S.key]=="string"&&O[S.key].length>0)&&S.required&&S.default!==void 0&&typeof S.default=="string"&&(O[S.key]=S.default)}const M=o.commands;let K;if(typeof M=="string"&&M.trim()){const S=g(t,M.trim());w(S)&&(K=S)}return{ok:!0,plugin:{name:o.name,version:typeof o.version=="string"?o.version:void 0,description:typeof o.description=="string"?o.description:void 0,source:n,installedAt:r,dir:t,enabled:!0,tools:c,listeners:p,commandDir:K,userConfig:v,configValues:O,status:"enabled",runtimes:p.map(S=>({def:S,stopping:!1,restarts:0,logs:[]})),moduleCache:new Map,importNonce:++this.moduleNonce}}}ensureListenersRunning(e){for(const t of e.plugins.values())if(t.enabled)for(const n of t.runtimes)!n.child&&!n.timer&&!n.backoffTimer&&!n.stopping&&this.startListener(e,t,n)}startAllListeners(e,t){for(const n of t.runtimes)this.stopListener(n),t.enabled&&this.startListener(e,t,n)}stopAllListeners(e){for(const t of e.runtimes)this.stopListener(t)}startListener(e,t,n){const r=n.def.transport??{type:"command-stream"};if(r.type==="http-callback"){n.stopping=!1;return}if(r.type==="poll-command"){const i=Math.max(5e3,r.intervalMs??3e4);n.stopping=!1,n.timer=setInterval(()=>{this.pollListenerOnce(e,t,n)},i),this.pollListenerOnce(e,t,n);return}if(!r.command){n.lastError="command-stream \u7F3A\u5C11 command",b(n,`ERROR ${n.lastError}`);return}n.stopping=!1,this.spawnListenerChild(e,t,n)}spawnListenerChild(e,t,n){const i=n.def.transport?.command??"",s=Y(i,{});try{b(n,`spawn: ${s.join(" ")}`);const o=_(s[0],s.slice(1),{cwd:t.dir,env:this.buildPluginEnv(t,e.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"]});n.child=o,n.lastError=void 0;let a="";o.stdout?.on("data",u=>{a+=u.toString("utf8");let c=a.indexOf(`
11
+ `);for(;c>=0;){const d=a.slice(0,c).trim();a=a.slice(c+1),d&&this.handleListenerLine(e,t,n,d),c=a.indexOf(`
12
+ `)}a.length>1024*1024&&(a=a.slice(-4096))}),o.stderr?.on("data",u=>{b(n,`stderr: ${A(u.toString("utf8").trimEnd(),400)}`)}),o.on("error",u=>{n.lastError=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${u.message}`,b(n,`ERROR ${n.lastError}`)}),o.on("close",u=>{n.child=void 0,!n.stopping&&(n.lastError=`\u76D1\u542C\u8FDB\u7A0B\u9000\u51FA\uFF08code=${u??"signal"}\uFF09`,b(n,`exit code=${u??"signal"}\uFF0C\u51C6\u5907\u91CD\u542F`),this.scheduleListenerRestart(e,t,n))})}catch(o){const a=o instanceof Error?o.message:String(o);n.lastError=a,b(n,`ERROR spawn: ${a}`),this.scheduleListenerRestart(e,t,n)}}scheduleListenerRestart(e,t,n){if(n.stopping)return;const r=Math.max(500,n.def.transport?.restartBackoffMs??2e3),i=Math.min(Ne,r*2**Math.min(n.restarts,6));n.restarts++,b(n,`restart #${n.restarts} in ${i}ms`),n.backoffTimer=setTimeout(()=>{n.backoffTimer=void 0,n.stopping||this.spawnListenerChild(e,t,n)},i)}async pollListenerOnce(e,t,n){if(n.polling)return;const r=n.def.transport?.command??"",i=Y(r,{});if(i.length===0)return;n.polling=!0;const s=new AbortController,o=setTimeout(()=>s.abort(),q);try{const a=await new Promise((u,c)=>{const d=_(i[0],i.slice(1),{cwd:t.dir,env:this.buildPluginEnv(t,e.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"],signal:s.signal});let y="",h="";d.stdout?.on("data",m=>{y.length<R&&(y+=m.toString("utf8"))}),d.stderr?.on("data",m=>{h.length<R&&(h+=m.toString("utf8"))});const p=()=>s.signal.aborted;d.on("error",m=>{c(p()?new Error(`poll \u8D85\u65F6(${q}ms)`):m)}),d.on("close",m=>{p()?c(new Error(`poll \u8D85\u65F6(${q}ms)`)):m===0?u(y):c(new Error(`exit ${m}: ${A(h||y,300)}`))})});n.lastError=void 0;for(const u of a.split(`
13
+ `)){const c=u.trim();c&&this.handleListenerLine(e,t,n,c)}}catch(a){const u=a instanceof Error?a.message:String(a);n.lastError=u,b(n,`poll \u5931\u8D25: ${u}`)}finally{clearTimeout(o),n.polling=!1}}stopListener(e){if(e.stopping=!0,e.restarts=0,e.child){try{e.child.kill()}catch{}e.child=void 0}e.timer&&(clearInterval(e.timer),e.timer=void 0),e.backoffTimer&&(clearTimeout(e.backoffTimer),e.backoffTimer=void 0)}handleListenerLine(e,t,n,r){b(n,`event: ${A(r,300)}`);let i;try{i=JSON.parse(r)}catch{n.lastError="\u4E8B\u4EF6\u884C\u4E0D\u662F\u5408\u6CD5 JSON\uFF08\u8981\u6C42 JSONL\uFF09";return}if(!P(i))return;const s=typeof i.event=="string"?i.event:n.def.event,o=s===n.def.event?n.def:t.listeners.find(a=>a.event===s);o&&(o.delivery&&o.delivery!=="poll"&&f.debug("[plugin:%s] delivery=%s \u6682\u6309 poll \u4EA4\u4ED8",t.name,o.delivery),this.enqueueEvent(e,t,o,i))}enqueueEvent(e,t,n,r){for(const[y,h]of Object.entries(n.matcher??{})){const p=I(r,y);if(!(Array.isArray(h)?h:[h]).some(v=>JSON.stringify(v)===JSON.stringify(p)))return}let i;if(n.dedupKey){const y=I(r,n.dedupKey);y!=null&&(i=A(String(y),256))}e.eventSeq++;const s=A(He(r.data??r),ke),o=n.promptTemplate?je(n.promptTemplate,r):`\u3010\u63D2\u4EF6\u4E8B\u4EF6\u3011${t.name} \xB7 ${n.event}${n.description?`
14
+ ${n.description}`:""}`,a=(n.toolHints??[]).join(","),u=`${o}
15
+ [plugin-event] plugin=${t.name} event=${n.event}`+(a?` toolHints=${a}`:"")+` payload=${s}`,c={msgId:A(i?`plugin-event-${t.name}-${i}`:`plugin-event-${t.name}-${n.event}-${e.eventSeq}`,512),channel:"plugin-event",senderId:`plugin:${t.name}`,senderName:`\u63D2\u4EF6[${t.name}]`,receiverId:e.agentId||void 0,content:u,requireReply:!1,role:"system",timestamp:new Date().toISOString()},d=n.priority??"normal";e.buffer.push({plugin:t.name,event:n.event,priority:d,dedupKey:i,receivedAt:Date.now(),message:c})}requiredParamsOf(e){const t=e.inputSchema;if(!(!t||!Array.isArray(t.required)))return t.required.filter(n=>typeof n=="string")}toSummary(e){return{name:e.name,version:e.version,description:e.description,status:e.status,enabled:e.enabled,source:e.source,installedAt:e.installedAt,toolCount:e.tools.length,tools:e.tools.map(t=>({name:t.name,title:t.title,description:t.description})),listeners:e.runtimes.map(t=>({event:t.def.event,delivery:t.def.delivery??"poll",running:!!(t.child||t.timer)||t.def.transport?.type==="http-callback",error:t.lastError})),running:e.runtimes.some(t=>!!(t.child||t.timer)||t.def.transport?.type==="http-callback"),error:e.error}}async getLogs(e,t){const n=await this.hydrate(e);if(t===$)return{ok:!0,logs:[`\u2500\u2500 ${$} \u4E3A\u7CFB\u7EDF\u5185\u7F6E\u63D2\u4EF6\uFF08\u65E0\u9700\u5B89\u88C5\uFF09\uFF0C\u65E0\u72EC\u7ACB\u76D1\u542C\u5668\u8FD0\u884C\u65E5\u5FD7\u3002`,"\u5176\u751F\u547D\u5468\u671F\u64CD\u4F5C\uFF08install/reload/disable/enable/list\uFF09\u7531 bridge plugin-manager \u5904\u7406\uFF0C\u53EF\u901A\u8FC7\u300C\u91CD\u8F7D/\u542F\u7528/\u505C\u7528\u300D\u6309\u94AE\u89C2\u5BDF\u72B6\u6001\u53D8\u5316\u3002"]};const r=n.plugins.get(t);if(!r)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5`,logs:[]};const i=[];for(const s of r.runtimes)i.push(`\u2500\u2500 listener ${s.def.event} (${s.def.transport?.type}) ${s.lastError?`[error: ${s.lastError}]`:""}`),i.push(...s.logs);return{ok:!0,logs:i}}async stopAgent(e){const t=this.agents.get(e);if(t){for(const n of t.plugins.values())this.stopAllListeners(n);this.agents.delete(e)}}async stopAll(){for(const e of[...this.agents.keys()])await this.stopAgent(e)}async listDeployed(){await this.migrateLegacySharedIfNeeded();const e=this.readSharedManifest(),t=[];for(const n of e){const r=this.deployedPluginDir(n.pluginName),i=this.deployedPluginHealthy(n.pluginName);let s;if(i)try{const o=JSON.parse(k(g(r,"plugin.json"),"utf8"));typeof o.version=="string"&&(s=o.version)}catch{}t.push({pluginName:n.pluginName,version:s,fileName:n.fileName??`${n.pluginName}.zip`,defaultEnabled:n.defaultEnabled!==!1,sha256:n.sha256,deployed:i})}return t}deployedDefaultEnabled(){const e=this.readSharedManifest(),t={};for(const n of e)t[n.pluginName]=n.defaultEnabled!==!1;return t}async removeDeployedPlugin(e){if(!B(e))return{ok:!1,error:"pluginName \u975E\u6CD5\uFF08\u987B\u4E3A kebab-case\uFF0C1~64 \u5B57\u7B26\uFF09"};await this.migrateLegacySharedIfNeeded();for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const n=t.queue.then(async()=>{const r=t.plugins.get(e);r&&(this.stopAllListeners(r),t.plugins.delete(e)),this.removeRuntimeLink(t.agentId,e),this.persistInstalled(t)});t.queue=n.catch(()=>{}),await n}await X(this.deployedManifestFile(),async()=>{const t=this.readSharedManifest().filter(n=>n.pluginName!==e);this.writeSharedManifest(t)});try{E(this.deployedPluginDir(e),{recursive:!0,force:!0})}catch(t){return{ok:!1,error:`\u90E8\u7F72\u76EE\u5F55\u6E05\u7406\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`}}return f.info("[shared] \u63D2\u4EF6\u5DF2\u4ECE bridge \u79FB\u9664\u90E8\u7F72: %s",e),{ok:!0}}}function B(l){return typeof l=="string"&&l.length>0&&l.length<=64&&z.test(l)}function Me(l){const e=l.name;if(typeof e!="string"||!z.test(e))return`plugin.json: name \u975E\u6CD5\uFF08\u987B\u4E3A kebab-case\uFF09: ${String(e)}`;if(e.length>64)return"plugin.json: name \u8FC7\u957F\uFF08\u226464\uFF09";for(const t of be)if(e===t.replace(/\.$/,"")||e.startsWith(t))return`plugin.json: name \u4F7F\u7528\u4E86\u4FDD\u7559\u524D\u7F00 ${t}`;return Te.test(e)?"plugin.json: name \u542B\u975E ASCII \u5B57\u7B26\uFF08\u540C\u5F62\u5B57\u9632\u62A4\uFF09":l.version!==void 0&&typeof l.version!="string"?"plugin.json: version \u987B\u4E3A\u5B57\u7B26\u4E32":l.userConfig!==void 0&&!Array.isArray(l.userConfig)?"plugin.json: userConfig \u987B\u4E3A\u6570\u7EC4":null}function _e(l){if(!P(l))return"\u5DE5\u5177\u6761\u76EE\u987B\u4E3A\u5BF9\u8C61";const e=l.name;if(typeof e!="string"||!Ae.test(e))return`\u5DE5\u5177 name \u975E\u6CD5: ${String(e)}`;if(typeof l.description!="string"||!l.description.trim())return`\u5DE5\u5177 ${e} \u7F3A\u5C11 description`;const t=l.handler;if(!P(t))return`\u5DE5\u5177 ${e} \u7F3A\u5C11 handler`;const n=t.type;return n!=="process"&&n!=="module"&&n!=="mcp"?`\u5DE5\u5177 ${e} handler.type \u975E\u6CD5: ${String(n)}`:n==="process"&&typeof t.command!="string"?`\u5DE5\u5177 ${e} \u7684 process handler \u7F3A\u5C11 command`:n==="module"&&typeof t.module!="string"?`\u5DE5\u5177 ${e} \u7684 module handler \u7F3A\u5C11 module`:l.inputSchema!==void 0&&!P(l.inputSchema)?`\u5DE5\u5177 ${e} inputSchema \u987B\u4E3A\u5BF9\u8C61`:null}function Fe(l){if(!P(l))return"\u76D1\u542C\u5668\u6761\u76EE\u987B\u4E3A\u5BF9\u8C61";if(typeof l.event!="string"||!l.event.trim())return"\u76D1\u542C\u5668\u7F3A\u5C11 event";const e=l.transport;if(!P(e))return`\u76D1\u542C\u5668 ${String(l.event)} \u7F3A\u5C11 transport`;const t=e.type;if(t!=="command-stream"&&t!=="poll-command"&&t!=="http-callback")return`\u76D1\u542C\u5668 ${String(l.event)} transport.type \u975E\u6CD5: ${String(t)}`;if((t==="command-stream"||t==="poll-command")&&typeof e.command!="string")return`\u76D1\u542C\u5668 ${String(l.event)} \u7684 ${t} transport \u7F3A\u5C11 command`;const n=l.delivery;return n!==void 0&&n!=="poll"&&n!=="force"&&n!=="wake"?`\u76D1\u542C\u5668 ${String(l.event)} delivery \u975E\u6CD5: ${String(n)}`:null}function Y(l,e){return l.trim().split(/\s+/).map(t=>{const n=/^\{\{(.+)\}\}$/.exec(t);if(n){const r=I(e,n[1].trim());return r==null?"":typeof r=="string"?r:JSON.stringify(r)}return t.replace(/\{\{(.+?)\}\}/g,(r,i)=>{const s=I(e,i.trim());return s==null?"":typeof s=="string"?s:JSON.stringify(s)})}).filter(t=>t!=="")}function je(l,e){return l.replace(/\{\{(.+?)\}\}/g,(t,n)=>{let r=I(e,n.trim());return r===void 0&&!n.trim().startsWith("params.")&&(r=I(e,`data.${n.trim()}`)),r==null?"":typeof r=="string"?r:JSON.stringify(r)})}function He(l){try{return JSON.stringify(l)??"null"}catch{return"(\u4E0D\u53EF\u5E8F\u5217\u5316\u7684\u4E8B\u4EF6\u8D1F\u8F7D)"}}const Ue=new Re;me("plugins",()=>Ue.deployedDefaultEnabled());const et=()=>he("plugins");export{Q as BUILTIN_PLUGIN_DESCRIPTION,ee as BUILTIN_PLUGIN_MANAGE_DESC,$ as BUILTIN_PLUGIN_NAME,Re as PluginManager,$e as getBuiltinCommandDir,B as isValidPluginName,Ue as pluginManager,et as reconcilePluginsDefaultsFromDeployed,Y as renderCommandArgv,V as validateAgainstSchema,Me as validateManifest};
10
16
 
@@ -1,4 +1,4 @@
1
- import{execFile as g}from"node:child_process";import{readFile as d,readlink as T}from"node:fs/promises";import{promisify as C}from"node:util";import F from"node:os";const l=C(g);import{createLogger as O}from"../utils/logger.js";const k=O("process-detail"),m=9e3,S=100,I=50,f="\u8FDB\u7A0B\u4E0D\u5B58\u5728\u3001\u5DF2\u9000\u51FA\u6216\u5F53\u524D\u7528\u6237\u65E0\u6743\u67E5\u770B";function v(n){const t=new Map;for(const c of n.split(/\r?\n/)){const a=c.indexOf(":");a<=0||t.set(c.slice(0,a).trim(),c.slice(a+1).trim())}const e=B(t.get("VmSize")),s=B(t.get("VmRSS")),r={},i=t.get("Name"),o=t.get("State"),u=Number(t.get("PPid")),p=Number(t.get("Threads"));return i&&(r.name=i),o&&(r.status=o.split(/\s+/)[0]),Number.isFinite(u)&&(r.ppid=u),Number.isFinite(p)&&(r.threads=p),e!==null&&(r.virtualBytes=e*1024),s!==null&&(r.rssBytes=s*1024),r}function B(n){if(!n)return null;const t=n.match(/^(\d+)\s*kB$/);if(!t)return null;const e=Number(t[1]);return Number.isFinite(e)?e:null}function L(n){const t=Number(n.trim().split(/\s+/)[0]);return Number.isFinite(t)?t:null}function D(n){const t=n.lastIndexOf(")");if(t<0)return null;const e=n.slice(t+1).trim().split(/\s+/),s=Number(e[11]),r=Number(e[12]),i=Number(e[19]);return!Number.isFinite(s)||!Number.isFinite(r)||!Number.isFinite(i)?null:{userTicks:s,systemTicks:r,startTicks:i}}function w(n){const t=n.trim();if(!t||!/^\d/.test(t))return null;const[e,s]=t.includes("-")?t.split("-",2):[void 0,t],r=s.split(":").map(Number);if(r.some(o=>!Number.isFinite(o)))return null;let i=0;for(const o of r)i=i*60+o;if(e!==void 0){if(!/^\d+$/.test(e))return null;i+=Number(e)*86400}return i}function E(n){const[t,e]=n.trim().split("."),s=w(t);return s===null?null:s+(e&&+`0.${e}`||0)}function M(n){const t=n.trim().split(/\s+/);if(t.length<8)return null;const e=t.slice(7).join(" ");if(e.includes("(LISTEN)"))return null;const s=e.match(/\(([A-Z ]+)\)$/),r=e.replace(/\s*\([A-Z ]+\)$/,""),i=r.includes("->")?r.split("->")[1]:r;return i?{remote:i,state:s?s[1]:void 0}:null}function R(n,t){const e=[];for(const s of n.split(/\r?\n/).slice(1)){if(!s.trim()||!s.includes(`pid=${t}`))continue;const r=s.trim().split(/\s+/);if(r[0]==="LISTEN")continue;const i=r[4]||"";i&&e.push({remote:i})}return e}function U(n){const t=[];for(const e of n.split(/\r?\n/).slice(1)){const s=M(e);s&&t.push(s)}return t}function _(n){const t=n.trim();return t?JSON.parse(t):null}async function W(n){let t;try{t=await d(`/proc/${n}/status`,"utf8")}catch{return{ok:!0,pid:n,unsupported:f}}const e=v(t),[s,r,i]=await Promise.all([d(`/proc/${n}/stat`,"utf8").catch(()=>""),d(`/proc/${n}/cmdline`,"utf8").catch(()=>""),d("/proc/uptime","utf8").catch(()=>"")]),o=s?D(s):null,u=i?L(i):null,[p,c,a,$]=await Promise.all([T(`/proc/${n}/exe`).catch(()=>""),d(`/proc/${n}/io`,"utf8").catch(()=>""),l("ps",["-o","user=","-p",String(n)],{encoding:"utf8",timeout:m}).then(N=>N.stdout.trim()).catch(()=>""),l("ss",["-tupn"],{encoding:"utf8",timeout:m}).then(N=>N.stdout).catch(()=>"")]),h=c?j(c):null,P=A(r)||e.name,x=o&&u!==null?Math.max(0,Math.round(u-o.startTicks/S)):void 0;return{ok:!0,pid:n,name:e.name,command:P||void 0,exePath:p||void 0,user:a||void 0,ppid:e.ppid,status:e.status,threads:e.threads,elapsedSeconds:x,cpuUserSeconds:o?y(o.userTicks/S):void 0,cpuSystemSeconds:o?y(o.systemTicks/S):void 0,virtualBytes:e.virtualBytes,rssBytes:e.rssBytes,ioReadBytes:h?.readBytes,ioWriteBytes:h?.writeBytes,connections:$?b(R($,n)):void 0}}function A(n){const t=n.replace(/\0+$/,"");return t?t.split("\0").filter(Boolean).join(" "):""}function j(n){let t,e;for(const s of n.split(/\r?\n/)){const[r,i]=s.split(":");if(!r||i===void 0)continue;const o=Number(i.trim());Number.isFinite(o)&&(r.trim()==="read_bytes"?t=o:r.trim()==="write_bytes"&&(e=o))}return{readBytes:t??0,writeBytes:e??0}}function G(n){const t=n.trim().match(/^(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+([\s\S]+)$/);if(!t)return null;const e=Number(t[2]),s=Number(t[5])*1024,r=Number(t[6])*1024,i=w(t[7]),o=E(t[8]),u={user:t[3],status:t[4],command:t[9].trim()};return Number.isFinite(e)&&(u.ppid=e),Number.isFinite(s)&&(u.rssBytes=s),Number.isFinite(r)&&(u.virtualBytes=r),i!==null&&(u.elapsedSeconds=i),o!==null&&(u.cpuTotalSeconds=y(o)),u}async function K(n){const{stdout:t}=await l("ps",["-ww","-p",String(n),"-o","pid=,ppid=,user=,state=,rss=,vsz=,etime=,cputime=,command="],{encoding:"utf8",timeout:m}),e=t.split(/\r?\n/).find(i=>i.trim()),s=e?G(e):null;if(!s)return{ok:!0,pid:n,unsupported:f};const r=await l("lsof",["-n","-P","-i","TCP","-a","-p",String(n),"+c0"],{encoding:"utf8",timeout:m}).then(i=>i.stdout).catch(()=>"");return{ok:!0,pid:n,user:s.user,ppid:s.ppid,status:s.status,command:s.command||void 0,elapsedSeconds:s.elapsedSeconds,cpuTotalSeconds:s.cpuTotalSeconds,virtualBytes:s.virtualBytes,rssBytes:s.rssBytes,connections:r?b(U(r)):void 0}}function z(n){return`
1
+ import{execFile as g}from"node:child_process";import{readFile as d,readlink as T}from"node:fs/promises";import C from"node:os";import{promisify as F}from"node:util";const l=F(g);import{createLogger as O}from"../utils/logger.js";const k=O("process-detail"),m=9e3,S=100,I=50,f="\u8FDB\u7A0B\u4E0D\u5B58\u5728\u3001\u5DF2\u9000\u51FA\u6216\u5F53\u524D\u7528\u6237\u65E0\u6743\u67E5\u770B";function v(n){const t=new Map;for(const c of n.split(/\r?\n/)){const a=c.indexOf(":");a<=0||t.set(c.slice(0,a).trim(),c.slice(a+1).trim())}const e=B(t.get("VmSize")),s=B(t.get("VmRSS")),r={},i=t.get("Name"),o=t.get("State"),u=Number(t.get("PPid")),p=Number(t.get("Threads"));return i&&(r.name=i),o&&(r.status=o.split(/\s+/)[0]),Number.isFinite(u)&&(r.ppid=u),Number.isFinite(p)&&(r.threads=p),e!==null&&(r.virtualBytes=e*1024),s!==null&&(r.rssBytes=s*1024),r}function B(n){if(!n)return null;const t=n.match(/^(\d+)\s*kB$/);if(!t)return null;const e=Number(t[1]);return Number.isFinite(e)?e:null}function L(n){const t=Number(n.trim().split(/\s+/)[0]);return Number.isFinite(t)?t:null}function D(n){const t=n.lastIndexOf(")");if(t<0)return null;const e=n.slice(t+1).trim().split(/\s+/),s=Number(e[11]),r=Number(e[12]),i=Number(e[19]);return!Number.isFinite(s)||!Number.isFinite(r)||!Number.isFinite(i)?null:{userTicks:s,systemTicks:r,startTicks:i}}function w(n){const t=n.trim();if(!t||!/^\d/.test(t))return null;const[e,s]=t.includes("-")?t.split("-",2):[void 0,t],r=s.split(":").map(Number);if(r.some(o=>!Number.isFinite(o)))return null;let i=0;for(const o of r)i=i*60+o;if(e!==void 0){if(!/^\d+$/.test(e))return null;i+=Number(e)*86400}return i}function E(n){const[t,e]=n.trim().split("."),s=w(t);return s===null?null:s+(e&&+`0.${e}`||0)}function M(n){const t=n.trim().split(/\s+/);if(t.length<8)return null;const e=t.slice(7).join(" ");if(e.includes("(LISTEN)"))return null;const s=e.match(/\(([A-Z ]+)\)$/),r=e.replace(/\s*\([A-Z ]+\)$/,""),i=r.includes("->")?r.split("->")[1]:r;return i?{remote:i,state:s?s[1]:void 0}:null}function R(n,t){const e=[];for(const s of n.split(/\r?\n/).slice(1)){if(!s.trim()||!s.includes(`pid=${t}`))continue;const r=s.trim().split(/\s+/);if(r[0]==="LISTEN")continue;const i=r[4]||"";i&&e.push({remote:i})}return e}function U(n){const t=[];for(const e of n.split(/\r?\n/).slice(1)){const s=M(e);s&&t.push(s)}return t}function _(n){const t=n.trim();return t?JSON.parse(t):null}async function W(n){let t;try{t=await d(`/proc/${n}/status`,"utf8")}catch{return{ok:!0,pid:n,unsupported:f}}const e=v(t),[s,r,i]=await Promise.all([d(`/proc/${n}/stat`,"utf8").catch(()=>""),d(`/proc/${n}/cmdline`,"utf8").catch(()=>""),d("/proc/uptime","utf8").catch(()=>"")]),o=s?D(s):null,u=i?L(i):null,[p,c,a,$]=await Promise.all([T(`/proc/${n}/exe`).catch(()=>""),d(`/proc/${n}/io`,"utf8").catch(()=>""),l("ps",["-o","user=","-p",String(n)],{encoding:"utf8",timeout:m}).then(N=>N.stdout.trim()).catch(()=>""),l("ss",["-tupn"],{encoding:"utf8",timeout:m}).then(N=>N.stdout).catch(()=>"")]),h=c?j(c):null,P=A(r)||e.name,x=o&&u!==null?Math.max(0,Math.round(u-o.startTicks/S)):void 0;return{ok:!0,pid:n,name:e.name,command:P||void 0,exePath:p||void 0,user:a||void 0,ppid:e.ppid,status:e.status,threads:e.threads,elapsedSeconds:x,cpuUserSeconds:o?y(o.userTicks/S):void 0,cpuSystemSeconds:o?y(o.systemTicks/S):void 0,virtualBytes:e.virtualBytes,rssBytes:e.rssBytes,ioReadBytes:h?.readBytes,ioWriteBytes:h?.writeBytes,connections:$?b(R($,n)):void 0}}function A(n){const t=n.replace(/\0+$/,"");return t?t.split("\0").filter(Boolean).join(" "):""}function j(n){let t,e;for(const s of n.split(/\r?\n/)){const[r,i]=s.split(":");if(!r||i===void 0)continue;const o=Number(i.trim());Number.isFinite(o)&&(r.trim()==="read_bytes"?t=o:r.trim()==="write_bytes"&&(e=o))}return{readBytes:t??0,writeBytes:e??0}}function G(n){const t=n.trim().match(/^(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+([\s\S]+)$/);if(!t)return null;const e=Number(t[2]),s=Number(t[5])*1024,r=Number(t[6])*1024,i=w(t[7]),o=E(t[8]),u={user:t[3],status:t[4],command:t[9].trim()};return Number.isFinite(e)&&(u.ppid=e),Number.isFinite(s)&&(u.rssBytes=s),Number.isFinite(r)&&(u.virtualBytes=r),i!==null&&(u.elapsedSeconds=i),o!==null&&(u.cpuTotalSeconds=y(o)),u}async function K(n){const{stdout:t}=await l("ps",["-ww","-p",String(n),"-o","pid=,ppid=,user=,state=,rss=,vsz=,etime=,cputime=,command="],{encoding:"utf8",timeout:m}),e=t.split(/\r?\n/).find(i=>i.trim()),s=e?G(e):null;if(!s)return{ok:!0,pid:n,unsupported:f};const r=await l("lsof",["-n","-P","-i","TCP","-a","-p",String(n),"+c0"],{encoding:"utf8",timeout:m}).then(i=>i.stdout).catch(()=>"");return{ok:!0,pid:n,user:s.user,ppid:s.ppid,status:s.status,command:s.command||void 0,elapsedSeconds:s.elapsedSeconds,cpuTotalSeconds:s.cpuTotalSeconds,virtualBytes:s.virtualBytes,rssBytes:s.rssBytes,connections:r?b(U(r)):void 0}}function z(n){return`
2
2
  $ErrorActionPreference = 'SilentlyContinue'
3
3
  $proc = Get-CimInstance Win32_Process -Filter 'ProcessId=${n}'
4
4
  if (-not $proc) { Write-Output 'null'; exit }
@@ -28,5 +28,5 @@ $row = [pscustomobject]@{
28
28
  connections = $conns
29
29
  }
30
30
  ConvertTo-Json -InputObject $row -Compress -Depth 3
31
- `.trim()}async function V(n){const{stdout:t}=await l("powershell",["-NoProfile","-NonInteractive","-Command",z(n)],{encoding:"utf8",timeout:m,windowsHide:!0}),e=_(t);return!e||!Number.isFinite(Number(e.pid))?{ok:!0,pid:n,unsupported:f}:{ok:!0,pid:n,name:e.name||void 0,command:e.command||void 0,exePath:e.exePath||void 0,user:e.user||void 0,ppid:Number.isFinite(Number(e.ppid))?Number(e.ppid):void 0,threads:Number.isFinite(Number(e.threads))?Number(e.threads):void 0,elapsedSeconds:Number.isFinite(Number(e.elapsedSeconds))?Number(e.elapsedSeconds):void 0,cpuUserSeconds:Number.isFinite(Number(e.cpuUserSeconds))?Number(e.cpuUserSeconds):void 0,cpuSystemSeconds:Number.isFinite(Number(e.cpuSystemSeconds))?Number(e.cpuSystemSeconds):void 0,virtualBytes:Number.isFinite(Number(e.virtualBytes))?Number(e.virtualBytes):void 0,rssBytes:Number.isFinite(Number(e.rssBytes))?Number(e.rssBytes):void 0,ioReadBytes:Number.isFinite(Number(e.ioReadBytes))?Number(e.ioReadBytes):void 0,ioWriteBytes:Number.isFinite(Number(e.ioWriteBytes))?Number(e.ioWriteBytes):void 0,connections:Array.isArray(e.connections)?b(e.connections.filter(s=>s&&s.remote).map(s=>({remote:String(s.remote),state:s.state?String(s.state):void 0}))):void 0}}function b(n){return n.slice(0,I)}function y(n){return Math.round(n*100)/100}async function Q(n){const t=F.platform();try{return t==="win32"?await V(n):t==="darwin"?await K(n):await W(n)}catch(e){return k.debug("Failed to collect process detail:",e),{ok:!0,pid:n,unsupported:f}}}export{Q as collectProcessDetail,G as parseDarwinPsDetailLine,_ as parseJsonObject,A as parseLinuxCmdline,j as parseLinuxIoBytes,D as parseLinuxStatTimes,M as parseLsofConnectionLine,U as parseLsofConnectionsForPid,v as parseProcStatus,L as parseProcUptime,E as parsePsCpuTimeSeconds,w as parsePsEtimeSeconds,R as parseSsConnectionsForPid};
31
+ `.trim()}async function V(n){const{stdout:t}=await l("powershell",["-NoProfile","-NonInteractive","-Command",z(n)],{encoding:"utf8",timeout:m,windowsHide:!0}),e=_(t);return!e||!Number.isFinite(Number(e.pid))?{ok:!0,pid:n,unsupported:f}:{ok:!0,pid:n,name:e.name||void 0,command:e.command||void 0,exePath:e.exePath||void 0,user:e.user||void 0,ppid:Number.isFinite(Number(e.ppid))?Number(e.ppid):void 0,threads:Number.isFinite(Number(e.threads))?Number(e.threads):void 0,elapsedSeconds:Number.isFinite(Number(e.elapsedSeconds))?Number(e.elapsedSeconds):void 0,cpuUserSeconds:Number.isFinite(Number(e.cpuUserSeconds))?Number(e.cpuUserSeconds):void 0,cpuSystemSeconds:Number.isFinite(Number(e.cpuSystemSeconds))?Number(e.cpuSystemSeconds):void 0,virtualBytes:Number.isFinite(Number(e.virtualBytes))?Number(e.virtualBytes):void 0,rssBytes:Number.isFinite(Number(e.rssBytes))?Number(e.rssBytes):void 0,ioReadBytes:Number.isFinite(Number(e.ioReadBytes))?Number(e.ioReadBytes):void 0,ioWriteBytes:Number.isFinite(Number(e.ioWriteBytes))?Number(e.ioWriteBytes):void 0,connections:Array.isArray(e.connections)?b(e.connections.filter(s=>s&&s.remote).map(s=>({remote:String(s.remote),state:s.state?String(s.state):void 0}))):void 0}}function b(n){return n.slice(0,I)}function y(n){return Math.round(n*100)/100}async function Q(n){const t=C.platform();try{return t==="win32"?await V(n):t==="darwin"?await K(n):await W(n)}catch(e){return k.debug("Failed to collect process detail:",e),{ok:!0,pid:n,unsupported:f}}}export{Q as collectProcessDetail,G as parseDarwinPsDetailLine,_ as parseJsonObject,A as parseLinuxCmdline,j as parseLinuxIoBytes,D as parseLinuxStatTimes,M as parseLsofConnectionLine,U as parseLsofConnectionsForPid,v as parseProcStatus,L as parseProcUptime,E as parsePsCpuTimeSeconds,w as parsePsEtimeSeconds,R as parseSsConnectionsForPid};
32
32
 
@@ -1,12 +1,12 @@
1
- import{execSync as L,exec as O}from"child_process";import{promisify as b}from"util";const h=b(O);import g from"os";import{createLogger as k}from"../utils/logger.js";const a=k("process-detector");function z(n,t=15e3){const r=Buffer.from(n,"utf16le").toString("base64");return L(`powershell -NoProfile -NonInteractive -EncodedCommand ${r}`,{encoding:"utf8",timeout:t,windowsHide:!0}).replace(/#\s*<\s*CLIXML[\s\S]*?(?=#<\s*CLIXML|$)/g,"").trim()}async function f(n,t=15e3){const r=Buffer.from(n,"utf16le").toString("base64"),{stdout:s}=await h(`powershell -NoProfile -NonInteractive -EncodedCommand ${r}`,{encoding:"utf8",timeout:t,windowsHide:!0,maxBuffer:10*1024*1024});return s.replace(/#\s*<\s*CLIXML[\s\S]*?(?=#<\s*CLIXML|$)/g,"").trim()}async function w(n){try{if(g.platform()==="win32"){const{stdout:t}=await h(`tasklist /FI "PID eq ${n}" /NH /FO CSV`,{encoding:"utf8",timeout:5e3,windowsHide:!0});return t.includes(String(n))}else return process.kill(n,0),!0}catch{return!1}}function X(n){try{return g.platform()==="win32"?L(`tasklist /FI "PID eq ${n}" /NH /FO CSV`,{encoding:"utf8",timeout:5e3,windowsHide:!0}).includes(String(n)):(process.kill(n,0),!0)}catch{return!1}}async function P(){const n=g.platform(),t=[];try{n==="win32"?t.push(...await A()):t.push(...await F())}catch(e){a.debug("Failed to list processes:",e)}return t}async function A(){const n=[];try{const e=await f(`Get-CimInstance Win32_Process -Filter "Name LIKE '%node%' OR Name LIKE '%claude%' OR Name LIKE '%opencode%' OR Name LIKE '%python%'" | Select-Object ProcessId, CommandLine | ConvertTo-Json -Compress`,1e4);if(!e||!e.trim())return n;let r;try{const s=JSON.parse(e);r=Array.isArray(s)?s:[s]}catch{return n}for(const s of r){if(!s.ProcessId||!s.CommandLine)continue;const i=s.CommandLine;if($(i)){const d=y(i);n.push({pid:s.ProcessId,command:i,agentId:d})}}}catch(t){a.debug("PowerShell process query failed, trying wmic fallback:",t),n.push(...await N())}return n}async function N(){const n=[];try{const{stdout:t}=await h(`wmic process where "name like '%node%' or name like '%claude%' or name like '%opencode%'" get processid,commandline /format:list`,{encoding:"utf8",timeout:5e3,windowsHide:!0}),e=t.split(`
2
- `);let r=null,s=null;for(const i of e){const d=i.trim();if(d.startsWith("CommandLine=")?s=d.substring(12):d.startsWith("ProcessId=")&&(r=d.substring(10)),r&&s){if($(s)){const c=y(s);n.push({pid:parseInt(r,10),command:s,agentId:c})}r=null,s=null}}}catch(t){a.debug("wmic process query failed:",t)}return n}async function F(){const n=[];try{const{stdout:t}=await h('ps aux | grep -E "claude|claude-code|opencode" | grep -v grep',{encoding:"utf8",timeout:5e3}),e=t.split(`
3
- `).filter(r=>r.trim());for(const r of e){const s=r.trim().split(/\s+/);if(s.length>=2){const i=parseInt(s[1],10),d=s.slice(10).join(" ");if($(d)){const c=y(d);n.push({pid:i,command:d,agentId:c})}}}}catch(t){a.debug("ps process query failed:",t)}return n}function $(n){if(!n)return!1;const t=n.toLowerCase();return!!(t.includes("claude")||t.includes("@anthropic-ai/claude-code")||t.includes("opencode")||t.includes("open-code")||t.includes("opencode.exe")||t.includes("opencode.cmd")||t.includes("aws-client-agent-mcp")||t.includes("aws-client-agent")||t.includes("acode")&&t.includes("sdk")||t.includes("cc-switch-sdk")||t.includes("cc-switch"))}function y(n){if(!n)return;const t=n.match(/AWS_AGENT_ID=(\S+)/);if(t)return C(t[1]);const e=n.match(/--agent-id[=\s]+(\S+)/);if(e)return C(e[1]);const r=n.match(/--id[=\s]+(\S+)/);if(r)return C(r[1])}function C(n){if(!n)return n;const t=n[0],e=n[n.length-1];return(t==='"'||t==="'")&&t===e?n.slice(1,-1):n}async function x(n){const e=(await P()).find(r=>r.agentId===n);if(e)return e;if(g.platform()==="win32"){const r=await T(n);if(r)return r;const s=await R(n);if(s)return s}}async function T(n){try{const t=`$targetId = '${n}'; $procs = Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -and ($_.Name -like '*node*' -or $_.Name -like '*claude*' -or $_.Name -like '*opencode*') }; foreach ($proc in $procs) { if ($proc.CommandLine -like "*$targetId*") { @{ProcessId=$proc.ProcessId; CommandLine=$proc.CommandLine; AgentId=$targetId} | ConvertTo-Json -Compress } }`,e=await f(t,1e4);if(!e||!e.trim())return;const r=e.trim().split(`
4
- `).filter(s=>s.trim());for(const s of r)try{const i=JSON.parse(s.trim());if(i.ProcessId)return{pid:i.ProcessId,command:i.CommandLine||"",agentId:i.AgentId||n}}catch{}}catch(t){a.debug("PowerShell env var query failed:",t)}}async function R(n){try{const e=await f("Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId, Name, CommandLine | ConvertTo-Json -Compress",15e3);return!e||!e.trim()?void 0:await W(e.trim(),n)}catch(t){a.debug("[findOrphanByAncestorEnvSearch] Failed:",t)}}async function W(n,t){let e;try{const o=n.replace(/#\s*<\s*CLIXML[\s\S]*?(?=\{|\[|$)/g,"").trim(),u=B(o),l=JSON.parse(u);e=Array.isArray(l)?l:[l]}catch(o){a.debug(`[searchOrphanInProcessTree] JSON parse failed, raw length=${n.length}`,o);return}if(!e.length)return;const r=new Map;for(const o of e)o.processId&&r.set(o.processId,o);function s(o){const u=o.name.toLowerCase(),l=(o.commandLine||"").toLowerCase();return!!(u.includes("claude")||l.includes("claude")||l.includes("@anthropic-ai/claude-code")||l.includes("cli.js")||u.includes("opencode")||l.includes("opencode")||l.includes("serve")&&l.includes("--port"))}function i(o){const u=o.toLowerCase();return u==="powershell.exe"||u==="cmd.exe"||u==="pwsh.exe"||u==="bash.exe"}function d(o){let u=o;const l=10;for(let I=0;I<l;I++){const p=r.get(u);if(!p)break;if(i(p.name)){const m=r.get(p.parentProcessId);if(m&&m.name.toLowerCase()==="node.exe"){const S=(m.commandLine||"").toLowerCase();if(S.includes("runtime-bridge")||S.includes("agentswork"))return a.debug(`[searchOrphanInProcessTree] Found bridge ancestor chain: agent(${o}) -> shell(${p.processId}) -> node(${m.processId})`),{shellPid:p.processId,shellCmd:p.commandLine||""}}}if(u=p.parentProcessId,u<=0)break}return null}for(const o of e){if(!s(o))continue;const u=d(o.processId);if(u){if(u.shellCmd.toLowerCase().includes(t.toLowerCase()))return a.info(`[searchOrphanInProcessTree] Found orphan by tree search (agentId verified): agentId=${t}, pid=${o.processId}, name=${o.name}`),{pid:o.processId,command:o.commandLine||"",agentId:t};const p=e.filter(m=>s(m)&&d(m.processId));if(p.length===1)return a.info(`[searchOrphanInProcessTree] Found orphan by tree search (single candidate): agentId=${t}, pid=${o.processId}, name=${o.name}`),{pid:o.processId,command:o.commandLine||"",agentId:t};a.debug(`[searchOrphanInProcessTree] Multiple candidates found (${p.length}), cannot determine which belongs to agentId=${t}`)}}const c=e.filter(o=>s(o)&&!d(o.processId));for(const o of c)if(await _(o.processId,t))return a.info(`[searchOrphanInProcessTree] Found orphan by env verification: agentId=${t}, pid=${o.processId}, name=${o.name}`),{pid:o.processId,command:o.commandLine||"",agentId:t}}function B(n){const t=n.indexOf("["),e=n.indexOf("{");let r=-1;return t>=0&&e>=0?r=Math.min(t,e):t>=0?r=t:e>=0&&(r=e),r<0?n:n.substring(r)}async function _(n,t){try{const e=`
1
+ import{execSync as O,exec as k}from"child_process";import h from"os";import{promisify as M}from"util";const g=M(k);import{createLogger as b}from"../utils/logger.js";const a=b("process-detector");async function m(n,t=15e3){const r=Buffer.from(n,"utf16le").toString("base64"),{stdout:s}=await g(`powershell -NoProfile -NonInteractive -EncodedCommand ${r}`,{encoding:"utf8",timeout:t,windowsHide:!0,maxBuffer:10*1024*1024});return s.replace(/#\s*<\s*CLIXML[\s\S]*?(?=#<\s*CLIXML|$)/g,"").trim()}async function w(n){try{if(h.platform()==="win32"){const{stdout:t}=await g(`tasklist /FI "PID eq ${n}" /NH /FO CSV`,{encoding:"utf8",timeout:5e3,windowsHide:!0});return t.includes(String(n))}else return process.kill(n,0),!0}catch{return!1}}function z(n){try{return h.platform()==="win32"?O(`tasklist /FI "PID eq ${n}" /NH /FO CSV`,{encoding:"utf8",timeout:5e3,windowsHide:!0}).includes(String(n)):(process.kill(n,0),!0)}catch{return!1}}async function I(){const n=h.platform(),t=[];try{n==="win32"?t.push(...await A()):t.push(...await N())}catch(e){a.debug("Failed to list processes:",e)}return t}async function A(){const n=[];try{const e=await m(`Get-CimInstance Win32_Process -Filter "Name LIKE '%node%' OR Name LIKE '%claude%' OR Name LIKE '%opencode%' OR Name LIKE '%python%'" | Select-Object ProcessId, CommandLine | ConvertTo-Json -Compress`,1e4);if(!e||!e.trim())return n;let r;try{const s=JSON.parse(e);r=Array.isArray(s)?s:[s]}catch{return n}for(const s of r){if(!s.ProcessId||!s.CommandLine)continue;const i=s.CommandLine;if($(i)){const d=y(i);n.push({pid:s.ProcessId,command:i,agentId:d})}}}catch(t){a.debug("PowerShell process query failed, trying wmic fallback:",t),n.push(...await F())}return n}async function F(){const n=[];try{const{stdout:t}=await g(`wmic process where "name like '%node%' or name like '%claude%' or name like '%opencode%'" get processid,commandline /format:list`,{encoding:"utf8",timeout:5e3,windowsHide:!0}),e=t.split(`
2
+ `);let r=null,s=null;for(const i of e){const d=i.trim();if(d.startsWith("CommandLine=")?s=d.substring(12):d.startsWith("ProcessId=")&&(r=d.substring(10)),r&&s){if($(s)){const c=y(s);n.push({pid:parseInt(r,10),command:s,agentId:c})}r=null,s=null}}}catch(t){a.debug("wmic process query failed:",t)}return n}async function N(){const n=[];try{const{stdout:t}=await g('ps aux | grep -E "claude|claude-code|opencode" | grep -v grep',{encoding:"utf8",timeout:5e3}),e=t.split(`
3
+ `).filter(r=>r.trim());for(const r of e){const s=r.trim().split(/\s+/);if(s.length>=2){const i=parseInt(s[1],10),d=s.slice(10).join(" ");if($(d)){const c=y(d);n.push({pid:i,command:d,agentId:c})}}}}catch(t){a.debug("ps process query failed:",t)}return n}function $(n){if(!n)return!1;const t=n.toLowerCase();return!!(t.includes("claude")||t.includes("@anthropic-ai/claude-code")||t.includes("opencode")||t.includes("open-code")||t.includes("opencode.exe")||t.includes("opencode.cmd")||t.includes("aws-client-agent-mcp")||t.includes("aws-client-agent")||t.includes("acode")&&t.includes("sdk")||t.includes("cc-switch-sdk")||t.includes("cc-switch"))}function y(n){if(!n)return;const t=n.match(/AWS_AGENT_ID=(\S+)/);if(t)return C(t[1]);const e=n.match(/--agent-id[=\s]+(\S+)/);if(e)return C(e[1]);const r=n.match(/--id[=\s]+(\S+)/);if(r)return C(r[1])}function C(n){if(!n)return n;const t=n[0],e=n[n.length-1];return(t==='"'||t==="'")&&t===e?n.slice(1,-1):n}async function x(n){const e=(await I()).find(r=>r.agentId===n);if(e)return e;if(h.platform()==="win32"){const r=await T(n);if(r)return r;const s=await R(n);if(s)return s}}async function T(n){try{const t=`$targetId = '${n}'; $procs = Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -and ($_.Name -like '*node*' -or $_.Name -like '*claude*' -or $_.Name -like '*opencode*') }; foreach ($proc in $procs) { if ($proc.CommandLine -like "*$targetId*") { @{ProcessId=$proc.ProcessId; CommandLine=$proc.CommandLine; AgentId=$targetId} | ConvertTo-Json -Compress } }`,e=await m(t,1e4);if(!e||!e.trim())return;const r=e.trim().split(`
4
+ `).filter(s=>s.trim());for(const s of r)try{const i=JSON.parse(s.trim());if(i.ProcessId)return{pid:i.ProcessId,command:i.CommandLine||"",agentId:i.AgentId||n}}catch{}}catch(t){a.debug("PowerShell env var query failed:",t)}}async function R(n){try{const e=await m("Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId, Name, CommandLine | ConvertTo-Json -Compress",15e3);return!e||!e.trim()?void 0:await W(e.trim(),n)}catch(t){a.debug("[findOrphanByAncestorEnvSearch] Failed:",t)}}async function W(n,t){let e;try{const o=n.replace(/#\s*<\s*CLIXML[\s\S]*?(?=\{|\[|$)/g,"").trim(),u=B(o),l=JSON.parse(u);e=Array.isArray(l)?l:[l]}catch(o){a.debug(`[searchOrphanInProcessTree] JSON parse failed, raw length=${n.length}`,o);return}if(!e.length)return;const r=new Map;for(const o of e)o.processId&&r.set(o.processId,o);function s(o){const u=o.name.toLowerCase(),l=(o.commandLine||"").toLowerCase();return!!(u.includes("claude")||l.includes("claude")||l.includes("@anthropic-ai/claude-code")||l.includes("cli.js")||u.includes("opencode")||l.includes("opencode")||l.includes("serve")&&l.includes("--port"))}function i(o){const u=o.toLowerCase();return u==="powershell.exe"||u==="cmd.exe"||u==="pwsh.exe"||u==="bash.exe"}function d(o){let u=o;const l=10;for(let P=0;P<l;P++){const p=r.get(u);if(!p)break;if(i(p.name)){const f=r.get(p.parentProcessId);if(f&&f.name.toLowerCase()==="node.exe"){const S=(f.commandLine||"").toLowerCase();if(S.includes("runtime-bridge")||S.includes("agentswork"))return a.debug(`[searchOrphanInProcessTree] Found bridge ancestor chain: agent(${o}) -> shell(${p.processId}) -> node(${f.processId})`),{shellPid:p.processId,shellCmd:p.commandLine||""}}}if(u=p.parentProcessId,u<=0)break}return null}for(const o of e){if(!s(o))continue;const u=d(o.processId);if(u){if(u.shellCmd.toLowerCase().includes(t.toLowerCase()))return a.info(`[searchOrphanInProcessTree] Found orphan by tree search (agentId verified): agentId=${t}, pid=${o.processId}, name=${o.name}`),{pid:o.processId,command:o.commandLine||"",agentId:t};const p=e.filter(f=>s(f)&&d(f.processId));if(p.length===1)return a.info(`[searchOrphanInProcessTree] Found orphan by tree search (single candidate): agentId=${t}, pid=${o.processId}, name=${o.name}`),{pid:o.processId,command:o.commandLine||"",agentId:t};a.debug(`[searchOrphanInProcessTree] Multiple candidates found (${p.length}), cannot determine which belongs to agentId=${t}`)}}const c=e.filter(o=>s(o)&&!d(o.processId));for(const o of c)if(await _(o.processId,t))return a.info(`[searchOrphanInProcessTree] Found orphan by env verification: agentId=${t}, pid=${o.processId}, name=${o.name}`),{pid:o.processId,command:o.commandLine||"",agentId:t}}function B(n){const t=n.indexOf("["),e=n.indexOf("{");let r=-1;return t>=0&&e>=0?r=Math.min(t,e):t>=0?r=t:e>=0&&(r=e),r<0?n:n.substring(r)}async function _(n,t){try{const e=`
5
5
  try {
6
6
  $proc = Get-CimInstance Win32_Process -Filter "ProcessId = ${n}" -ErrorAction SilentlyContinue
7
7
  if ($proc -and $proc.CommandLine -like '*${t}*') { 'MATCH' } else { 'NOMATCH' }
8
8
  } catch { 'ERROR' }
9
- `;if((await f(e,5e3)).trim()==="MATCH")return!0;const s=`
9
+ `;if((await m(e,5e3)).trim()==="MATCH")return!0;const s=`
10
10
  try {
11
11
  $proc = Get-CimInstance Win32_Process -Filter "ProcessId = ${n}" -ErrorAction SilentlyContinue
12
12
  if ($proc) {
@@ -15,7 +15,7 @@ import{execSync as L,exec as O}from"child_process";import{promisify as b}from"ut
15
15
  if ($parent -and $parent.CommandLine -like '*${t}*') { 'MATCH' } else { 'NOMATCH' }
16
16
  } else { 'NOPROC' }
17
17
  } catch { 'ERROR' }
18
- `;if((await f(s,5e3)).trim()==="MATCH")return!0;const d=`
18
+ `;if((await m(s,5e3)).trim()==="MATCH")return!0;const d=`
19
19
  try {
20
20
  $proc = Get-CimInstance Win32_Process -Filter "ProcessId = ${n}" -ErrorAction SilentlyContinue
21
21
  if ($proc) {
@@ -28,7 +28,7 @@ import{execSync as L,exec as O}from"child_process";import{promisify as b}from"ut
28
28
  } else { 'NOPARENT' }
29
29
  } else { 'NOPROC' }
30
30
  } catch { 'ERROR' }
31
- `;return(await f(d,5e3)).trim()==="MATCH"}catch(e){return a.debug(`[verifyProcessAgentId] Failed for pid=${n}, agentId=${t}:`,e),!1}}async function K(n){if(n)try{const t=await P(),e=n.replace(/\\/g,"/").toLowerCase();for(const r of t)if(r.command.replace(/\\/g,"/").toLowerCase().includes(e))return a.info(`[findOrphanProcessByWorkspace] Found process by workspace: pid=${r.pid}, workspace=${n}`),r;if(g.platform()==="win32"){const s=`
31
+ `;return(await m(d,5e3)).trim()==="MATCH"}catch(e){return a.debug(`[verifyProcessAgentId] Failed for pid=${n}, agentId=${t}:`,e),!1}}async function K(n){if(n)try{const t=await I(),e=n.replace(/\\/g,"/").toLowerCase();for(const r of t)if(r.command.replace(/\\/g,"/").toLowerCase().includes(e))return a.info(`[findOrphanProcessByWorkspace] Found process by workspace: pid=${r.pid}, workspace=${n}`),r;if(h.platform()==="win32"){const s=`
32
32
  $targetPath = '${n.replace(/'/g,"''")}'.ToLower().Replace('\\', '/')
33
33
  $procs = Get-CimInstance Win32_Process | Where-Object {
34
34
  $_.CommandLine -and ($_.Name -like '*node*' -or $_.Name -like '*claude*' -or $_.Name -like '*opencode*')
@@ -39,7 +39,7 @@ import{execSync as L,exec as O}from"child_process";import{promisify as b}from"ut
39
39
  @{ProcessId=$proc.ProcessId; CommandLine=$proc.CommandLine} | ConvertTo-Json -Compress
40
40
  }
41
41
  }
42
- `,i=await f(s,1e4);if(i&&i.trim()){const d=i.trim().split(`
43
- `).filter(c=>c.trim());for(const c of d)try{const o=JSON.parse(c.trim());if(o.ProcessId)return a.info(`[findOrphanProcessByWorkspace] Found process by PowerShell workspace search: pid=${o.ProcessId}`),{pid:o.ProcessId,command:o.CommandLine||""}}catch{}}}}catch(t){a.debug("[findOrphanProcessByWorkspace] Failed:",t)}}function v(n){try{return process.kill(n,"SIGTERM"),!0}catch(t){return a.warn(`Failed to terminate process ${n}:`,t),!1}}async function E(n){const t={terminated:0,failed:0};if(g.platform()==="win32")try{await h(`taskkill /PID ${n} /T /F`,{encoding:"utf8",timeout:5e3,windowsHide:!0}),t.terminated++,a.info(`Terminated process tree for pid=${n}`)}catch(e){const r=e;a.warn(`Failed to terminate process tree for pid=${n}:`,r.message),t.failed++}else{const e=await M(n);a.debug(`Found ${e.length} child processes for pid=${n}`);for(const r of e){const s=await E(r);t.terminated+=s.terminated,t.failed+=s.failed}v(n)?t.terminated++:t.failed++}return t}async function M(n){try{const{stdout:t}=await h(`pgrep -P ${n}`,{encoding:"utf8",timeout:3e3}),e=t.trim().split(`
44
- `).filter(Boolean).map(Number),r=[];for(const s of e)r.push(s),r.push(...await M(s));return r}catch{return[]}}async function U(n,t=5e3){const e=Date.now();for(;Date.now()-e<t;){if(!await w(n))return!0;const r=Math.min(100,t-(Date.now()-e));r>0&&await new Promise(s=>setTimeout(s,r))}return!1}async function V(n){const t=[];for(const e of n)if(e.pid&&await w(e.pid)){const s=(await P()).find(i=>i.pid===e.pid);s?(t.push({agentId:e.agentId,process:s,sessionInfo:{workspacePath:e.workspacePath,command:e.command}}),a.info(`Found orphan process by PID: agentId=${e.agentId}, pid=${e.pid}`)):(t.push({agentId:e.agentId,process:{pid:e.pid,command:e.command||"(unknown - persisted session)",agentId:e.agentId},sessionInfo:{workspacePath:e.workspacePath,command:e.command}}),a.info(`Found orphan process by PID (no cmd match): agentId=${e.agentId}, pid=${e.pid}`))}for(const e of n)if(!e.pid&&e.agentId){const r=await x(e.agentId);r&&!t.some(s=>s.agentId===e.agentId)&&(t.push({agentId:e.agentId,process:r,sessionInfo:{workspacePath:e.workspacePath,command:e.command}}),a.info(`Found orphan process by agentId: agentId=${e.agentId}, pid=${r.pid}`))}return t}async function H(n,t){const e={pid:n,agentId:t,alive:!1,cpu:0,memoryMB:0,status:"dead",lastUpdate:new Date};try{if(!await w(n))return e.status="dead",a.debug(`Process ${n} is not running`),e;e.alive=!0;const{cpu:r,memoryMB:s}=await D(n);return e.cpu=r,e.memoryMB=s,s>2048?e.status="high_memory":r>100?e.status="high_cpu":e.status="healthy",a.debug(`Process ${n} health: CPU=${r}%, Memory=${s}MB, Status=${e.status}`),e}catch(r){return a.warn(`Failed to check health for process ${n}:`,r),e.status="dead",e}}async function D(n){if(g.platform()==="win32"){const e=`Get-CimInstance Win32_Process -Filter "ProcessId=${n}" | Select-Object @{Name='CPU';Expression={$_.WorkingSetSize/1MB}}, @{Name='Mem';Expression={$_.WorkingSetSize/1MB}} | ConvertTo-Json -Compress`;try{const r=await f(e,5e3);if(!r||!r.trim())return{cpu:0,memoryMB:0};const s=JSON.parse(r);return{cpu:0,memoryMB:Math.round((s.WorkingSetSize||0)/1024/1024)}}catch{return{cpu:0,memoryMB:0}}}else try{const{stdout:e}=await h(`ps -p ${n} -o %cpu=,rss=`,{encoding:"utf8",timeout:5e3}),r=e.trim().split(/\s+/);if(r.length>=2)return{cpu:parseFloat(r[0])||0,memoryMB:Math.round(parseInt(r[1],10)/1024)}}catch{return{cpu:0,memoryMB:0}}return{cpu:0,memoryMB:0}}async function Q(n){const t=new Map,e=n.filter(r=>r.pid).map(async r=>{const s=await H(r.pid,r.agentId);t.set(r.agentId,s)});return await Promise.all(e),t}async function Y(n=new Set,t=new Set){const e=[],r=await P();for(const s of r){const i=n.has(s.pid),d=s.agentId?t.has(s.agentId):!1;e.push({...s,isRunning:!0,managementStatus:i||d?"managed":"orphan",sessionId:void 0,lastSeen:new Date().toISOString()})}return e}async function Z(n){const t=new Set(n.map(c=>c.pid)),e=new Set(n.map(c=>c.agentId)),r=new Map(n.map(c=>[c.pid,c])),s=[],i=new Set,d=await P();for(const c of d){i.add(c.pid);const o=t.has(c.pid),u=c.agentId?e.has(c.agentId):!1,l=r.get(c.pid),I=c.agentId||l?.agentId;s.push({...c,agentId:I,isRunning:!0,managementStatus:o||u?"managed":"orphan",sessionId:void 0,lastSeen:new Date().toISOString()})}for(const c of n)!i.has(c.pid)&&!await w(c.pid)&&s.push({pid:c.pid,command:"(process exited)",agentId:c.agentId,isRunning:!1,managementStatus:"unknown",lastSeen:void 0});return s}export{Q as checkAllSessionsHealth,H as checkProcessHealth,V as detectOrphanProcesses,Y as discoverAllProcesses,Z as discoverAllProcessesFull,P as findClaudeCodeProcesses,x as findOrphanProcessByAgentId,K as findOrphanProcessByWorkspace,X as isProcessRunning,w as isProcessRunningAsync,v as terminateProcess,E as terminateProcessTree,U as waitForProcessExit};
42
+ `,i=await m(s,1e4);if(i&&i.trim()){const d=i.trim().split(`
43
+ `).filter(c=>c.trim());for(const c of d)try{const o=JSON.parse(c.trim());if(o.ProcessId)return a.info(`[findOrphanProcessByWorkspace] Found process by PowerShell workspace search: pid=${o.ProcessId}`),{pid:o.ProcessId,command:o.CommandLine||""}}catch{}}}}catch(t){a.debug("[findOrphanProcessByWorkspace] Failed:",t)}}function v(n){try{return process.kill(n,"SIGTERM"),!0}catch(t){return a.warn(`Failed to terminate process ${n}:`,t),!1}}async function E(n){const t={terminated:0,failed:0};if(h.platform()==="win32")try{await g(`taskkill /PID ${n} /T /F`,{encoding:"utf8",timeout:5e3,windowsHide:!0}),t.terminated++,a.info(`Terminated process tree for pid=${n}`)}catch(e){const r=e;a.warn(`Failed to terminate process tree for pid=${n}:`,r.message),t.failed++}else{const e=await L(n);a.debug(`Found ${e.length} child processes for pid=${n}`);for(const r of e){const s=await E(r);t.terminated+=s.terminated,t.failed+=s.failed}v(n)?t.terminated++:t.failed++}return t}async function L(n){try{const{stdout:t}=await g(`pgrep -P ${n}`,{encoding:"utf8",timeout:3e3}),e=t.trim().split(`
44
+ `).filter(Boolean).map(Number),r=[];for(const s of e)r.push(s),r.push(...await L(s));return r}catch{return[]}}async function U(n,t=5e3){const e=Date.now();for(;Date.now()-e<t;){if(!await w(n))return!0;const r=Math.min(100,t-(Date.now()-e));r>0&&await new Promise(s=>setTimeout(s,r))}return!1}async function V(n){const t=[];for(const e of n)if(e.pid&&await w(e.pid)){const s=(await I()).find(i=>i.pid===e.pid);s?(t.push({agentId:e.agentId,process:s,sessionInfo:{workspacePath:e.workspacePath,command:e.command}}),a.info(`Found orphan process by PID: agentId=${e.agentId}, pid=${e.pid}`)):(t.push({agentId:e.agentId,process:{pid:e.pid,command:e.command||"(unknown - persisted session)",agentId:e.agentId},sessionInfo:{workspacePath:e.workspacePath,command:e.command}}),a.info(`Found orphan process by PID (no cmd match): agentId=${e.agentId}, pid=${e.pid}`))}for(const e of n)if(!e.pid&&e.agentId){const r=await x(e.agentId);r&&!t.some(s=>s.agentId===e.agentId)&&(t.push({agentId:e.agentId,process:r,sessionInfo:{workspacePath:e.workspacePath,command:e.command}}),a.info(`Found orphan process by agentId: agentId=${e.agentId}, pid=${r.pid}`))}return t}async function H(n,t){const e={pid:n,agentId:t,alive:!1,cpu:0,memoryMB:0,status:"dead",lastUpdate:new Date};try{if(!await w(n))return e.status="dead",a.debug(`Process ${n} is not running`),e;e.alive=!0;const{cpu:r,memoryMB:s}=await D(n);return e.cpu=r,e.memoryMB=s,s>2048?e.status="high_memory":r>100?e.status="high_cpu":e.status="healthy",a.debug(`Process ${n} health: CPU=${r}%, Memory=${s}MB, Status=${e.status}`),e}catch(r){return a.warn(`Failed to check health for process ${n}:`,r),e.status="dead",e}}async function D(n){if(h.platform()==="win32"){const e=`Get-CimInstance Win32_Process -Filter "ProcessId=${n}" | Select-Object @{Name='CPU';Expression={$_.WorkingSetSize/1MB}}, @{Name='Mem';Expression={$_.WorkingSetSize/1MB}} | ConvertTo-Json -Compress`;try{const r=await m(e,5e3);if(!r||!r.trim())return{cpu:0,memoryMB:0};const s=JSON.parse(r);return{cpu:0,memoryMB:Math.round((s.WorkingSetSize||0)/1024/1024)}}catch{return{cpu:0,memoryMB:0}}}else try{const{stdout:e}=await g(`ps -p ${n} -o %cpu=,rss=`,{encoding:"utf8",timeout:5e3}),r=e.trim().split(/\s+/);if(r.length>=2)return{cpu:parseFloat(r[0])||0,memoryMB:Math.round(parseInt(r[1],10)/1024)}}catch{return{cpu:0,memoryMB:0}}return{cpu:0,memoryMB:0}}async function X(n){const t=new Map,e=n.filter(r=>r.pid).map(async r=>{const s=await H(r.pid,r.agentId);t.set(r.agentId,s)});return await Promise.all(e),t}async function Q(n=new Set,t=new Set){const e=[],r=await I();for(const s of r){const i=n.has(s.pid),d=s.agentId?t.has(s.agentId):!1;e.push({...s,isRunning:!0,managementStatus:i||d?"managed":"orphan",sessionId:void 0,lastSeen:new Date().toISOString()})}return e}async function Y(n){const t=new Set(n.map(c=>c.pid)),e=new Set(n.map(c=>c.agentId)),r=new Map(n.map(c=>[c.pid,c])),s=[],i=new Set,d=await I();for(const c of d){i.add(c.pid);const o=t.has(c.pid),u=c.agentId?e.has(c.agentId):!1,l=r.get(c.pid),P=c.agentId||l?.agentId;s.push({...c,agentId:P,isRunning:!0,managementStatus:o||u?"managed":"orphan",sessionId:void 0,lastSeen:new Date().toISOString()})}for(const c of n)!i.has(c.pid)&&!await w(c.pid)&&s.push({pid:c.pid,command:"(process exited)",agentId:c.agentId,isRunning:!1,managementStatus:"unknown",lastSeen:void 0});return s}export{X as checkAllSessionsHealth,H as checkProcessHealth,V as detectOrphanProcesses,Q as discoverAllProcesses,Y as discoverAllProcessesFull,I as findClaudeCodeProcesses,x as findOrphanProcessByAgentId,K as findOrphanProcessByWorkspace,z as isProcessRunning,w as isProcessRunningAsync,v as terminateProcess,E as terminateProcessTree,U as waitForProcessExit};
45
45
 
@@ -1,2 +1,2 @@
1
- import c from"node:os";import u from"node:path";import{promises as h}from"node:fs";import{createLogger as g}from"../utils/logger.js";import{atomicWriteJsonFile as d,withFileLock as o}from"../utils/file-utils.js";const r=g("process-registry");function n(){return u.join(c.tmpdir(),"agentswork-runtime-bridge","process-registry.json")}class i{constructor(){this.records=new Map,this.pidToAgentId=new Map}static getInstance(){return i.instance===null&&(i.instance=new i),i.instance}async persist(){const t=n();try{const e=Array.from(this.records.values());await d(t,e),r.debug(`[persist] \u5DF2\u6301\u4E45\u5316 ${e.length} \u6761\u8FDB\u7A0B\u8BB0\u5F55`)}catch(e){r.error("[persist] \u6301\u4E45\u5316\u5931\u8D25:",e)}}async mutate(t){return o(n(),async()=>t())}async register(t){await this.mutate(async()=>{const e={...t,createdAt:new Date().toISOString()},s=this.records.get(t.agentId);s&&this.pidToAgentId.delete(s.pid),this.records.set(t.agentId,e),this.pidToAgentId.set(t.pid,t.agentId),r.info(`[register] \u6CE8\u518C\u8FDB\u7A0B: agentId=${t.agentId}, pid=${t.pid}, mode=${t.mode}, state=${t.state}`),await this.persist()})}async update(t,e){return this.mutate(async()=>{const s=this.records.get(t);return s?(e.pid!==void 0&&e.pid!==s.pid&&(this.pidToAgentId.delete(s.pid),this.pidToAgentId.set(e.pid,t)),Object.assign(s,e),r.debug(`[update] \u66F4\u65B0\u8FDB\u7A0B: agentId=${t}, updates=${JSON.stringify(e)}`),await this.persist(),!0):(r.warn(`[update] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}get(t){return this.records.get(t)}getByPid(t){const e=this.pidToAgentId.get(t);if(e)return this.records.get(e)}getAll(){return Array.from(this.records.values())}getByState(t){return this.getAll().filter(e=>e.state===t)}isManaged(t){return this.records.has(t)}isManagedByPid(t){return this.pidToAgentId.has(t)}async markOrphaned(t){return this.mutate(async()=>{const e=this.records.get(t);return e?(e.state="orphaned",e.orphanedAt=new Date().toISOString(),r.info(`[markOrphaned] \u6807\u8BB0\u8FDB\u7A0B\u4E3A\u5B64\u513F: agentId=${t}, orphanedAt=${e.orphanedAt}`),await this.persist(),!0):(r.warn(`[markOrphaned] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}async markTerminated(t){return this.mutate(async()=>{const e=this.records.get(t);return e?(e.state="terminated",r.info(`[markTerminated] \u6807\u8BB0\u8FDB\u7A0B\u4E3A\u7EC8\u6B62: agentId=${t}`),await this.persist(),!0):(r.warn(`[markTerminated] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}async remove(t){return this.mutate(async()=>{const e=this.records.get(t);return e?(this.records.delete(t),this.pidToAgentId.delete(e.pid),r.info(`[remove] \u79FB\u9664\u8FDB\u7A0B: agentId=${t}, pid=${e.pid}`),await this.persist(),!0):(r.warn(`[remove] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}async updateHeartbeat(t){return this.mutate(async()=>{const e=this.records.get(t);return e?(e.lastHeartbeat=new Date().toISOString(),r.debug(`[updateHeartbeat] \u66F4\u65B0\u5FC3\u8DF3: agentId=${t}, lastHeartbeat=${e.lastHeartbeat}`),await this.persist(),!0):(r.warn(`[updateHeartbeat] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}async updateHealth(t,e){return this.mutate(async()=>{const s=this.records.get(t);return s?(s.healthStatus=e,r.debug(`[updateHealth] \u66F4\u65B0\u5065\u5EB7\u72B6\u6001: agentId=${t}, health=${JSON.stringify(e)}`),await this.persist(),!0):(r.warn(`[updateHealth] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}async rebuildFromPersisted(t){await this.mutate(async()=>{r.info(`[rebuildFromPersisted] \u4ECE ${t.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u91CD\u5EFA\u6CE8\u518C\u8868`),this.records.clear(),this.pidToAgentId.clear();for(const e of t){if(!e.pid){r.warn(`[rebuildFromPersisted] \u8DF3\u8FC7\u65E0 PID \u7684\u4F1A\u8BDD: agentId=${e.agentId}`);continue}const s={agentId:e.agentId,sessionId:e.sessionId,pid:e.pid,mode:"sdk",state:"unknown",workspacePath:e.workspacePath||"",command:e.command||"",createdAt:new Date().toISOString()};this.records.set(s.agentId,s),this.pidToAgentId.set(s.pid,s.agentId),r.debug(`[rebuildFromPersisted] \u91CD\u5EFA\u8FDB\u7A0B\u8BB0\u5F55: agentId=${s.agentId}, pid=${s.pid}`)}r.info(`[rebuildFromPersisted] \u91CD\u5EFA\u5B8C\u6210\uFF0C\u5171 ${this.records.size} \u6761\u8BB0\u5F55`),await this.persist()})}exportState(){return this.getAll()}getStats(){const t={creating:0,running:0,stopping:0,orphaned:0,terminated:0,unknown:0,total:this.records.size};for(const e of this.records.values())t[e.state]++;return t}async clear(){await this.mutate(async()=>{const t=this.records.size;this.records.clear(),this.pidToAgentId.clear(),r.info(`[clear] \u6E05\u7A7A\u6240\u6709\u8FDB\u7A0B\u8BB0\u5F55: ${t} \u6761`),await this.persist()})}}i.instance=null;function w(){return i.getInstance()}async function I(){const a=n();try{const t=await h.readFile(a,"utf-8"),e=JSON.parse(t);return r.debug(`[loadPersistedProcessRegistry] \u52A0\u8F7D\u4E86 ${e.length} \u6761\u8FDB\u7A0B\u8BB0\u5F55`),e}catch{return[]}}async function $(a){const t=n();await o(t,async()=>{await d(t,a),r.debug(`[savePersistedProcessRegistry] \u4FDD\u5B58\u4E86 ${a.length} \u6761\u8FDB\u7A0B\u8BB0\u5F55`)})}export{i as ProcessRegistry,w as getProcessRegistry,n as getProcessRegistryFile,I as loadPersistedProcessRegistry,$ as savePersistedProcessRegistry};
1
+ import{promises as c}from"node:fs";import u from"node:os";import h from"node:path";import{atomicWriteJsonFile as d,withFileLock as o}from"../utils/file-utils.js";import{createLogger as g}from"../utils/logger.js";const r=g("process-registry");function n(){return h.join(u.tmpdir(),"agentswork-runtime-bridge","process-registry.json")}class i{constructor(){this.records=new Map,this.pidToAgentId=new Map}static getInstance(){return i.instance===null&&(i.instance=new i),i.instance}async persist(){const t=n();try{const e=Array.from(this.records.values());await d(t,e),r.debug(`[persist] \u5DF2\u6301\u4E45\u5316 ${e.length} \u6761\u8FDB\u7A0B\u8BB0\u5F55`)}catch(e){r.error("[persist] \u6301\u4E45\u5316\u5931\u8D25:",e)}}async mutate(t){return o(n(),async()=>t())}async register(t){await this.mutate(async()=>{const e={...t,createdAt:new Date().toISOString()},s=this.records.get(t.agentId);s&&this.pidToAgentId.delete(s.pid),this.records.set(t.agentId,e),this.pidToAgentId.set(t.pid,t.agentId),r.info(`[register] \u6CE8\u518C\u8FDB\u7A0B: agentId=${t.agentId}, pid=${t.pid}, mode=${t.mode}, state=${t.state}`),await this.persist()})}async update(t,e){return this.mutate(async()=>{const s=this.records.get(t);return s?(e.pid!==void 0&&e.pid!==s.pid&&(this.pidToAgentId.delete(s.pid),this.pidToAgentId.set(e.pid,t)),Object.assign(s,e),r.debug(`[update] \u66F4\u65B0\u8FDB\u7A0B: agentId=${t}, updates=${JSON.stringify(e)}`),await this.persist(),!0):(r.warn(`[update] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}get(t){return this.records.get(t)}getByPid(t){const e=this.pidToAgentId.get(t);if(e)return this.records.get(e)}getAll(){return Array.from(this.records.values())}getByState(t){return this.getAll().filter(e=>e.state===t)}isManaged(t){return this.records.has(t)}isManagedByPid(t){return this.pidToAgentId.has(t)}async markOrphaned(t){return this.mutate(async()=>{const e=this.records.get(t);return e?(e.state="orphaned",e.orphanedAt=new Date().toISOString(),r.info(`[markOrphaned] \u6807\u8BB0\u8FDB\u7A0B\u4E3A\u5B64\u513F: agentId=${t}, orphanedAt=${e.orphanedAt}`),await this.persist(),!0):(r.warn(`[markOrphaned] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}async markTerminated(t){return this.mutate(async()=>{const e=this.records.get(t);return e?(e.state="terminated",r.info(`[markTerminated] \u6807\u8BB0\u8FDB\u7A0B\u4E3A\u7EC8\u6B62: agentId=${t}`),await this.persist(),!0):(r.warn(`[markTerminated] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}async remove(t){return this.mutate(async()=>{const e=this.records.get(t);return e?(this.records.delete(t),this.pidToAgentId.delete(e.pid),r.info(`[remove] \u79FB\u9664\u8FDB\u7A0B: agentId=${t}, pid=${e.pid}`),await this.persist(),!0):(r.warn(`[remove] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}async updateHeartbeat(t){return this.mutate(async()=>{const e=this.records.get(t);return e?(e.lastHeartbeat=new Date().toISOString(),r.debug(`[updateHeartbeat] \u66F4\u65B0\u5FC3\u8DF3: agentId=${t}, lastHeartbeat=${e.lastHeartbeat}`),await this.persist(),!0):(r.warn(`[updateHeartbeat] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}async updateHealth(t,e){return this.mutate(async()=>{const s=this.records.get(t);return s?(s.healthStatus=e,r.debug(`[updateHealth] \u66F4\u65B0\u5065\u5EB7\u72B6\u6001: agentId=${t}, health=${JSON.stringify(e)}`),await this.persist(),!0):(r.warn(`[updateHealth] \u672A\u627E\u5230\u8FDB\u7A0B: agentId=${t}`),!1)})}async rebuildFromPersisted(t){await this.mutate(async()=>{r.info(`[rebuildFromPersisted] \u4ECE ${t.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u91CD\u5EFA\u6CE8\u518C\u8868`),this.records.clear(),this.pidToAgentId.clear();for(const e of t){if(!e.pid){r.warn(`[rebuildFromPersisted] \u8DF3\u8FC7\u65E0 PID \u7684\u4F1A\u8BDD: agentId=${e.agentId}`);continue}const s={agentId:e.agentId,sessionId:e.sessionId,pid:e.pid,mode:"sdk",state:"unknown",workspacePath:e.workspacePath||"",command:e.command||"",createdAt:new Date().toISOString()};this.records.set(s.agentId,s),this.pidToAgentId.set(s.pid,s.agentId),r.debug(`[rebuildFromPersisted] \u91CD\u5EFA\u8FDB\u7A0B\u8BB0\u5F55: agentId=${s.agentId}, pid=${s.pid}`)}r.info(`[rebuildFromPersisted] \u91CD\u5EFA\u5B8C\u6210\uFF0C\u5171 ${this.records.size} \u6761\u8BB0\u5F55`),await this.persist()})}exportState(){return this.getAll()}getStats(){const t={creating:0,running:0,stopping:0,orphaned:0,terminated:0,unknown:0,total:this.records.size};for(const e of this.records.values())t[e.state]++;return t}async clear(){await this.mutate(async()=>{const t=this.records.size;this.records.clear(),this.pidToAgentId.clear(),r.info(`[clear] \u6E05\u7A7A\u6240\u6709\u8FDB\u7A0B\u8BB0\u5F55: ${t} \u6761`),await this.persist()})}}i.instance=null;function w(){return i.getInstance()}async function I(){const a=n();try{const t=await c.readFile(a,"utf-8"),e=JSON.parse(t);return r.debug(`[loadPersistedProcessRegistry] \u52A0\u8F7D\u4E86 ${e.length} \u6761\u8FDB\u7A0B\u8BB0\u5F55`),e}catch{return[]}}async function $(a){const t=n();await o(t,async()=>{await d(t,a),r.debug(`[savePersistedProcessRegistry] \u4FDD\u5B58\u4E86 ${a.length} \u6761\u8FDB\u7A0B\u8BB0\u5F55`)})}export{i as ProcessRegistry,w as getProcessRegistry,n as getProcessRegistryFile,I as loadPersistedProcessRegistry,$ as savePersistedProcessRegistry};
2
2
 
@@ -1,4 +1,4 @@
1
- import{execFile as h}from"node:child_process";import{readdir as T,readFile as w}from"node:fs/promises";import{promisify as M}from"node:util";import I from"node:os";const l=M(h);import{createLogger as g}from"../utils/logger.js";const x=g("process-top"),E=["cpu","memory","storage","network"],a=400,O=100,P=10,_=50,m=9e3,B="\u5F53\u524D\u7CFB\u7EDF\u65E0\u6CD5\u6309\u8FDB\u7A0B\u7EDF\u8BA1\u7F51\u7EDC\u8FDE\u63A5",L="macOS \u6682\u4E0D\u652F\u6301\u6309\u8FDB\u7A0B\u7EDF\u8BA1\u78C1\u76D8 IO";function ce(t){const e=String(t??"").trim();return E.includes(e)?e:null}function ae(t){const e=Math.floor(Number(t??P));return Number.isFinite(e)?Math.min(_,Math.max(1,e)):P}function R(t,e){return[...t].sort((n,s)=>s.value-n.value).slice(0,e)}function A(t){const e=t.replace(/\\/g,"/"),n=e.split("/").filter(Boolean);return n[n.length-1]||e}function b(t){const e=t.indexOf("("),n=t.lastIndexOf(")");if(e<0||n<=e)return null;const s=t.slice(e+1,n),o=t.slice(n+1).trim().split(/\s+/),r=Number(o[11]),i=Number(o[12]);return!Number.isFinite(r)||!Number.isFinite(i)?null:{name:s,ticks:r+i}}function k(t){let e=0,n=0;for(const s of t.split(/\r?\n/)){const[o,r]=s.split(":");if(!o||r===void 0)continue;const i=Number(r.trim());Number.isFinite(i)&&(o.trim()==="read_bytes"?e=i:o.trim()==="write_bytes"&&(n=i))}return{readBytes:e,writeBytes:n}}function W(t){const e=t.trim().match(/^(\d+)\s+([\d.]+)\s+(\d+)\s+(.+)$/);if(!e)return null;const n=Number(e[1]),s=Number(e[2]),o=Number(e[3])*1024;return!Number.isFinite(n)||!Number.isFinite(s)||!Number.isFinite(o)?null:{pid:n,cpuPercent:s,rssBytes:o,name:A(e[4].trim())}}function F(t){const e=[];for(const n of t.split(/\r?\n/)){const s=W(n);s&&e.push(s)}return e}async function $(){const{stdout:t}=await l("ps",["-eo","pid=,pcpu=,rss=,comm="],{encoding:"utf8",timeout:m});return F(t)}function v(t){const e=new Map;for(const n of t.split(/\r?\n/).slice(1)){if(!n.trim()||n.startsWith("State ")||n.trim().split(/\s+/)[0]==="LISTEN")continue;const o=new Set;for(const r of n.matchAll(/\("([^"]+)",pid=(\d+)/g)){const i=Number(r[2]);if(!Number.isFinite(i)||o.has(i))continue;o.add(i);const c=e.get(i)||{name:r[1],connectionCount:0};c.connectionCount+=1,e.set(i,c)}}return e}async function N(){return(await T("/proc")).filter(e=>/^\d+$/.test(e)).map(e=>Number(e))}async function D(){const t=async()=>{const s=await N(),o=await Promise.all(s.map(async r=>{try{const i=await w(`/proc/${r}/stat`,"utf8"),c=b(i);return c?[r,c]:null}catch{return null}}));return new Map(o.filter(Boolean))},e=await t();await new Promise(s=>{setTimeout(s,a)});const n=await t();return{first:e,second:n}}async function G(){const{first:t,second:e}=await D(),n=[];for(const[s,o]of e){const r=t.get(s);if(!r)continue;const i=o.ticks-r.ticks;if(i<=0)continue;const c=a/1e3;n.push({pid:s,name:o.name,value:Math.round(i/O/c*1e3)/10})}return n}async function j(){return(await $()).map(e=>({pid:e.pid,name:e.name,value:e.rssBytes}))}async function U(){const t=async()=>{const r=await N(),i=await Promise.all(r.map(async c=>{try{const[u,p]=await Promise.all([w(`/proc/${c}/stat`,"utf8"),w(`/proc/${c}/io`,"utf8")]),S=b(u);if(!S)return null;const y=k(p);return[c,{name:S.name,readBytes:y.readBytes,writeBytes:y.writeBytes}]}catch{return null}}));return new Map(i.filter(Boolean))},e=await t();await new Promise(r=>{setTimeout(r,a)});const n=await t(),s=a/1e3,o=[];for(const[r,i]of n){const c=e.get(r);if(!c)continue;const u=Math.max(0,Math.round((i.readBytes-c.readBytes)/s)),p=Math.max(0,Math.round((i.writeBytes-c.writeBytes)/s));o.push({pid:r,name:i.name,value:u+p,readBytesPerSecond:u,writeBytesPerSecond:p})}return o}async function J(){const{stdout:t}=await l("ss",["-tupn"],{encoding:"utf8",timeout:m}),e=[];for(const[n,s]of v(t))e.push({pid:n,name:s.name,value:s.connectionCount});return e}async function K(){return(await $()).map(e=>({pid:e.pid,name:e.name,value:e.cpuPercent}))}async function V(){return(await $()).map(e=>({pid:e.pid,name:e.name,value:e.rssBytes}))}function X(t){const e=new Map;for(const n of t.split(/\r?\n/).slice(1)){const s=n.trim().split(/\s+/);if(s.length<8)continue;const o=s[0],r=Number(s[1]);if(!Number.isFinite(r)||r<=0||s.slice(7).join(" ").includes("(LISTEN)"))continue;const c=e.get(r)||{name:o,connectionCount:0};c.connectionCount+=1,e.set(r,c)}return e}async function z(){const{stdout:t}=await l("lsof",["-n","-P","-i","TCP","+c0"],{encoding:"utf8",timeout:m}),e=[];for(const[n,s]of X(t))e.push({pid:n,name:s.name,value:s.connectionCount});return e}const C=`
1
+ import{execFile as h}from"node:child_process";import{readdir as T,readFile as w}from"node:fs/promises";import M from"node:os";import{promisify as I}from"node:util";const l=I(h);import{createLogger as g}from"../utils/logger.js";const x=g("process-top"),E=["cpu","memory","storage","network"],a=400,O=100,P=10,_=50,m=9e3,B="\u5F53\u524D\u7CFB\u7EDF\u65E0\u6CD5\u6309\u8FDB\u7A0B\u7EDF\u8BA1\u7F51\u7EDC\u8FDE\u63A5",L="macOS \u6682\u4E0D\u652F\u6301\u6309\u8FDB\u7A0B\u7EDF\u8BA1\u78C1\u76D8 IO";function ce(t){const e=String(t??"").trim();return E.includes(e)?e:null}function ae(t){const e=Math.floor(Number(t??P));return Number.isFinite(e)?Math.min(_,Math.max(1,e)):P}function R(t,e){return[...t].sort((n,s)=>s.value-n.value).slice(0,e)}function A(t){const e=t.replace(/\\/g,"/"),n=e.split("/").filter(Boolean);return n[n.length-1]||e}function b(t){const e=t.indexOf("("),n=t.lastIndexOf(")");if(e<0||n<=e)return null;const s=t.slice(e+1,n),o=t.slice(n+1).trim().split(/\s+/),r=Number(o[11]),i=Number(o[12]);return!Number.isFinite(r)||!Number.isFinite(i)?null:{name:s,ticks:r+i}}function k(t){let e=0,n=0;for(const s of t.split(/\r?\n/)){const[o,r]=s.split(":");if(!o||r===void 0)continue;const i=Number(r.trim());Number.isFinite(i)&&(o.trim()==="read_bytes"?e=i:o.trim()==="write_bytes"&&(n=i))}return{readBytes:e,writeBytes:n}}function W(t){const e=t.trim().match(/^(\d+)\s+([\d.]+)\s+(\d+)\s+(.+)$/);if(!e)return null;const n=Number(e[1]),s=Number(e[2]),o=Number(e[3])*1024;return!Number.isFinite(n)||!Number.isFinite(s)||!Number.isFinite(o)?null:{pid:n,cpuPercent:s,rssBytes:o,name:A(e[4].trim())}}function F(t){const e=[];for(const n of t.split(/\r?\n/)){const s=W(n);s&&e.push(s)}return e}async function $(){const{stdout:t}=await l("ps",["-eo","pid=,pcpu=,rss=,comm="],{encoding:"utf8",timeout:m});return F(t)}function v(t){const e=new Map;for(const n of t.split(/\r?\n/).slice(1)){if(!n.trim()||n.startsWith("State ")||n.trim().split(/\s+/)[0]==="LISTEN")continue;const o=new Set;for(const r of n.matchAll(/\("([^"]+)",pid=(\d+)/g)){const i=Number(r[2]);if(!Number.isFinite(i)||o.has(i))continue;o.add(i);const c=e.get(i)||{name:r[1],connectionCount:0};c.connectionCount+=1,e.set(i,c)}}return e}async function N(){return(await T("/proc")).filter(e=>/^\d+$/.test(e)).map(e=>Number(e))}async function D(){const t=async()=>{const s=await N(),o=await Promise.all(s.map(async r=>{try{const i=await w(`/proc/${r}/stat`,"utf8"),c=b(i);return c?[r,c]:null}catch{return null}}));return new Map(o.filter(Boolean))},e=await t();await new Promise(s=>{setTimeout(s,a)});const n=await t();return{first:e,second:n}}async function G(){const{first:t,second:e}=await D(),n=[];for(const[s,o]of e){const r=t.get(s);if(!r)continue;const i=o.ticks-r.ticks;if(i<=0)continue;const c=a/1e3;n.push({pid:s,name:o.name,value:Math.round(i/O/c*1e3)/10})}return n}async function j(){return(await $()).map(e=>({pid:e.pid,name:e.name,value:e.rssBytes}))}async function U(){const t=async()=>{const r=await N(),i=await Promise.all(r.map(async c=>{try{const[u,p]=await Promise.all([w(`/proc/${c}/stat`,"utf8"),w(`/proc/${c}/io`,"utf8")]),S=b(u);if(!S)return null;const y=k(p);return[c,{name:S.name,readBytes:y.readBytes,writeBytes:y.writeBytes}]}catch{return null}}));return new Map(i.filter(Boolean))},e=await t();await new Promise(r=>{setTimeout(r,a)});const n=await t(),s=a/1e3,o=[];for(const[r,i]of n){const c=e.get(r);if(!c)continue;const u=Math.max(0,Math.round((i.readBytes-c.readBytes)/s)),p=Math.max(0,Math.round((i.writeBytes-c.writeBytes)/s));o.push({pid:r,name:i.name,value:u+p,readBytesPerSecond:u,writeBytesPerSecond:p})}return o}async function J(){const{stdout:t}=await l("ss",["-tupn"],{encoding:"utf8",timeout:m}),e=[];for(const[n,s]of v(t))e.push({pid:n,name:s.name,value:s.connectionCount});return e}async function K(){return(await $()).map(e=>({pid:e.pid,name:e.name,value:e.cpuPercent}))}async function V(){return(await $()).map(e=>({pid:e.pid,name:e.name,value:e.rssBytes}))}function X(t){const e=new Map;for(const n of t.split(/\r?\n/).slice(1)){const s=n.trim().split(/\s+/);if(s.length<8)continue;const o=s[0],r=Number(s[1]);if(!Number.isFinite(r)||r<=0||s.slice(7).join(" ").includes("(LISTEN)"))continue;const c=e.get(r)||{name:o,connectionCount:0};c.connectionCount+=1,e.set(r,c)}return e}async function z(){const{stdout:t}=await l("lsof",["-n","-P","-i","TCP","+c0"],{encoding:"utf8",timeout:m}),e=[];for(const[n,s]of X(t))e.push({pid:n,name:s.name,value:s.connectionCount});return e}const C=`
2
2
  $ErrorActionPreference = 'SilentlyContinue'
3
3
  $cores = [Environment]::ProcessorCount
4
4
  $sw = [System.Diagnostics.Stopwatch]::StartNew()
@@ -46,5 +46,5 @@ foreach ($key in $groups.Keys) {
46
46
  $rows += [pscustomobject]@{ pid = $pidInt; name = $names[$pidInt]; connectionCount = @($groups[$key]).Count }
47
47
  }
48
48
  ConvertTo-Json -InputObject $rows -Compress -Depth 2
49
- `.trim();function d(t){const e=t.trim();if(!e)return[];const n=JSON.parse(e);return Array.isArray(n)?n:[n]}function f(t){return l("powershell",["-NoProfile","-NonInteractive","-Command",t],{encoding:"utf8",timeout:m,windowsHide:!0}).then(e=>e.stdout)}async function q(){return d(await f(C)).filter(e=>Number.isFinite(Number(e.pid))&&Number(e.cpuPercent)>0).map(e=>({pid:Number(e.pid),name:String(e.name||"unknown"),value:Number(e.cpuPercent)}))}async function Q(){return d(await f(C)).filter(e=>Number.isFinite(Number(e.pid))).map(e=>({pid:Number(e.pid),name:String(e.name||"unknown"),value:Number(e.rssBytes||0)}))}async function Z(){return d(await f(H)).filter(e=>Number.isFinite(Number(e.pid))).map(e=>{const n=Number(e.readBytesPerSecond||0),s=Number(e.writeBytesPerSecond||0);return{pid:Number(e.pid),name:String(e.name||"unknown"),value:n+s,readBytesPerSecond:n,writeBytesPerSecond:s}})}async function ee(){return d(await f(Y)).filter(e=>Number.isFinite(Number(e.pid))).map(e=>({pid:Number(e.pid),name:String(e.name||"unknown"),value:Number(e.connectionCount||0)}))}function te(t){return!!(t&&typeof t=="object"&&t.code==="ENOENT")}async function ue(t,e){const n=I.platform(),s={ok:!0,resource:t,limit:e,collectedAt:new Date().toISOString()};if(n==="darwin"&&t==="storage")return{...s,samples:[],unsupported:L};try{let o;return n==="win32"?o=t==="cpu"?await q():t==="memory"?await Q():t==="storage"?await Z():await ee():n==="darwin"?o=t==="cpu"?await K():t==="memory"?await V():await z():o=t==="cpu"?await G():t==="memory"?await j():t==="storage"?await U():await J(),{...s,samples:R(o,e)}}catch(o){if(t==="network"&&(te(o)||n==="win32"))return x.debug("Failed to collect network process top:",o),{...s,samples:[],unsupported:B};throw o}}export{E as PROCESS_TOP_RESOURCES,ae as clampProcessTopLimit,ue as collectProcessTop,ce as normalizeProcessTopResource,d as parseJsonRows,k as parseLinuxIoFile,b as parseLinuxStatLine,X as parseLsofConnectionCounts,W as parsePsMetricsLine,F as parsePsMetricsRows,v as parseSsConnectionCounts,R as sortAndSliceSamples};
49
+ `.trim();function d(t){const e=t.trim();if(!e)return[];const n=JSON.parse(e);return Array.isArray(n)?n:[n]}function f(t){return l("powershell",["-NoProfile","-NonInteractive","-Command",t],{encoding:"utf8",timeout:m,windowsHide:!0}).then(e=>e.stdout)}async function q(){return d(await f(C)).filter(e=>Number.isFinite(Number(e.pid))&&Number(e.cpuPercent)>0).map(e=>({pid:Number(e.pid),name:String(e.name||"unknown"),value:Number(e.cpuPercent)}))}async function Q(){return d(await f(C)).filter(e=>Number.isFinite(Number(e.pid))).map(e=>({pid:Number(e.pid),name:String(e.name||"unknown"),value:Number(e.rssBytes||0)}))}async function Z(){return d(await f(H)).filter(e=>Number.isFinite(Number(e.pid))).map(e=>{const n=Number(e.readBytesPerSecond||0),s=Number(e.writeBytesPerSecond||0);return{pid:Number(e.pid),name:String(e.name||"unknown"),value:n+s,readBytesPerSecond:n,writeBytesPerSecond:s}})}async function ee(){return d(await f(Y)).filter(e=>Number.isFinite(Number(e.pid))).map(e=>({pid:Number(e.pid),name:String(e.name||"unknown"),value:Number(e.connectionCount||0)}))}function te(t){return!!(t&&typeof t=="object"&&t.code==="ENOENT")}async function ue(t,e){const n=M.platform(),s={ok:!0,resource:t,limit:e,collectedAt:new Date().toISOString()};if(n==="darwin"&&t==="storage")return{...s,samples:[],unsupported:L};try{let o;return n==="win32"?o=t==="cpu"?await q():t==="memory"?await Q():t==="storage"?await Z():await ee():n==="darwin"?o=t==="cpu"?await K():t==="memory"?await V():await z():o=t==="cpu"?await G():t==="memory"?await j():t==="storage"?await U():await J(),{...s,samples:R(o,e)}}catch(o){if(t==="network"&&(te(o)||n==="win32"))return x.debug("Failed to collect network process top:",o),{...s,samples:[],unsupported:B};throw o}}export{E as PROCESS_TOP_RESOURCES,ae as clampProcessTopLimit,ue as collectProcessTop,ce as normalizeProcessTopResource,d as parseJsonRows,k as parseLinuxIoFile,b as parseLinuxStatLine,X as parseLsofConnectionCounts,W as parsePsMetricsLine,F as parsePsMetricsRows,v as parseSsConnectionCounts,R as sortAndSliceSamples};
50
50