aws-runtime-bridge 1.9.137 → 1.9.140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/AcodeSdkAdapter.d.ts +4 -1
- package/dist/adapter/AcodeSdkAdapter.js +2 -2
- package/dist/adapter/ClaudeSdkAdapter.js +3 -3
- package/dist/adapter/CodexSdkAdapter.js +3 -3
- package/dist/adapter/OpencodeSdkAdapter.js +3 -3
- package/dist/browser/browser-pool.js +1 -1
- package/dist/browser/built-in-browser-tools.d.ts +1 -2
- package/dist/browser/built-in-browser-tools.js +1 -1
- package/dist/browser/ws-server.js +1 -1
- package/dist/config.d.ts +22 -6
- package/dist/config.js +2 -2
- package/dist/index.js +1 -1
- package/dist/middleware/auth.js +1 -1
- package/dist/remote-desktop/computer-control.d.ts +2 -2
- package/dist/remote-desktop/index.d.ts +1 -1
- package/dist/remote-desktop/index.js +2 -2
- package/dist/remote-desktop/screen-capture.js +1 -1
- package/dist/remote-desktop/session-manager.d.ts +2 -2
- package/dist/remote-desktop/session-manager.js +1 -1
- package/dist/remote-desktop/system-backend.js +3 -3
- package/dist/remote-desktop/types.d.ts +1 -1
- package/dist/remote-desktop/ui-automation.d.ts +2 -2
- package/dist/remote-desktop/ui-automation.js +5 -5
- package/dist/routes/ai-sources.js +1 -1
- package/dist/routes/background-tasks.js +5 -5
- package/dist/routes/browser-listeners.js +1 -1
- package/dist/routes/capabilities.js +1 -1
- package/dist/routes/dashboard.js +1 -1
- package/dist/routes/file-change-diff.js +3 -3
- package/dist/routes/file-diff-rollback.js +1 -1
- package/dist/routes/file-snapshot.js +1 -1
- package/dist/routes/git.js +20 -20
- package/dist/routes/instance.js +1 -1
- package/dist/routes/launch.js +1 -1
- package/dist/routes/mcp.js +1 -1
- package/dist/routes/plugins.js +1 -1
- package/dist/routes/properties.js +1 -1
- package/dist/routes/pty.d.ts +1 -1
- package/dist/routes/pty.js +1 -1
- package/dist/routes/runtime-binding.js +1 -1
- package/dist/routes/skills.js +1 -1
- package/dist/routes/sub-agents.js +1 -1
- package/dist/routes/task-context.js +1 -1
- package/dist/routes/terminal.js +27 -27
- package/dist/routes/yml.js +1 -1
- package/dist/services/access-control.js +1 -1
- package/dist/services/acode-bg-manager.js +1 -1
- package/dist/services/agent-capability-sync.js +1 -1
- package/dist/services/agent-process-manager.d.ts +1 -1
- package/dist/services/agent-process-manager.js +1 -1
- package/dist/services/ai-config-service.js +2 -2
- package/dist/services/ai-source-apply.d.ts +1 -1
- package/dist/services/auto-register.js +1 -1
- package/dist/services/aws-client-agent-mcp.d.ts +5 -0
- package/dist/services/aws-client-agent-mcp.js +2 -2
- package/dist/services/bridge-package-publish-hooks.js +1 -1
- package/dist/services/browser-session-manager.d.ts +3 -3
- package/dist/services/browser-session-manager.js +3 -3
- package/dist/services/capability-config.js +2 -2
- package/dist/services/cli-commands.js +2 -2
- package/dist/services/desktop-mcp-manager.js +1 -1
- package/dist/services/event-delta-pusher.d.ts +1 -1
- package/dist/services/fileSnapshotStore.js +1 -1
- package/dist/services/instance-ai-config-service.js +1 -1
- package/dist/services/instance-init-service.js +1 -1
- package/dist/services/instance-state.d.ts +1 -1
- package/dist/services/instance-state.js +1 -1
- package/dist/services/jdk-scanner.js +1 -1
- package/dist/services/launch-manager.js +1 -1
- package/dist/services/legacy-path-migration.d.ts +0 -2
- package/dist/services/legacy-path-migration.js +1 -1
- package/dist/services/lifecycle-state.js +2 -2
- package/dist/services/mcp-deploy.js +2 -2
- package/dist/services/orphan-monitor.js +1 -1
- package/dist/services/plugin-manager.d.ts +27 -5
- package/dist/services/plugin-manager.js +15 -9
- package/dist/services/process-detail.js +2 -2
- package/dist/services/process-detector.js +10 -10
- package/dist/services/process-registry.js +1 -1
- package/dist/services/process-top.js +2 -2
- package/dist/services/runtime-binding.js +4 -4
- package/dist/services/sdk-tool-file-change-recorder.js +1 -1
- package/dist/services/skill-manager.js +2 -2
- package/dist/services/startup-config-wizard.js +6 -6
- package/dist/services/system-metrics.js +1 -1
- package/dist/services/tunnel-client.js +1 -1
- package/dist/services/update-notifier.js +2 -2
- package/dist/services/windows-service-manager.js +1 -1
- package/dist/services/workspace-files.js +1 -1
- package/dist/services/workspaceTaskChangeWatcher.js +3 -3
- package/dist/utils/file-utils.js +2 -2
- package/dist/utils/instance-ai-config-debug-logger.js +1 -1
- package/dist/utils/mcp-utils.js +1 -1
- package/dist/utils/yaml-utils.js +1 -1
- package/package/acode/dist/cli.js +2 -2
- package/package/acode/dist/plugin-tools.js +3 -8
- package/package/acode/dist/plugin-types.d.ts +10 -0
- package/package/acode/dist/runtime.d.ts +4 -0
- package/package/acode/dist/runtime.js +18 -18
- package/package/acode/dist/types.d.ts +4 -0
- package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.js +10 -10
- package/package/aws-client-agent-mcp/dist/memory-tools.js +6 -6
- package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts +1 -1
- package/package/aws-client-agent-mcp/dist/server-memory-store.js +1 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/status-reporter.js +3 -2
- package/package/aws-client-agent-mcp/dist/types.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import d from"node:crypto";import{promises as i}from"node:fs";import c from"node:os";import n from"node:path";import{atomicWriteJsonFile as g,withFileLock as y}from"../utils/file-utils.js";import{createLogger as j}from"../utils/logger.js";const f=j("jdk-scanner");function h(){return n.join(c.tmpdir(),"agentswork-runtime-bridge","jdk-registry.json")}function k(){const a=[];return process.env.JAVA_HOME&&a.push(process.env.JAVA_HOME),c.platform()==="win32"?a.push(n.join(process.env.ProgramFiles||"C:\\Program Files","Java"),n.join(process.env.ProgramFiles||"C:\\Program Files","Eclipse Adoptium"),n.join(process.env.ProgramFiles||"C:\\Program Files","Microsoft"),n.join(process.env.ProgramFiles||"C:\\Program Files","Amazon Corretto"),n.join(process.env.ProgramFiles||"C:\\Program Files","Zulu")):c.platform()==="darwin"?a.push("/Library/Java/JavaVirtualMachines"):a.push("/usr/lib/jvm","/opt/java","/opt/jdk","/usr/local/opt"),a.filter(Boolean)}function w(){return c.platform()==="win32"?"java.exe":"java"}async function u(a){try{return await i.access(n.join(a,"bin",w())),!0}catch{return!1}}async function m(a){try{return(await i.readFile(n.join(a,"release"),"utf-8")).match(/^JAVA_VERSION="?([^"\n]+)"?/m)?.[1]?.trim()||""}catch{return""}}async function C(a){try{return(await i.readdir(a,{withFileTypes:!0})).filter(r=>r.isDirectory()).map(r=>n.join(a,r.name))}catch{return[]}}function v(a){return`scan-${d.createHash("sha1").update(a.toLowerCase()).digest("hex").slice(0,12)}`}async function A(){const a=[],e=new Set,r=k();for(const t of r){const o=await C(t);for(const s of o){const p=s.toLowerCase();e.has(p)||(e.add(p),await u(s)&&a.push({id:v(s),name:n.basename(s),path:s,version:await m(s),source:"scan"}))}}if(process.env.JAVA_HOME&&!e.has(process.env.JAVA_HOME.toLowerCase())){const t=process.env.JAVA_HOME;e.add(t.toLowerCase()),await u(t)&&a.push({id:v(t),name:n.basename(t),path:t,version:await m(t),source:"scan"})}return a.sort((t,o)=>(o.version||"").localeCompare(t.version||"")||t.name.localeCompare(o.name)),a}async function l(){try{const a=await i.readFile(h(),"utf-8"),e=JSON.parse(a);return Array.isArray(e)?e:[]}catch{return[]}}async function J(a){const e=h();await y(e,async()=>{await g(e,a)})}async function D(){const a=await A(),e=await l();if(e.length===0)return a;const r=new Set(a.map(o=>o.path.toLowerCase())),t=[...a];for(const o of e){const s=o.path.toLowerCase();r.has(s)||await u(o.path)&&t.push({id:o.id,name:n.basename(o.path),path:o.path,version:await m(o.path),source:"manual"})}return t}async function V(a){const e=a.trim();if(!e)throw new Error("JDK \u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");const r=n.resolve(e);if(!await u(r))throw new Error(`\u4E0D\u662F\u6709\u6548\u7684 JDK \u76EE\u5F55\uFF08\u7F3A\u5C11 bin/${w()}\uFF09: ${r}`);const t=await l();if(t.some(s=>s.path.toLowerCase()===r.toLowerCase()))throw new Error("\u8BE5 JDK \u5DF2\u6DFB\u52A0");const o=`manual-${d.randomUUID().slice(0,8)}`;return t.push({id:o,path:r}),await J(t),f.info(`[jdk] \u624B\u52A8\u6DFB\u52A0 JDK: id=${o}, path=${r}`),{id:o,name:n.basename(r),path:r,version:await m(r),source:"manual"}}async function x(a){if(!a.startsWith("manual-"))throw new Error("\u4EC5\u652F\u6301\u5220\u9664\u624B\u52A8\u6DFB\u52A0\u7684 JDK");const e=await l(),r=e.filter(t=>t.id!==a);return r.length===e.length?!1:(await J(r),f.info(`[jdk] \u5220\u9664\u624B\u52A8 JDK: id=${a}`),!0)}export{V as addManualJdk,D as listJdks,x as removeManualJdk,A as scanInstalledJdks};
|
|
2
2
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{exec as _,spawn as j}from"node:child_process";import{promises as z}from"node:fs";import A from"node:os";import M from"node:path";import{promisify as F}from"node:util";import{atomicWriteJsonFile as J,withFileLock as U}from"../utils/file-utils.js";import{createLogger as G}from"../utils/logger.js";import{
|
|
1
|
+
import{exec as _,spawn as j}from"node:child_process";import{promises as z}from"node:fs";import A from"node:os";import M from"node:path";import{promisify as F}from"node:util";import{atomicWriteJsonFile as J,withFileLock as U}from"../utils/file-utils.js";import{createLogger as G}from"../utils/logger.js";import{LaunchMetricsMonitor as V}from"./launch-metrics.js";import{getLaunchStreamHub as P}from"./launch-streams.js";import{getListeningPortsForProcessTrees as L}from"./port-detector.js";import{isProcessRunning as E,terminateProcessTree as k}from"./process-detector.js";import{RingBuffer as O}from"./ring-buffer.js";const C=F(_),g=G("launch-manager"),D=5e3,B=4096,X=1500,K=20;function H(){return M.join(A.tmpdir(),"agentswork-runtime-bridge","launch-runs.json")}function Y(l,t){return l.replace(/\$\{([^}]+)\}/g,(e,s)=>{const r=s.trim(),i=r.toUpperCase();if(i==="WORKSPACE")return t.workspacePath||"";if(i==="JAVA_HOME")return t.jdkPath||process.env.JAVA_HOME||"";if(i==="HOME")return A.homedir();if(t.env&&t.env[r]!==void 0)return t.env[r];if(t.env){for(const[n,a]of Object.entries(t.env))if(n.toUpperCase()===i)return a}return e})}function Z(l){const t={...process.env};l.env&&Object.assign(t,l.env);for(const e of Object.keys(t))if(e.toUpperCase()==="PATH"&&e!=="PATH"){const s=t[e];delete t[e],t.PATH===void 0&&typeof s=="string"&&(t.PATH=s)}if(l.jdkPath){t.JAVA_HOME=l.jdkPath;const e=M.join(l.jdkPath,"bin"),s=M.delimiter;t.PATH=t.PATH?`${e}${s}${t.PATH}`:e}return t}const Q=256,q=120;class N{constructor(t=()=>{}){this.utf8Probe=new TextDecoder("utf-8",{fatal:!0}),this.utf8=new TextDecoder("utf-8"),this.gbk=new TextDecoder("gbk"),this.mode=null,this.buffered=[],this.bufferedSize=0,this.flushTimer=null,this.onFlush=t}decode(t){return this.mode!==null?(this.mode==="gbk"?this.gbk:this.utf8).decode(t,{stream:!0}):(this.buffered.push(t),this.bufferedSize+=t.length,this.bufferedSize>=Q?this.commit():(this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.onFlush(this.commit())},q)),""))}finalize(){return this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.mode===null?this.commit():(this.mode==="gbk"?this.gbk:this.utf8).decode()}commit(){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.mode!==null)return"";const t=Buffer.concat(this.buffered,this.bufferedSize);this.buffered=[],this.bufferedSize=0;try{return this.utf8Probe.decode(t),this.mode="utf8",this.utf8.decode(t)}catch{return this.mode="gbk",this.gbk.decode(t)}}}function tt(l){const t=l.length>0&&!l.endsWith(`
|
|
2
2
|
`)?l+`
|
|
3
3
|
`:l;return t.length>B?t.slice(-B):t}async function et(l){const t=A.platform();for(let e=0;e<6;e+=1){try{if(t==="win32"){const s=`Get-CimInstance Win32_Process -Filter "ParentProcessId = ${l} AND Name <> 'conhost.exe'" | Select-Object -First 1 ProcessId | ConvertTo-Json -Compress`,r=Buffer.from(s,"utf16le").toString("base64"),{stdout:i}=await C(`powershell -NoProfile -NonInteractive -EncodedCommand ${r}`,{encoding:"utf8",timeout:5e3,windowsHide:!0}),n=i.replace(/#\s*<\s*CLIXML[\s\S]*?(?=\{|\[|$)/g,"").trim(),a=JSON.parse(n||"null"),h=Number(a?.ProcessId);if(Number.isFinite(h)&&h>0)return h}else{const{stdout:s}=await C(`pgrep -P ${l} | head -n 1`,{encoding:"utf8",timeout:3e3}),r=Number(s.trim());if(Number.isFinite(r)&&r>0)return r}}catch{}await new Promise(s=>setTimeout(s,300))}return null}class S{constructor(){this.runs=new Map,this.logs=new Map,this.startupWaiters=new Map,this.readinessMatchers=new Map,this.logListeners=new Map,this.metricsMonitor=new V(()=>this.runningRefs()),this.restored=!1}static getInstance(){return S.instance===null&&(S.instance=new S),S.instance}runningRefs(){const t=[];for(const e of this.runs.values())e.state==="running"&&e.pid>0&&t.push({configId:e.configId,pid:e.pid});return t}async start(t){const e=t.configId;if(!e||!e.trim())throw new Error("configId is required");if(!t.command||!t.command.trim())throw new Error("command is required");let s=null;if(t.readinessPattern&&t.readinessPattern.trim())try{s=new RegExp(t.readinessPattern.trim())}catch(o){throw new Error(`readinessPattern \u6B63\u5219\u8BED\u6CD5\u65E0\u6548: ${o.message}`)}const r=t.startedBy?.trim()||void 0;await this.ensureRestored();const i=this.runs.get(e);if(i&&i.state==="running"&&E(i.pid))throw new Error(`\u542F\u52A8\u9879\u5DF2\u5728\u8FD0\u884C: pid=${i.pid}`);const n=Y(t.command,{workspacePath:t.workspacePath,jdkPath:t.jdkPath,env:t.env}),a=t.cwd||t.workspacePath||process.cwd(),h=Z(t);g.info(`[start] \u542F\u52A8\u547D\u4EE4: configId=${e}, cwd=${a}, command=${n}`);let m;try{m=j(n,{cwd:a,env:h,shell:!0,windowsHide:!0})}catch(o){const c=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${o.message}`;throw g.error(`[start] spawn \u5931\u8D25: configId=${e}, error=${c}`),new Error(c)}const w=m.pid??0,T={configId:e,pid:w,state:"running",startedAt:new Date().toISOString(),command:n,cwd:a,...r?{startedBy:r}:{}};this.runs.set(e,T),this.publishRunStatus(e,!0),this.metricsMonitor.clear(e),this.metricsMonitor.ensureRunning();let p=this.logs.get(e);p||(p=new O(D),this.logs.set(e,p));const $=p.getSinceIndex(-1).nextIndex;s?this.readinessMatchers.set(e,{pattern:s,fromIndex:$+1}):this.readinessMatchers.delete(e);const b=p.append({stream:"stdout",text:`> ${n}
|
|
4
4
|
`});P().publish(e,"logs",b.index,b.data);let R=null;(async()=>{const o=await et(w),c=this.runs.get(e);o&&c?.pid===w&&(R=o,this.runs.set(e,{...c,pid:o}),await this.persist(),this.publishRunStatus(e))})();const x=o=>o!==void 0&&(o.pid===w||o.pid===R),u=new N(o=>{f("stdout",o)}),d=new N(o=>{f("stderr",o)}),f=(o,c)=>{const y=tt(c);if(y){const v=p.append({stream:o,text:y});P().publish(e,"logs",v.index,v.data);const I=this.logListeners.get(e);if(I&&I.size>0)for(const W of I)try{W(v)}catch{}}};return m.stdout.on("data",o=>{f("stdout",u.decode(o))}),m.stderr.on("data",o=>{f("stderr",d.decode(o))}),m.on("error",o=>{f("stderr",`[\u542F\u52A8\u5931\u8D25] ${o.message}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as i,mkdirSync as a,copyFileSync as f,readdirSync as u}from"node:fs";import o from"node:path";import{getRuntimeHomeDir as r}from"../config.js";import{createLogger as p}from"../utils/logger.js";import{migrateOldBindingDir as j}from"./runtime-binding.js";const e=p("legacy-path-migration");function m(){return o.join(r(),".agentswork","runtime-bridge")}function s(){return o.join(r(),".aws-bridge")}function y(){const n=o.join(m(),"lifecycle-state.json"),t=o.join(s(),"lifecycle-state.json");i(n)&&!i(t)&&(a(s(),{recursive:!0}),f(n,t),e.info(`[runtime-bridge] \u5DF2\u8FC1\u79FB lifecycle-state.json \u2192 ${t}`))}function h(){const n=o.join(r(),".agentswork","snapshots"),t=o.join(s(),"snapshots");if(i(n)&&!i(t)){a(t,{recursive:!0});try{const g=u(n);for(const c of g){const d=o.join(n,c),l=o.join(t,c);f(d,l)}e.info(`[runtime-bridge] \u5DF2\u8FC1\u79FB snapshots/ \u5230 ${t}`)}catch{e.warn("[runtime-bridge] snapshots/ \u8FC1\u79FB\u5931\u8D25\uFF08\u90E8\u5206\u6587\u4EF6\u53EF\u80FD\u88AB\u8DF3\u8FC7\uFF09")}}}function R(){const n=m();if(!i(n)){const t=o.join(r(),".agentswork","snapshots");if(!i(t))return}e.info("[runtime-bridge] \u68C0\u6D4B\u5230\u65E7\u8DEF\u5F84 ~/.agentswork/\uFF0C\u6B63\u5728\u8FC1\u79FB\u5230 ~/.aws-bridge/ ..."),j(),y(),h()}export{R as migrateOldPathsOnStartup};
|
|
2
2
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
`,{encoding:"utf8",mode:384})}function D(e){const t=new Date().toISOString(),r=n(e.schedulerBaseUrl)||c(void 0).url;return{operationId:p(),operationType:e.operationType,status:e.status||"accepted",requestedByUserId:e.requestedByUserId,requestedAt:t,updatedAt:t,schedulerBaseUrl:r,runtimeBridgeBaseUrl:u(e.runtimeBridgeBaseUrl),message:e.message,latestVersion:u(e.latestVersion)}}async function V(e){const r=(await a()).operations.filter(i=>i.operationId!==e.operationId);r.push({...e,updatedAt:new Date().toISOString()}),await f({operations:r})}async function I(e){const t=await a();await f({operations:t.operations.filter(r=>r.operationId!==e)})}function h(e){return["succeeded","failed","startup-confirmed"].includes(e.status)}async function S(e){const t=n(e.schedulerBaseUrl)||n(
|
|
1
|
+
import{randomUUID as p}from"node:crypto";import s from"node:fs/promises";import o from"node:path";import g from"axios";import{getRuntimeHomeDir as y,resolveSchedulerBaseUrlFrom as c}from"../config.js";import{createLogger as B}from"../utils/logger.js";import{getRuntimeAccessToken as w,loadRuntimeBinding as U,normalizeSchedulerBaseUrl as n}from"./runtime-binding.js";const d=B("bridge-lifecycle");function l(){return o.join(y(),".aws-bridge","lifecycle-state.json")}function u(e){return String(e||"").trim()||void 0}async function a(){try{const e=await s.readFile(l(),"utf8"),t=JSON.parse(e);return{operations:Array.isArray(t.operations)?t.operations:[]}}catch{return{operations:[]}}}async function f(e){const t=l();await s.mkdir(o.dirname(t),{recursive:!0}),await s.writeFile(t,`${JSON.stringify(e,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384})}function D(e){const t=new Date().toISOString(),r=n(e.schedulerBaseUrl)||c(void 0).url;return{operationId:p(),operationType:e.operationType,status:e.status||"accepted",requestedByUserId:e.requestedByUserId,requestedAt:t,updatedAt:t,schedulerBaseUrl:r,runtimeBridgeBaseUrl:u(e.runtimeBridgeBaseUrl),message:e.message,latestVersion:u(e.latestVersion)}}async function V(e){const r=(await a()).operations.filter(i=>i.operationId!==e.operationId);r.push({...e,updatedAt:new Date().toISOString()}),await f({operations:r})}async function I(e){const t=await a();await f({operations:t.operations.filter(r=>r.operationId!==e)})}function h(e){return["succeeded","failed","startup-confirmed"].includes(e.status)}async function S(e){const t=n(e.schedulerBaseUrl)||n(U().schedulerBaseUrl)||c(void 0).url,r=w(t);if(!r)throw new Error("runtime access token is missing");await g.post(`${t}/api/runtime/callback/bridge-lifecycle`,{operationId:e.operationId,operationType:e.operationType,status:e.status,requestedByUserId:e.requestedByUserId,message:e.message,error:e.error,runtimeBridgeBaseUrl:e.runtimeBridgeBaseUrl,latestVersion:e.latestVersion},{headers:{"X-Runtime-Token":r}})}function v(e){return e.operationType==="update"&&(e.status==="accepted"||e.status==="running")?{...e,status:"failed",message:"Bridge \u66F4\u65B0\u4E2D\u65AD\uFF0C\u8FDB\u7A0B\u5DF2\u91CD\u542F\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77\u66F4\u65B0\u3002",error:e.error||"update interrupted by process restart"}:{...e,status:"startup-confirmed",message:e.operationType==="update"?e.latestVersion?`\u66F4\u65B0\u5E76\u91CD\u542F\u5B8C\u6210\uFF0C\u5F53\u524D\u7248\u672C v${e.latestVersion}\u3002`:"\u66F4\u65B0\u5E76\u91CD\u542F\u5B8C\u6210\u3002":"Bridge \u91CD\u542F\u5B8C\u6210\uFF0C\u5B9E\u4F8B\u5DF2\u6062\u590D\u8FD0\u884C\u3002"}}async function $(){const e=await a();for(const t of e.operations){const r=v(t);if(h(r))try{await S(r),await I(t.operationId),d.info(`[bridge-lifecycle] notification delivered: ${t.operationId}`)}catch(i){const m=i;d.warn(`[bridge-lifecycle] notification delivery failed: ${t.operationId}, ${m.message}`)}}}export{D as createBridgeLifecycleOperation,$ as deliverPendingBridgeLifecycleNotifications,a as loadLifecycleState,I as removeBridgeLifecycleOperation,V as upsertBridgeLifecycleOperation};
|
|
3
3
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{existsSync as h,mkdirSync as a,readFileSync as l,rmSync as
|
|
1
|
+
import{existsSync as h,mkdirSync as a,readFileSync as l,rmSync as y,writeFileSync as f}from"node:fs";import n from"node:path";import{getBridgeTemplateMcpDir as m}from"../config.js";import{createLogger as d}from"../utils/logger.js";import{setDeployedDefaultsProvider as M,reconcileDefaultsFromDeployed as g}from"./capability-config.js";import{isCapabilityEnabled as p}from"./instance-features.js";const u=d("mcp-deploy"),D=1;class c{static getInstance(){return this._instance||(this._instance=new c(n.join(m(),"deployed"))),this._instance}constructor(e){this.rootDir=e}manifestFile(){return n.join(this.rootDir,"manifest.json")}specFile(e){const t=n.join(this.rootDir,`${e}.json`),r=n.resolve(this.rootDir);if(n.resolve(t)!==n.join(r,`${e}.json`))throw new Error(`MCP \u6A21\u677F\u6587\u4EF6\u8D8A\u51FA\u90E8\u7F72\u533A: ${e}`);return t}isHealthy(e){return h(this.specFile(e))}readManifest(){try{const e=JSON.parse(l(this.manifestFile(),"utf8"));return Array.isArray(e.servers)?e.servers.filter(t=>t&&t.name):[]}catch{return[]}}writeManifest(e){a(this.rootDir,{recursive:!0}),f(this.manifestFile(),`${JSON.stringify({version:D,servers:e},null,2)}
|
|
2
2
|
`,"utf8")}saveMcp(e,t,r=!0,i){if(!e||!/^[a-zA-Z0-9_.-]+$/.test(e))return{ok:!1,error:`MCP \u540D\u975E\u6CD5: ${JSON.stringify(e)}`};a(this.rootDir,{recursive:!0});try{f(this.specFile(e),`${JSON.stringify(t,null,2)}
|
|
3
|
-
`,"utf8")}catch(o){return{ok:!1,error:`MCP \u6A21\u677F\u5199\u5165\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`}}const s=this.readManifest().filter(o=>o.name!==e);return s.push({name:e,fileName:`${e}.json`,defaultEnabled:r,sha256:i}),this.writeManifest(s),u.info("[mcp] MCP \u6A21\u677F\u5DF2\u90E8\u7F72\u5230 bridge: %s",e),{ok:!0,name:e}}removeMcp(e){if(!e||!/^[a-zA-Z0-9_.-]+$/.test(e))return{ok:!1,error:"name \u975E\u6CD5"};const t=this.readManifest().filter(r=>r.name!==e);this.writeManifest(t);try{
|
|
3
|
+
`,"utf8")}catch(o){return{ok:!1,error:`MCP \u6A21\u677F\u5199\u5165\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`}}const s=this.readManifest().filter(o=>o.name!==e);return s.push({name:e,fileName:`${e}.json`,defaultEnabled:r,sha256:i}),this.writeManifest(s),u.info("[mcp] MCP \u6A21\u677F\u5DF2\u90E8\u7F72\u5230 bridge: %s",e),{ok:!0,name:e}}removeMcp(e){if(!e||!/^[a-zA-Z0-9_.-]+$/.test(e))return{ok:!1,error:"name \u975E\u6CD5"};const t=this.readManifest().filter(r=>r.name!==e);this.writeManifest(t);try{y(this.specFile(e),{force:!0})}catch(r){return{ok:!1,error:`\u6A21\u677F\u6587\u4EF6\u6E05\u7406\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`}}return u.info("[mcp] MCP \u6A21\u677F\u5DF2\u4ECE bridge \u79FB\u9664\u90E8\u7F72: %s",e),{ok:!0}}listDeployed(){return this.readManifest().map(e=>({...e,deployed:this.isHealthy(e.name)}))}getSpec(e){if(!this.isHealthy(e))return null;try{return JSON.parse(l(this.specFile(e),"utf8"))}catch{return null}}resolveEnabledMcp(e,t){const r={};for(const i of this.readManifest()){if(!p(e,"mcp",i.name)||!this.isHealthy(i.name))continue;const s=this.getSpec(i.name);s&&(r[i.name]={...s,type:s.type||"stdio"})}for(const[i,s]of Object.entries(t))p(e,"mcp",i)&&(r[i]||(r[i]=s));return r}deployedDefaultEnabled(){const e={};for(const t of this.readManifest())e[t.name]=t.defaultEnabled;return e}}c._instance=null;const S=c.getInstance();M("mcp",()=>S.deployedDefaultEnabled());const w=()=>g("mcp");export{c as McpDeployManager,S as mcpDeployManager,w as reconcileMcpDefaultsFromDeployed};
|
|
4
4
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{ORPHAN_SCAN_INTERVAL as d,ORPHAN_AUTO_CLEAN_MODE as r,ORPHAN_SCAN_ENABLED as m,schedulerBaseUrl as o}from"../config.js";import{createLogger as f}from"../utils/logger.js";import{detectOrphanProcesses as g,checkAllSessionsHealth as w,terminateProcessTree as S,waitForProcessExit as $}from"./process-detector.js";import{getRuntimeAccessToken as c}from"./runtime-binding.js";import{shouldAutoCleanOrphanProcesses as l}from"./runtime-lifecycle-policy.js";import{loadPersistedSessions as y,savePersistedSessions as v}from"./terminal-persistence.js";const n=f("orphan-monitor");class O{constructor(){this.intervalId=null,this.lastScanTime=null,this.eventListeners=[],this.stopped=!1}async start(){if(!m){n.info("\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5DF2\u7981\u7528 (AWS_ORPHAN_SCAN_ENABLED=false)");return}this.stopped=!1,n.info(`\u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\uFF0C\u626B\u63CF\u95F4\u9694: ${d}ms, \u81EA\u52A8\u6E05\u7406\u6A21\u5F0F: ${r}`),await this.scan(),this.intervalId=setInterval(async()=>{await this.scan()},d),n.info("\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5DF2\u542F\u52A8")}stop(){this.stopped=!0,this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,n.info("\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5DF2\u505C\u6B62"))}async scan(){if(this.stopped){n.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u8DF3\u8FC7\u626B\u63CF");return}this.lastScanTime=new Date,n.debug("\u5F00\u59CB\u626B\u63CF\u5B64\u513F\u8FDB\u7A0B...");try{const e=await y();if(this.stopped){n.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u4E2D\u65AD\u626B\u63CF");return}if(e.length===0){n.debug("\u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u8DF3\u8FC7\u626B\u63CF");return}const t=await g(e.map(s=>({agentId:s.agentId,pid:s.pid,workspacePath:s.workspacePath,command:s.command})));if(this.stopped){n.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u4E2D\u65AD\u626B\u63CF");return}const a=await w(e.filter(s=>s.pid).map(s=>({agentId:s.agentId,pid:s.pid})));if(this.stopped){n.debug("\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u4E2D\u65AD\u626B\u63CF");return}for(const s of t){if(this.stopped)break;await this.handleOrphanDetected(s.agentId,s.process.pid)}for(const[s,i]of a){if(this.stopped)break;i.status!=="healthy"&&i.alive&&await this.handleHealthIssue(s,i)}this.stopped||await this.cleanupDeadSessions(e,a)}catch(e){n.warn("\u626B\u63CF\u5B64\u513F\u8FDB\u7A0B\u5931\u8D25:",e)}}async handleOrphanDetected(e,t){const a={type:"orphan_detected",agentId:e,pid:t,message:`\u68C0\u6D4B\u5230\u5B64\u513F\u8FDB\u7A0B: agentId=${e}, pid=${t}`,timestamp:new Date};if(this.emit(a),n.warn(`\u68C0\u6D4B\u5230\u5B64\u513F\u8FDB\u7A0B: agentId=${e}, pid=${t}`),await this.checkAgentExistsOnServer(e)===!1){n.info(`agent ${e} \u5DF2\u4ECE\u670D\u52A1\u7AEF\u5220\u9664\uFF0C\u81EA\u52A8\u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B pid=${t}`),await this.autoCleanOrphan(e,t);return}switch(r){case"auto":l()?await this.autoCleanOrphan(e,t):(n.warn("auto \u6A21\u5F0F\u672A\u542F\u7528\u7834\u574F\u6027\u6E05\u7406\u5F00\u5173\uFF0C\u6539\u4E3A\u544A\u8B66\u5E76\u4FDD\u7559\u5B64\u513F\u8FDB\u7A0B"),await this.reportToScheduler(e,"orphan_detected",{pid:t}));break;case"alert":await this.reportToScheduler(e,"orphan_detected",{pid:t});break;case"manual":n.info("manual \u6A21\u5F0F\uFF0C\u4EC5\u8BB0\u5F55\u65E5\u5FD7\uFF0C\u4E0D\u81EA\u52A8\u5904\u7406");break}}async handleHealthIssue(e,t){const a=t.status==="unresponsive"?"process_unresponsive":t.status==="high_cpu"?"process_high_cpu":"process_high_memory",s={type:a,agentId:e,pid:t.pid,message:`\u8FDB\u7A0B\u5065\u5EB7\u5F02\u5E38: ${t.status}, CPU=${t.cpu}%, Memory=${t.memoryMB}MB`,timestamp:new Date,details:{cpu:t.cpu,memoryMB:t.memoryMB}};this.emit(s),await this.reportToScheduler(e,a,{pid:t.pid,cpu:t.cpu,memoryMB:t.memoryMB}),r==="auto"&&t.status!=="healthy"&&l()?(n.warn(`auto \u6A21\u5F0F: \u7EC8\u6B62\u5F02\u5E38\u8FDB\u7A0B ${t.pid} (${t.status})`),await this.autoCleanOrphan(e,t.pid)):r==="auto"&&t.status!=="healthy"&&n.warn(`auto \u6A21\u5F0F\u672A\u542F\u7528\u7834\u574F\u6027\u6E05\u7406\u5F00\u5173\uFF0C\u4FDD\u7559\u5F02\u5E38\u8FDB\u7A0B ${t.pid} (${t.status})`)}async autoCleanOrphan(e,t){n.info(`\u81EA\u52A8\u6E05\u7406\u5B64\u513F\u8FDB\u7A0B\uFF1AagentId=${e}, pid=${t}`);const a=await S(t),s=await $(t,5e3);if(a.terminated>0&&s){const i={type:"orphan_cleaned",agentId:e,pid:t,message:`\u81EA\u52A8\u6E05\u7406\u6210\u529F\uFF1AagentId=${e}, pid=${t}, \u7EC8\u6B62\u4E86 ${a.terminated} \u4E2A\u8FDB\u7A0B`,timestamp:new Date,details:{terminated:a.terminated,failed:a.failed}};this.emit(i),await this.reportToScheduler(e,"orphan_cleaned",{pid:t,terminated:a.terminated,failed:a.failed})}else n.warn(`\u81EA\u52A8\u6E05\u7406\u5931\u8D25\uFF1AagentId=${e}, pid=${t}, terminated=${a.terminated}, exited=${s}`),await this.reportToScheduler(e,"orphan_clean_failed",{pid:t,terminated:a.terminated,failed:a.failed})}async cleanupDeadSessions(e,t){const a=e.filter(s=>s.pid?!t.get(s.agentId)?.alive:!1);if(a.length>0){n.info(`\u6E05\u7406 ${a.length} \u4E2A\u5DF2\u6B7B\u4EA1\u4F1A\u8BDD\u8BB0\u5F55`);const s=e.filter(i=>t.get(i.agentId)?.alive!==!1);await v(s)}}async checkAgentExistsOnServer(e){if(this.stopped)return null;try{const t=c(o)||c();if(!t)return n.debug("\u7F3A\u5C11 runtimeAccessToken\uFF0C\u65E0\u6CD5\u67E5\u8BE2 agent \u5B58\u5728\u6027"),null;const a=await fetch(`${o}/api/runtime/callback/agent-exists`,{method:"POST",headers:{"Content-Type":"application/json","X-Runtime-Token":t},body:JSON.stringify({agentId:e}),signal:AbortSignal.timeout(5e3)});return a.ok?(await a.json()).exists===!0:(n.debug(`\u67E5\u8BE2 agent \u5B58\u5728\u6027\u5931\u8D25: ${a.status}`),null)}catch(t){return n.debug("\u67E5\u8BE2 agent \u5B58\u5728\u6027\u5F02\u5E38:",t),null}}async reportToScheduler(e,t,a){if(this.stopped){n.debug(`\u76D1\u63A7\u5668\u5DF2\u505C\u6B62\uFF0C\u8DF3\u8FC7\u4E0A\u62A5: ${t}`);return}try{const s=c(o)||c();if(!s){n.debug(`\u7F3A\u5C11 runtimeAccessToken\uFF0C\u8DF3\u8FC7\u4E0A\u62A5: ${t}`);return}const i=await fetch(`${o}/api/runtime/callback/orphan-event`,{method:"POST",headers:{"Content-Type":"application/json","X-Runtime-Token":s},body:JSON.stringify({agentId:e,eventType:t,details:a,timestamp:new Date().toISOString()})});i.ok||(i.status===404?n.debug(`\u4E0A\u62A5\u5931\u8D25: \u8C03\u5EA6\u4E2D\u5FC3\u4E0D\u53EF\u8FBE (404)\uFF0C\u4E8B\u4EF6: ${t}`):n.warn(`\u4E0A\u62A5\u5931\u8D25: ${i.status}`))}catch(s){n.debug("\u4E0A\u62A5\u5230\u8C03\u5EA6\u4E2D\u5FC3\u5931\u8D25:",s)}}onEvent(e){this.eventListeners.push(e)}offEvent(e){const t=this.eventListeners.indexOf(e);t>-1&&this.eventListeners.splice(t,1)}emit(e){for(const t of this.eventListeners)try{t(e)}catch(a){n.warn("\u4E8B\u4EF6\u76D1\u542C\u5668\u6267\u884C\u5931\u8D25:",a)}}getStatus(){return{running:this.intervalId!==null,lastScanTime:this.lastScanTime,mode:r}}}let p=null;function h(){return p||(p=new O),p}async function E(){await h().start()}function M(){h().stop()}export{O as OrphanMonitor,h as getOrphanMonitor,E as startOrphanMonitor,M as stopOrphanMonitor};
|
|
2
2
|
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
|
|
2
2
|
import { type ACodeCommandSpec, type ACodePluginBridge, type PluginCatalogSnapshot, type PluginInvokeContext, type PluginManageRequest, type PluginManageResult, type PluginSummary, type PluginToolInvocationResult, type PluginToolSchema, type JsonObject } from "@agentswork/acode";
|
|
3
3
|
import { type PluginEventMessage, type PluginEventPriority } from "./plugin-event-buffer.js";
|
|
4
|
+
|
|
5
|
+
export declare const BUILTIN_PLUGIN_NAME = "plugin-manager";
|
|
6
|
+
export declare const BUILTIN_PLUGIN_DESCRIPTION = "\u7CFB\u7EDF\u5185\u7F6E\uFF1A\u7BA1\u7406\u63D2\u4EF6\u7684\u751F\u547D\u5468\u671F\uFF08\u5B89\u88C5/\u5378\u8F7D/\u542F\u505C/\u91CD\u8F7D\uFF09\uFF1B\u5F00\u53D1\u63D2\u4EF6\u7528\u5185\u7F6E /create-plugin \u547D\u4EE4";
|
|
7
|
+
|
|
8
|
+
export declare const BUILTIN_PLUGIN_MANAGE_DESC = "\u300C\u63D2\u4EF6\u7BA1\u7406\u63D2\u4EF6\u300D\u7684\u751F\u547D\u5468\u671F\u5DE5\u5177\uFF1A\u7BA1\u7406\u63D2\u4EF6\uFF08\u5B89\u88C5/\u5378\u8F7D/\u91CD\u8F7D/\u542F\u505C/\u5217\u8868\uFF09\u3002\u4EC5\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u5B89\u88C5\u3001\u79FB\u9664\u6216\u4FEE\u590D\u63D2\u4EF6\u65F6\u4F7F\u7528\u3002\n- action=list\uFF1A\u5217\u51FA\u5DF2\u5B89\u88C5\u63D2\u4EF6\uFF08\u72B6\u6001\u3001\u76D1\u542C\u5668\u5065\u5EB7\u3001\u5DE5\u5177\u6570\uFF09\u3002\n- action=install\uFF1Asource \u4E3A\u63D2\u4EF6\u6765\u6E90\uFF0C\u5F53\u524D\u652F\u6301 \"local:<\u4EFB\u610F\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>\"\uFF08\u4E0D\u505A\u76EE\u5F55\u4F4D\u7F6E\u9650\u5236\uFF09\uFF1Bconfig \u4F20\u63D2\u4EF6 manifest \u91CC userConfig \u58F0\u660E\u7684\u914D\u7F6E\u503C\u3002\u5B89\u88C5\u65F6\u4F1A\u5148\u628A\u8BE5\u76EE\u5F55\u79FB\u52A8\u5230\u672C agent \u52A0\u8F7D\u63D2\u4EF6\u7684\u4F4D\u7F6E\uFF0C\u518D\u52A0\u8F7D\u79FB\u52A8\u540E\u7684\u526F\u672C\uFF08\u79FB\u52A8\u540E\u6E90\u76EE\u5F55\u4E0D\u518D\u4FDD\u7559\uFF09\uFF0C\u5B89\u88C5\u540E\u7ACB\u5373\u751F\u6548\uFF1A\u4E0B\u4E00\u6B21 poll_message \u7684 pluginCatalog \u5373\u53EF\u89C1\u3002\n- action=reload\uFF1A\u91CD\u8F7D\u6307\u5B9A\u63D2\u4EF6\uFF08\u6539\u8FC7\u63D2\u4EF6\u6587\u4EF6\u540E\u4F7F\u7528\uFF09\uFF0C\u539F\u5B50\u6362\u88C5\uFF0C\u76D1\u542C\u5668\u91CD\u542F\u3002\n- action=enable / disable\uFF1A\u505C\u7528/\u542F\u7528\uFF08disable \u4FDD\u7559\u5B89\u88C5\u4E0E\u914D\u7F6E\uFF0C\u4EC5\u505C\u6B62\u76D1\u542C\u4E0E\u5DE5\u5177\u8C03\u7528\uFF09\u3002\n- action=uninstall\uFF1A\u5378\u8F7D\u5E76\u5220\u9664\u63D2\u4EF6\u76EE\u5F55\uFF08\u4E0D\u53EF\u9006\uFF0C\u9700\u7528\u6237\u660E\u786E\u8981\u6C42\uFF09\u3002";
|
|
9
|
+
|
|
10
|
+
export declare function getBuiltinCommandDir(): string;
|
|
4
11
|
export interface PluginUserConfigField {
|
|
5
12
|
key: string;
|
|
6
13
|
type?: "string" | "number" | "boolean";
|
|
@@ -77,7 +84,9 @@ export interface PluginManagerOptions {
|
|
|
77
84
|
export declare class PluginManager {
|
|
78
85
|
private agents;
|
|
79
86
|
private readonly rootDir;
|
|
80
|
-
private readonly runtimeRootDir
|
|
87
|
+
private readonly runtimeRootDir?;
|
|
88
|
+
|
|
89
|
+
private moduleNonce;
|
|
81
90
|
constructor(options?: PluginManagerOptions);
|
|
82
91
|
forAgent(agentId: string): ACodePluginBridge;
|
|
83
92
|
|
|
@@ -89,12 +98,15 @@ export declare class PluginManager {
|
|
|
89
98
|
|
|
90
99
|
getPluginCommands(agentId: string): Promise<ACodeCommandSpec[]>;
|
|
91
100
|
private parsePluginCommandDir;
|
|
101
|
+
private parseCommandDir;
|
|
92
102
|
list(agentId: string): Promise<PluginSummary[]>;
|
|
93
103
|
|
|
94
104
|
private deployedPluginVersion;
|
|
95
105
|
getCatalog(agentId: string): Promise<PluginCatalogSnapshot>;
|
|
96
106
|
getToolSchema(agentId: string, qualifiedName: string): Promise<PluginToolSchema | null>;
|
|
97
107
|
invokeTool(agentId: string, pluginName: string, toolName: string, params: JsonObject, ctx?: PluginInvokeContext): Promise<PluginToolInvocationResult>;
|
|
108
|
+
|
|
109
|
+
private buildManageRequest;
|
|
98
110
|
private executeHandler;
|
|
99
111
|
private invokeProcessHandler;
|
|
100
112
|
private invokeModuleHandler;
|
|
@@ -178,13 +190,27 @@ export declare class PluginManager {
|
|
|
178
190
|
ok: boolean;
|
|
179
191
|
error?: string;
|
|
180
192
|
}>;
|
|
193
|
+
|
|
194
|
+
private bumpCatalogRevision;
|
|
181
195
|
private agentState;
|
|
182
196
|
|
|
183
197
|
private hydrate;
|
|
198
|
+
private doHydrate;
|
|
184
199
|
private installedFile;
|
|
185
200
|
private persistInstalled;
|
|
201
|
+
|
|
202
|
+
private sensitiveKeysOf;
|
|
203
|
+
|
|
204
|
+
private stripSensitiveValues;
|
|
205
|
+
private secretsFile;
|
|
206
|
+
|
|
207
|
+
private readSecrets;
|
|
208
|
+
|
|
209
|
+
private persistSecrets;
|
|
186
210
|
private readJsonFile;
|
|
187
211
|
private loadManifestOnly;
|
|
212
|
+
|
|
213
|
+
private validateUserConfigValues;
|
|
188
214
|
private loadPluginFromDir;
|
|
189
215
|
|
|
190
216
|
private ensureListenersRunning;
|
|
@@ -226,10 +252,6 @@ export declare class PluginManager {
|
|
|
226
252
|
error?: string;
|
|
227
253
|
}>;
|
|
228
254
|
}
|
|
229
|
-
export declare function splitQualifiedName(qualifiedName: string): {
|
|
230
|
-
plugin: string;
|
|
231
|
-
tool: string;
|
|
232
|
-
} | null;
|
|
233
255
|
|
|
234
256
|
export declare function isValidPluginName(name: unknown): name is string;
|
|
235
257
|
export declare function validateManifest(manifest: Record<string, unknown>): string | null;
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import{spawn as
|
|
2
|
-
|
|
3
|
-
`,"utf8")}async migrateLegacySharedIfNeeded(){try{if(S(this.deployedManifestFile()))return;const e=g(this.legacySharedDir(),"manifest.json");if(!S(e))return;const t=JSON.parse(E(e,"utf8")),n=Array.isArray(t.plugins)?t.plugins:[];if(n.length===0)return;const r=[];for(const s of n){const o=g(this.legacySharedDir(),s.zipFile);if(!(!s.pluginName||!S(o)))try{const i=await this.deployPluginZipToPersistentDir(E(o),s.pluginName);if(!i)continue;r.push(i),d.info("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u5230\u90E8\u7F72\u533A: %s",s.pluginName)}catch(i){d.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6 %s \u8FC1\u79FB\u5931\u8D25: %s",s.pluginName,i instanceof Error?i.message:String(i))}}r.length>0&&this.writeSharedManifest(r),v(this.legacySharedDir(),{recursive:!0,force:!0})}catch(e){d.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u672A\u6267\u884C\uFF08\u4E0B\u6B21\u91CD\u8BD5\uFF09: %s",e instanceof Error?e.message:String(e))}}deployedPluginHealthy(e){return S(g(this.deployedPluginDir(e),"plugin.json"))}runtimeDirFor(e){return g(this.runtimeRootDir,M(e))}runtimeLinkPath(e,t){return g(this.runtimeDirFor(e),t)}ensureRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t),r=this.deployedPluginDir(t);if(!S(g(r,"plugin.json")))return!1;L(this.runtimeDirFor(e),{recursive:!0});try{if(S(n)){let s=!1;try{s=X(n).isSymbolicLink()}catch{s=!1}if(s)try{return H(n),!0}catch{}v(n,{recursive:!0,force:!0})}return Q(r,n,Se),d.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u5EFA\u7ACB: %s \u2192 %s",e,n,r),!0}catch(s){return d.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5931\u8D25\uFF08%s \u2192 %s\uFF09: %s",e,t,r,s instanceof Error?s.message:String(s)),!1}}removeRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t);try{S(n)&&(v(n,{recursive:!0,force:!0}),d.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u79FB\u9664: %s",e,t))}catch(r){d.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u79FB\u9664\u5931\u8D25\uFF08%s\uFF09: %s",e,t,r instanceof Error?r.message:String(r))}}async saveSharedPlugin(e,t,n=!0,r){if(!e||e.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};await this.migrateLegacySharedIfNeeded();const s=g(this.rootDir,"tmp",`deploy-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const o=await j(e,s),i=this.loadManifestOnly(o.pluginDir);if(!i.ok)return i;const a=i.manifest.name,u=this.readSharedManifest().find(p=>p.pluginName===a);if(u&&u.sha256===r&&this.deployedPluginHealthy(a))return{ok:!0,pluginName:a};await this.suspendDeployedPluginAcrossAgents(a),L(this.deployedDir(),{recursive:!0});const c=this.deployedPluginDir(a),f=g(this.deployedDir(),`.old-${a}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);if(S(c))try{V(c,f)}catch{v(c,{recursive:!0,force:!0})}try{F(o.pluginDir,c,{recursive:!0,filter:p=>!/[\\/]\.git([\\/]|$)/.test(p)&&!/[\\/]node_modules([\\/]|$)/.test(p)})}catch(p){throw S(f)&&(v(c,{recursive:!0,force:!0}),V(f,c)),p}S(f)&&v(f,{recursive:!0,force:!0}),await W(this.deployedManifestFile(),async()=>{const p=this.readSharedManifest().filter(w=>w.pluginName!==a);p.push({pluginName:a,zipFile:u?.zipFile??`${a}.zip`,fileName:t,defaultEnabled:n,sha256:r}),this.writeSharedManifest(p)}),d.info("[shared] \u63D2\u4EF6\u5DF2\u90E8\u7F72\u5230 bridge: %s\uFF08\u6765\u6E90 %s%s\uFF09",a,t,r?`, sha256=${r.slice(0,12)}\u2026`:"");const m=(await this.applySharedToKnownAgents()).find(p=>p.installed.includes(a));return m&&d.info("[shared] \u5DF2\u540C\u6B65\u5230\u8FD0\u884C\u4E2D agent: %s",m.agentId),{ok:!0,pluginName:a}}catch(o){const i=o instanceof Error?o.message:String(o);return d.warn("[shared] \u63D2\u4EF6\u90E8\u7F72\u5931\u8D25\uFF08%s\uFF09: %s",t,i),{ok:!1,error:`\u63D2\u4EF6\u90E8\u7F72\u5931\u8D25: ${i}`}}finally{await b(s,3,100).catch(()=>{})}}async deployPluginZipToPersistentDir(e,t){if(!e||e.length===0)return null;const n=g(this.rootDir,"tmp",`migrate-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const r=await j(e,n),s=this.loadManifestOnly(r.pluginDir);if(!s.ok)return null;const o=s.manifest.name;if(t&&o!==t)return null;L(this.deployedDir(),{recursive:!0});const i=this.deployedPluginDir(o);return S(i)&&v(i,{recursive:!0,force:!0}),F(r.pluginDir,i,{recursive:!0,filter:a=>!/[\\/]\.git([\\/]|$)/.test(a)&&!/[\\/]node_modules([\\/]|$)/.test(a)}),{pluginName:o,zipFile:`${o}.zip`,fileName:`${o}.zip`,defaultEnabled:!0}}finally{v(n,{recursive:!0,force:!0})}}async suspendDeployedPluginAcrossAgents(e){for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const n=t.queue.then(async()=>{const r=t.plugins.get(e);r&&(this.stopAllListeners(r),t.plugins.delete(e),d.info("[agent:%s] \u5DF2\u6458\u9664\u63D2\u4EF6\u7B49\u5F85\u90E8\u7F72\u533A\u66F4\u65B0: %s",t.agentId,e))});t.queue=n.catch(()=>{}),await n}}async applySharedToKnownAgents(){const e=[];for(const t of this.agents.values()){if(!t.hydrated)continue;const n=await this.syncSharedIntoStateQueued(t);n.length>0&&e.push({agentId:t.agentId,installed:n})}return e}async syncSharedIntoStateQueued(e){const t=e.queue.then(()=>this.syncSharedIntoState(e));return e.queue=t.catch(()=>[]),t}effectiveSharedEnabled(e,t){return se(e,"plugins",t.pluginName)&&(t.defaultEnabled??!0)}async pullTemplatePluginsFromCapabilities(e){const t=ie(e.agentId);if(!t)return;const n=this.readSharedManifest();for(const[r,s]of Object.entries(t)){if(!s.url)continue;const o=n.find(a=>a.pluginName===r);if(!o||!o.sha256||o.sha256===s.sha256&&this.deployedPluginHealthy(r)||this.templatePullInFlight.has(r))continue;this.templatePullInFlight.add(r);const i=g(this.rootDir,"tmp",`pull-${M(e.agentId)}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{L(i,{recursive:!0});let a=`${r}.zip`;try{const y=decodeURIComponent(s.url.split("/").pop()||"");y.toLowerCase().endsWith(".zip")&&(a=ue(y,`${r}.zip`))}catch{}const u=await le({downloadUrl:s.url,fileName:a,sha256:s.sha256},i);if(!u)continue;const c=E(u.outputPath),f=await this.saveSharedPlugin(c,u.fileName,o.defaultEnabled??!0,s.sha256);f.ok?d.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u81EA\u52A8\u5BF9\u8D26\u66F4\u65B0\u6210\u529F: %s",e.agentId,f.pluginName??r):d.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u66F4\u65B0\u5931\u8D25: %s: %s",e.agentId,r,f.error)}catch(a){d.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6 %s \u66F4\u65B0\u5931\u8D25: %s",e.agentId,r,a instanceof Error?a.message:String(a))}finally{this.templatePullInFlight.delete(r),await b(i,3,100).catch(()=>{})}}}queueTemplatePull(e){this.backgroundTemplatePulls.has(e.agentId)||(this.backgroundTemplatePulls.add(e.agentId),this.pullTemplatePluginsFromCapabilities(e).catch(t=>{d.warn("[agent:%s] \u540E\u53F0\u63D2\u4EF6\u5BF9\u8D26\u66F4\u65B0\u5931\u8D25: %s",e.agentId,t instanceof Error?t.message:String(t))}).finally(()=>{this.backgroundTemplatePulls.delete(e.agentId)}))}async syncSharedIntoState(e){this.queueTemplatePull(e);const t=this.readSharedManifest(),n=new Set,r=[];for(const s of t)if(n.add(s.pluginName),this.effectiveSharedEnabled(e.agentId,s)){const i=e.plugins.get(s.pluginName);if(!this.ensureRuntimeLink(e.agentId,s.pluginName))continue;const a=this.runtimeLinkPath(e.agentId,s.pluginName);if(!i){const u=this.loadPluginFromDir(e,a,`shared:${s.fileName}`,new Date().toISOString(),{});u.ok?(e.plugins.set(u.plugin.name,u.plugin),r.push(u.plugin.name),d.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u5DF2\u6309\u5F00\u542F\u6001\u52A0\u8F7D: %s",e.agentId,s.pluginName)):d.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25: %s: %s",e.agentId,s.pluginName,u.error)}}else{const i=e.plugins.get(s.pluginName);i&&(this.stopAllListeners(i),e.plugins.delete(s.pluginName)),this.removeRuntimeLink(e.agentId,s.pluginName)}return this.cleanupRuntimeDir(e,n),this.persistInstalled(e),r}cleanupRuntimeDir(e,t){const n=this.runtimeDirFor(e.agentId);try{if(!S(n))return;const r=new Set(t);for(const s of H(n))!r.has(s)&&!e.plugins.has(s)&&this.removeRuntimeLink(e.agentId,s)}catch{}}async applyCapabilities(e){const t=await this.hydrate(e);await this.pullTemplatePluginsFromCapabilities(t),await this.syncSharedIntoState(t)}async drainEvents(e,t={}){const n=await this.hydrate(e);this.ensureListenersRunning(n);const r=n.buffer.drain(t),s=await this.getCatalog(e);return{revision:r.revision,events:r.events,catalog:s,compactionSeq:n.compactionSeq}}markAgentCompacted(e){const t=this.agentState(e);t.compactionSeq++,d.debug("[agent:%s] \u4E0A\u4E0B\u6587\u538B\u7F29\u6807\u8BB0: compactionSeq=%d",e,t.compactionSeq)}async enqueueExternalEvent(e,t,n){const r=await this.hydrate(e),s=r.plugins.get(t);if(!s||!s.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\u6216\u5DF2\u505C\u7528`};const o=typeof n.event=="string"?n.event:"",i=s.listeners.find(a=>a.transport.type==="http-callback"&&(!o||a.event===o));return i?(this.enqueueEvent(r,s,i,n),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5339\u914D\u7684 http-callback \u76D1\u542C\u5668\uFF08event=${o||"(\u7A7A)"}\uFF09`}}agentState(e){let t=this.agents.get(e);return t||(t={agentId:e,plugins:new Map,buffer:new ce(e),hydrated:!1,queue:Promise.resolve(),eventSeq:0,compactionSeq:0},this.agents.set(e,t)),t}async hydrate(e){await this.migrateLegacySharedIfNeeded();const t=this.agentState(e);if(t.hydrated)return t;t.hydrated=!0;const n=this.installedFile(e);if(!S(n))return await this.syncSharedIntoState(t).catch(()=>{}),t;try{const r=JSON.parse(E(n,"utf8"));for(const s of r.plugins??[]){if(String(s.source||"").startsWith("shared:"))continue;const i=g(this.rootDir,"cache",M(e),s.name);if(!S(g(i,"plugin.json"))){d.warn("[agent:%s] \u5DF2\u5B89\u88C5\u63D2\u4EF6\u76EE\u5F55\u7F3A\u5931\uFF0C\u8DF3\u8FC7: %s",e,s.name);continue}const a=this.loadPluginFromDir(t,i,s.source,s.installedAt,s.config??{});if(a.ok){const u=a.plugin;u.enabled=s.enabled,t.plugins.set(u.name,u)}else d.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25: %s: %s",e,s.name,a.error)}}catch(r){const s=r instanceof Error?r.message:String(r);d.error("[agent:%s] installed.json \u89E3\u6790\u5931\u8D25: %s",e,s)}return await this.syncSharedIntoState(t).catch(r=>{d.warn("[agent:%s] \u5171\u4EAB\u63D2\u4EF6\u540C\u6B65\u5931\u8D25: %s",e,r instanceof Error?r.message:String(r))}),t}installedFile(e){return g(this.rootDir,"agents",M(e),"installed.json")}persistInstalled(e){const t=this.installedFile(e.agentId);L(Z(t),{recursive:!0});const n=[...e.plugins.values()].map(r=>({name:r.name,source:r.source,installedAt:r.installedAt,enabled:r.enabled,config:r.configValues}));B(t,`${JSON.stringify({version:1,plugins:n},null,2)}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
`)}a.length>1024*1024&&(a=a.slice(-4096))}),i.stderr?.on("data",u=>{k(n,`stderr: ${A(u.toString("utf8").trimEnd(),400)}`)}),i.on("error",u=>{n.lastError=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${u.message}`,k(n,`ERROR ${n.lastError}`)}),i.on("close",u=>{n.child=void 0,!n.stopping&&(n.lastError=`\u76D1\u542C\u8FDB\u7A0B\u9000\u51FA\uFF08code=${u??"signal"}\uFF09`,k(n,`exit code=${u??"signal"}\uFF0C\u51C6\u5907\u91CD\u542F`),this.scheduleListenerRestart(e,t,n))})}catch(i){const a=i instanceof Error?i.message:String(i);n.lastError=a,k(n,`ERROR spawn: ${a}`),this.scheduleListenerRestart(e,t,n)}}scheduleListenerRestart(e,t,n){if(n.stopping)return;const r=Math.max(500,n.def.transport?.restartBackoffMs??2e3),s=Math.min($e,r*2**Math.min(n.restarts,6));n.restarts++,k(n,`restart #${n.restarts} in ${s}ms`),n.backoffTimer=setTimeout(()=>{n.backoffTimer=void 0,n.stopping||this.spawnListenerChild(e,t,n)},s)}async pollListenerOnce(e,t,n){if(n.polling)return;const r=n.def.transport?.command??"",s=U(r,{});if(s.length===0)return;n.polling=!0;const o=new AbortController,i=setTimeout(()=>o.abort(),J);try{const a=await new Promise((u,c)=>{const f=C(s[0],s.slice(1),{cwd:t.dir,env:this.buildPluginEnv(t,e.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"],signal:o.signal});let y="",m="";f.stdout?.on("data",w=>{y.length<_&&(y+=w.toString("utf8"))}),f.stderr?.on("data",w=>{m.length<_&&(m+=w.toString("utf8"))});const p=()=>o.signal.aborted;f.on("error",w=>{c(p()?new Error(`poll \u8D85\u65F6(${J}ms)`):w)}),f.on("close",w=>{p()?c(new Error(`poll \u8D85\u65F6(${J}ms)`)):w===0?u(y):c(new Error(`exit ${w}: ${A(m||y,300)}`))})});n.lastError=void 0;for(const u of a.split(`
|
|
7
|
-
`)){
|
|
8
|
-
${n.description}`:""}`,a=(n.toolHints??[]).join(","),u=`${i}
|
|
9
|
-
|
|
1
|
+
import{spawn as _}from"node:child_process";import{cpSync as F,existsSync as w,lstatSync as ie,mkdirSync as D,readFileSync as k,readdirSync as j,renameSync as H,rmSync as E,symlinkSync as se,writeFileSync as U}from"node:fs";import{dirname as J,join as m,resolve as Z}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 N,withFileLock as W,downloadPluginZip as ge,sanitizeArchiveFileName as pe}from"../utils/file-utils.js";import{createLogger as me}from"../utils/logger.js";import{setDeployedDefaultsProvider as he,reconcileDefaultsFromDeployed as ye}from"./capability-config.js";import{isCapabilityEnabled as Se,getAgentPluginSources as we}from"./instance-features.js";import{PluginEventBuffer as ve}from"./plugin-event-buffer.js";import{extractPluginZip as x}from"./plugin-package.js";const f=me("plugin-manager"),$="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`,Pe={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},$e=new Set(["install","uninstall","reload","enable","disable","list"]);function ee(){const l=fe();return l&&l!=="unknown"?l:void 0}function Ee(){return oe(new URL("./builtin-commands/",import.meta.url))}const ke=200,R=256*1024,Ae=4*1024,te=6e4,q=6e4,be=/^[a-zA-Z0-9_][a-zA-Z0-9_-]*$/,z=/^[a-z0-9][a-z0-9-]*$/,De=["system.","aws-","acode-"],Le=new Set(["NODE_OPTIONS","NODE_PATH","NODE_EXTRA_CA_CERTS","NODE_REPL_HISTORY","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","PYTHONPATH","PYTHONSTARTUP","PYTHONHOME","PERL5LIB","PERL5OPT","RUBYOPT","RUBYLIB","BASH_ENV","ENV","SHELLOPTS","BASHOPTS","IFS","PS1","PS4","GIT_SSH","GIT_SSH_COMMAND","GIT_CONFIG","GIT_CONFIG_GLOBAL","PATH","HOME","USERPROFILE","SYSTEMROOT","COMSPEC","TEMP","TMP","LANG","TZ"]),Oe=/^[A-Za-z_][A-Za-z0-9_]*$/,Te=process.platform==="win32"?"junction":"dir",Ne=/[^\x20-\x7E]/,Ie=6e4,G=20,ne=80;function P(l){return typeof l=="object"&&l!==null&&!Array.isArray(l)}function I(l,e){let t=l;for(const n of e.split(".")){if(!P(t))return;t=t[n]}return t}function A(l,e){return l.length<=e?l:`${l.slice(0,e)}\u2026(\u622A\u65AD,\u5171 ${l.length} \u5B57\u7B26)`}async function C(l,e=8,t=200){for(let n=0;;n++)try{E(l,{recursive:!0,force:!0});return}catch(r){if(n>=e-1)throw r;await new Promise(i=>setTimeout(i,t))}}async function re(l,e){D(J(e),{recursive:!0});try{H(l,e);return}catch(t){const n=t?.code;if(!n||!["EXDEV","EPERM","EACCES","EBUSY","EINVAL"].includes(n))throw t}F(l,e,{recursive:!0,filter:t=>!/[\\/]\.git([\\/]|$)/.test(t)&&!/[\\/]node_modules([\\/]|$)/.test(t)}),await C(l)}function b(l,e){l.logs.push(`${new Date().toISOString()} ${e}`),l.logs.length>ke&&l.logs.shift()}function B(l,e,t="params"){if(!P(l))return[];const n=[],r=l.type;if(typeof r=="string"&&!Ce(r,e))return[`${t}: \u671F\u671B ${r}\uFF0C\u5B9E\u9645 ${Re(e)}`];if(Array.isArray(l.enum)&&l.enum.length>0&&(l.enum.some(s=>JSON.stringify(s)===JSON.stringify(e))||n.push(`${t}: \u503C ${JSON.stringify(e)} \u4E0D\u5728\u679A\u4E3E ${JSON.stringify(l.enum)} \u5185`)),r==="object"&&P(e)){const i=P(l.properties)?l.properties:{},s=Array.isArray(l.required)?l.required:[];for(const o of s)(!(o in e)||e[o]===void 0)&&n.push(`${t}.${o}: \u5FC5\u586B\u53C2\u6570\u7F3A\u5931`);for(const[o,a]of Object.entries(i))o in e&&e[o]!==void 0&&n.push(...B(a,e[o],`${t}.${o}`));if(l.additionalProperties===!1)for(const o of Object.keys(e))o in i||n.push(`${t}.${o}: \u4E0D\u5141\u8BB8\u7684\u672A\u77E5\u53C2\u6570\uFF08schema additionalProperties=false\uFF09`)}return r==="array"&&Array.isArray(e)&&P(l.items)&&e.forEach((i,s)=>{n.push(...B(l.items,i,`${t}[${s}]`))}),n}function Ce(l,e){switch(l){case"string":return typeof e=="string";case"number":return typeof e=="number"&&Number.isFinite(e);case"boolean":return typeof e=="boolean";case"object":return P(e);case"array":return Array.isArray(e);case"null":return e===null;default:return!0}}function Re(l){return l===null?"null":Array.isArray(l)?"array":typeof l}class Me{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)}}setOnPluginsChanged(e){this.onPluginsChanged=e}notifyPluginsChanged(e){try{this.onPluginsChanged?.(e)}catch(t){f.warn("[agent:%s] onPluginsChanged \u56DE\u8C03\u5931\u8D25: %s",e,t instanceof Error?t.message:String(t))}}async getCommandDirs(e){return[...(await this.hydrate(e)).plugins.values()].filter(n=>n.enabled&&n.commandDir).map(n=>n.commandDir)}async getPluginCommands(e){const t=await this.hydrate(e),n=[];n.push(...this.parseCommandDir($,Ee()));for(const r of t.plugins.values())!r.enabled||!r.commandDir||n.push(...this.parsePluginCommandDir(r));return n}parsePluginCommandDir(e){return this.parseCommandDir(e.name,e.commandDir)}parseCommandDir(e,t){const n=[];if(!t)return n;try{for(const r of j(t)){if(!r.endsWith(".md"))continue;const i=m(t,r);try{const s=le(i,k(i,"utf8"));s.plugin=e,n.push(s)}catch(s){f.warn("[plugin:%s] \u547D\u4EE4\u89E3\u6790\u5931\u8D25 %s: %s",e,r,s instanceof Error?s.message:String(s))}}}catch{}return n}async list(e){const t=await this.hydrate(e),n=new Map;for(const r of t.plugins.values()){const i=this.toSummary(r);n.set(i.name,i)}n.has($)||n.set($,{name:$,version: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(k(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,G).map(s=>({name:s.name,description:A(s.title||s.description,ne),requiredParams:this.requiredParamsOf(s)}));r.tools.length>G&&i.push({name:`(\u53E6\u6709 ${r.tools.length-G} \u4E2A\u5DE5\u5177\u672A\u5217\u51FA)`,description:'\u7528 function_call {action:"catalog"} \u67E5\u770B\u5168\u91CF',requiredParams:void 0}),n.push({plugin:r.name,version:r.version,description:r.description,status:r.status,tools:i})}return n.push({plugin:$,version:ee(),description:X,status:"enabled",tools:[{name:"manage",description:A(Q,ne),requiredParams:["action"]}]}),{revision:t.catalogRevision,plugins:n}}async getToolSchema(e,t){const n=ue(t);if(!n)return null;if(n.plugin===$&&n.tool==="manage")return{plugin:$,name:"manage",description:Q,inputSchema:Pe};const i=(await this.hydrate(e)).plugins.get(n.plugin);if(!i||!i.enabled)return null;const s=i.tools.find(o=>o.name===n.tool);return s?{plugin:i.name,name:s.name,title:s.title,description:s.description,inputSchema:s.inputSchema??{type:"object",properties:{}}}:null}async invokeTool(e,t,n,r,i){if(t===$&&n==="manage"){const u=this.buildManageRequest(r);if(!u)return{ok:!1,error:"plugin-manager.manage \u7F3A\u5C11 action"};const c=await this.manage(e,u);if(!c.ok)return{ok:!1,error:c.error??"\u63D2\u4EF6\u7BA1\u7406\u64CD\u4F5C\u5931\u8D25"};const d={ok:!0};return c.plugins&&(d.plugins=c.plugins),c.summary&&(d.summary=c.summary),{ok:!0,result:d}}const s=await this.hydrate(e),o=s.plugins.get(t);if(!o)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\uFF08\u53EF\u7528\u63D2\u4EF6: ${[...s.plugins.keys()].join(", ")||"\u65E0"}\uFF09`};if(!o.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u5DF2\u505C\u7528\uFF0C\u53EF\u8BA9\u7528\u6237\u5728\u9762\u677F\u6216\u7528 plugin-manager.manage enable \u542F\u7528`};const a=o.tools.find(u=>u.name===n);if(!a)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5DE5\u5177 ${n}\uFF08\u53EF\u7528: ${o.tools.map(u=>u.name).join(", ")||"\u65E0"}\uFF09`};if(a.inputSchema){const u=B(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"||!$e.has(t))return null;const n={action:t};if(typeof e.name=="string"&&e.name.trim()&&(n.name=e.name.trim()),typeof e.source=="string"&&e.source.trim()&&(n.source=e.source.trim()),e.config&&typeof e.config=="object"&&!Array.isArray(e.config)){const r={};for(const[i,s]of Object.entries(e.config))typeof s=="string"&&(r[i]=s);n.config=r}return n}async executeHandler(e,t,n,r,i){const s=Date.now(),o=n.handler??{type:"process"};try{return o.type==="mcp"?{ok:!1,error:"handler.type=mcp \u5C06\u5728\u540E\u7EED\u7248\u672C\u652F\u6301\uFF0C\u8BF7\u6539\u7528 process/module handler"}:o.type==="module"?{ok:!0,result:await this.invokeModuleHandler(t,o,r,e,i),durationMs:Date.now()-s}:!o.command||!o.command.trim()?{ok:!1,error:`\u5DE5\u5177 ${n.name} \u7684 process handler \u7F3A\u5C11 command`}:{ok:!0,result:await this.invokeProcessHandler(t,o,r,e,i),durationMs:Date.now()-s}}catch(a){return{ok:!1,error:a instanceof Error?a.message:String(a),durationMs:Date.now()-s}}}async invokeProcessHandler(e,t,n,r,i){const s=Y(t.command??"",{params:n});if(s.length===0)throw new Error("process handler command \u4E3A\u7A7A");const o=typeof t.timeoutMs=="number"&&t.timeoutMs>0?t.timeoutMs: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 h=_(s[0],s.slice(1),{cwd:e.dir,env:this.buildPluginEnv(e,r),shell:t.shell===!0,windowsHide:!0,signal:a.signal});let g="",p="";h.stdin?.on("error",()=>{}),h.stdout?.on("data",v=>{g.length<R&&(g+=v.toString("utf8"))}),h.stderr?.on("data",v=>{p.length<R&&(p+=v.toString("utf8"))}),h.on("error",v=>{y(new Error(`\u63D2\u4EF6\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${v.message}`))}),h.on("close",v=>{const L=g.trim();if(v!==0){const O=A(p.trim()||L||"(\u65E0\u8F93\u51FA)",600);y(new Error(a.signal.aborted?`\u63D2\u4EF6\u8FDB\u7A0B\u8D85\u65F6(${o}ms)\u6216\u88AB\u4E2D\u6B62`:`\u63D2\u4EF6\u8FDB\u7A0B\u9000\u51FA\u7801 ${v}: ${O}`));return}if(!L){d({ok:!0});return}try{d(JSON.parse(L))}catch{d(L)}});try{t.stdin==="params"?h.stdin?.end(`${JSON.stringify(n)}
|
|
7
|
+
`):h.stdin?.end()}catch{}})}finally{clearTimeout(c),i?.signal?.removeEventListener("abort",u)}}async invokeModuleHandler(e,t,n,r,i){if(!t.module)throw new Error("module handler \u7F3A\u5C11 module \u8DEF\u5F84");const s=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 h=Promise.resolve().then(()=>c(n,{agentId:r,signal:i?.signal,pluginRoot:e.dir}));try{return await Promise.race([h,new Promise((g,p)=>{y=setTimeout(()=>p(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)&&(!Oe.test(i)||Le.has(i.toUpperCase())||(n[i]=s));return n}async manage(e,t){const n=this.agentState(e),r=n.queue.then(async()=>{const i=await this.hydrate(e);return this.doManage(i,t)});return n.queue=r.catch(()=>{}),r}async doManage(e,t){if(t.name===$&&(t.action==="uninstall"||t.action==="disable"||t.action==="enable"||t.action==="reload"))return{ok:!1,error:`\u5185\u7F6E\u7CFB\u7EDF\u63D2\u4EF6 ${$} \u4E0D\u53EF${t.action==="uninstall"?"\u5378\u8F7D":t.action==="reload"?"\u91CD\u8F7D":"\u505C\u7528/\u542F\u7528"}`};switch(t.action){case"list":return{ok:!0,plugins:await this.list(e.agentId)};case"install":return this.installPlugin(e,t);case"uninstall":return this.uninstallPlugin(e,t);case"reload":return this.reloadPlugin(e,t);case"enable":case"disable":return this.setEnabled(e,t,t.action==="enable");default:return{ok:!1,error:`\u672A\u77E5 action: ${String(t.action)}`}}}async installPlugin(e,t){const n=(t.source??"").trim();if(!n)return{ok:!1,error:"install \u9700\u8981 source\uFF08\u5F53\u524D\u652F\u6301 local:<\u63D2\u4EF6\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84>\uFF09"};const r=n.split(":",1)[0];if(r!=="local")return{ok:!1,error:`\u6682\u4E0D\u652F\u6301\u63D2\u4EF6\u6765\u6E90 "${r}:"\uFF08npm:/git: \u5728\u8DEF\u7EBF\u56FE\u4E2D\uFF1Bzip \u5305\u8BF7\u7528\u9762\u677F\u5BFC\u5165\u6216 POST /runtime/plugins/:agentId/upload\uFF09`};const i=n.slice(6).trim();return!i||!w(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 x(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 C(o,3,100).catch(()=>{})}});return i.queue=s.catch(()=>{}),s}async installFromDirectory(e,t,n,r){const i=this.loadManifestOnly(t);if(!i.ok)return i;const s=i.manifest,o=s.name;if(o===$)return{ok:!1,error:`\u63D2\u4EF6\u540D ${o} \u4E3A\u7CFB\u7EDF\u4FDD\u7559\u540D\u79F0\uFF0C\u4E0D\u5141\u8BB8\u5B89\u88C5\u540C\u540D\u63D2\u4EF6`};const a=this.validateUserConfigValues(s,r??{});if(a)return{ok:!1,error:a};const u=this.loadPluginFromDir(e,t,n,new Date().toISOString(),r??{});if(!u.ok)return f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u6821\u9A8C\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,u.error),u;const c=m(this.rootDir,"cache",N(e.agentId),o),d=t===c,y=e.plugins.get(o);if(y&&this.stopAllListeners(y),!d)try{await C(c),await re(t,c)}catch(p){const v=p instanceof Error?p.message:String(p);return f.warn("[agent:%s] \u63D2\u4EF6\u79FB\u52A8\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,v),y&&this.startAllListeners(e,y),{ok:!1,error:`\u63D2\u4EF6\u79FB\u52A8\u5931\u8D25: ${v}`}}const h=this.loadPluginFromDir(e,c,n,new Date().toISOString(),r??{});if(!h.ok){if(f.warn("[agent:%s] \u63D2\u4EF6\u88C5\u8F7D\u5931\u8D25\uFF08%s\uFF09: %s",e.agentId,n,h.error),!d)try{await re(c,t)}catch(p){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,p instanceof Error?p.message:String(p))}if(y)try{this.startAllListeners(e,y)}catch(p){f.warn("[agent:%s] \u6062\u590D\u65E7\u5B9E\u4F8B\u76D1\u542C\u5931\u8D25: %s",e.agentId,p instanceof Error?p.message:String(p))}return h}const g=h.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),this.bumpCatalogRevision(e),this.readSharedManifest().some(s=>s.pluginName===n)&&this.removeRuntimeLink(e.agentId,n),this.persistInstalled(e),await C(r.dir),f.info("[agent:%s] \u63D2\u4EF6\u5DF2\u5378\u8F7D: %s",e.agentId,n),this.notifyPluginsChanged(e.agentId),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${n} \u672A\u5B89\u88C5`}}async reloadPlugin(e,t){const n=(t.name??"").trim(),r=e.plugins.get(n);if(!r)return{ok:!1,error:`\u63D2\u4EF6 ${n} \u672A\u5B89\u88C5`};const i=this.loadPluginFromDir(e,r.dir,r.source,r.installedAt,r.configValues);if(!i.ok)return{ok:!1,error:`\u91CD\u8F7D\u5931\u8D25\uFF08\u4FDD\u7559\u65E7\u7248\u672C\u8FD0\u884C\uFF09: ${i.error}`};const s=i.plugin;return this.stopAllListeners(r),e.plugins.set(n,s),this.bumpCatalogRevision(e),this.persistInstalled(e),this.startAllListeners(e,s),f.info("[agent:%s] \u63D2\u4EF6\u5DF2\u91CD\u8F7D: %s",e.agentId,n),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(s)}}async setEnabled(e,t,n){const r=(t.name??"").trim(),i=e.plugins.get(r);return i?(i.enabled=n,this.bumpCatalogRevision(e),n?this.startAllListeners(e,i):this.stopAllListeners(i),this.persistInstalled(e),this.notifyPluginsChanged(e.agentId),{ok:!0,summary:this.toSummary(i)}):{ok:!1,error:`\u63D2\u4EF6 ${r} \u672A\u5B89\u88C5`}}deployedDir(){return m(this.rootDir,"deployed")}deployedManifestFile(){return m(this.deployedDir(),"manifest.json")}deployedPluginDir(e){if(!V(e))throw new Error(`\u975E\u6CD5\u63D2\u4EF6\u540D\uFF08\u4EC5\u5141\u8BB8 ${z}\uFF09: ${JSON.stringify(e)}`);const t=m(this.deployedDir(),e),n=Z(this.deployedDir());if(Z(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(k(this.deployedManifestFile(),"utf8"));return Array.isArray(e.plugins)?e.plugins.filter(t=>t&&V(t.pluginName)):[]}catch{return[]}}writeSharedManifest(e){D(this.deployedDir(),{recursive:!0}),U(this.deployedManifestFile(),`${JSON.stringify({version:2,plugins:e},null,2)}
|
|
8
|
+
`,"utf8")}async migrateLegacySharedIfNeeded(){try{if(w(this.deployedManifestFile()))return;const e=m(this.legacySharedDir(),"manifest.json");if(!w(e))return;const t=JSON.parse(k(e,"utf8")),n=Array.isArray(t.plugins)?t.plugins:[];if(n.length===0)return;const r=[];for(const i of n){const s=m(this.legacySharedDir(),i.zipFile);if(!(!i.pluginName||!w(s)))try{const o=await this.deployPluginZipToPersistentDir(k(s),i.pluginName);if(!o)continue;r.push(o),f.info("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u5230\u90E8\u7F72\u533A: %s",i.pluginName)}catch(o){f.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6 %s \u8FC1\u79FB\u5931\u8D25: %s",i.pluginName,o instanceof Error?o.message:String(o))}}r.length>0&&this.writeSharedManifest(r),E(this.legacySharedDir(),{recursive:!0,force:!0})}catch(e){f.warn("[shared] \u65E7\u5171\u4EAB\u63D2\u4EF6\u8FC1\u79FB\u672A\u6267\u884C\uFF08\u4E0B\u6B21\u91CD\u8BD5\uFF09: %s",e instanceof Error?e.message:String(e))}}deployedPluginHealthy(e){return w(m(this.deployedPluginDir(e),"plugin.json"))}runtimeDirFor(e){return this.runtimeRootDir?m(this.runtimeRootDir,N(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;D(this.runtimeDirFor(e),{recursive:!0});try{if(w(n)){let i=!1;try{i=ie(n).isSymbolicLink()}catch{i=!1}if(i)try{return j(n),!0}catch{}E(n,{recursive:!0,force:!0})}return se(r,n,Te),f.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u5EFA\u7ACB: %s \u2192 %s",e,n,r),!0}catch(i){return f.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5931\u8D25\uFF08%s \u2192 %s\uFF09: %s",e,t,r,i instanceof Error?i.message:String(i)),!1}}removeRuntimeLink(e,t){const n=this.runtimeLinkPath(e,t);try{w(n)&&(E(n,{recursive:!0,force:!0}),f.info("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u5DF2\u79FB\u9664: %s",e,t))}catch(r){f.warn("[agent:%s] \u63D2\u4EF6\u8FD0\u884C\u65F6\u94FE\u63A5\u79FB\u9664\u5931\u8D25\uFF08%s\uFF09: %s",e,t,r instanceof Error?r.message:String(r))}}async saveSharedPlugin(e,t,n=!0,r){if(!e||e.length===0)return{ok:!1,error:"zip \u5305\u5185\u5BB9\u4E3A\u7A7A"};await this.migrateLegacySharedIfNeeded();const i=m(this.rootDir,"tmp",`deploy-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const s=await x(e,i),o=this.loadManifestOnly(s.pluginDir);if(!o.ok)return o;const a=o.manifest.name,u=this.readSharedManifest().find(g=>g.pluginName===a);if(u&&u.sha256===r&&this.deployedPluginHealthy(a))return{ok:!0,pluginName:a};await this.suspendDeployedPluginAcrossAgents(a),D(this.deployedDir(),{recursive:!0});const c=this.deployedPluginDir(a),d=m(this.deployedDir(),`.old-${a}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);if(w(c))try{H(c,d)}catch{E(c,{recursive:!0,force:!0})}try{F(s.pluginDir,c,{recursive:!0,filter:g=>!/[\\/]\.git([\\/]|$)/.test(g)&&!/[\\/]node_modules([\\/]|$)/.test(g)})}catch(g){throw w(d)&&(E(c,{recursive:!0,force:!0}),H(d,c)),g}w(d)&&E(d,{recursive:!0,force:!0}),await W(this.deployedManifestFile(),async()=>{const g=this.readSharedManifest().filter(p=>p.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 h=(await this.applySharedToKnownAgents()).find(g=>g.installed.includes(a));return h&&f.info("[shared] \u5DF2\u540C\u6B65\u5230\u8FD0\u884C\u4E2D agent: %s",h.agentId),{ok:!0,pluginName:a}}catch(s){const o=s instanceof Error?s.message:String(s);return f.warn("[shared] \u63D2\u4EF6\u90E8\u7F72\u5931\u8D25\uFF08%s\uFF09: %s",t,o),{ok:!1,error:`\u63D2\u4EF6\u90E8\u7F72\u5931\u8D25: ${o}`}}finally{await C(i,3,100).catch(()=>{})}}async deployPluginZipToPersistentDir(e,t){if(!e||e.length===0)return null;const n=m(this.rootDir,"tmp",`migrate-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{const r=await x(e,n),i=this.loadManifestOnly(r.pluginDir);if(!i.ok)return null;const s=i.manifest.name;if(t&&s!==t)return null;D(this.deployedDir(),{recursive:!0});const o=this.deployedPluginDir(s);return w(o)&&E(o,{recursive:!0,force:!0}),F(r.pluginDir,o,{recursive:!0,filter:a=>!/[\\/]\.git([\\/]|$)/.test(a)&&!/[\\/]node_modules([\\/]|$)/.test(a)}),{pluginName:s,zipFile:`${s}.zip`,fileName:`${s}.zip`,defaultEnabled:!0}}finally{E(n,{recursive:!0,force:!0})}}async suspendDeployedPluginAcrossAgents(e){for(const t of[...this.agents.values()]){if(!t.hydrated)continue;const n=t.queue.then(async()=>{const r=t.plugins.get(e);r&&(this.stopAllListeners(r),t.plugins.delete(e),this.bumpCatalogRevision(t),f.info("[agent:%s] \u5DF2\u6458\u9664\u63D2\u4EF6\u7B49\u5F85\u90E8\u7F72\u533A\u66F4\u65B0: %s",t.agentId,e))});t.queue=n.catch(()=>{}),await n}}async applySharedToKnownAgents(){const e=[];for(const t of this.agents.values()){if(!t.hydrated)continue;const n=await this.syncSharedIntoStateQueued(t);n.length>0&&e.push({agentId:t.agentId,installed:n})}return e}async syncSharedIntoStateQueued(e){const t=e.queue.then(()=>this.syncSharedIntoState(e));return e.queue=t.catch(()=>[]),t}effectiveSharedEnabled(e,t){return Se(e,"plugins",t.pluginName)&&(t.defaultEnabled??!0)}async pullTemplatePluginsFromCapabilities(e){const t=we(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-${N(e.agentId)}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);try{D(o,{recursive:!0});let a=`${r}.zip`;try{const y=decodeURIComponent(i.url.split("/").pop()||"");y.toLowerCase().endsWith(".zip")&&(a=pe(y,`${r}.zip`))}catch{}const u=await ge({downloadUrl:i.url,fileName:a,sha256:i.sha256},o);if(!u)continue;const c=k(u.outputPath),d=await this.saveSharedPlugin(c,u.fileName,s.defaultEnabled??!0,i.sha256);d.ok?f.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u81EA\u52A8\u5BF9\u8D26\u66F4\u65B0\u6210\u529F: %s",e.agentId,d.pluginName??r):f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u66F4\u65B0\u5931\u8D25: %s: %s",e.agentId,r,d.error)}catch(a){f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6 %s \u66F4\u65B0\u5931\u8D25: %s",e.agentId,r,a instanceof Error?a.message:String(a))}finally{this.templatePullInFlight.delete(r),await C(o,3,100).catch(()=>{})}}}queueTemplatePull(e){this.backgroundTemplatePulls.has(e.agentId)||(this.backgroundTemplatePulls.add(e.agentId),this.pullTemplatePluginsFromCapabilities(e).catch(t=>{f.warn("[agent:%s] \u540E\u53F0\u63D2\u4EF6\u5BF9\u8D26\u66F4\u65B0\u5931\u8D25: %s",e.agentId,t instanceof Error?t.message:String(t))}).finally(()=>{this.backgroundTemplatePulls.delete(e.agentId)}))}async syncSharedIntoState(e){this.queueTemplatePull(e);const t=this.readSharedManifest(),n=new Set,r=[];let i=0;for(const s of t)if(n.add(s.pluginName),this.effectiveSharedEnabled(e.agentId,s)){const a=e.plugins.get(s.pluginName);if(!this.ensureRuntimeLink(e.agentId,s.pluginName))continue;const u=this.runtimeLinkPath(e.agentId,s.pluginName);if(!a){const c=this.loadPluginFromDir(e,u,`shared:${s.fileName}`,new Date().toISOString(),{});c.ok?(e.plugins.set(c.plugin.name,c.plugin),r.push(c.plugin.name),f.info("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u5DF2\u6309\u5F00\u542F\u6001\u52A0\u8F7D: %s",e.agentId,s.pluginName)):f.warn("[agent:%s] \u5DF2\u90E8\u7F72\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25: %s: %s",e.agentId,s.pluginName,c.error)}}else{const a=e.plugins.get(s.pluginName);a&&(this.stopAllListeners(a),e.plugins.delete(s.pluginName),i++),this.removeRuntimeLink(e.agentId,s.pluginName)}return this.cleanupRuntimeDir(e,n),(r.length>0||i>0)&&this.bumpCatalogRevision(e),this.persistInstalled(e),r}cleanupRuntimeDir(e,t){const n=this.runtimeDirFor(e.agentId);try{if(!w(n))return;const r=new Set(t);for(const i of j(n))!r.has(i)&&!e.plugins.has(i)&&this.removeRuntimeLink(e.agentId,i)}catch{}}async applyCapabilities(e){const t=await this.hydrate(e);await this.pullTemplatePluginsFromCapabilities(t),await this.syncSharedIntoState(t)}async drainEvents(e,t={}){const n=await this.hydrate(e);this.ensureListenersRunning(n);const r=n.buffer.drain(t),i=await this.getCatalog(e);return{revision:r.revision,events:r.events,catalog:i,compactionSeq:n.compactionSeq}}markAgentCompacted(e){const t=this.agentState(e);t.compactionSeq++,f.debug("[agent:%s] \u4E0A\u4E0B\u6587\u538B\u7F29\u6807\u8BB0: compactionSeq=%d",e,t.compactionSeq)}async enqueueExternalEvent(e,t,n){const r=await this.hydrate(e),i=r.plugins.get(t);if(!i||!i.enabled)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5\u6216\u5DF2\u505C\u7528`};const s=typeof n.event=="string"?n.event:"",o=i.listeners.find(a=>a.transport.type==="http-callback"&&(!s||a.event===s));return o?(this.enqueueEvent(r,i,o,n),{ok:!0}):{ok:!1,error:`\u63D2\u4EF6 ${t} \u65E0\u5339\u914D\u7684 http-callback \u76D1\u542C\u5668\uFF08event=${s||"(\u7A7A)"}\uFF09`}}bumpCatalogRevision(e){e.catalogRevision++}agentState(e){let t=this.agents.get(e);return t||(t={agentId:e,plugins:new Map,buffer:new ve(e),hydrated:!1,queue:Promise.resolve(),catalogRevision:0,eventSeq:0,compactionSeq:0},this.agents.set(e,t)),t}async hydrate(e){const t=this.agentState(e);return t.hydratePromise||(t.hydratePromise=this.doHydrate(t).catch(n=>{throw t.hydratePromise=void 0,n})),await t.hydratePromise,t}async doHydrate(e){const t=e.agentId;await this.migrateLegacySharedIfNeeded();const n=this.installedFile(t);if(!w(n)){await this.syncSharedIntoState(e).catch(()=>{}),e.hydrated=!0;return}try{const r=JSON.parse(k(n,"utf8")),i=this.readSecrets(t);for(const s of r.plugins??[]){if(String(s.source||"").startsWith("shared:"))continue;const a=m(this.rootDir,"cache",N(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",N(e),"installed.json")}persistInstalled(e){this.persistSecrets(e);const t=this.installedFile(e.agentId);D(J(t),{recursive:!0});const n=[...e.plugins.values()].map(r=>({name:r.name,source:r.source,installedAt:r.installedAt,enabled:r.enabled,config:this.stripSensitiveValues(r)}));U(t,`${JSON.stringify({version:1,plugins:n},null,2)}
|
|
9
|
+
`,"utf8")}sensitiveKeysOf(e){return(e.userConfig??[]).filter(t=>t?.sensitive===!0&&typeof t.key=="string").map(t=>t.key)}stripSensitiveValues(e){const t=new Set(this.sensitiveKeysOf(e)),n={};for(const[r,i]of Object.entries(e.configValues))t.has(r)||(n[r]=i);return n}secretsFile(e){return m(this.rootDir,"agents",N(e),"secrets.json")}readSecrets(e){try{const t=JSON.parse(k(this.secretsFile(e),"utf8"));if(!P(t)||!P(t.secrets))return{};const n={};for(const[r,i]of Object.entries(t.secrets)){if(!P(i))continue;const s={};for(const[o,a]of Object.entries(i))typeof a=="string"&&(s[o]=a);n[r]=s}return n}catch{return{}}}persistSecrets(e){const t={};for(const r of e.plugins.values()){const i={};for(const s of this.sensitiveKeysOf(r)){const o=r.configValues[s];typeof o=="string"&&o.length>0&&(i[s]=o)}Object.keys(i).length>0&&(t[r.name]=i)}const n=this.secretsFile(e.agentId);if(Object.keys(t).length===0){try{E(n,{force:!0})}catch{}return}D(J(n),{recursive:!0}),U(n,`${JSON.stringify({version:1,secrets:t},null,2)}
|
|
10
|
+
`,{encoding:"utf8",mode:384})}readJsonFile(e){if(!w(e))return{ok:!0,data:{}};try{const t=JSON.parse(k(e,"utf8"));return P(t)?{ok:!0,data:t}:{ok:!1,error:`${e}: \u6839\u8282\u70B9\u987B\u4E3A\u5BF9\u8C61`}}catch(t){const n=t instanceof Error?t.message:String(t);return{ok:!1,error:`${e}: JSON \u89E3\u6790\u5931\u8D25: ${n}`}}}loadManifestOnly(e){const t=this.readJsonFile(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 T=Fe(S);if(T)return{ok:!1,error:`${o.tools??"tools/tools.json"}: ${T}`};c.push(S)}const y=m(t,o.listeners??"listeners/listeners.json"),h=this.readJsonFile(y);if(!h.ok)return h;const g=[],p=Array.isArray(h.data.listeners)?h.data.listeners:[];for(const S of p){const T=je(S);if(T)return{ok:!1,error:`${o.listeners??"listeners/listeners.json"}: ${T}`};g.push(S)}const v=Array.isArray(o.userConfig)?o.userConfig:[],L=this.validateUserConfigValues(o,i);if(L)return{ok:!1,error:L};const O={...i};for(const S of v){if(!S||typeof S.key!="string")continue;!(typeof O[S.key]=="string"&&O[S.key].length>0)&&S.required&&S.default!==void 0&&typeof S.default=="string"&&(O[S.key]=S.default)}const M=o.commands;let K;if(typeof M=="string"&&M.trim()){const S=m(t,M.trim());w(S)&&(K=S)}return{ok:!0,plugin:{name:o.name,version:typeof o.version=="string"?o.version:void 0,description:typeof o.description=="string"?o.description:void 0,source:n,installedAt:r,dir:t,enabled:!0,tools:c,listeners:g,commandDir:K,userConfig:v,configValues:O,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",b(n,`ERROR ${n.lastError}`);return}n.stopping=!1,this.spawnListenerChild(e,t,n)}spawnListenerChild(e,t,n){const i=n.def.transport?.command??"",s=Y(i,{});try{b(n,`spawn: ${s.join(" ")}`);const o=_(s[0],s.slice(1),{cwd:t.dir,env:this.buildPluginEnv(t,e.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"]});n.child=o,n.lastError=void 0;let a="";o.stdout?.on("data",u=>{a+=u.toString("utf8");let c=a.indexOf(`
|
|
11
|
+
`);for(;c>=0;){const d=a.slice(0,c).trim();a=a.slice(c+1),d&&this.handleListenerLine(e,t,n,d),c=a.indexOf(`
|
|
12
|
+
`)}a.length>1024*1024&&(a=a.slice(-4096))}),o.stderr?.on("data",u=>{b(n,`stderr: ${A(u.toString("utf8").trimEnd(),400)}`)}),o.on("error",u=>{n.lastError=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${u.message}`,b(n,`ERROR ${n.lastError}`)}),o.on("close",u=>{n.child=void 0,!n.stopping&&(n.lastError=`\u76D1\u542C\u8FDB\u7A0B\u9000\u51FA\uFF08code=${u??"signal"}\uFF09`,b(n,`exit code=${u??"signal"}\uFF0C\u51C6\u5907\u91CD\u542F`),this.scheduleListenerRestart(e,t,n))})}catch(o){const a=o instanceof Error?o.message:String(o);n.lastError=a,b(n,`ERROR spawn: ${a}`),this.scheduleListenerRestart(e,t,n)}}scheduleListenerRestart(e,t,n){if(n.stopping)return;const r=Math.max(500,n.def.transport?.restartBackoffMs??2e3),i=Math.min(Ie,r*2**Math.min(n.restarts,6));n.restarts++,b(n,`restart #${n.restarts} in ${i}ms`),n.backoffTimer=setTimeout(()=>{n.backoffTimer=void 0,n.stopping||this.spawnListenerChild(e,t,n)},i)}async pollListenerOnce(e,t,n){if(n.polling)return;const r=n.def.transport?.command??"",i=Y(r,{});if(i.length===0)return;n.polling=!0;const s=new AbortController,o=setTimeout(()=>s.abort(),q);try{const a=await new Promise((u,c)=>{const d=_(i[0],i.slice(1),{cwd:t.dir,env:this.buildPluginEnv(t,e.agentId),shell:!1,windowsHide:!0,stdio:["ignore","pipe","pipe"],signal:s.signal});let y="",h="";d.stdout?.on("data",p=>{y.length<R&&(y+=p.toString("utf8"))}),d.stderr?.on("data",p=>{h.length<R&&(h+=p.toString("utf8"))});const g=()=>s.signal.aborted;d.on("error",p=>{c(g()?new Error(`poll \u8D85\u65F6(${q}ms)`):p)}),d.on("close",p=>{g()?c(new Error(`poll \u8D85\u65F6(${q}ms)`)):p===0?u(y):c(new Error(`exit ${p}: ${A(h||y,300)}`))})});n.lastError=void 0;for(const u of a.split(`
|
|
13
|
+
`)){const c=u.trim();c&&this.handleListenerLine(e,t,n,c)}}catch(a){const u=a instanceof Error?a.message:String(a);n.lastError=u,b(n,`poll \u5931\u8D25: ${u}`)}finally{clearTimeout(o),n.polling=!1}}stopListener(e){if(e.stopping=!0,e.restarts=0,e.child){try{e.child.kill()}catch{}e.child=void 0}e.timer&&(clearInterval(e.timer),e.timer=void 0),e.backoffTimer&&(clearTimeout(e.backoffTimer),e.backoffTimer=void 0)}handleListenerLine(e,t,n,r){b(n,`event: ${A(r,300)}`);let i;try{i=JSON.parse(r)}catch{n.lastError="\u4E8B\u4EF6\u884C\u4E0D\u662F\u5408\u6CD5 JSON\uFF08\u8981\u6C42 JSONL\uFF09";return}if(!P(i))return;const s=typeof i.event=="string"?i.event:n.def.event,o=s===n.def.event?n.def:t.listeners.find(a=>a.event===s);o&&(o.delivery&&o.delivery!=="poll"&&f.debug("[plugin:%s] delivery=%s \u6682\u6309 poll \u4EA4\u4ED8",t.name,o.delivery),this.enqueueEvent(e,t,o,i))}enqueueEvent(e,t,n,r){for(const[y,h]of Object.entries(n.matcher??{})){const g=I(r,y);if(!(Array.isArray(h)?h:[h]).some(v=>JSON.stringify(v)===JSON.stringify(g)))return}let i;if(n.dedupKey){const y=I(r,n.dedupKey);y!=null&&(i=A(String(y),256))}e.eventSeq++;const s=A(Ue(r.data??r),Ae),o=n.promptTemplate?He(n.promptTemplate,r):`\u3010\u63D2\u4EF6\u4E8B\u4EF6\u3011${t.name} \xB7 ${n.event}${n.description?`
|
|
14
|
+
${n.description}`:""}`,a=(n.toolHints??[]).join(","),u=`${o}
|
|
15
|
+
[plugin-event] plugin=${t.name} event=${n.event}`+(a?` toolHints=${a}`:"")+` payload=${s}`,c={msgId:A(i?`plugin-event-${t.name}-${i}`:`plugin-event-${t.name}-${n.event}-${e.eventSeq}`,512),channel:"plugin-event",senderId:`plugin:${t.name}`,senderName:`\u63D2\u4EF6[${t.name}]`,receiverId:e.agentId||void 0,content:u,requireReply:!1,role:"system",timestamp:new Date().toISOString()},d=n.priority??"normal";e.buffer.push({plugin:t.name,event:n.event,priority:d,dedupKey:i,receivedAt:Date.now(),message:c})}requiredParamsOf(e){const t=e.inputSchema;if(!(!t||!Array.isArray(t.required)))return t.required.filter(n=>typeof n=="string")}toSummary(e){return{name:e.name,version:e.version,description:e.description,status:e.status,enabled:e.enabled,source:e.source,installedAt:e.installedAt,toolCount:e.tools.length,tools:e.tools.map(t=>({name:t.name,title:t.title,description:t.description})),listeners:e.runtimes.map(t=>({event:t.def.event,delivery:t.def.delivery??"poll",running:!!(t.child||t.timer)||t.def.transport?.type==="http-callback",error:t.lastError})),running:e.runtimes.some(t=>!!(t.child||t.timer)||t.def.transport?.type==="http-callback"),error:e.error}}async getLogs(e,t){const n=await this.hydrate(e);if(t===$)return{ok:!0,logs:[`\u2500\u2500 ${$} \u4E3A\u7CFB\u7EDF\u5185\u7F6E\u63D2\u4EF6\uFF08\u65E0\u9700\u5B89\u88C5\uFF09\uFF0C\u65E0\u72EC\u7ACB\u76D1\u542C\u5668\u8FD0\u884C\u65E5\u5FD7\u3002`,"\u5176\u751F\u547D\u5468\u671F\u64CD\u4F5C\uFF08install/reload/disable/enable/list\uFF09\u7531 bridge plugin-manager \u5904\u7406\uFF0C\u53EF\u901A\u8FC7\u300C\u91CD\u8F7D/\u542F\u7528/\u505C\u7528\u300D\u6309\u94AE\u89C2\u5BDF\u72B6\u6001\u53D8\u5316\u3002"]};const r=n.plugins.get(t);if(!r)return{ok:!1,error:`\u63D2\u4EF6 ${t} \u672A\u5B89\u88C5`,logs:[]};const i=[];for(const s of r.runtimes)i.push(`\u2500\u2500 listener ${s.def.event} (${s.def.transport?.type}) ${s.lastError?`[error: ${s.lastError}]`:""}`),i.push(...s.logs);return{ok:!0,logs:i}}async stopAgent(e){const t=this.agents.get(e);if(t){for(const n of t.plugins.values())this.stopAllListeners(n);this.agents.delete(e)}}async stopAll(){for(const e of[...this.agents.keys()])await this.stopAgent(e)}async listDeployed(){await this.migrateLegacySharedIfNeeded();const e=this.readSharedManifest(),t=[];for(const n of e){const r=this.deployedPluginDir(n.pluginName),i=this.deployedPluginHealthy(n.pluginName);let s;if(i)try{const o=JSON.parse(k(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(!V(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{E(this.deployedPluginDir(e),{recursive:!0,force:!0})}catch(t){return{ok:!1,error:`\u90E8\u7F72\u76EE\u5F55\u6E05\u7406\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`}}return f.info("[shared] \u63D2\u4EF6\u5DF2\u4ECE bridge \u79FB\u9664\u90E8\u7F72: %s",e),{ok:!0}}}function V(l){return typeof l=="string"&&l.length>0&&l.length<=64&&z.test(l)}function _e(l){const e=l.name;if(typeof e!="string"||!z.test(e))return`plugin.json: name \u975E\u6CD5\uFF08\u987B\u4E3A kebab-case\uFF09: ${String(e)}`;if(e.length>64)return"plugin.json: name \u8FC7\u957F\uFF08\u226464\uFF09";for(const t of De)if(e===t.replace(/\.$/,"")||e.startsWith(t))return`plugin.json: name \u4F7F\u7528\u4E86\u4FDD\u7559\u524D\u7F00 ${t}`;return Ne.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(!P(l))return"\u5DE5\u5177\u6761\u76EE\u987B\u4E3A\u5BF9\u8C61";const e=l.name;if(typeof e!="string"||!be.test(e))return`\u5DE5\u5177 name \u975E\u6CD5: ${String(e)}`;if(typeof l.description!="string"||!l.description.trim())return`\u5DE5\u5177 ${e} \u7F3A\u5C11 description`;const t=l.handler;if(!P(t))return`\u5DE5\u5177 ${e} \u7F3A\u5C11 handler`;const n=t.type;return n!=="process"&&n!=="module"&&n!=="mcp"?`\u5DE5\u5177 ${e} handler.type \u975E\u6CD5: ${String(n)}`:n==="process"&&typeof t.command!="string"?`\u5DE5\u5177 ${e} \u7684 process handler \u7F3A\u5C11 command`:n==="module"&&typeof t.module!="string"?`\u5DE5\u5177 ${e} \u7684 module handler \u7F3A\u5C11 module`:l.inputSchema!==void 0&&!P(l.inputSchema)?`\u5DE5\u5177 ${e} inputSchema \u987B\u4E3A\u5BF9\u8C61`:null}function je(l){if(!P(l))return"\u76D1\u542C\u5668\u6761\u76EE\u987B\u4E3A\u5BF9\u8C61";if(typeof l.event!="string"||!l.event.trim())return"\u76D1\u542C\u5668\u7F3A\u5C11 event";const e=l.transport;if(!P(e))return`\u76D1\u542C\u5668 ${String(l.event)} \u7F3A\u5C11 transport`;const t=e.type;if(t!=="command-stream"&&t!=="poll-command"&&t!=="http-callback")return`\u76D1\u542C\u5668 ${String(l.event)} transport.type \u975E\u6CD5: ${String(t)}`;if((t==="command-stream"||t==="poll-command")&&typeof e.command!="string")return`\u76D1\u542C\u5668 ${String(l.event)} \u7684 ${t} transport \u7F3A\u5C11 command`;const n=l.delivery;return n!==void 0&&n!=="poll"&&n!=="force"&&n!=="wake"?`\u76D1\u542C\u5668 ${String(l.event)} delivery \u975E\u6CD5: ${String(n)}`:null}function Y(l,e){return l.trim().split(/\s+/).map(t=>{const n=/^\{\{(.+)\}\}$/.exec(t);if(n){const r=I(e,n[1].trim());return r==null?"":typeof r=="string"?r:JSON.stringify(r)}return t.replace(/\{\{(.+?)\}\}/g,(r,i)=>{const s=I(e,i.trim());return s==null?"":typeof s=="string"?s:JSON.stringify(s)})}).filter(t=>t!=="")}function He(l,e){return l.replace(/\{\{(.+?)\}\}/g,(t,n)=>{let r=I(e,n.trim());return r===void 0&&!n.trim().startsWith("params.")&&(r=I(e,`data.${n.trim()}`)),r==null?"":typeof r=="string"?r:JSON.stringify(r)})}function Ue(l){try{return JSON.stringify(l)??"null"}catch{return"(\u4E0D\u53EF\u5E8F\u5217\u5316\u7684\u4E8B\u4EF6\u8D1F\u8F7D)"}}const Je=new Me;he("plugins",()=>Je.deployedDefaultEnabled());const tt=()=>ye("plugins");export{X as BUILTIN_PLUGIN_DESCRIPTION,Q as BUILTIN_PLUGIN_MANAGE_DESC,$ as BUILTIN_PLUGIN_NAME,Me as PluginManager,Ee as getBuiltinCommandDir,V as isValidPluginName,Je as pluginManager,tt as reconcilePluginsDefaultsFromDeployed,Y as renderCommandArgv,B as validateAgainstSchema,_e as validateManifest};
|
|
10
16
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{execFile as g}from"node:child_process";import{readFile as d,readlink as T}from"node:fs/promises";import
|
|
1
|
+
import{execFile as g}from"node:child_process";import{readFile as d,readlink as T}from"node:fs/promises";import C from"node:os";import{promisify as F}from"node:util";const l=F(g);import{createLogger as O}from"../utils/logger.js";const k=O("process-detail"),m=9e3,S=100,I=50,f="\u8FDB\u7A0B\u4E0D\u5B58\u5728\u3001\u5DF2\u9000\u51FA\u6216\u5F53\u524D\u7528\u6237\u65E0\u6743\u67E5\u770B";function v(n){const t=new Map;for(const c of n.split(/\r?\n/)){const a=c.indexOf(":");a<=0||t.set(c.slice(0,a).trim(),c.slice(a+1).trim())}const e=B(t.get("VmSize")),s=B(t.get("VmRSS")),r={},i=t.get("Name"),o=t.get("State"),u=Number(t.get("PPid")),p=Number(t.get("Threads"));return i&&(r.name=i),o&&(r.status=o.split(/\s+/)[0]),Number.isFinite(u)&&(r.ppid=u),Number.isFinite(p)&&(r.threads=p),e!==null&&(r.virtualBytes=e*1024),s!==null&&(r.rssBytes=s*1024),r}function B(n){if(!n)return null;const t=n.match(/^(\d+)\s*kB$/);if(!t)return null;const e=Number(t[1]);return Number.isFinite(e)?e:null}function L(n){const t=Number(n.trim().split(/\s+/)[0]);return Number.isFinite(t)?t:null}function D(n){const t=n.lastIndexOf(")");if(t<0)return null;const e=n.slice(t+1).trim().split(/\s+/),s=Number(e[11]),r=Number(e[12]),i=Number(e[19]);return!Number.isFinite(s)||!Number.isFinite(r)||!Number.isFinite(i)?null:{userTicks:s,systemTicks:r,startTicks:i}}function w(n){const t=n.trim();if(!t||!/^\d/.test(t))return null;const[e,s]=t.includes("-")?t.split("-",2):[void 0,t],r=s.split(":").map(Number);if(r.some(o=>!Number.isFinite(o)))return null;let i=0;for(const o of r)i=i*60+o;if(e!==void 0){if(!/^\d+$/.test(e))return null;i+=Number(e)*86400}return i}function E(n){const[t,e]=n.trim().split("."),s=w(t);return s===null?null:s+(e&&+`0.${e}`||0)}function M(n){const t=n.trim().split(/\s+/);if(t.length<8)return null;const e=t.slice(7).join(" ");if(e.includes("(LISTEN)"))return null;const s=e.match(/\(([A-Z ]+)\)$/),r=e.replace(/\s*\([A-Z ]+\)$/,""),i=r.includes("->")?r.split("->")[1]:r;return i?{remote:i,state:s?s[1]:void 0}:null}function R(n,t){const e=[];for(const s of n.split(/\r?\n/).slice(1)){if(!s.trim()||!s.includes(`pid=${t}`))continue;const r=s.trim().split(/\s+/);if(r[0]==="LISTEN")continue;const i=r[4]||"";i&&e.push({remote:i})}return e}function U(n){const t=[];for(const e of n.split(/\r?\n/).slice(1)){const s=M(e);s&&t.push(s)}return t}function _(n){const t=n.trim();return t?JSON.parse(t):null}async function W(n){let t;try{t=await d(`/proc/${n}/status`,"utf8")}catch{return{ok:!0,pid:n,unsupported:f}}const e=v(t),[s,r,i]=await Promise.all([d(`/proc/${n}/stat`,"utf8").catch(()=>""),d(`/proc/${n}/cmdline`,"utf8").catch(()=>""),d("/proc/uptime","utf8").catch(()=>"")]),o=s?D(s):null,u=i?L(i):null,[p,c,a,$]=await Promise.all([T(`/proc/${n}/exe`).catch(()=>""),d(`/proc/${n}/io`,"utf8").catch(()=>""),l("ps",["-o","user=","-p",String(n)],{encoding:"utf8",timeout:m}).then(N=>N.stdout.trim()).catch(()=>""),l("ss",["-tupn"],{encoding:"utf8",timeout:m}).then(N=>N.stdout).catch(()=>"")]),h=c?j(c):null,P=A(r)||e.name,x=o&&u!==null?Math.max(0,Math.round(u-o.startTicks/S)):void 0;return{ok:!0,pid:n,name:e.name,command:P||void 0,exePath:p||void 0,user:a||void 0,ppid:e.ppid,status:e.status,threads:e.threads,elapsedSeconds:x,cpuUserSeconds:o?y(o.userTicks/S):void 0,cpuSystemSeconds:o?y(o.systemTicks/S):void 0,virtualBytes:e.virtualBytes,rssBytes:e.rssBytes,ioReadBytes:h?.readBytes,ioWriteBytes:h?.writeBytes,connections:$?b(R($,n)):void 0}}function A(n){const t=n.replace(/\0+$/,"");return t?t.split("\0").filter(Boolean).join(" "):""}function j(n){let t,e;for(const s of n.split(/\r?\n/)){const[r,i]=s.split(":");if(!r||i===void 0)continue;const o=Number(i.trim());Number.isFinite(o)&&(r.trim()==="read_bytes"?t=o:r.trim()==="write_bytes"&&(e=o))}return{readBytes:t??0,writeBytes:e??0}}function G(n){const t=n.trim().match(/^(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+([\s\S]+)$/);if(!t)return null;const e=Number(t[2]),s=Number(t[5])*1024,r=Number(t[6])*1024,i=w(t[7]),o=E(t[8]),u={user:t[3],status:t[4],command:t[9].trim()};return Number.isFinite(e)&&(u.ppid=e),Number.isFinite(s)&&(u.rssBytes=s),Number.isFinite(r)&&(u.virtualBytes=r),i!==null&&(u.elapsedSeconds=i),o!==null&&(u.cpuTotalSeconds=y(o)),u}async function K(n){const{stdout:t}=await l("ps",["-ww","-p",String(n),"-o","pid=,ppid=,user=,state=,rss=,vsz=,etime=,cputime=,command="],{encoding:"utf8",timeout:m}),e=t.split(/\r?\n/).find(i=>i.trim()),s=e?G(e):null;if(!s)return{ok:!0,pid:n,unsupported:f};const r=await l("lsof",["-n","-P","-i","TCP","-a","-p",String(n),"+c0"],{encoding:"utf8",timeout:m}).then(i=>i.stdout).catch(()=>"");return{ok:!0,pid:n,user:s.user,ppid:s.ppid,status:s.status,command:s.command||void 0,elapsedSeconds:s.elapsedSeconds,cpuTotalSeconds:s.cpuTotalSeconds,virtualBytes:s.virtualBytes,rssBytes:s.rssBytes,connections:r?b(U(r)):void 0}}function z(n){return`
|
|
2
2
|
$ErrorActionPreference = 'SilentlyContinue'
|
|
3
3
|
$proc = Get-CimInstance Win32_Process -Filter 'ProcessId=${n}'
|
|
4
4
|
if (-not $proc) { Write-Output 'null'; exit }
|
|
@@ -28,5 +28,5 @@ $row = [pscustomobject]@{
|
|
|
28
28
|
connections = $conns
|
|
29
29
|
}
|
|
30
30
|
ConvertTo-Json -InputObject $row -Compress -Depth 3
|
|
31
|
-
`.trim()}async function V(n){const{stdout:t}=await l("powershell",["-NoProfile","-NonInteractive","-Command",z(n)],{encoding:"utf8",timeout:m,windowsHide:!0}),e=_(t);return!e||!Number.isFinite(Number(e.pid))?{ok:!0,pid:n,unsupported:f}:{ok:!0,pid:n,name:e.name||void 0,command:e.command||void 0,exePath:e.exePath||void 0,user:e.user||void 0,ppid:Number.isFinite(Number(e.ppid))?Number(e.ppid):void 0,threads:Number.isFinite(Number(e.threads))?Number(e.threads):void 0,elapsedSeconds:Number.isFinite(Number(e.elapsedSeconds))?Number(e.elapsedSeconds):void 0,cpuUserSeconds:Number.isFinite(Number(e.cpuUserSeconds))?Number(e.cpuUserSeconds):void 0,cpuSystemSeconds:Number.isFinite(Number(e.cpuSystemSeconds))?Number(e.cpuSystemSeconds):void 0,virtualBytes:Number.isFinite(Number(e.virtualBytes))?Number(e.virtualBytes):void 0,rssBytes:Number.isFinite(Number(e.rssBytes))?Number(e.rssBytes):void 0,ioReadBytes:Number.isFinite(Number(e.ioReadBytes))?Number(e.ioReadBytes):void 0,ioWriteBytes:Number.isFinite(Number(e.ioWriteBytes))?Number(e.ioWriteBytes):void 0,connections:Array.isArray(e.connections)?b(e.connections.filter(s=>s&&s.remote).map(s=>({remote:String(s.remote),state:s.state?String(s.state):void 0}))):void 0}}function b(n){return n.slice(0,I)}function y(n){return Math.round(n*100)/100}async function Q(n){const t=
|
|
31
|
+
`.trim()}async function V(n){const{stdout:t}=await l("powershell",["-NoProfile","-NonInteractive","-Command",z(n)],{encoding:"utf8",timeout:m,windowsHide:!0}),e=_(t);return!e||!Number.isFinite(Number(e.pid))?{ok:!0,pid:n,unsupported:f}:{ok:!0,pid:n,name:e.name||void 0,command:e.command||void 0,exePath:e.exePath||void 0,user:e.user||void 0,ppid:Number.isFinite(Number(e.ppid))?Number(e.ppid):void 0,threads:Number.isFinite(Number(e.threads))?Number(e.threads):void 0,elapsedSeconds:Number.isFinite(Number(e.elapsedSeconds))?Number(e.elapsedSeconds):void 0,cpuUserSeconds:Number.isFinite(Number(e.cpuUserSeconds))?Number(e.cpuUserSeconds):void 0,cpuSystemSeconds:Number.isFinite(Number(e.cpuSystemSeconds))?Number(e.cpuSystemSeconds):void 0,virtualBytes:Number.isFinite(Number(e.virtualBytes))?Number(e.virtualBytes):void 0,rssBytes:Number.isFinite(Number(e.rssBytes))?Number(e.rssBytes):void 0,ioReadBytes:Number.isFinite(Number(e.ioReadBytes))?Number(e.ioReadBytes):void 0,ioWriteBytes:Number.isFinite(Number(e.ioWriteBytes))?Number(e.ioWriteBytes):void 0,connections:Array.isArray(e.connections)?b(e.connections.filter(s=>s&&s.remote).map(s=>({remote:String(s.remote),state:s.state?String(s.state):void 0}))):void 0}}function b(n){return n.slice(0,I)}function y(n){return Math.round(n*100)/100}async function Q(n){const t=C.platform();try{return t==="win32"?await V(n):t==="darwin"?await K(n):await W(n)}catch(e){return k.debug("Failed to collect process detail:",e),{ok:!0,pid:n,unsupported:f}}}export{Q as collectProcessDetail,G as parseDarwinPsDetailLine,_ as parseJsonObject,A as parseLinuxCmdline,j as parseLinuxIoBytes,D as parseLinuxStatTimes,M as parseLsofConnectionLine,U as parseLsofConnectionsForPid,v as parseProcStatus,L as parseProcUptime,E as parsePsCpuTimeSeconds,w as parsePsEtimeSeconds,R as parseSsConnectionsForPid};
|
|
32
32
|
|