aws-runtime-bridge 1.9.168 → 1.9.170

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/adapter/AcodeSdkAdapter.d.ts +46 -0
  3. package/dist/adapter/AcodeSdkAdapter.js +4 -4
  4. package/dist/adapter/ClaudeSdkAdapter.js +2 -2
  5. package/dist/adapter/types.d.ts +7 -0
  6. package/dist/config.d.ts +6 -0
  7. package/dist/config.js +2 -2
  8. package/dist/index.js +1 -1
  9. package/dist/routes/agent-state.d.ts +2 -0
  10. package/dist/routes/agent-state.js +2 -0
  11. package/dist/routes/capabilities.js +1 -1
  12. package/dist/routes/debug-mount.d.ts +2 -0
  13. package/dist/routes/debug-mount.js +2 -0
  14. package/dist/routes/mcp.js +1 -1
  15. package/dist/routes/plugins.js +1 -1
  16. package/dist/routes/skills.js +1 -1
  17. package/dist/routes/terminal.js +28 -32
  18. package/dist/services/acode-bg-manager.d.ts +2 -0
  19. package/dist/services/agent-capability-sync.js +1 -1
  20. package/dist/services/debug-mount.d.ts +122 -0
  21. package/dist/services/debug-mount.js +2 -0
  22. package/dist/services/desktop-mcp-manager.js +1 -1
  23. package/dist/services/instance-ai-config-service.js +1 -1
  24. package/dist/services/instance-features.d.ts +4 -0
  25. package/dist/services/instance-features.js +1 -1
  26. package/dist/services/instance-init-service.js +1 -1
  27. package/dist/services/mcp-deploy.d.ts +31 -0
  28. package/dist/services/mcp-deploy.js +4 -3
  29. package/dist/services/mcp-env-injector.d.ts +24 -0
  30. package/dist/services/mcp-env-injector.js +1 -1
  31. package/dist/services/mcp-package.d.ts +35 -0
  32. package/dist/services/mcp-package.js +2 -0
  33. package/dist/services/mcp-probe-client.d.ts +25 -0
  34. package/dist/services/mcp-probe-client.js +2 -0
  35. package/dist/services/panel-env.d.ts +5 -0
  36. package/dist/services/panel-env.js +1 -1
  37. package/dist/services/plugin-deployment.d.ts +36 -0
  38. package/dist/services/plugin-deployment.js +3 -0
  39. package/dist/services/plugin-event-buffer.js +2 -1
  40. package/dist/services/plugin-fs.d.ts +5 -0
  41. package/dist/services/plugin-fs.js +2 -0
  42. package/dist/services/plugin-handler-adapter.d.ts +7 -0
  43. package/dist/services/plugin-handler-adapter.js +3 -0
  44. package/dist/services/plugin-listener-runner.d.ts +18 -0
  45. package/dist/services/plugin-listener-runner.js +8 -0
  46. package/dist/services/plugin-loader.d.ts +32 -0
  47. package/dist/services/plugin-loader.js +2 -0
  48. package/dist/services/plugin-manager.d.ts +17 -136
  49. package/dist/services/plugin-manager.js +4 -15
  50. package/dist/services/plugin-manifest.d.ts +83 -0
  51. package/dist/services/plugin-manifest.js +2 -0
  52. package/dist/services/plugin-runtime.d.ts +67 -0
  53. package/dist/services/plugin-runtime.js +1 -0
  54. package/dist/services/skill-manager.d.ts +15 -0
  55. package/dist/services/skill-manager.js +3 -2
  56. package/dist/types.d.ts +6 -0
  57. package/dist/utils/mcp-utils.js +1 -1
  58. package/package/acode/dist/compaction.d.ts +35 -1
  59. package/package/acode/dist/compaction.js +6 -6
  60. package/package/acode/dist/plugin-types.d.ts +6 -27
  61. package/package/acode/dist/runtime.d.ts +37 -0
  62. package/package/acode/dist/runtime.js +31 -30
  63. package/package/acode/dist/tool-group-manager.d.ts +10 -0
  64. package/package/acode/dist/tool-group-manager.js +5 -10
  65. package/package/acode/dist/types.d.ts +2 -0
  66. package/package/aws-client-agent-mcp/dist/ability-market-tools.d.ts +18 -0
  67. package/package/aws-client-agent-mcp/dist/ability-market-tools.js +2 -0
  68. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +15 -4
  69. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  70. package/package/aws-client-agent-mcp/dist/http-client.d.ts +2 -0
  71. package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
  72. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +0 -7
  73. package/package/aws-client-agent-mcp/dist/mcp-server.js +12 -12
  74. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +3 -0
  75. package/package/aws-client-agent-mcp/dist/mcp-tools.js +20 -20
  76. package/package/aws-client-agent-mcp/dist/memory-store.d.ts +1 -1
  77. package/package/aws-client-agent-mcp/dist/memory-store.js +2 -2
  78. package/package/aws-client-agent-mcp/dist/memory-tools.js +7 -7
  79. package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
  80. package/package/aws-client-agent-mcp/dist/types.d.ts +2 -21
  81. package/package.json +3 -2
  82. package/dist/services/builtin-commands/create-plugin.md +0 -44
@@ -0,0 +1,2 @@
1
+ import{existsSync as A,readFileSync as S}from"node:fs";import{join as p}from"node:path";import{isRecord as b,validateListenerDef as j,validateManifest as J,validateToolDef as R}from"./plugin-manifest.js";class O{constructor(){this.importNonce=0}readJsonFile(t){if(!A(t))return{ok:!0,data:{}};try{const n=JSON.parse(S(t,"utf8"));return b(n)?{ok:!0,data:n}:{ok:!1,error:`${t}: \u6839\u8282\u70B9\u987B\u4E3A\u5BF9\u8C61`}}catch(n){const i=n instanceof Error?n.message:String(n);return{ok:!1,error:`${t}: JSON \u89E3\u6790\u5931\u8D25: ${i}`}}}loadManifestOnly(t){const n=this.readJsonFile(p(t,"plugin.json"));if(!n.ok)return n;const i=n.data,a=J(i);return a?{ok:!1,error:a}:{ok:!0,manifest:i}}validateUserConfigValues(t,n){const i=Array.isArray(t.userConfig)?t.userConfig:[],a={...n};for(const e of i){if(!e||typeof e.key!="string"||!/^[A-Za-z_][A-Za-z0-9_]*$/.test(e.key))return"plugin.json: userConfig.key \u975E\u6CD5\uFF08\u987B\u4E3A\u73AF\u5883\u53D8\u91CF\u540D\uFF09";if(!(typeof a[e.key]=="string"&&a[e.key].length>0)&&e.required){const f=e.default!==void 0&&typeof e.default=="string"?e.default:"";if(!f)return`\u7F3A\u5C11\u5FC5\u9700\u914D\u7F6E ${e.key}${e.description?`\uFF08${e.description}\uFF09`:""}\uFF0C\u5B89\u88C5\u65F6\u8BF7\u5728 config \u4E2D\u63D0\u4F9B`;a[e.key]=f}}return null}loadPluginFromDir(t,n,i,a){const e=this.loadManifestOnly(t);if(!e.ok)return e;const s=e.manifest,f=p(t,s.tools??"tools/tools.json"),u=this.readJsonFile(f);if(!u.ok)return u;const g=[],C=Array.isArray(u.data.tools)?u.data.tools:[];for(const r of C){const l=R(r);if(l)return{ok:!1,error:`${s.tools??"tools/tools.json"}: ${l}`};g.push(r)}const $=p(t,s.listeners??"listeners/listeners.json"),c=this.readJsonFile($);if(!c.ok)return c;const m=[],F=Array.isArray(c.data.listeners)?c.data.listeners:[];for(const r of F){const l=j(r);if(l)return{ok:!1,error:`${s.listeners??"listeners/listeners.json"}: ${l}`};m.push(r)}const k=Array.isArray(s.userConfig)?s.userConfig:[],h=this.validateUserConfigValues(s,a);if(h)return{ok:!1,error:h};const d={...a};for(const r of k){if(!r||typeof r.key!="string")continue;!(typeof d[r.key]=="string"&&d[r.key].length>0)&&r.required&&r.default!==void 0&&typeof r.default=="string"&&(d[r.key]=r.default)}const y=s.commands;let v;if(typeof y=="string"&&y.trim()){const r=p(t,y.trim());A(r)&&(v=r)}return{ok:!0,plugin:{name:s.name,version:typeof s.version=="string"?s.version:void 0,description:typeof s.description=="string"?s.description:void 0,source:n,installedAt:i,dir:t,enabled:!0,tools:g,listeners:m,commandDir:v,userConfig:k,configValues:d,status:"enabled",runtimes:m.map(r=>({def:r,stopping:!1,restarts:0,logs:[]})),moduleCache:new Map,importNonce:++this.importNonce}}}}function w(o){const t=o.inputSchema;if(!(!t||!Array.isArray(t.required)))return t.required.filter(n=>typeof n=="string")}function x(o){const t=e=>!!(e.child||e.timer)||e.def.transport?.type==="http-callback",n=e=>o.enabled?t(e)?"running":e.stopping?"stopped":"pending":"stopped",i=o.runtimes.map(e=>{const s=n(e);return{event:e.def.event,delivery:e.def.delivery??"poll",running:s==="running",state:s,error:e.lastError}}),a=i.some(e=>e.state==="running")?"running":i.some(e=>e.state==="pending")?"pending":"stopped";return{name:o.name,version:o.version,description:o.description,status:o.status,enabled:o.enabled,source:o.source,installedAt:o.installedAt,toolCount:o.tools.length,tools:o.tools.map(e=>({name:e.name,title:e.title,description:e.description})),listeners:i,running:a==="running",listenerState:a,error:o.error}}export{O as PluginLoader,w as requiredParamsOf,x as toSummary};
2
+
@@ -1,80 +1,9 @@
1
1
 
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
- 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;
11
- export interface PluginUserConfigField {
12
- key: string;
13
- type?: "string" | "number" | "boolean";
14
- required?: boolean;
15
- sensitive?: boolean;
16
- description?: string;
17
- default?: string;
18
- }
19
- export interface PluginHandlerDef {
20
- type: "process" | "module" | "mcp";
21
-
22
- command?: string;
23
-
24
- shell?: boolean;
25
-
26
- stdin?: "none" | "params";
27
-
28
- timeoutMs?: number;
29
-
30
- module?: string;
31
-
32
- export?: string;
33
- }
34
- export interface PluginToolDef {
35
- name: string;
36
- title?: string;
37
- description: string;
38
- inputSchema?: Record<string, unknown>;
39
- handler: PluginHandlerDef;
40
- }
41
- export interface PluginTransportDef {
42
- type: "command-stream" | "poll-command" | "http-callback";
43
-
44
- command?: string;
45
-
46
- intervalMs?: number;
47
-
48
- restartBackoffMs?: number;
49
- }
50
- export interface PluginListenerDef {
51
- event: string;
52
- description?: string;
53
- transport: PluginTransportDef;
54
-
55
- delivery?: "poll" | "force" | "wake";
56
- priority?: PluginEventPriority;
57
-
58
- matcher?: Record<string, string | number | boolean | Array<string | number | boolean>>;
59
-
60
- dedupKey?: string;
61
-
62
- toolHints?: string[];
63
-
64
- promptTemplate?: string;
65
- }
66
- export interface PluginManifest {
67
- name: string;
68
- version?: string;
69
- description?: string;
70
- author?: Record<string, unknown>;
71
- tools?: string;
72
- listeners?: string;
73
- commands?: string;
74
- userConfig?: PluginUserConfigField[];
75
- [key: string]: unknown;
76
- }
77
- export declare function validateAgainstSchema(schema: unknown, value: unknown, path?: string): string[];
2
+ import { type ACodeCommandSpec, type ACodePluginBridge, type PluginInvokeContext, type PluginManageRequest, type PluginManageResult, type PluginSummary, type PluginToolInvocationResult, type PluginToolSchema, type JsonObject } from "@agentswork/acode";
3
+ import { type PluginEventMessage } from "./plugin-event-buffer.js";
4
+ export { isValidPluginName, validateManifest, validateAgainstSchema, renderCommandArgv, } from "./plugin-manifest.js";
5
+ export type { PluginUserConfigField, PluginHandlerDef, PluginToolDef, PluginTransportDef, PluginListenerDef, PluginManifest, } from "./plugin-manifest.js";
6
+ export type { ListenerRuntime, LoadedPlugin, InstalledRecord, AgentState, SharedPluginEntry, } from "./plugin-runtime.js";
78
7
  export interface PluginManagerOptions {
79
8
 
80
9
  rootDir?: string;
@@ -86,7 +15,11 @@ export declare class PluginManager {
86
15
  private readonly rootDir;
87
16
  private readonly runtimeRootDir?;
88
17
 
89
- private moduleNonce;
18
+ private readonly listeners;
19
+
20
+ private readonly loader;
21
+
22
+ private readonly deploy;
90
23
  constructor(options?: PluginManagerOptions);
91
24
  forAgent(agentId: string): ACodePluginBridge;
92
25
 
@@ -102,16 +35,15 @@ export declare class PluginManager {
102
35
  list(agentId: string): Promise<PluginSummary[]>;
103
36
 
104
37
  private deployedPluginVersion;
105
- getCatalog(agentId: string): Promise<PluginCatalogSnapshot>;
106
- getToolSchema(agentId: string, qualifiedName: string): Promise<PluginToolSchema | null>;
107
- invokeTool(agentId: string, pluginName: string, toolName: string, params: JsonObject, ctx?: PluginInvokeContext): Promise<PluginToolInvocationResult>;
108
38
 
109
- private buildManageRequest;
110
- private executeHandler;
111
- private invokeProcessHandler;
112
- private invokeModuleHandler;
39
+ getPluginTools(agentId: string, pluginName: string): Promise<PluginToolSchema[]>;
40
+
41
+ debugMountPlugin(agentId: string, dir: string, config?: Record<string, string>): Promise<PluginManageResult>;
42
+
43
+ listDebugPlugins(agentId: string): Promise<PluginSummary[]>;
113
44
 
114
- private buildPluginEnv;
45
+ debugPluginNames(agentId: string): Promise<string[]>;
46
+ invokeTool(agentId: string, pluginName: string, toolName: string, params: JsonObject, ctx?: PluginInvokeContext): Promise<PluginToolInvocationResult>;
115
47
  manage(agentId: string, request: PluginManageRequest): Promise<PluginManageResult>;
116
48
  private doManage;
117
49
  private installPlugin;
@@ -122,25 +54,6 @@ export declare class PluginManager {
122
54
  private uninstallPlugin;
123
55
  private reloadPlugin;
124
56
  private setEnabled;
125
- private deployedDir;
126
- private deployedManifestFile;
127
-
128
- private deployedPluginDir;
129
-
130
- private legacySharedDir;
131
- private readSharedManifest;
132
- private writeSharedManifest;
133
-
134
- private migrateLegacySharedIfNeeded;
135
-
136
- private deployedPluginHealthy;
137
-
138
- private runtimeDirFor;
139
- private runtimeLinkPath;
140
-
141
- private ensureRuntimeLink;
142
-
143
- private removeRuntimeLink;
144
57
 
145
58
  saveSharedPlugin(zipBuffer: Buffer, originalName: string, defaultEnabled?: boolean, sha256?: string): Promise<{
146
59
  ok: boolean;
@@ -148,8 +61,6 @@ export declare class PluginManager {
148
61
  pluginName?: string;
149
62
  }>;
150
63
 
151
- private deployPluginZipToPersistentDir;
152
-
153
64
  private suspendDeployedPluginAcrossAgents;
154
65
 
155
66
  applySharedToKnownAgents(): Promise<Array<{
@@ -174,31 +85,19 @@ export declare class PluginManager {
174
85
  private cleanupRuntimeDir;
175
86
 
176
87
  applyCapabilities(agentId: string): Promise<void>;
177
-
178
- exposePlugin(agentId: string, plugin: string): void;
179
88
  drainEvents(agentId: string, opts?: {
180
89
  maxPerKey?: number;
181
90
  }): Promise<{
182
91
  revision: number;
183
92
  events: PluginEventMessage[];
184
-
185
- catalog: PluginCatalogSnapshot | null;
186
-
187
- compactionSeq: number;
188
93
  }>;
189
94
 
190
- private consumeExposedCatalog;
191
-
192
95
  private pushDeprecatedNotice;
193
96
 
194
- markAgentCompacted(agentId: string): void;
195
-
196
97
  enqueueExternalEvent(agentId: string, pluginName: string, payload: Record<string, unknown>): Promise<{
197
98
  ok: boolean;
198
99
  error?: string;
199
100
  }>;
200
-
201
- private bumpCatalogRevision;
202
101
  private agentState;
203
102
 
204
103
  private hydrate;
@@ -214,25 +113,12 @@ export declare class PluginManager {
214
113
  private readSecrets;
215
114
 
216
115
  private persistSecrets;
217
- private readJsonFile;
218
- private loadManifestOnly;
219
-
220
- private validateUserConfigValues;
221
- private loadPluginFromDir;
222
116
 
223
117
  private ensureListenersRunning;
224
118
  private startAllListeners;
225
119
  private stopAllListeners;
226
- private startListener;
227
- private spawnListenerChild;
228
- private scheduleListenerRestart;
229
120
 
230
- private pollListenerOnce;
231
- private stopListener;
232
- private handleListenerLine;
233
121
  private enqueueEvent;
234
- private requiredParamsOf;
235
- private toSummary;
236
122
  getLogs(agentId: string, pluginName: string): Promise<{
237
123
  ok: boolean;
238
124
  error?: string;
@@ -260,10 +146,5 @@ export declare class PluginManager {
260
146
  }>;
261
147
  }
262
148
 
263
- export declare function isValidPluginName(name: unknown): name is string;
264
- export declare function validateManifest(manifest: Record<string, unknown>): string | null;
265
-
266
- export declare function renderCommandArgv(command: string, lookup: Record<string, unknown>): string[];
267
-
268
149
  export declare const pluginManager: PluginManager;
269
150
  export declare const reconcilePluginsDefaultsFromDeployed: () => number;
@@ -1,16 +1,5 @@
1
- import{spawn as _}from"node:child_process";import{cpSync as F,existsSync as w,lstatSync as ie,mkdirSync as N,readFileSync as b,readdirSync as x,renameSync as j,rmSync as P,symlinkSync as se,writeFileSync as q}from"node:fs";import{dirname as J,join as m,resolve as Y}from"node:path";import{fileURLToPath as oe,pathToFileURL as ae}from"node:url";import{parseAcodeCommandMarkdown as le,splitQualifiedToolName as ue}from"@agentswork/acode";import{getBridgeInstancePluginsDir as ce,getBridgeTemplatePluginsDir as de,getBridgeVersion as fe}from"../config.js";import{sanitizeAgentId as I,withFileLock as W,downloadPluginZip as ge,sanitizeArchiveFileName as pe}from"../utils/file-utils.js";import{BLOCKED_ENV_KEYS as he}from"../utils/env-safety.js";import{createLogger as me}from"../utils/logger.js";import{setDeployedDefaultsProvider as ye,reconcileDefaultsFromDeployed as Se}from"./capability-config.js";import{isCapabilityEnabled as we,getAgentPluginSources as ve}from"./instance-features.js";import{PluginEventBuffer as $e}from"./plugin-event-buffer.js";import{extractPluginZip as U}from"./plugin-package.js";const f=me("plugin-manager"),k="plugin-manager",X="\u7CFB\u7EDF\u5185\u7F6E\uFF1A\u7BA1\u7406\u63D2\u4EF6\u7684\u751F\u547D\u5468\u671F\uFF08\u5B89\u88C5/\u5378\u8F7D/\u542F\u505C/\u91CD\u8F7D\uFF09\uFF1B\u5F00\u53D1\u63D2\u4EF6\u7528\u5185\u7F6E /create-plugin \u547D\u4EE4",Q=`\u300C\u63D2\u4EF6\u7BA1\u7406\u63D2\u4EF6\u300D\u7684\u751F\u547D\u5468\u671F\u5DE5\u5177\uFF1A\u7BA1\u7406\u63D2\u4EF6\uFF08\u5B89\u88C5/\u5378\u8F7D/\u91CD\u8F7D/\u542F\u505C/\u5217\u8868\uFF09\u3002\u4EC5\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u5B89\u88C5\u3001\u79FB\u9664\u6216\u4FEE\u590D\u63D2\u4EF6\u65F6\u4F7F\u7528\u3002
2
- - 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`,ke={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 ee(){const l=fe();return l&&l!=="unknown"?l:void 0}function be(){return oe(new URL("./builtin-commands/",import.meta.url))}const Ee=200,M=256*1024,De=4*1024,te=6e4,z=6e4,Ae=/^[a-zA-Z0-9_][a-zA-Z0-9_-]*$/,H=/^[a-z0-9][a-z0-9-]*$/,Ne=["system.","aws-","acode-"],Ce=/^[A-Za-z_][A-Za-z0-9_]*$/,Le=process.platform==="win32"?"junction":"dir",Ie=/[^\x20-\x7E]/,Oe=6e4,V=20,ne=80;function v(l){return typeof l=="object"&&l!==null&&!Array.isArray(l)}function O(l,e){let t=l;for(const n of e.split(".")){if(!v(t))return;t=t[n]}return t}function D(l,e){return l.length<=e?l:`${l.slice(0,e)}\u2026(\u622A\u65AD,\u5171 ${l.length} \u5B57\u7B26)`}async function T(l,e=8,t=200){for(let n=0;;n++)try{P(l,{recursive:!0,force:!0});return}catch(r){if(n>=e-1)throw r;await new Promise(i=>setTimeout(i,t))}}async function re(l,e){N(J(e),{recursive:!0});try{j(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 T(l)}function A(l,e){l.logs.push(`${new Date().toISOString()} ${e}`),l.logs.length>Ee&&l.logs.shift()}function G(l,e,t="params"){if(!v(l))return[];const n=[],r=l.type;if(typeof r=="string"&&!Te(r,e))return[`${t}: \u671F\u671B ${r}\uFF0C\u5B9E\u9645 ${Me(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"&&v(e)){const i=v(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(...G(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)&&v(l.items)&&e.forEach((i,s)=>{n.push(...G(l.items,i,`${t}[${s}]`))}),n}function Te(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 v(e);case"array":return Array.isArray(e);case"null":return e===null;default:return!0}}function Me(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??de(),this.runtimeRootDir=e.runtimeRootDir}forAgent(e){return{listPlugins:()=>this.list(e),getCatalog:()=>this.getCatalog(e),getToolSchema:t=>this.getToolSchema(e,t),invokeTool:(t,n,r,i)=>this.invokeTool(e,t,n,r,i),manage:t=>this.manage(e,t),getCommandDirs:()=>this.getCommandDirs(e),exposePlugin:t=>this.exposePlugin(e,t)}}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=[],r=be(),i=this.parseCommandDir(k,r);i.length===0&&f.warn("[plugin-manager] \u5185\u7F6E\u547D\u4EE4\u76EE\u5F55\u4E0D\u53EF\u8BFB\u6216\u4E3A\u7A7A: %s\uFF08/create-plugin \u4E0D\u53EF\u7528\uFF0C\u8BF7\u68C0\u67E5\u5B89\u88C5\u5305\u662F\u5426\u5B8C\u6574\uFF09",r),n.push(...i);for(const s of t.plugins.values())!s.enabled||!s.commandDir||n.push(...this.parsePluginCommandDir(s));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 x(t)){if(!r.endsWith(".md"))continue;const i=m(t,r);try{const s=le(i,b(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(k)||n.set(k,{name:k,version:ee(),description:X,status:"enabled",enabled:!0,source:"builtin",installedAt:new Date().toISOString(),toolCount:1,tools:[{name:"plugin-manager.manage",description:"\u63D2\u4EF6\u751F\u547D\u5468\u671F\u7BA1\u7406\uFF08install/uninstall/reload/disable/enable/list\uFF09"}],listeners:[],builtin:!0});for(const r of this.readSharedManifest()){const i=r.pluginName;if(!this.deployedPluginHealthy(i))continue;const o=n.get(i);if(o){String(o.source||"").startsWith("shared:")&&(o.enabled=this.effectiveSharedEnabled(e,r));continue}n.set(i,{name:i,version:this.deployedPluginVersion(i),status:"enabled",enabled:this.effectiveSharedEnabled(e,r),source:`shared:${r.fileName??`${i}.zip`}`,installedAt:new Date().toISOString(),toolCount:0,listeners:[]})}return[...n.values()].sort((r,i)=>r.name.localeCompare(i.name))}deployedPluginVersion(e){try{const t=JSON.parse(b(m(this.deployedPluginDir(e),"plugin.json"),"utf8"));return typeof t.version=="string"?t.version:void 0}catch{return}}async getCatalog(e){const t=await this.hydrate(e),n=[];for(const r of t.plugins.values()){if(!r.enabled||r.status==="error")continue;const i=r.tools.slice(0,V).map(s=>({name:s.name,description:D(s.title||s.description,ne),requiredParams:this.requiredParamsOf(s)}));r.tools.length>V&&i.push({name:`(\u53E6\u6709 ${r.tools.length-V} \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:k,version:ee(),description:X,status:"enabled",tools:[{name:"manage",description:D(Q,ne),requiredParams:["action"]}]}),{revision:t.catalogRevision,plugins:n}}async getToolSchema(e,t){const n=ue(t);if(!n)return null;if(n.plugin===k&&n.tool==="manage")return{plugin:k,name:"manage",description:Q,inputSchema:ke};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===k&&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=G(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=K(t.command??"",{params:n});if(s.length===0)throw new Error("process handler command \u4E3A\u7A7A");const o=typeof t.timeoutMs=="number"&&t.timeoutMs>0?t.timeoutMs:te,a=new AbortController,u=()=>a.abort();i?.signal?.addEventListener("abort",u,{once:!0});const c=setTimeout(()=>a.abort(),o);try{return await new Promise((d,y)=>{f.info("[plugin:%s] spawn: %s",e.name,s.join(" "));const p=_(s[0],s.slice(1),{cwd:e.dir,env:this.buildPluginEnv(e,r),shell:t.shell===!0,windowsHide:!0,signal:a.signal});let g="",h="";p.stdin?.on("error",()=>{}),p.stdout?.on("data",$=>{g.length<M&&(g+=$.toString("utf8"))}),p.stderr?.on("data",$=>{h.length<M&&(h+=$.toString("utf8"))}),p.on("error",$=>{y(new Error(`\u63D2\u4EF6\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${$.message}`))}),p.on("close",$=>{const E=g.trim();if($!==0){const C=D(h.trim()||E||"(\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 ${$}: ${C}`));return}if(!E){d({ok:!0});return}try{d(JSON.parse(E))}catch{d(E)}});try{t.stdin==="params"?p.stdin?.end(`${JSON.stringify(n)}
7
- `):p.stdin?.end()}catch{}})}finally{clearTimeout(c),i?.signal?.removeEventListener("abort",u)}}async invokeModuleHandler(e,t,n,r,i){if(!t.module)throw new Error("module handler \u7F3A\u5C11 module \u8DEF\u5F84");const s=m(e.dir,t.module);let o=e.moduleCache.get(s);o||(o=await import(`${ae(s).href}?acode_nonce=${e.importNonce}`),e.moduleCache.set(s,o));const a=t.export||"default",c=o[a];if(typeof c!="function")throw new Error(`\u6A21\u5757 ${t.module} \u672A\u5BFC\u51FA\u51FD\u6570 ${a}`);const d=typeof t.timeoutMs=="number"&&t.timeoutMs>0?t.timeoutMs:te;let y;const p=Promise.resolve().then(()=>c(n,{agentId:r,signal:i?.signal,pluginRoot:e.dir}));try{return await Promise.race([p,new Promise((g,h)=>{y=setTimeout(()=>h(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)&&(!Ce.test(i)||he.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===k&&(t.action==="uninstall"||t.action==="disable"||t.action==="enable"||t.action==="reload"))return{ok:!1,error:`\u5185\u7F6E\u7CFB\u7EDF\u63D2\u4EF6 ${k} \u4E0D\u53EF${t.action==="uninstall"?"\u5378\u8F7D":t.action==="reload"?"\u91CD\u8F7D":"\u505C\u7528/\u542F\u7528"}`};switch(t.action){case"list":return{ok:!0,plugins:await this.list(e.agentId)};case"install":return this.installPlugin(e,t);case"uninstall":return this.uninstallPlugin(e,t);case"reload":return this.reloadPlugin(e,t);case"enable":case"disable":return this.setEnabled(e,t,t.action==="enable");default:return{ok:!1,error:`\u672A\u77E5 action: ${String(t.action)}`}}}async installPlugin(e,t){const n=(t.source??"").trim();if(!n)return{ok:!1,error:"install \u9700\u8981 source\uFF08\u5F53\u524D\u652F\u6301 local:<\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>\uFF09"};const r=n.split(":",1)[0];if(r!=="local")return{ok:!1,error:`\u6682\u4E0D\u652F\u6301\u63D2\u4EF6\u6765\u6E90 "${r}:"\uFF08npm:/git: \u5728\u8DEF\u7EBF\u56FE\u4E2D\uFF1Bzip \u5305\u8BF7\u7528\u9762\u677F\u5BFC\u5165\u6216 POST /runtime/plugins/:agentId/upload\uFF09`};const i=n.slice(6).trim();return!i||!w(m(i,"plugin.json"))?{ok:!1,error:`\u63D2\u4EF6\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u7F3A\u5C11 plugin.json: ${i}`}:this.installFromDirectory(e,i,n,t.config)}async installFromZip(e,t,n,r){if(!t||t.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};const i=this.agentState(e),s=i.queue.then(async()=>{await this.hydrate(e);const o=m(this.rootDir,"tmp",`upload-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const a=await U(t,o);return w(m(a.pluginDir,"plugin.json"))?(f.info("[agent:%s] zip \u5BFC\u5165: %s\uFF08%d \u4E2A\u6587\u4EF6\uFF09",e,n,a.fileCount),await this.installFromDirectory(i,a.pluginDir,`upload:${n}`,r)):{ok:!1,error:"zip \u5185\u672A\u627E\u5230 plugin.json\uFF08\u8BF7\u6253\u5305\u63D2\u4EF6\u76EE\u5F55\uFF0C\u4E14 zip \u5185\u8DEF\u5F84\u4F7F\u7528\u82F1\u6587\uFF09"}}catch(a){const u=a instanceof Error?a.message:String(a);return f.warn("[agent:%s] zip \u5BFC\u5165\u5931\u8D25: %s",e,u),{ok:!1,error:`zip \u5BFC\u5165\u5931\u8D25: ${u}`}}finally{await T(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===k)return{ok:!1,error:`\u63D2\u4EF6\u540D ${o} \u4E3A\u7CFB\u7EDF\u4FDD\u7559\u540D\u79F0\uFF0C\u4E0D\u5141\u8BB8\u5B89\u88C5\u540C\u540D\u63D2\u4EF6`};const a=this.validateUserConfigValues(s,r??{});if(a)return{ok:!1,error:a};const u=this.loadPluginFromDir(e,t,n,new Date().toISOString(),r??{});if(!u.ok)return f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u6821\u9A8C\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,u.error),u;const c=m(this.rootDir,"cache",I(e.agentId),o),d=t===c,y=e.plugins.get(o);if(y&&this.stopAllListeners(y),!d)try{await T(c),await re(t,c)}catch(h){const $=h instanceof Error?h.message:String(h);return f.warn("[agent:%s] \u63D2\u4EF6\u79FB\u52A8\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,$),y&&this.startAllListeners(e,y),{ok:!1,error:`\u63D2\u4EF6\u79FB\u52A8\u5931\u8D25: ${$}`}}const p=this.loadPluginFromDir(e,c,n,new Date().toISOString(),r??{});if(!p.ok){if(f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,p.error),!d)try{await re(c,t)}catch(h){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,h instanceof Error?h.message:String(h))}if(y)try{this.startAllListeners(e,y)}catch(h){f.warn("[agent:%s] \u6062\u590D\u65E7\u5B9E\u4F8B\u76D1\u542C\u5931\u8D25: %s",e.agentId,h instanceof Error?h.message:String(h))}return p}const g=p.plugin;return e.plugins.set(g.name,g),this.bumpCatalogRevision(e),this.persistInstalled(e),this.startAllListeners(e,g),f.info("[agent:%s] \u63D2\u4EF6\u5DF2\u5B89\u88C5: %s@%s",e.agentId,g.name,g.version??"?"),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(g)}}async uninstallPlugin(e,t){const n=(t.name??"").trim(),r=e.plugins.get(n);return r?(this.stopAllListeners(r),e.plugins.delete(n),e.pendingExposed.delete(n),e.exposedThisSession.has(n)&&this.pushDeprecatedNotice(e,n,"\u5DF2\u88AB\u5378\u8F7D"),this.bumpCatalogRevision(e),this.readSharedManifest().some(s=>s.pluginName===n)&&this.removeRuntimeLink(e.agentId,n),this.persistInstalled(e),await T(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):(e.pendingExposed.delete(r),e.exposedThisSession.has(r)&&this.pushDeprecatedNotice(e,r,"\u5DF2\u505C\u7528"),this.stopAllListeners(i)),this.persistInstalled(e),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(i)}):{ok:!1,error:`\u63D2\u4EF6 ${r} \u672A\u5B89\u88C5`}}deployedDir(){return m(this.rootDir,"deployed")}deployedManifestFile(){return m(this.deployedDir(),"manifest.json")}deployedPluginDir(e){if(!B(e))throw new Error(`\u975E\u6CD5\u63D2\u4EF6\u540D\uFF08\u4EC5\u5141\u8BB8 ${H}\uFF09: ${JSON.stringify(e)}`);const t=m(this.deployedDir(),e),n=Y(this.deployedDir());if(Y(t)!==m(n,e))throw new Error(`\u63D2\u4EF6\u76EE\u5F55\u8D8A\u51FA\u90E8\u7F72\u533A: ${e}`);return t}legacySharedDir(){return m(this.rootDir,"shared")}readSharedManifest(){try{const e=JSON.parse(b(this.deployedManifestFile(),"utf8"));return Array.isArray(e.plugins)?e.plugins.filter(t=>t&&B(t.pluginName)):[]}catch{return[]}}writeSharedManifest(e){N(this.deployedDir(),{recursive:!0}),q(this.deployedManifestFile(),`${JSON.stringify({version:2,plugins:e},null,2)}
8
- `,"utf8")}async migrateLegacySharedIfNeeded(){try{if(w(this.deployedManifestFile()))return;const e=m(this.legacySharedDir(),"manifest.json");if(!w(e))return;const t=JSON.parse(b(e,"utf8")),n=Array.isArray(t.plugins)?t.plugins:[];if(n.length===0)return;const r=[];for(const i of n){const s=m(this.legacySharedDir(),i.zipFile);if(!(!i.pluginName||!w(s)))try{const o=await this.deployPluginZipToPersistentDir(b(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),P(this.legacySharedDir(),{recursive:!0,force:!0})}catch(e){f.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u672A\u6267\u884C\uFF08\u4E0B\u6B21\u91CD\u8BD5\uFF09: %s",e instanceof Error?e.message:String(e))}}deployedPluginHealthy(e){return w(m(this.deployedPluginDir(e),"plugin.json"))}runtimeDirFor(e){return this.runtimeRootDir?m(this.runtimeRootDir,I(e)):ce(e)}runtimeLinkPath(e,t){return m(this.runtimeDirFor(e),t)}ensureRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t),r=this.deployedPluginDir(t);if(!w(m(r,"plugin.json")))return!1;N(this.runtimeDirFor(e),{recursive:!0});try{if(w(n)){let i=!1;try{i=ie(n).isSymbolicLink()}catch{i=!1}if(i)try{return x(n),!0}catch{}P(n,{recursive:!0,force:!0})}return se(r,n,Le),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)&&(P(n,{recursive:!0,force:!0}),f.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u79FB\u9664: %s",e,t))}catch(r){f.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u79FB\u9664\u5931\u8D25\uFF08%s\uFF09: %s",e,t,r instanceof Error?r.message:String(r))}}async saveSharedPlugin(e,t,n=!0,r){if(!e||e.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};await this.migrateLegacySharedIfNeeded();const i=m(this.rootDir,"tmp",`deploy-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const s=await U(e,i),o=this.loadManifestOnly(s.pluginDir);if(!o.ok)return o;const a=o.manifest.name,u=this.readSharedManifest().find(g=>g.pluginName===a);if(u&&u.sha256===r&&this.deployedPluginHealthy(a))return{ok:!0,pluginName:a};await this.suspendDeployedPluginAcrossAgents(a),N(this.deployedDir(),{recursive:!0});const c=this.deployedPluginDir(a),d=m(this.deployedDir(),`.old-${a}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);if(w(c))try{j(c,d)}catch{P(c,{recursive:!0,force:!0})}try{F(s.pluginDir,c,{recursive:!0,filter:g=>!/[\\/]\.git([\\/]|$)/.test(g)&&!/[\\/]node_modules([\\/]|$)/.test(g)})}catch(g){throw w(d)&&(P(c,{recursive:!0,force:!0}),j(d,c)),g}w(d)&&P(d,{recursive:!0,force:!0}),await W(this.deployedManifestFile(),async()=>{const g=this.readSharedManifest().filter(h=>h.pluginName!==a);g.push({pluginName:a,zipFile:u?.zipFile??`${a}.zip`,fileName:t,defaultEnabled:n,sha256:r}),this.writeSharedManifest(g)}),f.info("[shared] \u63D2\u4EF6\u5DF2\u90E8\u7F72\u5230 bridge: %s\uFF08\u6765\u6E90 %s%s\uFF09",a,t,r?`, sha256=${r.slice(0,12)}\u2026`:"");const p=(await this.applySharedToKnownAgents()).find(g=>g.installed.includes(a));return p&&f.info("[shared] \u5DF2\u540C\u6B65\u5230\u8FD0\u884C\u4E2D agent: %s",p.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 T(i,3,100).catch(()=>{})}}async deployPluginZipToPersistentDir(e,t){if(!e||e.length===0)return null;const n=m(this.rootDir,"tmp",`migrate-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const r=await U(e,n),i=this.loadManifestOnly(r.pluginDir);if(!i.ok)return null;const s=i.manifest.name;if(t&&s!==t)return null;N(this.deployedDir(),{recursive:!0});const o=this.deployedPluginDir(s);return w(o)&&P(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{P(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 we(e,"plugins",t.pluginName)&&(t.defaultEnabled??!0)}async pullTemplatePluginsFromCapabilities(e){const t=ve(e.agentId);if(!t)return;const n=this.readSharedManifest();for(const[r,i]of Object.entries(t)){if(!i.url)continue;const s=n.find(a=>a.pluginName===r);if(!s||!s.sha256||s.sha256===i.sha256&&this.deployedPluginHealthy(r)||this.templatePullInFlight.has(r))continue;this.templatePullInFlight.add(r);const o=m(this.rootDir,"tmp",`pull-${I(e.agentId)}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{N(o,{recursive:!0});let a=`${r}.zip`;try{const y=decodeURIComponent(i.url.split("/").pop()||"");y.toLowerCase().endsWith(".zip")&&(a=pe(y,`${r}.zip`))}catch{}const u=await ge({downloadUrl:i.url,fileName:a,sha256:i.sha256},o);if(!u)continue;const c=b(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 T(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 x(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)}exposePlugin(e,t){if(!t)return;const n=this.agentState(e);n.pendingExposed.add(t),n.exposedThisSession.add(t),f.debug("[agent:%s] \u63D2\u4EF6\u5DF2\u89E6\u53D1\u5F85\u66B4\u9732: %s",e,t)}async drainEvents(e,t={}){const n=await this.hydrate(e);this.ensureListenersRunning(n);const r=n.buffer.drain(t),i=await this.consumeExposedCatalog(n);return{revision:r.revision,events:r.events,catalog:i,compactionSeq:n.compactionSeq}}async consumeExposedCatalog(e){if(e.pendingExposed.size===0)return null;const t=await this.getCatalog(e.agentId),n=[...e.pendingExposed];e.pendingExposed.clear();const r=t.plugins.filter(i=>n.includes(i.plugin));return r.length===0?null:{revision:t.revision,plugins:r}}pushDeprecatedNotice(e,t,n){e.buffer.push({plugin:t,event:"plugin-deprecated",priority:"urgent",receivedAt:Date.now(),message:{msgId:`plugin-deprecated-${t}-${Date.now()}`,channel:"plugin-event",senderId:`plugin:${t}`,senderName:`\u63D2\u4EF6[${t}]`,receiverId:e.agentId||void 0,content:`\u3010\u7CFB\u7EDF\u63D0\u793A\u3011\u63D2\u4EF6 ${t} ${n}\uFF0C\u5176\u63D0\u4F9B\u7684\u5DE5\u5177\u4E0D\u518D\u53EF\u8C03\u7528\u3002\u5982\u4ECD\u9700\u4F7F\u7528\u8BF7\u91CD\u65B0\u5B89\u88C5/\u542F\u7528\u8BE5\u63D2\u4EF6\u3002`,requireReply:!1,role:"system",timestamp:new Date().toISOString()}})}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 $e(e),hydrated:!1,queue:Promise.resolve(),catalogRevision:0,eventSeq:0,compactionSeq:0,pendingExposed:new Set,exposedThisSession:new Set},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(b(n,"utf8")),i=this.readSecrets(t);for(const s of r.plugins??[]){if(String(s.source||"").startsWith("shared:"))continue;const a=m(this.rootDir,"cache",I(t),s.name);if(!w(m(a,"plugin.json"))){f.warn("[agent:%s] \u5DF2\u5B89\u88C5\u63D2\u4EF6\u76EE\u5F55\u7F3A\u5931\uFF0C\u8DF3\u8FC7: %s",t,s.name);continue}const u={...s.config,...i[s.name]??{}},c=this.loadPluginFromDir(e,a,s.source,s.installedAt,u);if(c.ok){const d=c.plugin;d.enabled=s.enabled,e.plugins.set(d.name,d)}else f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25: %s: %s",t,s.name,c.error)}}catch(r){const i=r instanceof Error?r.message:String(r);f.error("[agent:%s] installed.json \u89E3\u6790\u5931\u8D25: %s",t,i)}await this.syncSharedIntoState(e).catch(r=>{f.warn("[agent:%s] \u5171\u4EAB\u63D2\u4EF6\u540C\u6B65\u5931\u8D25: %s",t,r instanceof Error?r.message:String(r))}),e.hydrated=!0}installedFile(e){return m(this.rootDir,"agents",I(e),"installed.json")}persistInstalled(e){this.persistSecrets(e);const t=this.installedFile(e.agentId);N(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)}));q(t,`${JSON.stringify({version:1,plugins:n},null,2)}
9
- `,"utf8")}sensitiveKeysOf(e){return(e.userConfig??[]).filter(t=>t?.sensitive===!0&&typeof t.key=="string").map(t=>t.key)}stripSensitiveValues(e){const t=new Set(this.sensitiveKeysOf(e)),n={};for(const[r,i]of Object.entries(e.configValues))t.has(r)||(n[r]=i);return n}secretsFile(e){return m(this.rootDir,"agents",I(e),"secrets.json")}readSecrets(e){try{const t=JSON.parse(b(this.secretsFile(e),"utf8"));if(!v(t)||!v(t.secrets))return{};const n={};for(const[r,i]of Object.entries(t.secrets)){if(!v(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{P(n,{force:!0})}catch{}return}N(J(n),{recursive:!0}),q(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(b(e,"utf8"));return v(t)?{ok:!0,data:t}:{ok:!1,error:`${e}: \u6839\u8282\u70B9\u987B\u4E3A\u5BF9\u8C61`}}catch(t){const n=t instanceof Error?t.message:String(t);return{ok:!1,error:`${e}: JSON \u89E3\u6790\u5931\u8D25: ${n}`}}}loadManifestOnly(e){const t=this.readJsonFile(m(e,"plugin.json"));if(!t.ok)return t;const n=t.data,r=_e(n);return r?{ok:!1,error:r}:{ok:!0,manifest:n}}validateUserConfigValues(e,t){const n=Array.isArray(e.userConfig)?e.userConfig:[],r={...t};for(const i of n){if(!i||typeof i.key!="string"||!/^[A-Za-z_][A-Za-z0-9_]*$/.test(i.key))return"plugin.json: userConfig.key \u975E\u6CD5\uFF08\u987B\u4E3A\u73AF\u5883\u53D8\u91CF\u540D\uFF09";if(!(typeof r[i.key]=="string"&&r[i.key].length>0)&&i.required){const o=i.default!==void 0&&typeof i.default=="string"?i.default:"";if(!o)return`\u7F3A\u5C11\u5FC5\u9700\u914D\u7F6E ${i.key}${i.description?`\uFF08${i.description}\uFF09`:""}\uFF0C\u5B89\u88C5\u65F6\u8BF7\u5728 config \u4E2D\u63D0\u4F9B`;r[i.key]=o}}return null}loadPluginFromDir(e,t,n,r,i){const s=this.loadManifestOnly(t);if(!s.ok)return s;const o=s.manifest,a=m(t,o.tools??"tools/tools.json"),u=this.readJsonFile(a);if(!u.ok)return u;const c=[],d=Array.isArray(u.data.tools)?u.data.tools:[];for(const S of d){const L=Fe(S);if(L)return{ok:!1,error:`${o.tools??"tools/tools.json"}: ${L}`};c.push(S)}const y=m(t,o.listeners??"listeners/listeners.json"),p=this.readJsonFile(y);if(!p.ok)return p;const g=[],h=Array.isArray(p.data.listeners)?p.data.listeners:[];for(const S of h){const L=xe(S);if(L)return{ok:!1,error:`${o.listeners??"listeners/listeners.json"}: ${L}`};g.push(S)}const $=Array.isArray(o.userConfig)?o.userConfig:[],E=this.validateUserConfigValues(o,i);if(E)return{ok:!1,error:E};const C={...i};for(const S of $){if(!S||typeof S.key!="string")continue;!(typeof C[S.key]=="string"&&C[S.key].length>0)&&S.required&&S.default!==void 0&&typeof S.default=="string"&&(C[S.key]=S.default)}const R=o.commands;let Z;if(typeof R=="string"&&R.trim()){const S=m(t,R.trim());w(S)&&(Z=S)}return{ok:!0,plugin:{name:o.name,version:typeof o.version=="string"?o.version:void 0,description:typeof o.description=="string"?o.description:void 0,source:n,installedAt:r,dir:t,enabled:!0,tools:c,listeners:g,commandDir:Z,userConfig:$,configValues:C,status:"enabled",runtimes:g.map(S=>({def:S,stopping:!1,restarts:0,logs:[]})),moduleCache:new Map,importNonce:++this.moduleNonce}}}ensureListenersRunning(e){for(const t of e.plugins.values())if(t.enabled)for(const n of t.runtimes)!n.child&&!n.timer&&!n.backoffTimer&&!n.stopping&&this.startListener(e,t,n)}startAllListeners(e,t){for(const n of t.runtimes)this.stopListener(n),t.enabled&&this.startListener(e,t,n)}stopAllListeners(e){for(const t of e.runtimes)this.stopListener(t)}startListener(e,t,n){const r=n.def.transport??{type:"command-stream"};if(r.type==="http-callback"){n.stopping=!1;return}if(r.type==="poll-command"){const i=Math.max(5e3,r.intervalMs??3e4);n.stopping=!1,n.timer=setInterval(()=>{this.pollListenerOnce(e,t,n)},i),this.pollListenerOnce(e,t,n);return}if(!r.command){n.lastError="command-stream \u7F3A\u5C11 command",A(n,`ERROR ${n.lastError}`);return}n.stopping=!1,this.spawnListenerChild(e,t,n)}spawnListenerChild(e,t,n){const i=n.def.transport?.command??"",s=K(i,{});try{A(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=>{A(n,`stderr: ${D(u.toString("utf8").trimEnd(),400)}`)}),o.on("error",u=>{n.lastError=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${u.message}`,A(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`,A(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,A(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(Oe,r*2**Math.min(n.restarts,6));n.restarts++,A(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=K(r,{});if(i.length===0)return;n.polling=!0;const s=new AbortController,o=setTimeout(()=>s.abort(),z);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="",p="";d.stdout?.on("data",h=>{y.length<M&&(y+=h.toString("utf8"))}),d.stderr?.on("data",h=>{p.length<M&&(p+=h.toString("utf8"))});const g=()=>s.signal.aborted;d.on("error",h=>{c(g()?new Error(`poll \u8D85\u65F6(${z}ms)`):h)}),d.on("close",h=>{g()?c(new Error(`poll \u8D85\u65F6(${z}ms)`)):h===0?u(y):c(new Error(`exit ${h}: ${D(p||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,A(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){A(n,`event: ${D(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(!v(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[p,g]of Object.entries(n.matcher??{})){const h=O(r,p);if(!(Array.isArray(g)?g:[g]).some(E=>JSON.stringify(E)===JSON.stringify(h)))return}let i;if(n.dedupKey){const p=O(r,n.dedupKey);p!=null&&(i=D(String(p),256))}e.eventSeq++;const s=D(qe(r.data??r),De),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:D(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})&&this.exposePlugin(e.agentId,t.name)}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===k)return{ok:!0,logs:[`\u2500\u2500 ${k} \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(b(m(r,"plugin.json"),"utf8"));typeof o.version=="string"&&(s=o.version)}catch{}t.push({pluginName:n.pluginName,version:s,fileName:n.fileName??`${n.pluginName}.zip`,defaultEnabled:n.defaultEnabled!==!1,sha256:n.sha256,deployed:i})}return t}deployedDefaultEnabled(){const e=this.readSharedManifest(),t={};for(const n of e)t[n.pluginName]=n.defaultEnabled!==!1;return t}async removeDeployedPlugin(e){if(!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 W(this.deployedManifestFile(),async()=>{const t=this.readSharedManifest().filter(n=>n.pluginName!==e);this.writeSharedManifest(t)});try{P(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&&H.test(l)}function _e(l){const e=l.name;if(typeof e!="string"||!H.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 Ne)if(e===t.replace(/\.$/,"")||e.startsWith(t))return`plugin.json: name \u4F7F\u7528\u4E86\u4FDD\u7559\u524D\u7F00 ${t}`;return Ie.test(e)?"plugin.json: name \u542B\u975E ASCII \u5B57\u7B26\uFF08\u540C\u5F62\u5B57\u9632\u62A4\uFF09":l.version!==void 0&&typeof l.version!="string"?"plugin.json: version \u987B\u4E3A\u5B57\u7B26\u4E32":l.userConfig!==void 0&&!Array.isArray(l.userConfig)?"plugin.json: userConfig \u987B\u4E3A\u6570\u7EC4":null}function Fe(l){if(!v(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(!v(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&&!v(l.inputSchema)?`\u5DE5\u5177 ${e} inputSchema \u987B\u4E3A\u5BF9\u8C61`:null}function xe(l){if(!v(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(!v(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 K(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,i)=>{const s=O(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=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 qe(l){try{return JSON.stringify(l)??"null"}catch{return"(\u4E0D\u53EF\u5E8F\u5217\u5316\u7684\u4E8B\u4EF6\u8D1F\u8F7D)"}}const Je=new Re;ye("plugins",()=>Je.deployedDefaultEnabled());const nt=()=>Se("plugins");export{X as BUILTIN_PLUGIN_DESCRIPTION,Q as BUILTIN_PLUGIN_MANAGE_DESC,k as BUILTIN_PLUGIN_NAME,Re as PluginManager,be as getBuiltinCommandDir,B as isValidPluginName,Je as pluginManager,nt as reconcilePluginsDefaultsFromDeployed,K as renderCommandArgv,G as validateAgainstSchema,_e as validateManifest};
1
+ import{existsSync as y,mkdirSync as D,readFileSync as S,readdirSync as I,rmSync as C,writeFileSync as $}from"node:fs";import{dirname as A,join as h}from"node:path";import{parseAcodeCommandMarkdown as F}from"@agentswork/acode";import{getBridgeTemplatePluginsDir as L}from"../config.js";import{sanitizeAgentId as v,downloadPluginZip as O,sanitizeArchiveFileName as R}from"../utils/file-utils.js";import{createLogger as M}from"../utils/logger.js";import{setDeployedDefaultsProvider as j,reconcileDefaultsFromDeployed as T}from"./capability-config.js";import{executeHandler as x}from"./plugin-handler-adapter.js";import{isCapabilityEnabled as z,getAgentPluginSources as q}from"./instance-features.js";import{PluginEventBuffer as V}from"./plugin-event-buffer.js";import{ListenerRunner as H}from"./plugin-listener-runner.js";import{PluginLoader as J,toSummary as w}from"./plugin-loader.js";import{extractPluginZip as E}from"./plugin-package.js";import{isRecord as k,isValidPluginName as K,validateAgainstSchema as W}from"./plugin-manifest.js";import{movePluginDir as N,rmWithRetry as P}from"./plugin-fs.js";import{PluginDeploymentStore as U}from"./plugin-deployment.js";import{isValidPluginName as pe,validateManifest as me,validateAgainstSchema as ye,renderCommandArgv as Se}from"./plugin-manifest.js";const u=M("plugin-manager");class Z{constructor(e={}){this.agents=new Map,this.listeners=new H,this.loader=new J,this.templatePullInFlight=new Set,this.backgroundTemplatePulls=new Set,this.rootDir=e.rootDir??L(),this.runtimeRootDir=e.runtimeRootDir,this.deploy=new U(this.rootDir,this.runtimeRootDir,this.loader)}forAgent(e){return{listPlugins:()=>this.list(e),getPluginTools:t=>this.getPluginTools(e,t),invokeTool:(t,s,n,i)=>this.invokeTool(e,t,s,n,i),manage:t=>this.manage(e,t),getCommandDirs:()=>this.getCommandDirs(e)}}setOnPluginsChanged(e){this.onPluginsChanged=e}notifyPluginsChanged(e){try{this.onPluginsChanged?.(e)}catch(t){u.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(s=>s.enabled&&s.commandDir).map(s=>s.commandDir)}async getPluginCommands(e){const t=await this.hydrate(e),s=[];for(const n of t.plugins.values())!n.enabled||!n.commandDir||s.push(...this.parsePluginCommandDir(n));return s}parsePluginCommandDir(e){return this.parseCommandDir(e.name,e.commandDir)}parseCommandDir(e,t){const s=[];if(!t)return s;try{for(const n of I(t)){if(!n.endsWith(".md"))continue;const i=h(t,n);try{const r=F(i,S(i,"utf8"));r.plugin=e,s.push(r)}catch(r){u.warn("[plugin:%s] \u547D\u4EE4\u89E3\u6790\u5931\u8D25 %s: %s",e,n,r instanceof Error?r.message:String(r))}}}catch{}return s}async list(e){const t=await this.hydrate(e),s=new Map;for(const n of t.plugins.values()){const i=w(n);s.set(i.name,i)}for(const n of this.deploy.readSharedManifest()){const i=n.pluginName;if(!this.deploy.deployedPluginHealthy(i))continue;const o=s.get(i);if(o){String(o.source||"").startsWith("shared:")&&(o.enabled=this.effectiveSharedEnabled(e,n));continue}s.set(i,{name:i,version:this.deployedPluginVersion(i),status:"enabled",enabled:this.effectiveSharedEnabled(e,n),source:`shared:${n.fileName??`${i}.zip`}`,installedAt:new Date().toISOString(),toolCount:0,listeners:[]})}return[...s.values()].sort((n,i)=>n.name.localeCompare(i.name))}deployedPluginVersion(e){try{const t=JSON.parse(S(h(this.deploy.deployedPluginDir(e),"plugin.json"),"utf8"));return typeof t.version=="string"?t.version:void 0}catch{return}}async getPluginTools(e,t){const n=(await this.hydrate(e)).plugins.get(t);return!n||!n.enabled?[]:n.tools.map(i=>({plugin:n.name,name:i.name,title:i.title,description:i.description,inputSchema:i.inputSchema??{type:"object",properties:{}}}))}async debugMountPlugin(e,t,s={}){const n=String(t??"").trim();if(!n)return{ok:!1,error:"\u63D2\u4EF6\u76EE\u5F55\u4E0D\u80FD\u4E3A\u7A7A"};if(!y(n))return{ok:!1,error:`\u63D2\u4EF6\u76EE\u5F55\u4E0D\u5B58\u5728: ${n}`};const i=this.loader.loadManifestOnly(n);if(!i.ok)return i;const r=i.manifest.name,o=this.agentState(e),a=o.queue.then(async()=>{const l=await this.hydrate(e),c=l.plugins.get(r);c&&this.stopAllListeners(c);const g=this.loader.loadPluginFromDir(n,`debug:${n}`,new Date().toISOString(),s);if(!g.ok)return c&&this.startAllListeners(l,c),{ok:!1,error:`\u8C03\u8BD5\u6302\u8F7D\u5931\u8D25: ${g.error}`};const d=g.plugin;return d.debug=!0,l.plugins.set(d.name,d),this.startAllListeners(l,d),u.info("[agent:%s] \u63D2\u4EF6\u5DF2\u8C03\u8BD5\u6302\u8F7D: %s@%s\uFF08dir=%s\uFF09",l.agentId,d.name,d.version??"?",n),this.notifyPluginsChanged(l.agentId),{ok:!0,summary:w(d)}});return o.queue=a.catch(()=>{}),a}async listDebugPlugins(e){return[...(await this.hydrate(e)).plugins.values()].filter(s=>s.debug===!0).map(s=>w(s))}async debugPluginNames(e){return[...(await this.hydrate(e)).plugins.values()].filter(s=>s.debug===!0).map(s=>s.name)}async invokeTool(e,t,s,n,i){const r=await this.hydrate(e),o=r.plugins.get(t);if(!o)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\uFF08\u53EF\u7528\u63D2\u4EF6: ${[...r.plugins.keys()].join(", ")||"\u65E0"}\uFF09`};if(!o.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u5DF2\u505C\u7528\uFF0C\u8BF7\u8BA9\u7528\u6237\u5728\u9762\u677F\u542F\u7528`};const a=o.tools.find(l=>l.name===s);if(!a)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5DE5\u5177 ${s}\uFF08\u53EF\u7528: ${o.tools.map(l=>l.name).join(", ")||"\u65E0"}\uFF09`};if(a.inputSchema){const l=W(a.inputSchema,n);if(l.length>0)return{ok:!1,error:`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${l.join("; ")}`,inputSchema:a.inputSchema}}return x(e,o,a,n,i)}async manage(e,t){const s=this.agentState(e),n=s.queue.then(async()=>{const i=await this.hydrate(e);return this.doManage(i,t)});return s.queue=n.catch(()=>{}),n}async doManage(e,t){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 s=(t.source??"").trim();if(!s)return{ok:!1,error:"install \u9700\u8981 source\uFF08\u5F53\u524D\u652F\u6301 local:<\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>\uFF09"};const n=s.split(":",1)[0];if(n!=="local")return{ok:!1,error:`\u6682\u4E0D\u652F\u6301\u63D2\u4EF6\u6765\u6E90 "${n}:"\uFF08npm:/git: \u5728\u8DEF\u7EBF\u56FE\u4E2D\uFF1Bzip \u5305\u8BF7\u7528\u9762\u677F\u5BFC\u5165\u6216 POST /runtime/plugins/:agentId/upload\uFF09`};const i=s.slice(6).trim();return!i||!y(h(i,"plugin.json"))?{ok:!1,error:`\u63D2\u4EF6\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u7F3A\u5C11 plugin.json: ${i}`}:this.installFromDirectory(e,i,s,t.config)}async installFromZip(e,t,s,n){if(!t||t.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};const i=this.agentState(e),r=i.queue.then(async()=>{await this.hydrate(e);const o=h(this.rootDir,"tmp",`upload-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const a=await E(t,o);return y(h(a.pluginDir,"plugin.json"))?(u.info("[agent:%s] zip \u5BFC\u5165: %s\uFF08%d \u4E2A\u6587\u4EF6\uFF09",e,s,a.fileCount),await this.installFromDirectory(i,a.pluginDir,`upload:${s}`,n)):{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 l=a instanceof Error?a.message:String(a);return u.warn("[agent:%s] zip \u5BFC\u5165\u5931\u8D25: %s",e,l),{ok:!1,error:`zip \u5BFC\u5165\u5931\u8D25: ${l}`}}finally{await P(o,3,100).catch(()=>{})}});return i.queue=r.catch(()=>{}),r}async installFromDirectory(e,t,s,n){const i=this.loader.loadManifestOnly(t);if(!i.ok)return i;const r=i.manifest,o=r.name,a=this.loader.validateUserConfigValues(r,n??{});if(a)return{ok:!1,error:a};const l=this.loader.loadPluginFromDir(t,s,new Date().toISOString(),n??{});if(!l.ok)return u.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u6821\u9A8C\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,s,l.error),l;const c=h(this.rootDir,"cache",v(e.agentId),o),g=t===c,d=e.plugins.get(o);if(d&&this.stopAllListeners(d),!g)try{await P(c),await N(t,c)}catch(f){const b=f instanceof Error?f.message:String(f);return u.warn("[agent:%s] \u63D2\u4EF6\u79FB\u52A8\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,s,b),d&&this.startAllListeners(e,d),{ok:!1,error:`\u63D2\u4EF6\u79FB\u52A8\u5931\u8D25: ${b}`}}const m=this.loader.loadPluginFromDir(c,s,new Date().toISOString(),n??{});if(!m.ok){if(u.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,s,m.error),!g)try{await N(c,t)}catch(f){u.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,f instanceof Error?f.message:String(f))}if(d)try{this.startAllListeners(e,d)}catch(f){u.warn("[agent:%s] \u6062\u590D\u65E7\u5B9E\u4F8B\u76D1\u542C\u5931\u8D25: %s",e.agentId,f instanceof Error?f.message:String(f))}return m}const p=m.plugin;return e.plugins.set(p.name,p),this.persistInstalled(e),this.startAllListeners(e,p),u.info("[agent:%s] \u63D2\u4EF6\u5DF2\u5B89\u88C5: %s@%s",e.agentId,p.name,p.version??"?"),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:w(p)}}async uninstallPlugin(e,t){const s=(t.name??"").trim(),n=e.plugins.get(s);return n?(this.stopAllListeners(n),e.plugins.delete(s),n.tools.length>0&&this.pushDeprecatedNotice(e,s,"\u5DF2\u88AB\u5378\u8F7D"),this.deploy.readSharedManifest().some(r=>r.pluginName===s)&&this.deploy.removeRuntimeLink(e.agentId,s),this.persistInstalled(e),n.debug!==!0&&await P(n.dir),u.info("[agent:%s] \u63D2\u4EF6\u5DF2\u5378\u8F7D: %s",e.agentId,s),this.notifyPluginsChanged(e.agentId),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${s} \u672A\u5B89\u88C5`}}async reloadPlugin(e,t){const s=(t.name??"").trim(),n=e.plugins.get(s);if(!n)return{ok:!1,error:`\u63D2\u4EF6 ${s} \u672A\u5B89\u88C5`};const i=this.loader.loadPluginFromDir(n.dir,n.source,n.installedAt,n.configValues);if(!i.ok)return{ok:!1,error:`\u91CD\u8F7D\u5931\u8D25\uFF08\u4FDD\u7559\u65E7\u7248\u672C\u8FD0\u884C\uFF09: ${i.error}`};const r=i.plugin;return r.debug=n.debug,this.stopAllListeners(n),e.plugins.set(s,r),this.persistInstalled(e),this.startAllListeners(e,r),u.info("[agent:%s] \u63D2\u4EF6\u5DF2\u91CD\u8F7D: %s",e.agentId,s),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:w(r)}}async setEnabled(e,t,s){const n=(t.name??"").trim(),i=e.plugins.get(n);return i?(i.enabled=s,s?this.startAllListeners(e,i):(i.tools.length>0&&this.pushDeprecatedNotice(e,n,"\u5DF2\u505C\u7528"),this.stopAllListeners(i)),this.persistInstalled(e),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:w(i)}):{ok:!1,error:`\u63D2\u4EF6 ${n} \u672A\u5B89\u88C5`}}async saveSharedPlugin(e,t,s=!0,n){if(!e||e.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};await this.deploy.migrateLegacySharedIfNeeded();const i=h(this.rootDir,"tmp",`deploy-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const r=await E(e,i),o=this.loader.loadManifestOnly(r.pluginDir);if(!o.ok)return o;const a=o.manifest.name,l=this.deploy.readSharedManifest().find(d=>d.pluginName===a);if(l&&l.sha256===n&&this.deploy.deployedPluginHealthy(a))return{ok:!0,pluginName:a};await this.suspendDeployedPluginAcrossAgents(a),this.deploy.replaceDeployedDir(a,r.pluginDir),await this.deploy.updateSharedManifest(d=>{const m=d.filter(p=>p.pluginName!==a);return m.push({pluginName:a,zipFile:l?.zipFile??`${a}.zip`,fileName:t,defaultEnabled:s,sha256:n}),m}),u.info("[shared] \u63D2\u4EF6\u5DF2\u90E8\u7F72\u5230 bridge: %s\uFF08\u6765\u6E90 %s%s\uFF09",a,t,n?`, sha256=${n.slice(0,12)}\u2026`:"");const g=(await this.applySharedToKnownAgents()).find(d=>d.installed.includes(a));return g&&u.info("[shared] \u5DF2\u540C\u6B65\u5230\u8FD0\u884C\u4E2D agent: %s",g.agentId),{ok:!0,pluginName:a}}catch(r){const o=r instanceof Error?r.message:String(r);return u.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 P(i,3,100).catch(()=>{})}}async suspendDeployedPluginAcrossAgents(e){for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const s=t.queue.then(async()=>{const n=t.plugins.get(e);n&&(this.stopAllListeners(n),t.plugins.delete(e),u.info("[agent:%s] \u5DF2\u6458\u9664\u63D2\u4EF6\u7B49\u5F85\u90E8\u7F72\u533A\u66F4\u65B0: %s",t.agentId,e))});t.queue=s.catch(()=>{}),await s}}async applySharedToKnownAgents(){const e=[];for(const t of this.agents.values()){if(!t.hydrated)continue;const s=await this.syncSharedIntoStateQueued(t);s.length>0&&e.push({agentId:t.agentId,installed:s})}return e}async syncSharedIntoStateQueued(e){const t=e.queue.then(()=>this.syncSharedIntoState(e));return e.queue=t.catch(()=>[]),t}effectiveSharedEnabled(e,t){return z(e,"plugins",t.pluginName)&&(t.defaultEnabled??!0)}async pullTemplatePluginsFromCapabilities(e){const t=q(e.agentId);if(!t)return;const s=this.deploy.readSharedManifest();for(const[n,i]of Object.entries(t)){if(!i.url)continue;const r=s.find(a=>a.pluginName===n);if(!r||!r.sha256||r.sha256===i.sha256&&this.deploy.deployedPluginHealthy(n)||this.templatePullInFlight.has(n))continue;this.templatePullInFlight.add(n);const o=h(this.rootDir,"tmp",`pull-${v(e.agentId)}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{D(o,{recursive:!0});let a=`${n}.zip`;try{const d=decodeURIComponent(i.url.split("/").pop()||"");d.toLowerCase().endsWith(".zip")&&(a=R(d,`${n}.zip`))}catch{}const l=await O({downloadUrl:i.url,fileName:a,sha256:i.sha256},o);if(!l)continue;const c=S(l.outputPath),g=await this.saveSharedPlugin(c,l.fileName,r.defaultEnabled??!0,i.sha256);g.ok?u.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u81EA\u52A8\u5BF9\u8D26\u66F4\u65B0\u6210\u529F: %s",e.agentId,g.pluginName??n):u.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u66F4\u65B0\u5931\u8D25: %s: %s",e.agentId,n,g.error)}catch(a){u.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6 %s \u66F4\u65B0\u5931\u8D25: %s",e.agentId,n,a instanceof Error?a.message:String(a))}finally{this.templatePullInFlight.delete(n),await P(o,3,100).catch(()=>{})}}}queueTemplatePull(e){this.backgroundTemplatePulls.has(e.agentId)||(this.backgroundTemplatePulls.add(e.agentId),this.pullTemplatePluginsFromCapabilities(e).catch(t=>{u.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.deploy.readSharedManifest(),s=new Set,n=[];let i=0;for(const r of t)if(s.add(r.pluginName),this.effectiveSharedEnabled(e.agentId,r)){const a=e.plugins.get(r.pluginName);if(!this.deploy.ensureRuntimeLink(e.agentId,r.pluginName))continue;const l=this.deploy.runtimeLinkPath(e.agentId,r.pluginName);if(!a){const c=this.loader.loadPluginFromDir(l,`shared:${r.fileName}`,new Date().toISOString(),{});c.ok?(e.plugins.set(c.plugin.name,c.plugin),n.push(c.plugin.name),u.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u5DF2\u6309\u5F00\u542F\u6001\u52A0\u8F7D: %s",e.agentId,r.pluginName)):u.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25: %s: %s",e.agentId,r.pluginName,c.error)}}else{const a=e.plugins.get(r.pluginName);a&&(this.stopAllListeners(a),e.plugins.delete(r.pluginName),i++),this.deploy.removeRuntimeLink(e.agentId,r.pluginName)}return this.cleanupRuntimeDir(e,s),this.persistInstalled(e),n}cleanupRuntimeDir(e,t){const s=this.deploy.runtimeDirFor(e.agentId);try{if(!y(s))return;const n=new Set(t);for(const i of I(s))!n.has(i)&&!e.plugins.has(i)&&this.deploy.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 s=await this.hydrate(e);this.ensureListenersRunning(s);const n=s.buffer.drain(t);return{revision:n.revision,events:n.events}}pushDeprecatedNotice(e,t,s){e.buffer.push({plugin:t,event:"plugin-deprecated",priority:"urgent",receivedAt:Date.now(),message:{msgId:`plugin-deprecated-${t}-${Date.now()}`,channel:"plugin-event",senderId:`plugin:${t}`,senderName:`\u63D2\u4EF6[${t}]`,receiverId:e.agentId||void 0,content:`[plugin:${t}] plugin-deprecated
2
+ \u3010\u7CFB\u7EDF\u63D0\u793A\u3011\u63D2\u4EF6 ${t} ${s}\uFF0C\u5176\u63D0\u4F9B\u7684\u5DE5\u5177\u4E0D\u518D\u53EF\u8C03\u7528\uFF08\u5176 plugin:${t} \u6536\u7EB3\u7EC4\u5DF2\u5931\u6548\uFF09\u3002\u5982\u4ECD\u9700\u4F7F\u7528\u8BF7\u91CD\u65B0\u5B89\u88C5/\u542F\u7528\u8BE5\u63D2\u4EF6\u3002`,requireReply:!1,role:"system",timestamp:new Date().toISOString()}})}async enqueueExternalEvent(e,t,s){const n=await this.hydrate(e),i=n.plugins.get(t);if(!i||!i.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\u6216\u5DF2\u505C\u7528`};const r=typeof s.event=="string"?s.event:"",o=i.listeners.find(a=>a.transport.type==="http-callback"&&(!r||a.event===r));return o?(this.enqueueEvent(n,i,o,s),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5339\u914D\u7684 http-callback \u76D1\u542C\u5668\uFF08event=${r||"(\u7A7A)"}\uFF09`}}agentState(e){let t=this.agents.get(e);return t||(t={agentId:e,plugins:new Map,buffer:new V(e),hydrated:!1,queue:Promise.resolve(),eventSeq:0},this.agents.set(e,t)),t}async hydrate(e){const t=this.agentState(e);return t.hydratePromise||(t.hydratePromise=this.doHydrate(t).catch(s=>{throw t.hydratePromise=void 0,s})),await t.hydratePromise,t}async doHydrate(e){const t=e.agentId;await this.deploy.migrateLegacySharedIfNeeded();const s=this.installedFile(t);if(!y(s)){await this.syncSharedIntoState(e).catch(()=>{}),e.hydrated=!0;return}try{const n=JSON.parse(S(s,"utf8")),i=this.readSecrets(t);for(const r of n.plugins??[]){if(String(r.source||"").startsWith("shared:"))continue;const a=h(this.rootDir,"cache",v(t),r.name);if(!y(h(a,"plugin.json"))){u.warn("[agent:%s] \u5DF2\u5B89\u88C5\u63D2\u4EF6\u76EE\u5F55\u7F3A\u5931\uFF0C\u8DF3\u8FC7: %s",t,r.name);continue}const l={...r.config,...i[r.name]??{}},c=this.loader.loadPluginFromDir(a,r.source,r.installedAt,l);if(c.ok){const g=c.plugin;g.enabled=r.enabled,e.plugins.set(g.name,g)}else u.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25: %s: %s",t,r.name,c.error)}}catch(n){const i=n instanceof Error?n.message:String(n);u.error("[agent:%s] installed.json \u89E3\u6790\u5931\u8D25: %s",t,i)}await this.syncSharedIntoState(e).catch(n=>{u.warn("[agent:%s] \u5171\u4EAB\u63D2\u4EF6\u540C\u6B65\u5931\u8D25: %s",t,n instanceof Error?n.message:String(n))}),e.hydrated=!0}installedFile(e){return h(this.rootDir,"agents",v(e),"installed.json")}persistInstalled(e){this.persistSecrets(e);const t=this.installedFile(e.agentId);D(A(t),{recursive:!0});const s=[...e.plugins.values()].filter(n=>n.debug!==!0).map(n=>({name:n.name,source:n.source,installedAt:n.installedAt,enabled:n.enabled,config:this.stripSensitiveValues(n)}));$(t,`${JSON.stringify({version:1,plugins:s},null,2)}
3
+ `,"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)),s={};for(const[n,i]of Object.entries(e.configValues))t.has(n)||(s[n]=i);return s}secretsFile(e){return h(this.rootDir,"agents",v(e),"secrets.json")}readSecrets(e){try{const t=JSON.parse(S(this.secretsFile(e),"utf8"));if(!k(t)||!k(t.secrets))return{};const s={};for(const[n,i]of Object.entries(t.secrets)){if(!k(i))continue;const r={};for(const[o,a]of Object.entries(i))typeof a=="string"&&(r[o]=a);s[n]=r}return s}catch{return{}}}persistSecrets(e){const t={};for(const n of e.plugins.values()){if(n.debug===!0)continue;const i={};for(const r of this.sensitiveKeysOf(n)){const o=n.configValues[r];typeof o=="string"&&o.length>0&&(i[r]=o)}Object.keys(i).length>0&&(t[n.name]=i)}const s=this.secretsFile(e.agentId);if(Object.keys(t).length===0){try{C(s,{force:!0})}catch{}return}D(A(s),{recursive:!0}),$(s,`${JSON.stringify({version:1,secrets:t},null,2)}
4
+ `,{encoding:"utf8",mode:384})}ensureListenersRunning(e){this.listeners.ensureRunning(e)}startAllListeners(e,t){this.listeners.startAll(e,t)}stopAllListeners(e){this.listeners.stopAll(e)}enqueueEvent(e,t,s,n){this.listeners.enqueue(e,t,s,n)}async getLogs(e,t){const n=(await this.hydrate(e)).plugins.get(t);if(!n)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5`,logs:[]};const i=[];for(const r of n.runtimes)i.push(`\u2500\u2500 listener ${r.def.event} (${r.def.transport?.type}) ${r.lastError?`[error: ${r.lastError}]`:""}`),i.push(...r.logs);return{ok:!0,logs:i}}async stopAgent(e){const t=this.agents.get(e);if(t){for(const s of t.plugins.values())this.stopAllListeners(s);this.agents.delete(e)}}async stopAll(){for(const e of[...this.agents.keys()])await this.stopAgent(e)}async listDeployed(){await this.deploy.migrateLegacySharedIfNeeded();const e=this.deploy.readSharedManifest(),t=[];for(const s of e){const n=this.deploy.deployedPluginDir(s.pluginName),i=this.deploy.deployedPluginHealthy(s.pluginName);let r;if(i)try{const o=JSON.parse(S(h(n,"plugin.json"),"utf8"));typeof o.version=="string"&&(r=o.version)}catch{}t.push({pluginName:s.pluginName,version:r,fileName:s.fileName??`${s.pluginName}.zip`,defaultEnabled:s.defaultEnabled!==!1,sha256:s.sha256,deployed:i})}return t}deployedDefaultEnabled(){const e=this.deploy.readSharedManifest(),t={};for(const s of e)t[s.pluginName]=s.defaultEnabled!==!1;return t}async removeDeployedPlugin(e){if(!K(e))return{ok:!1,error:"pluginName \u975E\u6CD5\uFF08\u987B\u4E3A kebab-case\uFF0C1~64 \u5B57\u7B26\uFF09"};await this.deploy.migrateLegacySharedIfNeeded();for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const s=t.queue.then(async()=>{const n=t.plugins.get(e);n&&(this.stopAllListeners(n),t.plugins.delete(e)),this.deploy.removeRuntimeLink(t.agentId,e),this.persistInstalled(t)});t.queue=s.catch(()=>{}),await s}await this.deploy.updateSharedManifest(t=>t.filter(s=>s.pluginName!==e));try{this.deploy.removeDeployedDir(e)}catch(t){return{ok:!1,error:`\u90E8\u7F72\u76EE\u5F55\u6E05\u7406\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`}}return u.info("[shared] \u63D2\u4EF6\u5DF2\u4ECE bridge \u79FB\u9664\u90E8\u7F72: %s",e),{ok:!0}}}const Q=new Z;j("plugins",()=>Q.deployedDefaultEnabled());const ge=()=>T("plugins");export{Z as PluginManager,pe as isValidPluginName,Q as pluginManager,ge as reconcilePluginsDefaultsFromDeployed,Se as renderCommandArgv,ye as validateAgainstSchema,me as validateManifest};
16
5
 
@@ -0,0 +1,83 @@
1
+
2
+ import type { PluginEventPriority } from "./plugin-event-buffer.js";
3
+ export interface PluginUserConfigField {
4
+ key: string;
5
+ type?: "string" | "number" | "boolean";
6
+ required?: boolean;
7
+ sensitive?: boolean;
8
+ description?: string;
9
+ default?: string;
10
+ }
11
+ export interface PluginHandlerDef {
12
+ type: "process" | "module" | "mcp";
13
+
14
+ command?: string;
15
+
16
+ shell?: boolean;
17
+
18
+ stdin?: "none" | "params";
19
+
20
+ timeoutMs?: number;
21
+
22
+ module?: string;
23
+
24
+ export?: string;
25
+ }
26
+ export interface PluginToolDef {
27
+ name: string;
28
+ title?: string;
29
+ description: string;
30
+ inputSchema?: Record<string, unknown>;
31
+ handler: PluginHandlerDef;
32
+ }
33
+ export interface PluginTransportDef {
34
+ type: "command-stream" | "poll-command" | "http-callback";
35
+
36
+ command?: string;
37
+
38
+ intervalMs?: number;
39
+
40
+ restartBackoffMs?: number;
41
+ }
42
+ export interface PluginListenerDef {
43
+ event: string;
44
+ description?: string;
45
+ transport: PluginTransportDef;
46
+
47
+ delivery?: "poll" | "force" | "wake";
48
+ priority?: PluginEventPriority;
49
+
50
+ matcher?: Record<string, string | number | boolean | Array<string | number | boolean>>;
51
+
52
+ dedupKey?: string;
53
+
54
+ toolHints?: string[];
55
+
56
+ summary?: string;
57
+ }
58
+ export interface PluginManifest {
59
+ name: string;
60
+ version?: string;
61
+ description?: string;
62
+ author?: Record<string, unknown>;
63
+ tools?: string;
64
+ listeners?: string;
65
+ commands?: string;
66
+ userConfig?: PluginUserConfigField[];
67
+ [key: string]: unknown;
68
+ }
69
+ export declare const PLUGIN_NAME_PATTERN: RegExp;
70
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
71
+
72
+ export declare function getPath(obj: unknown, path: string): unknown;
73
+ export declare function truncate(text: string, max: number): string;
74
+ export declare function validateAgainstSchema(schema: unknown, value: unknown, path?: string): string[];
75
+
76
+ export declare function isValidPluginName(name: unknown): name is string;
77
+ export declare function validateManifest(manifest: Record<string, unknown>): string | null;
78
+ export declare function validateToolDef(item: unknown): string | null;
79
+ export declare function validateListenerDef(item: unknown): string | null;
80
+
81
+ export declare function renderCommandArgv(command: string, lookup: Record<string, unknown>): string[];
82
+ export declare function renderTemplate(template: string, eventObj: Record<string, unknown>): string;
83
+ export declare function safeStableStringify(value: unknown): string;
@@ -0,0 +1,2 @@
1
+ const l=/^[a-zA-Z0-9_][a-zA-Z0-9_-]*$/,c=/^[a-z0-9][a-z0-9-]*$/,y=["system.","aws-","acode-"],g=/[^\x20-\x7E]/;function f(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function p(r,n){let t=r;for(const e of n.split(".")){if(!f(t))return;t=t[e]}return t}function S(r,n){return r.length<=n?r:`${r.slice(0,n)}\u2026(\u622A\u65AD,\u5171 ${r.length} \u5B57\u7B26)`}function a(r,n,t="params"){if(!f(r))return[];const e=[],i=r.type;if(typeof i=="string"&&!$(i,n))return[`${t}: \u671F\u671B ${i}\uFF0C\u5B9E\u9645 ${m(n)}`];if(Array.isArray(r.enum)&&r.enum.length>0&&(r.enum.some(o=>JSON.stringify(o)===JSON.stringify(n))||e.push(`${t}: \u503C ${JSON.stringify(n)} \u4E0D\u5728\u679A\u4E3E ${JSON.stringify(r.enum)} \u5185`)),i==="object"&&f(n)){const u=f(r.properties)?r.properties:{},o=Array.isArray(r.required)?r.required:[];for(const s of o)(!(s in n)||n[s]===void 0)&&e.push(`${t}.${s}: \u5FC5\u586B\u53C2\u6570\u7F3A\u5931`);for(const[s,d]of Object.entries(u))s in n&&n[s]!==void 0&&e.push(...a(d,n[s],`${t}.${s}`));if(r.additionalProperties===!1)for(const s of Object.keys(n))s in u||e.push(`${t}.${s}: \u4E0D\u5141\u8BB8\u7684\u672A\u77E5\u53C2\u6570\uFF08schema additionalProperties=false\uFF09`)}return i==="array"&&Array.isArray(n)&&f(r.items)&&n.forEach((u,o)=>{e.push(...a(r.items,u,`${t}[${o}]`))}),e}function $(r,n){switch(r){case"string":return typeof n=="string";case"number":return typeof n=="number"&&Number.isFinite(n);case"boolean":return typeof n=="boolean";case"object":return f(n);case"array":return Array.isArray(n);case"null":return n===null;default:return!0}}function m(r){return r===null?"null":Array.isArray(r)?"array":typeof r}function A(r){return typeof r=="string"&&r.length>0&&r.length<=64&&c.test(r)}function N(r){const n=r.name;if(typeof n!="string"||!c.test(n))return`plugin.json: name \u975E\u6CD5\uFF08\u987B\u4E3A kebab-case\uFF09: ${String(n)}`;if(n.length>64)return"plugin.json: name \u8FC7\u957F\uFF08\u226464\uFF09";for(const t of y)if(n===t.replace(/\.$/,"")||n.startsWith(t))return`plugin.json: name \u4F7F\u7528\u4E86\u4FDD\u7559\u524D\u7F00 ${t}`;return g.test(n)?"plugin.json: name \u542B\u975E ASCII \u5B57\u7B26\uFF08\u540C\u5F62\u5B57\u9632\u62A4\uFF09":r.version!==void 0&&typeof r.version!="string"?"plugin.json: version \u987B\u4E3A\u5B57\u7B26\u4E32":r.userConfig!==void 0&&!Array.isArray(r.userConfig)?"plugin.json: userConfig \u987B\u4E3A\u6570\u7EC4":null}function h(r){if(!f(r))return"\u5DE5\u5177\u6761\u76EE\u987B\u4E3A\u5BF9\u8C61";const n=r.name;if(typeof n!="string"||!l.test(n))return`\u5DE5\u5177 name \u975E\u6CD5: ${String(n)}`;if(typeof r.description!="string"||!r.description.trim())return`\u5DE5\u5177 ${n} \u7F3A\u5C11 description`;const t=r.handler;if(!f(t))return`\u5DE5\u5177 ${n} \u7F3A\u5C11 handler`;const e=t.type;return e!=="process"&&e!=="module"&&e!=="mcp"?`\u5DE5\u5177 ${n} handler.type \u975E\u6CD5: ${String(e)}`:e==="process"&&typeof t.command!="string"?`\u5DE5\u5177 ${n} \u7684 process handler \u7F3A\u5C11 command`:e==="module"&&typeof t.module!="string"?`\u5DE5\u5177 ${n} \u7684 module handler \u7F3A\u5C11 module`:r.inputSchema!==void 0&&!f(r.inputSchema)?`\u5DE5\u5177 ${n} inputSchema \u987B\u4E3A\u5BF9\u8C61`:null}function b(r){if(!f(r))return"\u76D1\u542C\u5668\u6761\u76EE\u987B\u4E3A\u5BF9\u8C61";if(typeof r.event!="string"||!r.event.trim())return"\u76D1\u542C\u5668\u7F3A\u5C11 event";const n=r.transport;if(!f(n))return`\u76D1\u542C\u5668 ${String(r.event)} \u7F3A\u5C11 transport`;const t=n.type;if(t!=="command-stream"&&t!=="poll-command"&&t!=="http-callback")return`\u76D1\u542C\u5668 ${String(r.event)} transport.type \u975E\u6CD5: ${String(t)}`;if((t==="command-stream"||t==="poll-command")&&typeof n.command!="string")return`\u76D1\u542C\u5668 ${String(r.event)} \u7684 ${t} transport \u7F3A\u5C11 command`;const e=r.delivery;return e!==void 0&&e!=="poll"&&e!=="force"&&e!=="wake"?`\u76D1\u542C\u5668 ${String(r.event)} delivery \u975E\u6CD5: ${String(e)}`:null}function O(r,n){return r.trim().split(/\s+/).map(t=>{const e=/^\{\{(.+)\}\}$/.exec(t);if(e){const i=p(n,e[1].trim());return i==null?"":typeof i=="string"?i:JSON.stringify(i)}return t.replace(/\{\{(.+?)\}\}/g,(i,u)=>{const o=p(n,u.trim());return o==null?"":typeof o=="string"?o:JSON.stringify(o)})}).filter(t=>t!=="")}function E(r,n){return r.replace(/\{\{(.+?)\}\}/g,(t,e)=>{let i=p(n,e.trim());return i===void 0&&!e.trim().startsWith("params.")&&(i=p(n,`data.${e.trim()}`)),i==null?"":typeof i=="string"?i:JSON.stringify(i)})}function P(r){try{return JSON.stringify(r)??"null"}catch{return"(\u4E0D\u53EF\u5E8F\u5217\u5316\u7684\u4E8B\u4EF6\u8D1F\u8F7D)"}}export{c as PLUGIN_NAME_PATTERN,p as getPath,f as isRecord,A as isValidPluginName,O as renderCommandArgv,E as renderTemplate,P as safeStableStringify,S as truncate,a as validateAgainstSchema,b as validateListenerDef,N as validateManifest,h as validateToolDef};
2
+
@@ -0,0 +1,67 @@
1
+
2
+ import type { ChildProcess } from "node:child_process";
3
+ import type { PluginStatus } from "@agentswork/acode";
4
+ import type { PluginEventBuffer } from "./plugin-event-buffer.js";
5
+ import type { PluginListenerDef, PluginToolDef, PluginUserConfigField } from "./plugin-manifest.js";
6
+ export interface ListenerRuntime {
7
+ def: PluginListenerDef;
8
+ child?: ChildProcess;
9
+ timer?: ReturnType<typeof setInterval>;
10
+ backoffTimer?: ReturnType<typeof setTimeout>;
11
+ stopping: boolean;
12
+ restarts: number;
13
+ lastError?: string;
14
+ logs: string[];
15
+
16
+ polling?: boolean;
17
+ }
18
+ export interface LoadedPlugin {
19
+ name: string;
20
+ version?: string;
21
+ description?: string;
22
+ source: string;
23
+ installedAt: string;
24
+ dir: string;
25
+ enabled: boolean;
26
+ tools: PluginToolDef[];
27
+ listeners: PluginListenerDef[];
28
+ commandDir?: string;
29
+ userConfig: PluginUserConfigField[];
30
+ configValues: Record<string, string>;
31
+ status: PluginStatus;
32
+ error?: string;
33
+ runtimes: ListenerRuntime[];
34
+ moduleCache: Map<string, unknown>;
35
+
36
+ debug?: boolean;
37
+
38
+ importNonce: number;
39
+ }
40
+ export interface InstalledRecord {
41
+ name: string;
42
+ source: string;
43
+ installedAt: string;
44
+ enabled: boolean;
45
+ config: Record<string, string>;
46
+ }
47
+ export interface AgentState {
48
+ agentId: string;
49
+ plugins: Map<string, LoadedPlugin>;
50
+ buffer: PluginEventBuffer;
51
+ hydrated: boolean;
52
+
53
+ queue: Promise<unknown>;
54
+
55
+ hydratePromise?: Promise<void>;
56
+ eventSeq: number;
57
+ }
58
+
59
+ export interface SharedPluginEntry {
60
+ pluginName: string;
61
+ zipFile: string;
62
+ fileName: string;
63
+
64
+ defaultEnabled?: boolean;
65
+
66
+ sha256?: string;
67
+ }
@@ -0,0 +1 @@
1
+
@@ -5,6 +5,8 @@ export interface DeployedSkillEntry {
5
5
  fileName: string;
6
6
  defaultEnabled: boolean;
7
7
  sha256?: string;
8
+
9
+ deployed?: boolean;
8
10
  }
9
11
  export interface DeployedSkillResult {
10
12
  ok: boolean;
@@ -32,6 +34,19 @@ export declare class SkillManager {
32
34
  }>;
33
35
 
34
36
  listDeployed(): DeployedSkillEntry[];
37
+ private privateManifestFile;
38
+ private privateSkillDir;
39
+ private readPrivateManifest;
40
+ private writePrivateManifest;
41
+
42
+ savePrivateSkill(agentId: string, zipBuffer: Buffer, originalName: string, sha256?: string, requestedSkillName?: string): Promise<DeployedSkillResult>;
43
+
44
+ removePrivateSkill(agentId: string, skillName: string): Promise<{
45
+ ok: boolean;
46
+ error?: string;
47
+ }>;
48
+
49
+ listPrivateSkills(agentId: string): DeployedSkillEntry[];
35
50
 
36
51
  deployedDefaultEnabled(): Record<string, boolean>;
37
52