aws-runtime-bridge 1.9.96 → 1.9.100
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 +7 -1
- package/dist/adapter/AcodeSdkAdapter.js +5 -5
- package/dist/adapter/ClaudeSdkAdapter.d.ts +4 -0
- package/dist/adapter/ClaudeSdkAdapter.js +2 -2
- package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
- package/dist/adapter/CodexSdkAdapter.js +3 -3
- package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/OpencodeSdkAdapter.js +2 -2
- package/dist/adapter/idle-poll-loop.d.ts +4 -1
- package/dist/adapter/idle-poll-loop.js +1 -1
- package/dist/adapter/types.d.ts +4 -2
- package/dist/browser/browser-pool.d.ts +73 -0
- package/dist/browser/browser-pool.js +2 -0
- package/dist/browser/browser-profile-store.d.ts +28 -0
- package/dist/browser/browser-profile-store.js +2 -0
- package/dist/browser/built-in-browser-tools.d.ts +27 -0
- package/dist/browser/built-in-browser-tools.js +2 -0
- package/dist/browser/element-locator.d.ts +24 -0
- package/dist/browser/element-locator.js +2 -0
- package/dist/browser/element-picker.d.ts +17 -0
- package/dist/browser/element-picker.js +2 -0
- package/dist/browser/input-dispatcher.d.ts +34 -0
- package/dist/browser/input-dispatcher.js +2 -0
- package/dist/browser/listener-store.d.ts +32 -0
- package/dist/browser/listener-store.js +2 -0
- package/dist/browser/page-listener-manager.d.ts +106 -0
- package/dist/browser/page-listener-manager.js +307 -0
- package/dist/browser/page-listener-types.d.ts +90 -0
- package/dist/browser/page-listener-types.js +1 -0
- package/dist/browser/screencast-manager.d.ts +42 -0
- package/dist/browser/screencast-manager.js +2 -0
- package/dist/browser/snapshot-serializer.d.ts +15 -0
- package/dist/browser/snapshot-serializer.js +5 -0
- package/dist/browser/ssrf-guard.d.ts +15 -0
- package/dist/browser/ssrf-guard.js +2 -0
- package/dist/browser/stealth.d.ts +7 -0
- package/dist/browser/stealth.js +173 -0
- package/dist/browser/step-archive.d.ts +52 -0
- package/dist/browser/step-archive.js +2 -0
- package/dist/browser/types.d.ts +192 -0
- package/dist/browser/types.js +2 -0
- package/dist/browser/ws-server.d.ts +67 -0
- package/dist/browser/ws-server.js +2 -0
- package/dist/config.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/middleware/auth.d.ts +2 -0
- package/dist/middleware/auth.js +1 -1
- package/dist/remote-desktop/computer-control.d.ts +30 -0
- package/dist/remote-desktop/computer-control.js +2 -0
- package/dist/remote-desktop/coords.d.ts +13 -0
- package/dist/remote-desktop/coords.js +2 -0
- package/dist/remote-desktop/frame-backpressure.d.ts +7 -0
- package/dist/remote-desktop/frame-backpressure.js +2 -0
- package/dist/remote-desktop/index.d.ts +7 -0
- package/dist/remote-desktop/index.js +4 -0
- package/dist/remote-desktop/input-backends/interface.d.ts +17 -0
- package/dist/remote-desktop/input-backends/interface.js +1 -0
- package/dist/remote-desktop/input-backends/key-map.d.ts +2 -0
- package/dist/remote-desktop/input-backends/key-map.js +2 -0
- package/dist/remote-desktop/input-dispatcher.d.ts +11 -0
- package/dist/remote-desktop/input-dispatcher.js +2 -0
- package/dist/remote-desktop/permission-manager.d.ts +7 -0
- package/dist/remote-desktop/permission-manager.js +2 -0
- package/dist/remote-desktop/screen-capture.d.ts +27 -0
- package/dist/remote-desktop/screen-capture.js +2 -0
- package/dist/remote-desktop/session-manager.d.ts +59 -0
- package/dist/remote-desktop/session-manager.js +2 -0
- package/dist/remote-desktop/system-backend.d.ts +65 -0
- package/dist/remote-desktop/system-backend.js +5 -0
- package/dist/remote-desktop/types.d.ts +68 -0
- package/dist/remote-desktop/types.js +1 -0
- package/dist/remote-desktop/ui-automation.d.ts +48 -0
- package/dist/remote-desktop/ui-automation.js +31 -0
- package/dist/remote-desktop/win32-api.d.ts +29 -0
- package/dist/remote-desktop/win32-api.js +2 -0
- package/dist/routes/background-tasks.d.ts +2 -0
- package/dist/routes/background-tasks.js +2 -0
- package/dist/routes/browser-listeners.d.ts +2 -0
- package/dist/routes/browser-listeners.js +2 -0
- package/dist/routes/browser-sessions.d.ts +2 -0
- package/dist/routes/browser-sessions.js +2 -0
- package/dist/routes/instance.js +2 -2
- package/dist/routes/pty.js +3 -3
- package/dist/routes/terminal.js +30 -30
- package/dist/services/agent-pty-manager.d.ts +22 -0
- package/dist/services/agent-pty-manager.js +5 -0
- package/dist/services/browser-session-manager.d.ts +55 -0
- package/dist/services/browser-session-manager.js +12 -0
- package/dist/services/cli-commands.d.ts +4 -0
- package/dist/services/cli-commands.js +5 -5
- package/dist/services/workspace-files.js +1 -1
- package/package/acode/dist/await-complete-tool.d.ts +17 -0
- package/package/acode/dist/await-complete-tool.js +21 -0
- package/package/acode/dist/background-command-manager.d.ts +148 -0
- package/package/acode/dist/background-command-manager.js +8 -0
- package/package/acode/dist/background-command-store.d.ts +46 -0
- package/package/acode/dist/background-command-store.js +2 -0
- package/package/acode/dist/background-command-tools.d.ts +5 -0
- package/package/acode/dist/background-command-tools.js +18 -0
- package/package/acode/dist/background-output-ringbuffer.d.ts +23 -0
- package/package/acode/dist/background-output-ringbuffer.js +3 -0
- package/package/acode/dist/built-in-file-tools.d.ts +8 -1
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/compaction.js +6 -6
- package/package/acode/dist/index.d.ts +1 -0
- package/package/acode/dist/index.js +1 -1
- package/package/acode/dist/runtime.d.ts +6 -0
- package/package/acode/dist/runtime.js +27 -27
- package/package/acode/dist/sub-agent-tools.d.ts +0 -1
- package/package/acode/dist/sub-agent-tools.js +11 -28
- package/package/acode/dist/terminal-tool.d.ts +7 -0
- package/package/acode/dist/terminal-tool.js +2 -0
- package/package/acode/dist/terminal-types.d.ts +38 -0
- package/package/acode/dist/terminal-types.js +1 -0
- package/package/acode/dist/types.d.ts +10 -1
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +3 -1
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/logger.js +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +8 -0
- package/package/aws-client-agent-mcp/dist/mcp-server.js +30 -19
- package/package/aws-client-agent-mcp/dist/types.d.ts +25 -0
- package/package.json +6 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{spawnSync as
|
|
1
|
+
import{spawnSync as f}from"node:child_process";import{createInterface as X}from"node:readline/promises";import{existsSync as g,mkdirSync as T,readFileSync as Z,rmSync as ee,unlinkSync as F,writeFileSync as G}from"node:fs";import c from"node:path";import v from"node:os";import{fileURLToPath as H}from"node:url";import{configureStartupConfig as re,printConfigExampleCommand as te}from"./startup-config-wizard.js";import{createWindowsServiceManager as ne,isNodeWindowsAvailable as se}from"./windows-service-manager.js";const h="awsb.service",I=`/etc/systemd/system/${h}`,j="awsb",l=`${j}.exe`,q=c.join(v.homedir(),".aws-bridge","log"),B=c.join(q,"awsb.out.log"),N="com.agentsworkstudio.awsb",D=c.join(v.homedir(),"Library","LaunchAgents",`${N}.plist`),ie=c.join(v.homedir(),".aws-bridge","log"),L=c.join(ie,"awsb.out.log");function ae(){const e=H(import.meta.url);return c.resolve(c.dirname(e),"..","..")}function ue(e=ae()){const r=c.join(e,"package.json");return JSON.parse(Z(r,"utf-8")).version||"unknown"}function k(e,r){const t=f(e,r,{shell:process.platform==="win32",stdio:"inherit"});return{status:t.status,error:t.error}}function de(){try{const e=f("npm",["root","-g"],{shell:process.platform==="win32",encoding:"utf-8",stdio:["ignore","pipe","ignore"]});if(e.status===0&&e.stdout){const r=e.stdout.trim();if(r)return r}}catch{}return null}function oe(e){try{const r=new SharedArrayBuffer(4);Atomics.wait(new Int32Array(r),0,0,e)}catch{const r=Date.now()+e;for(;Date.now()<r;);}}function A(e){if(process.platform!=="win32")return null;try{const r=f("sc.exe",["query",e],{shell:!0,encoding:"utf-8",stdio:["ignore","pipe","ignore"]});if(r.status!==0||!r.stdout)return null;const t=r.stdout.match(/STATE\s*:\s*\d+\s+(\S+)/);return t?t[1]:null}catch{return null}}function V(e,r,t=15e3,s=500){const i=Date.now()+t;for(;Date.now()<i;){const n=e(r);if(n===null||n==="STOPPED")return!0;oe(s)}return!1}function ce(e){process.stdout.write(`${e}
|
|
2
2
|
`)}function le(e){process.stderr.write(`${e}
|
|
3
|
-
`)}function me(e){return e==="-v"||e==="--version"||e==="version"}function fe(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function
|
|
4
|
-
`)}function P(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function he(e,r={}){const t=r.userHomeDir??v.homedir(),
|
|
5
|
-
`)}function
|
|
6
|
-
npm install -g aws-runtime-bridge`),{handled:!0,exitCode:1}}async function A(e){const r=e.windowsServiceManager;if(!r&&!ne())return ve(e.stderr);const t=e.windowsServiceLogPath||G,a=o.dirname(e.executablePath),i=v.homedir();try{await(r||te()).install({name:H,description:"awsb runtime bridge",script:e.executablePath,workingDirectory:a,env:[{name:"AWS_BRIDGE_SKIP_SETUP",value:"true"},{name:"AWS_RUNTIME_HOME_DIR",value:i}],logpath:B})}catch(s){const c=s instanceof Error?s:new Error(String(s));return e.stderr(`[runtime-bridge] \u5B89\u88C5 Windows \u670D\u52A1\u5931\u8D25: ${c.message}`),{handled:!0,exitCode:1}}const n=e.runCommand("sc.exe",["start",g]);return d(n)?(e.stdout(`[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u52A8\uFF08\u65E5\u5FD7: ${t}\uFF09\u3002`),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u542F\u52A8 Windows \u670D\u52A1\u5931\u8D25: ${n.error?.message??`\u9000\u51FA\u7801 ${n.status??"unknown"}`}`),{handled:!0,exitCode:n.status??1})}function Pe(e){const r=a=>e.runCommand("sc.exe",a);r(["stop",g]);const t=r(["delete",g]);return d(t)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u5378\u8F7D Windows \u670D\u52A1\u5931\u8D25: ${t.error?.message??`\u9000\u51FA\u7801 ${t.status??"unknown"}`}`),{handled:!0,exitCode:t.status??1})}async function ye(e){e.runCommand("sc.exe",["stop",g]);const r=e.queryWindowsServiceState||q;return ce(r,g)||e.stdout("[runtime-bridge] \u7B49\u5F85 Windows \u670D\u52A1\u505C\u6B62\u8D85\u65F6\uFF0C\u4ECD\u5C1D\u8BD5\u542F\u52A8\uFF08\u53EF\u80FD\u62A5 1056\uFF09\u3002"),Y(e,"\u91CD\u542F")}async function Ee(e){return Y(e,"\u542F\u52A8")}const $e=2,Re=1056;async function Y(e,r){const t=e.runCommand("sc.exe",["start",g]);if(d(t))return e.stdout(`[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2${r}\u3002`),{handled:!0,exitCode:0};if(t.status===Re)return e.stdout(`[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u5728\u8FD0\u884C\u4E2D\uFF08\u65E0\u9700${r}\uFF09\u3002`),{handled:!0,exitCode:0};if(t.status===$e){e.stdout("[runtime-bridge] \u68C0\u6D4B\u5230 Windows \u670D\u52A1\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E22\u5931\uFF08winsw.exe\uFF09\uFF0C\u6B63\u5728\u91CD\u5EFA..."),e.runCommand("sc.exe",["delete",g]);try{const a=await A(e);return a.exitCode!==0&&e.stderr(`[runtime-bridge] ${r} Windows \u670D\u52A1\u5931\u8D25\u4E14\u81EA\u52A8\u91CD\u5EFA\u5931\u8D25\u3002\u8BF7\u624B\u52A8\u6267\u884C \`awsb service uninstall && awsb service install\` \u4FEE\u590D\u3002`),a}catch(a){const i=a instanceof Error?a:new Error(String(a));return e.stderr(`[runtime-bridge] ${r} Windows \u670D\u52A1\u5931\u8D25\u4E14\u81EA\u52A8\u91CD\u5EFA\u5F02\u5E38: ${i.message}\u3002\u8BF7\u624B\u52A8\u6267\u884C \`awsb service uninstall && awsb service install\` \u4FEE\u590D\u3002`),{handled:!0,exitCode:1}}}return e.stderr(`[runtime-bridge] ${r} Windows \u670D\u52A1\u5931\u8D25: ${t.error?.message??`\u9000\u51FA\u7801 ${t.status??"unknown"}`}`),{handled:!0,exitCode:t.status??1}}function We(e){const r=e.runCommand("sc.exe",["stop",g]);return d(r)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u505C\u6B62 Windows \u670D\u52A1\u5931\u8D25: ${r.error?.message??`\u9000\u51FA\u7801 ${r.status??"unknown"}`}`),{handled:!0,exitCode:r.status??1})}function _e(){return`gui/${process.getuid?.()??0}`}function W(e){return e.launchdDomainTarget||_e()}function _(e){return`${e}/${I}`}function D(e,r){return r.error?`[runtime-bridge] ${e}\u5931\u8D25: ${r.error.message}`:`[runtime-bridge] ${e}\u5931\u8D25\uFF0Claunchctl \u9000\u51FA\u7801: ${r.status??"unknown"}`}function De(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||k,t=e.launchdLogPath||U,a=he(e.executablePath,{userHomeDir:v.homedir(),logPath:t});try{T(o.dirname(r),{recursive:!0}),T(o.dirname(t),{recursive:!0}),F(r,a,{encoding:"utf-8",mode:420})}catch(s){const c=s instanceof Error?s:new Error(String(s));return e.stderr(`[runtime-bridge] \u5199\u5165 launchd plist \u5931\u8D25: ${c.message}`),{handled:!0,exitCode:1}}const i=W(e);e.runCommand("launchctl",["bootout",_(i)]);const n=e.runCommand("launchctl",["bootstrap",i,r]);return d(n)?(e.stdout(`[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u52A8\uFF08\u65E5\u5FD7: ${t}\uFF09\u3002`),{handled:!0,exitCode:0}):(e.stderr(D("\u5B89\u88C5 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1})}function ke(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||k,t=W(e),a=_(t),i=e.runCommand("launchctl",["bootout",a]);if(i.error)return e.stderr(D("\u5378\u8F7D awsb \u670D\u52A1",i)),{handled:!0,exitCode:1};if(m(r))try{O(r)}catch(n){const s=n instanceof Error?n:new Error(String(n));return e.stderr(`[runtime-bridge] \u5220\u9664 launchd plist \u5931\u8D25: ${s.message}`),{handled:!0,exitCode:1}}else e.stdout("[runtime-bridge] awsb launchd plist \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5220\u9664\u3002");return e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}}function pe(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||k;if(!m(r))return e.stderr("[runtime-bridge] awsb launchd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const t=W(e),a=_(t),i=e.runCommand("launchctl",["kickstart",a]);if(d(i))return e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0};const n=e.runCommand("launchctl",["bootstrap",t,r]);return d(n)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(D("\u542F\u52A8 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1})}function Te(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=W(e),t=e.runCommand("launchctl",["bootout",_(r)]);return d(t)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(D("\u505C\u6B62 awsb \u670D\u52A1",t)),{handled:!0,exitCode:t.status??1})}function Le(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||k;if(!m(r))return e.stderr("[runtime-bridge] awsb launchd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const t=W(e);e.runCommand("launchctl",["bootout",_(t)]);const a=e.runCommand("launchctl",["bootstrap",t,r]);return d(a)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u91CD\u542F\u3002"),{handled:!0,exitCode:0}):(e.stderr(D("\u91CD\u542F awsb \u670D\u52A1",a)),{handled:!0,exitCode:a.status??1})}async function Ie(e,r,t,a){const i=e[1];if(!i||i==="-h"||i==="--help"||i==="help")return K(t),{handled:!0,exitCode:i?0:1};const n={stdout:t,stderr:a,runCommand:r.runCommand||p,platform:r.platform||process.platform,serviceUnitPath:r.serviceUnitPath||L,executablePath:r.executablePath||V(),windowsServiceManager:r.windowsServiceManager,launchdPlistPath:r.launchdPlistPath,launchdLogPath:r.launchdLogPath,launchdDomainTarget:r.launchdDomainTarget,queryWindowsServiceState:r.queryWindowsServiceState||q};return n.platform!=="linux"&&n.platform!=="win32"&&n.platform!=="darwin"?(a("[runtime-bridge] service \u547D\u4EE4\u4EC5\u652F\u6301 Linux systemd\u3001Windows \u670D\u52A1\u4E0E macOS launchd \u73AF\u5883\u3002"),{handled:!0,exitCode:1}):i==="install"?n.platform==="win32"?await A(n):n.platform==="darwin"?De(n):we(n):i==="uninstall"?n.platform==="win32"?Pe(n):n.platform==="darwin"?ke(n):be(n):i==="restart"?n.platform==="win32"?ye(n):n.platform==="darwin"?Le(n):Ce(n):i==="start"?n.platform==="win32"?Ee(n):n.platform==="darwin"?pe(n):xe(n):i==="stop"?n.platform==="win32"?We(n):n.platform==="darwin"?Te(n):Se(n):(a(`[runtime-bridge] \u672A\u77E5 service \u5B50\u547D\u4EE4: ${i}`),K(t),{handled:!0,exitCode:1})}function J(e){return e?e.split(/\r?\n/).map(r=>r.trim()).filter(r=>/^\d+$/.test(r)).map(Number):[]}function Ue(e){try{if(e==="win32"){const t=S("powershell",["-NoProfile","-Command",`Get-CimInstance Win32_Process -Filter "Name='node.exe'" | Where-Object { $_.CommandLine -like '*aws-runtime-bridge*' -and $_.ProcessId -ne ${process.pid} } | ForEach-Object { $_.ProcessId }`],{encoding:"utf-8"});return J(t.stdout)}const r=S("pgrep",["-f","aws-runtime-bridge"],{encoding:"utf-8"});return J(r.stdout).filter(t=>t!==process.pid)}catch{return[]}}function Ae(e,r){if(r==="win32"){S("taskkill",["/PID",String(e),"/F","/T"],{stdio:"ignore"});return}S("kill",["-9",String(e)],{stdio:"ignore"})}function Ne(e){if(!process.stdin.isTTY)return Promise.resolve("n");const r=z({input:process.stdin,output:process.stdout});return r.question(e).finally(()=>r.close())}async function Me(e,r,t){const a=e.runCommand||p,i=e.platform||process.platform,n=e.findRunningBridgeProcesses||Ue,s=e.prompt||Ne,c=e.killBridgeProcess||Ae,u=e.globalModulePath||ue;r("[runtime-bridge] \u6B63\u5728\u66F4\u65B0 aws-runtime-bridge \u5230\u6700\u65B0\u7248\u672C...");const l=n(i).filter(C=>C!==process.pid);let b=!1;if(l.length>0){r(`[runtime-bridge] \u68C0\u6D4B\u5230 aws-runtime-bridge \u6B63\u5728\u8FD0\u884C (PID: ${l.join(", ")})\uFF0C\u66F4\u65B0\u65F6\u8FD9\u4E9B\u8FDB\u7A0B\u53EF\u80FD\u5360\u7528\u6587\u4EF6\u5BFC\u81F4\u8986\u76D6\u5931\u8D25\u3002`);const C=(await s("\u662F\u5426\u5173\u95ED\u4E0A\u8FF0\u8FDB\u7A0B\u4EE5\u7EE7\u7EED\u66F4\u65B0? (y/N) ")).trim().toLowerCase();if(C==="y"||C==="yes")for(const x of l)try{c(x,i),r(`[runtime-bridge] \u5DF2\u5173\u95ED\u8FDB\u7A0B PID: ${x}`)}catch(E){const Q=E instanceof Error?E:new Error(String(E));t(`[runtime-bridge] \u5173\u95ED\u8FDB\u7A0B PID ${x} \u5931\u8D25: ${Q.message}`)}else b=!0,r("[runtime-bridge] \u5DF2\u9009\u62E9\u4E0D\u5173\u95ED\u8FDB\u7A0B\uFF0C\u5C06\u4EE5 --force \u65B9\u5F0F\u5F3A\u5236\u5B89\u88C5\uFF08\u82E5\u6587\u4EF6\u4ECD\u88AB\u5360\u7528\u53EF\u80FD\u4F1A\u6709\u8B66\u544A\uFF09\u3002")}const N=u();if(N){const C=o.join(N,"aws-runtime-bridge");if(m(C)){r("[runtime-bridge] \u6E05\u7406\u65E7\u7248\u672C\u6B8B\u7559\u76EE\u5F55...");try{Z(C,{recursive:!0,force:!0})}catch(x){const E=x instanceof Error?x:new Error(String(x));t(`[runtime-bridge] \u6E05\u7406\u6B8B\u7559\u76EE\u5F55\u5931\u8D25\uFF08\u5C06\u5C1D\u8BD5\u7EE7\u7EED\u5B89\u88C5\uFF09: ${E.message}`)}}}const M=["install","-g","aws-runtime-bridge@latest","--omit=optional"];b&&M.push("--force");const y=a("npm",M);if(y.error)return t(`[runtime-bridge] \u66F4\u65B0\u5931\u8D25: ${y.error.message}`),{handled:!0,exitCode:1};if(y.status!==0)return t(`[runtime-bridge] \u66F4\u65B0\u5931\u8D25\uFF0Cnpm \u9000\u51FA\u7801: ${y.status??"unknown"}`),{handled:!0,exitCode:y.status??1};if(i==="win32"){const C=await Oe(e,r,t);if(C.exitCode!==0)return C}return r("[runtime-bridge] \u66F4\u65B0\u5B8C\u6210\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C awsb -v \u67E5\u770B\u5F53\u524D\u7248\u672C\u3002"),{handled:!0,exitCode:0}}async function Oe(e,r,t){const a=e.runCommand||p,i=a("sc.exe",["query",g]);if(!d(i))return{handled:!0,exitCode:0};r("[runtime-bridge] \u68C0\u6D4B\u5230 Windows \u670D\u52A1\u5DF2\u6CE8\u518C\uFF0C\u6B63\u5728\u91CD\u5EFA\u670D\u52A1\u6587\u4EF6\uFF08daemon/winsw.exe\uFF09..."),a("sc.exe",["stop",g]);const n=a("sc.exe",["delete",g]);d(n)||t(`[runtime-bridge] \u5220\u9664\u65E7 SCM \u8BB0\u5F55\u5931\u8D25: ${n.error?.message??`\u9000\u51FA\u7801 ${n.status??"unknown"}`}\uFF08\u5C1D\u8BD5\u7EE7\u7EED\u5B89\u88C5\uFF09`);const s={stdout:r,stderr:t,runCommand:a,platform:"win32",serviceUnitPath:e.serviceUnitPath||L,executablePath:e.executablePath||V(),windowsServiceManager:e.windowsServiceManager};try{return(await A(s)).exitCode!==0?(t("[runtime-bridge] \u91CD\u5EFA Windows \u670D\u52A1\u6587\u4EF6\u5931\u8D25\u3002\u5305\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u624B\u52A8\u6267\u884C `awsb service uninstall && awsb service install` \u4FEE\u590D\u670D\u52A1\u3002"),{handled:!0,exitCode:0}):(r("[runtime-bridge] Windows \u670D\u52A1\u6587\u4EF6\u5DF2\u91CD\u5EFA\u3002"),{handled:!0,exitCode:0})}catch(c){const u=c instanceof Error?c:new Error(String(c));return t(`[runtime-bridge] \u91CD\u5EFA Windows \u670D\u52A1\u6587\u4EF6\u5F02\u5E38: ${u.message}\u3002\u5305\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u624B\u52A8\u6267\u884C \`awsb service uninstall && awsb service install\` \u4FEE\u590D\u670D\u52A1\u3002`),{handled:!0,exitCode:0}}}function Fe(e,r,t){const i=(e.argv||process.argv.slice(2)).slice(1).some(u=>u==="--follow"||u==="-f"),n=e.platform||process.platform,s=e.runCommand||p,c=e.serviceUnitPath||L;if(n==="linux"){if(!m(c))return t("[runtime-bridge] awsb \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF08awsb service install\uFF09\uFF0C\u65E0\u65E5\u5FD7\u53EF\u67E5\u770B\u3002"),{handled:!0,exitCode:1};const u=["-u",f];i?u.push("-f"):u.push("-n","200","--no-pager");const l=s("journalctl",u);return l.error?(t(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${l.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:l.status??0}}if(n==="win32"){const u=e.windowsServiceLogPath||G;if(!m(u))return t(`[runtime-bridge] \u5C1A\u672A\u751F\u6210\u65E5\u5FD7\u6587\u4EF6: ${u}\u3002\u8BF7\u5148\u6267\u884C \`awsb service install\` \u5E76\u8FD0\u884C\u670D\u52A1\u3002`),{handled:!0,exitCode:1};const l=`Get-Content -Encoding UTF8 -Tail 200 "${u}"`+(i?" -Wait":""),b=s("powershell",["-NoProfile","-Command",l]);return b.error?(t(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${b.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:b.status??0}}if(n==="darwin"){const u=e.launchdLogPath||U;if(!m(u))return t(`[runtime-bridge] \u5C1A\u672A\u751F\u6210\u65E5\u5FD7\u6587\u4EF6: ${u}\u3002\u8BF7\u5148\u6267\u884C \`awsb service install\` \u5E76\u8FD0\u884C\u670D\u52A1\u3002`),{handled:!0,exitCode:1};const b=s("tail",i?["-f",u]:["-n","200",u]);return b.error?(t(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${b.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:b.status??0}}return t("[runtime-bridge] awsb log \u4EC5\u652F\u6301 Linux systemd\u3001Windows \u670D\u52A1\u4E0E macOS launchd \u73AF\u5883\u3002"),{handled:!0,exitCode:1}}async function Je(e={}){const r=e.argv||process.argv.slice(2),t=r[0],a=e.stdout||oe,i=e.stderr||le;if(me(t))return a(`aws-runtime-bridge ${se(e.packageRoot)}`),{handled:!0,exitCode:0};if(t==="update")return await Me(e,a,i);if(t==="config"){const n=r[1];if(n==="example"||n==="minimal"||n==="--minimal"||n==="-m")return{handled:!0,exitCode:await(e.configureExample||re)()==="created"?0:1};const c=await(e.configure||ee)();return{handled:!0,exitCode:c==="configured"||c==="created"?0:1}}return t==="service"?await Ie(r,e,a,i):t==="log"?Fe(e,a,i):{handled:!1,exitCode:0}}export{he as createLaunchdPlistContent,ge as createSystemdUnitContent,Je as handleCliCommand,se as readPackageVersion};
|
|
3
|
+
`)}function me(e){return e==="-v"||e==="--version"||e==="version"}function fe(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function K(){return process.argv[1]?c.resolve(process.argv[1]):H(import.meta.url)}function ge(e){return["[Unit]","Description=AgentsWorkStudio Runtime Bridge","After=network-online.target","Wants=network-online.target","","[Service]","Type=simple","Environment=AWS_BRIDGE_SKIP_SETUP=true",`ExecStart=${[process.execPath,e].map(t=>fe(t)).join(" ")}`,"Restart=on-failure","RestartSec=5s","","[Install]","WantedBy=multi-user.target",""].join(`
|
|
4
|
+
`)}function P(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function he(e,r={}){const t=r.userHomeDir??v.homedir(),s=r.logPath??L,i=s.replace(/\.out\.log$/,".err.log");return['<?xml version="1.0" encoding="UTF-8"?>','<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">','<plist version="1.0">',"<dict>"," <key>Label</key>",` <string>${P(N)}</string>`," <key>ProgramArguments</key>"," <array>",` <string>${P(process.execPath)}</string>`,` <string>${P(e)}</string>`," </array>"," <key>EnvironmentVariables</key>"," <dict>"," <key>AWS_BRIDGE_SKIP_SETUP</key>"," <string>true</string>"," <key>AWS_RUNTIME_HOME_DIR</key>",` <string>${P(t)}</string>`," </dict>"," <key>RunAtLoad</key>"," <true/>"," <key>KeepAlive</key>"," <true/>"," <key>StandardOutPath</key>",` <string>${P(s)}</string>`," <key>StandardErrorPath</key>",` <string>${P(i)}</string>`,"</dict>","</plist>",""].join(`
|
|
5
|
+
`)}function w(e,r){return e("systemctl",r)}function b(e,r){return r.error?`[runtime-bridge] ${e}\u5931\u8D25: ${r.error.message}`:`[runtime-bridge] ${e}\u5931\u8D25\uFF0Csystemctl \u9000\u51FA\u7801: ${r.status??"unknown"}`}function d(e){return!e.error&&e.status===0}function $(e,r){return e==="linux"?!0:(r("[runtime-bridge] service \u547D\u4EE4\u4EC5\u652F\u6301 Linux systemd \u73AF\u5883\u3002"),!1)}function R(e,r){return e==="darwin"?!0:(r("[runtime-bridge] service \u547D\u4EE4\u4EC5\u652F\u6301 macOS launchd \u73AF\u5883\u3002"),!1)}function Y(e){e("Usage: awsb service <install|uninstall|start|stop|restart>")}function we(e){if(!$(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=ge(e.executablePath);try{T(c.dirname(e.serviceUnitPath),{recursive:!0}),G(e.serviceUnitPath,r,{encoding:"utf-8",mode:420})}catch(n){const a=n instanceof Error?n:new Error(String(n));return e.stderr(`[runtime-bridge] \u5199\u5165 systemd unit \u5931\u8D25: ${a.message}`),{handled:!0,exitCode:1}}const t=w(e.runCommand,["daemon-reload"]);if(!d(t))return e.stderr(b("\u91CD\u8F7D systemd",t)),{handled:!0,exitCode:t.status??1};const s=w(e.runCommand,["enable",h]);if(!d(s))return e.stderr(b("\u542F\u7528 awsb \u5F00\u673A\u81EA\u542F",s)),{handled:!0,exitCode:s.status??1};const i=w(e.runCommand,["is-active","--quiet",h]);if(i.error)return e.stderr(b("\u68C0\u67E5 awsb \u670D\u52A1\u72B6\u6001",i)),{handled:!0,exitCode:1};if(i.status!==0){const n=w(e.runCommand,["start",h]);return d(n)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u5B89\u88C5\u3001\u5DF2\u542F\u7528\u5F00\u673A\u81EA\u542F\u5E76\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(b("\u542F\u52A8 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1})}return e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u7528\u5F00\u673A\u81EA\u542F\uFF1B\u670D\u52A1\u5DF2\u5728\u8FD0\u884C\u3002"),{handled:!0,exitCode:0}}function be(e){if(!$(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=g(e.serviceUnitPath),t=w(e.runCommand,["is-active","--quiet",h]);if(t.error)return e.stderr(b("\u68C0\u67E5 awsb \u670D\u52A1\u72B6\u6001",t)),{handled:!0,exitCode:1};if(t.status===0){const n=w(e.runCommand,["stop",h]);if(!d(n))return e.stderr(b("\u505C\u6B62 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1}}const s=w(e.runCommand,["disable",h]);if(s.error||s.status!==0&&r)return e.stderr(b("\u7981\u7528 awsb \u5F00\u673A\u81EA\u542F",s)),{handled:!0,exitCode:s.status??1};if(r)try{F(e.serviceUnitPath)}catch(n){const a=n instanceof Error?n:new Error(String(n));return e.stderr(`[runtime-bridge] \u5220\u9664 systemd unit \u5931\u8D25: ${a.message}`),{handled:!0,exitCode:1}}else e.stdout("[runtime-bridge] awsb systemd unit \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5220\u9664\u3002");const i=w(e.runCommand,["daemon-reload"]);return d(i)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}):(e.stderr(b("\u91CD\u8F7D systemd",i)),{handled:!0,exitCode:i.status??1})}function Ce(e){if(!$(e.platform,e.stderr))return{handled:!0,exitCode:1};if(!g(e.serviceUnitPath))return e.stderr("[runtime-bridge] awsb systemd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const r=w(e.runCommand,["restart",h]);return d(r)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u91CD\u542F\u3002"),{handled:!0,exitCode:0}):(e.stderr(b("\u91CD\u542F awsb \u670D\u52A1",r)),{handled:!0,exitCode:r.status??1})}function xe(e){if(!$(e.platform,e.stderr))return{handled:!0,exitCode:1};if(!g(e.serviceUnitPath))return e.stderr("[runtime-bridge] awsb systemd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const r=w(e.runCommand,["start",h]);return d(r)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(b("\u542F\u52A8 awsb \u670D\u52A1",r)),{handled:!0,exitCode:r.status??1})}function Se(e){if(!$(e.platform,e.stderr))return{handled:!0,exitCode:1};if(!g(e.serviceUnitPath))return e.stderr("[runtime-bridge] awsb systemd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const r=w(e.runCommand,["stop",h]);return d(r)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(b("\u505C\u6B62 awsb \u670D\u52A1",r)),{handled:!0,exitCode:r.status??1})}function ve(e){return e(`[runtime-bridge] \u672A\u68C0\u6D4B\u5230 node-windows \u6A21\u5757\u3002\u8BF7\u91CD\u65B0\u5B89\u88C5 aws-runtime-bridge\uFF1A
|
|
6
|
+
npm install -g aws-runtime-bridge`),{handled:!0,exitCode:1}}async function U(e){const r=e.windowsServiceManager;if(!r&&!se())return ve(e.stderr);const t=e.windowsServiceLogPath||B,s=c.dirname(e.executablePath),i=v.homedir();try{await(r||ne()).install({name:j,description:"awsb runtime bridge",script:e.executablePath,workingDirectory:s,env:[{name:"AWS_BRIDGE_SKIP_SETUP",value:"true"},{name:"AWS_RUNTIME_HOME_DIR",value:i}],logpath:q})}catch(a){const o=a instanceof Error?a:new Error(String(a));return e.stderr(`[runtime-bridge] \u5B89\u88C5 Windows \u670D\u52A1\u5931\u8D25: ${o.message}`),{handled:!0,exitCode:1}}const n=e.runCommand("sc.exe",["start",l]);return d(n)?(e.stdout(`[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u52A8\uFF08\u65E5\u5FD7: ${t}\uFF09\u3002`),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u542F\u52A8 Windows \u670D\u52A1\u5931\u8D25: ${n.error?.message??`\u9000\u51FA\u7801 ${n.status??"unknown"}`}`),{handled:!0,exitCode:n.status??1})}function Pe(e){const r=s=>e.runCommand("sc.exe",s);r(["stop",l]);const t=r(["delete",l]);return d(t)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u5378\u8F7D Windows \u670D\u52A1\u5931\u8D25: ${t.error?.message??`\u9000\u51FA\u7801 ${t.status??"unknown"}`}`),{handled:!0,exitCode:t.status??1})}async function ye(e){e.runCommand("sc.exe",["stop",l]);const r=e.queryWindowsServiceState||A;return V(r,l)||e.stdout("[runtime-bridge] \u7B49\u5F85 Windows \u670D\u52A1\u505C\u6B62\u8D85\u65F6\uFF0C\u4ECD\u5C1D\u8BD5\u542F\u52A8\uFF08\u53EF\u80FD\u62A5 1056\uFF09\u3002"),J(e,"\u91CD\u542F")}async function Ee(e){return J(e,"\u542F\u52A8")}const $e=2,Re=1056;async function J(e,r){const t=e.runCommand("sc.exe",["start",l]);if(d(t))return e.stdout(`[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2${r}\u3002`),{handled:!0,exitCode:0};if(t.status===Re)return e.stdout(`[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u5728\u8FD0\u884C\u4E2D\uFF08\u65E0\u9700${r}\uFF09\u3002`),{handled:!0,exitCode:0};if(t.status===$e){e.stdout("[runtime-bridge] \u68C0\u6D4B\u5230 Windows \u670D\u52A1\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E22\u5931\uFF08winsw.exe\uFF09\uFF0C\u6B63\u5728\u91CD\u5EFA..."),e.runCommand("sc.exe",["delete",l]);try{const s=await U(e);return s.exitCode!==0&&e.stderr(`[runtime-bridge] ${r} Windows \u670D\u52A1\u5931\u8D25\u4E14\u81EA\u52A8\u91CD\u5EFA\u5931\u8D25\u3002\u8BF7\u624B\u52A8\u6267\u884C \`awsb service uninstall && awsb service install\` \u4FEE\u590D\u3002`),s}catch(s){const i=s instanceof Error?s:new Error(String(s));return e.stderr(`[runtime-bridge] ${r} Windows \u670D\u52A1\u5931\u8D25\u4E14\u81EA\u52A8\u91CD\u5EFA\u5F02\u5E38: ${i.message}\u3002\u8BF7\u624B\u52A8\u6267\u884C \`awsb service uninstall && awsb service install\` \u4FEE\u590D\u3002`),{handled:!0,exitCode:1}}}return e.stderr(`[runtime-bridge] ${r} Windows \u670D\u52A1\u5931\u8D25: ${t.error?.message??`\u9000\u51FA\u7801 ${t.status??"unknown"}`}`),{handled:!0,exitCode:t.status??1}}function We(e){const r=e.runCommand("sc.exe",["stop",l]);return d(r)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u505C\u6B62 Windows \u670D\u52A1\u5931\u8D25: ${r.error?.message??`\u9000\u51FA\u7801 ${r.status??"unknown"}`}`),{handled:!0,exitCode:r.status??1})}function pe(){return`gui/${process.getuid?.()??0}`}function W(e){return e.launchdDomainTarget||pe()}function p(e){return`${e}/${N}`}function _(e,r){return r.error?`[runtime-bridge] ${e}\u5931\u8D25: ${r.error.message}`:`[runtime-bridge] ${e}\u5931\u8D25\uFF0Claunchctl \u9000\u51FA\u7801: ${r.status??"unknown"}`}function _e(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||D,t=e.launchdLogPath||L,s=he(e.executablePath,{userHomeDir:v.homedir(),logPath:t});try{T(c.dirname(r),{recursive:!0}),T(c.dirname(t),{recursive:!0}),G(r,s,{encoding:"utf-8",mode:420})}catch(a){const o=a instanceof Error?a:new Error(String(a));return e.stderr(`[runtime-bridge] \u5199\u5165 launchd plist \u5931\u8D25: ${o.message}`),{handled:!0,exitCode:1}}const i=W(e);e.runCommand("launchctl",["bootout",p(i)]);const n=e.runCommand("launchctl",["bootstrap",i,r]);return d(n)?(e.stdout(`[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u52A8\uFF08\u65E5\u5FD7: ${t}\uFF09\u3002`),{handled:!0,exitCode:0}):(e.stderr(_("\u5B89\u88C5 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1})}function De(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||D,t=W(e),s=p(t),i=e.runCommand("launchctl",["bootout",s]);if(i.error)return e.stderr(_("\u5378\u8F7D awsb \u670D\u52A1",i)),{handled:!0,exitCode:1};if(g(r))try{F(r)}catch(n){const a=n instanceof Error?n:new Error(String(n));return e.stderr(`[runtime-bridge] \u5220\u9664 launchd plist \u5931\u8D25: ${a.message}`),{handled:!0,exitCode:1}}else e.stdout("[runtime-bridge] awsb launchd plist \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5220\u9664\u3002");return e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}}function ke(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||D;if(!g(r))return e.stderr("[runtime-bridge] awsb launchd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const t=W(e),s=p(t),i=e.runCommand("launchctl",["kickstart",s]);if(d(i))return e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0};const n=e.runCommand("launchctl",["bootstrap",t,r]);return d(n)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(_("\u542F\u52A8 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1})}function Te(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=W(e),t=e.runCommand("launchctl",["bootout",p(r)]);return d(t)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(_("\u505C\u6B62 awsb \u670D\u52A1",t)),{handled:!0,exitCode:t.status??1})}function Ie(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||D;if(!g(r))return e.stderr("[runtime-bridge] awsb launchd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const t=W(e);e.runCommand("launchctl",["bootout",p(t)]);const s=e.runCommand("launchctl",["bootstrap",t,r]);return d(s)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u91CD\u542F\u3002"),{handled:!0,exitCode:0}):(e.stderr(_("\u91CD\u542F awsb \u670D\u52A1",s)),{handled:!0,exitCode:s.status??1})}async function Ne(e,r,t,s){const i=e[1];if(!i||i==="-h"||i==="--help"||i==="help")return Y(t),{handled:!0,exitCode:i?0:1};const n={stdout:t,stderr:s,runCommand:r.runCommand||k,platform:r.platform||process.platform,serviceUnitPath:r.serviceUnitPath||I,executablePath:r.executablePath||K(),windowsServiceManager:r.windowsServiceManager,launchdPlistPath:r.launchdPlistPath,launchdLogPath:r.launchdLogPath,launchdDomainTarget:r.launchdDomainTarget,queryWindowsServiceState:r.queryWindowsServiceState||A};return n.platform!=="linux"&&n.platform!=="win32"&&n.platform!=="darwin"?(s("[runtime-bridge] service \u547D\u4EE4\u4EC5\u652F\u6301 Linux systemd\u3001Windows \u670D\u52A1\u4E0E macOS launchd \u73AF\u5883\u3002"),{handled:!0,exitCode:1}):i==="install"?n.platform==="win32"?await U(n):n.platform==="darwin"?_e(n):we(n):i==="uninstall"?n.platform==="win32"?Pe(n):n.platform==="darwin"?De(n):be(n):i==="restart"?n.platform==="win32"?ye(n):n.platform==="darwin"?Ie(n):Ce(n):i==="start"?n.platform==="win32"?Ee(n):n.platform==="darwin"?ke(n):xe(n):i==="stop"?n.platform==="win32"?We(n):n.platform==="darwin"?Te(n):Se(n):(s(`[runtime-bridge] \u672A\u77E5 service \u5B50\u547D\u4EE4: ${i}`),Y(t),{handled:!0,exitCode:1})}function Q(e){return e?e.split(/\r?\n/).map(r=>r.trim()).filter(r=>/^\d+$/.test(r)).map(Number):[]}function Le(e){try{if(e==="win32"){const t=f("powershell",["-NoProfile","-Command",`Get-CimInstance Win32_Process -Filter "Name='node.exe'" | Where-Object { $_.CommandLine -like '*aws-runtime-bridge*' -and $_.ProcessId -ne ${process.pid} } | ForEach-Object { $_.ProcessId }`],{encoding:"utf-8"}),s=Ae(e);return Ue([...Q(t.stdout),...s]).filter(i=>i!==process.pid)}const r=f("pgrep",["-f","aws-runtime-bridge"],{encoding:"utf-8"});return Q(r.stdout).filter(t=>t!==process.pid)}catch{return[]}}function Ae(e){if(e!=="win32")return[];try{const r=f("sc.exe",["query",l],{encoding:"utf-8",shell:!0,stdio:["ignore","pipe","ignore"]});if(r.status!==0||!r.stdout)return[];const t=r.stdout.match(/STATE\s*:\s*\d+\s+(\S+)/);if(!t)return[];const s=t[1];if(s!=="RUNNING"&&s!=="START_PENDING"&&s!=="STOP_PENDING")return[];const i=f("tasklist",["/FI","IMAGENAME eq awsb.exe","/FO","CSV","/NH"],{encoding:"utf-8",shell:!0,stdio:["ignore","pipe","ignore"]});return i.status!==0||!i.stdout?[]:i.stdout.split(/\r?\n/).map(n=>n.trim()).filter(n=>n.length>0).map(n=>{const a=n.match(/^"awsb\.exe","(\d+)"/i);return a?Number(a[1]):NaN}).filter(n=>Number.isFinite(n)&&n>0)}catch{return[]}}function Ue(e){const r=new Set,t=[];for(const s of e)r.has(s)||(r.add(s),t.push(s));return t}function Me(e,r){if(r==="win32"){if(Oe(e,r)){f("sc.exe",["stop",l],{stdio:"ignore",shell:!0}),V(A,l);return}f("taskkill",["/PID",String(e),"/F","/T"],{stdio:"ignore"});return}f("kill",["-9",String(e)],{stdio:"ignore"})}function Oe(e,r){if(r!=="win32"||!Number.isFinite(e)||e<=0)return!1;try{const t=f("powershell",["-NoProfile","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId=${e}" -ErrorAction SilentlyContinue).Name`],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]});return t.status!==0||!t.stdout?!1:/^awsb\.exe$/i.test(t.stdout.trim())}catch{return!1}}function Fe(e){if(!process.stdin.isTTY)return Promise.resolve("n");const r=X({input:process.stdin,output:process.stdout});return r.question(e).finally(()=>r.close())}async function Ge(e,r,t){const s=e.runCommand||k,i=e.platform||process.platform,n=e.findRunningBridgeProcesses||Le,a=e.prompt||Fe,o=e.killBridgeProcess||Me,u=e.globalModulePath||de;r("[runtime-bridge] \u6B63\u5728\u66F4\u65B0 aws-runtime-bridge \u5230\u6700\u65B0\u7248\u672C...");const m=n(i).filter(x=>x!==process.pid);let C=!1;if(m.length>0){r(`[runtime-bridge] \u68C0\u6D4B\u5230 aws-runtime-bridge \u6B63\u5728\u8FD0\u884C (PID: ${m.join(", ")})\uFF0C\u66F4\u65B0\u65F6\u8FD9\u4E9B\u8FDB\u7A0B\u53EF\u80FD\u5360\u7528\u6587\u4EF6\u5BFC\u81F4\u8986\u76D6\u5931\u8D25\u3002`);const x=(await a("\u662F\u5426\u5173\u95ED\u4E0A\u8FF0\u8FDB\u7A0B\u4EE5\u7EE7\u7EED\u66F4\u65B0? (y/N) ")).trim().toLowerCase();if(x==="y"||x==="yes")for(const S of m)try{o(S,i),r(`[runtime-bridge] \u5DF2\u5173\u95ED\u8FDB\u7A0B PID: ${S}`)}catch(E){const z=E instanceof Error?E:new Error(String(E));t(`[runtime-bridge] \u5173\u95ED\u8FDB\u7A0B PID ${S} \u5931\u8D25: ${z.message}`)}else C=!0,r("[runtime-bridge] \u5DF2\u9009\u62E9\u4E0D\u5173\u95ED\u8FDB\u7A0B\uFF0C\u5C06\u4EE5 --force \u65B9\u5F0F\u5F3A\u5236\u5B89\u88C5\uFF08\u82E5\u6587\u4EF6\u4ECD\u88AB\u5360\u7528\u53EF\u80FD\u4F1A\u6709\u8B66\u544A\uFF09\u3002")}const M=u();if(M){const x=c.join(M,"aws-runtime-bridge");if(g(x)){r("[runtime-bridge] \u6E05\u7406\u65E7\u7248\u672C\u6B8B\u7559\u76EE\u5F55...");try{ee(x,{recursive:!0,force:!0})}catch(S){const E=S instanceof Error?S:new Error(String(S));t(`[runtime-bridge] \u6E05\u7406\u6B8B\u7559\u76EE\u5F55\u5931\u8D25\uFF08\u5C06\u5C1D\u8BD5\u7EE7\u7EED\u5B89\u88C5\uFF09: ${E.message}`)}}}const O=["install","-g","aws-runtime-bridge@latest","--omit=optional"];C&&O.push("--force");const y=s("npm",O);if(y.error)return t(`[runtime-bridge] \u66F4\u65B0\u5931\u8D25: ${y.error.message}`),{handled:!0,exitCode:1};if(y.status!==0)return t(`[runtime-bridge] \u66F4\u65B0\u5931\u8D25\uFF0Cnpm \u9000\u51FA\u7801: ${y.status??"unknown"}`),{handled:!0,exitCode:y.status??1};if(i==="win32"){const x=await He(e,r,t);if(x.exitCode!==0)return x}return r("[runtime-bridge] \u66F4\u65B0\u5B8C\u6210\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C awsb -v \u67E5\u770B\u5F53\u524D\u7248\u672C\u3002"),{handled:!0,exitCode:0}}async function He(e,r,t){const s=e.runCommand||k,i=s("sc.exe",["query",l]);if(!d(i))return{handled:!0,exitCode:0};r("[runtime-bridge] \u68C0\u6D4B\u5230 Windows \u670D\u52A1\u5DF2\u6CE8\u518C\uFF0C\u6B63\u5728\u91CD\u5EFA\u670D\u52A1\u6587\u4EF6\uFF08daemon/winsw.exe\uFF09..."),s("sc.exe",["stop",l]);const n=s("sc.exe",["delete",l]);d(n)||t(`[runtime-bridge] \u5220\u9664\u65E7 SCM \u8BB0\u5F55\u5931\u8D25: ${n.error?.message??`\u9000\u51FA\u7801 ${n.status??"unknown"}`}\uFF08\u5C1D\u8BD5\u7EE7\u7EED\u5B89\u88C5\uFF09`);const a={stdout:r,stderr:t,runCommand:s,platform:"win32",serviceUnitPath:e.serviceUnitPath||I,executablePath:e.executablePath||K(),windowsServiceManager:e.windowsServiceManager};try{return(await U(a)).exitCode!==0?(t("[runtime-bridge] \u91CD\u5EFA Windows \u670D\u52A1\u6587\u4EF6\u5931\u8D25\u3002\u5305\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u624B\u52A8\u6267\u884C `awsb service uninstall && awsb service install` \u4FEE\u590D\u670D\u52A1\u3002"),{handled:!0,exitCode:0}):(r("[runtime-bridge] Windows \u670D\u52A1\u6587\u4EF6\u5DF2\u91CD\u5EFA\u3002"),{handled:!0,exitCode:0})}catch(o){const u=o instanceof Error?o:new Error(String(o));return t(`[runtime-bridge] \u91CD\u5EFA Windows \u670D\u52A1\u6587\u4EF6\u5F02\u5E38: ${u.message}\u3002\u5305\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u624B\u52A8\u6267\u884C \`awsb service uninstall && awsb service install\` \u4FEE\u590D\u670D\u52A1\u3002`),{handled:!0,exitCode:0}}}function je(e,r,t){const i=(e.argv||process.argv.slice(2)).slice(1).some(u=>u==="--follow"||u==="-f"),n=e.platform||process.platform,a=e.runCommand||k,o=e.serviceUnitPath||I;if(n==="linux"){if(!g(o))return t("[runtime-bridge] awsb \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF08awsb service install\uFF09\uFF0C\u65E0\u65E5\u5FD7\u53EF\u67E5\u770B\u3002"),{handled:!0,exitCode:1};const u=["-u",h];i?u.push("-f"):u.push("-n","200","--no-pager");const m=a("journalctl",u);return m.error?(t(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${m.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:m.status??0}}if(n==="win32"){const u=e.windowsServiceLogPath||B;if(!g(u))return t(`[runtime-bridge] \u5C1A\u672A\u751F\u6210\u65E5\u5FD7\u6587\u4EF6: ${u}\u3002\u8BF7\u5148\u6267\u884C \`awsb service install\` \u5E76\u8FD0\u884C\u670D\u52A1\u3002`),{handled:!0,exitCode:1};const m=`Get-Content -Encoding UTF8 -Tail 200 "${u}"`+(i?" -Wait":""),C=a("powershell",["-NoProfile","-Command",m]);return C.error?(t(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${C.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:C.status??0}}if(n==="darwin"){const u=e.launchdLogPath||L;if(!g(u))return t(`[runtime-bridge] \u5C1A\u672A\u751F\u6210\u65E5\u5FD7\u6587\u4EF6: ${u}\u3002\u8BF7\u5148\u6267\u884C \`awsb service install\` \u5E76\u8FD0\u884C\u670D\u52A1\u3002`),{handled:!0,exitCode:1};const C=a("tail",i?["-f",u]:["-n","200",u]);return C.error?(t(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${C.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:C.status??0}}return t("[runtime-bridge] awsb log \u4EC5\u652F\u6301 Linux systemd\u3001Windows \u670D\u52A1\u4E0E macOS launchd \u73AF\u5883\u3002"),{handled:!0,exitCode:1}}async function Xe(e={}){const r=e.argv||process.argv.slice(2),t=r[0],s=e.stdout||ce,i=e.stderr||le;if(me(t))return s(`aws-runtime-bridge ${ue(e.packageRoot)}`),{handled:!0,exitCode:0};if(t==="update")return await Ge(e,s,i);if(t==="config"){const n=r[1];if(n==="example"||n==="minimal"||n==="--minimal"||n==="-m")return{handled:!0,exitCode:await(e.configureExample||te)()==="created"?0:1};const o=await(e.configure||re)();return{handled:!0,exitCode:o==="configured"||o==="created"?0:1}}return t==="service"?await Ne(r,e,s,i):t==="log"?je(e,s,i):{handled:!1,exitCode:0}}export{he as createLaunchdPlistContent,ge as createSystemdUnitContent,Le as defaultFindRunningBridgeProcesses,Me as defaultKillBridgeProcess,Xe as handleCliCommand,ue as readPackageVersion};
|
|
7
7
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createReadStream as U,createWriteStream as ot,promises as o}from"node:fs";import d from"node:path";import{Readable as st}from"node:stream";import{pipeline as ct}from"node:stream/promises";import{TextDecoder as lt}from"node:util";import{createGunzip as ht}from"node:zlib";import*as ut from"tar";import dt from"unzipper";const{ZipArchive:wt}=await import("archiver"),y={maxEntries:1e4,maxFileBytes:512*1024*1024,maxTotalBytes:2*1024*1024*1024,maxPathDepth:64,maxPathLength:4096},ft=new lt("gbk");function h(t){return String(t||"").replace(/\\/g,"/")}function j(t){const e=d.resolve(String(t||"").trim());if(!e)throw new Error("workspacePath is required");return e}async function pt(t){const e=j(t),r=await o.realpath(e);if(!(await o.stat(r)).isDirectory())throw new Error(`Workspace path is not a directory: ${e}`);return r}async function k(t){return{requestedRoot:j(t),workspaceRoot:await pt(t)}}function p(t,e){const r=d.resolve(e),i=d.relative(t,r);if(i.startsWith("..")||d.isAbsolute(i))throw new Error(`Target path is outside workspace: ${r}`);return r}async function x(t,e){const r=await o.realpath(e);return p(t,r)}async function v(t,e){const r=await o.realpath(d.dirname(e));p(t,r);try{if((await o.lstat(e)).isSymbolicLink())throw new Error(`Refusing to write through symbolic link: ${e}`)}catch(i){if((typeof i=="object"&&i!==null?Reflect.get(i,"code"):void 0)!=="ENOENT")throw i}}function z(t,e,r){const i=d.resolve(r),a=d.relative(t,i);if(a.startsWith("..")||d.isAbsolute(a))throw new Error(`Target path is outside workspace: ${i}`);return p(e,d.join(e,a))}async function $({workspacePath:t,targetPath:e=""}){const{requestedRoot:r,workspaceRoot:i}=await k(t),a=String(e||"").trim(),n=a?z(r,i,a):i,s=await x(i,n);return{workspaceRoot:i,resolvedTargetPath:s}}function D(t){const e=String(t||"").trim();if(!e)throw new Error("entryName is required");if(e==="."||e==="..")throw new Error("entryName is invalid");if(e.includes("/")||e.includes("\\")||d.basename(e)!==e)throw new Error(`entryName must be a plain file or directory name: ${e}`);return e}function q(t){const e=String(t||"");if(!/[\u00c0-\u00ff]/.test(e))return e;const r=Buffer.from(e,"latin1").toString("utf8");return!r||r.includes("\uFFFD")?e:r}function B(t){const e=q(t);return D(d.basename(e.replace(/\\/g,"/")))}function mt(t,e){if(!t)return B(e);const i=q(String(t||e||"")).replace(/\\/g,"/").split("/").filter(Boolean).map(a=>D(a));return i.length===0?B(e):d.join(...i)}function _(t){return(t&4095).toString(8).padStart(4,"0")}function gt(t){const e=String(t||"").trim();if(!/^[0-7]{3,4}$/.test(e))throw new Error("mode must be a 3 or 4 digit octal string");return Number.parseInt(e,8)}function C(t,e,r,i,a,n,s){const c=t&e?"r":"-",u=t&r?"w":"-",l=(t&i)!==0,w=(t&a)!==0?l?n:s:l?"x":"-";return`${c}${u}${w}`}function yt(t){return[C(t,256,128,64,2048,"s","S"),C(t,32,16,8,1024,"s","S"),C(t,4,2,1,512,"t","T")].join("")}function Pt(t){if(!(t.length<24||t.toString("hex",0,8)!=="89504e470d0a1a0a"))return{format:"png",width:t.readUInt32BE(16),height:t.readUInt32BE(20)}}function kt(t){if(!(t.length<10||t.toString("ascii",0,6)!=="GIF87a"&&t.toString("ascii",0,6)!=="GIF89a"))return{format:"gif",width:t.readUInt16LE(6),height:t.readUInt16LE(8)}}function xt(t){if(t.length<4||t[0]!==255||t[1]!==216)return;let e=2;for(;e+9<t.length;){if(t[e]!==255){e+=1;continue}const r=t[e+1],i=t.readUInt16BE(e+2);if(i<2)return;if(r>=192&&r<=207&&![196,200,204].includes(r)&&e+8<t.length)return{format:"jpeg",height:t.readUInt16BE(e+5),width:t.readUInt16BE(e+7)};e+=2+i}}function Et(t){if(t.length<30||t.toString("ascii",0,4)!=="RIFF"||t.toString("ascii",8,12)!=="WEBP")return;const e=t.toString("ascii",12,16);if(e==="VP8X"&&t.length>=30)return{format:"webp",width:1+t.readUIntLE(24,3),height:1+t.readUIntLE(27,3)};if(e==="VP8 "&&t.length>=30)return{format:"webp",width:t.readUInt16LE(26)&16383,height:t.readUInt16LE(28)&16383};if(e==="VP8L"&&t.length>=25){const r=t.readUInt32LE(21);return{format:"webp",width:(r&16383)+1,height:(r>>14&16383)+1}}}async function G(t,e,r){if((await o.lstat(e)).isSymbolicLink())throw new Error(`Refusing to change permissions on symbolic link: ${e}`);const a=await o.stat(e);if(!r||!a.isDirectory())return[e];const n=await o.readdir(e),s=await Promise.all(n.map(c=>{const u=p(t,d.join(e,c));return G(t,u,!0)}));return[e,...s.flat()]}async function vt(t,e){if((await o.lstat(e)).isSymbolicLink())throw new Error(`Refusing to change permissions on symbolic link: ${e}`);await x(t,e)}async function St(t){const e=await o.open(t,"r");try{const r=Buffer.alloc(512),{bytesRead:i}=await e.read(r,0,r.length,0),a=r.subarray(0,i);return Pt(a)||kt(a)||xt(a)||Et(a)}finally{await e.close()}}async function S({workspacePath:t,targetPath:e},r={}){const{requestedRoot:i,workspaceRoot:a}=await k(t),n=String(e||"").trim();if(!n)throw new Error("targetPath is required");const s=z(i,a,n),c=await x(a,s);if(!r.allowWorkspaceRoot&&c===a)throw new Error("Workspace root cannot be modified");return{workspaceRoot:a,resolvedTargetPath:c}}async function Z(t){const{requestedRoot:e,workspaceRoot:r}=await k(t.workspacePath),i=String(t.targetPath||"").trim();if(!i)return{workspaceRoot:r,resolvedTargetPath:r};const a=z(e,r,i);if(await J(a))return{workspaceRoot:r,resolvedTargetPath:await x(r,a)};const n=await o.realpath(d.dirname(a));return p(r,n),{workspaceRoot:r,resolvedTargetPath:a}}function H(t){const e=t.toLowerCase();return e.endsWith(".zip")?"zip":e.endsWith(".tar.gz")||e.endsWith(".tgz")?"tgz":e.endsWith(".tar")?"tar":e.endsWith(".gz")?"gz":null}function K(t){return t.replace(/\.tar\.gz$/i,"").replace(/\.tgz$/i,"").replace(/\.zip$/i,"").replace(/\.tar$/i,"").replace(/\.gz$/i,"")}function Ft(t,e){const r=D(K(e)||"extracted");return d.join(t,r)}function I(t,e){const r=String(e||"").replace(/\\/g,"/"),i=r.split("/").filter(Boolean);if(!r||r.startsWith("/")||/^[A-Za-z]:/.test(r))throw new Error(`Archive entry path is invalid: ${e}`);if(r.length>y.maxPathLength||i.length>y.maxPathDepth)throw new Error(`Archive entry path is too deep or too long: ${e}`);return p(t,d.join(t,r))}function Tt(t){const e=t.props?.pathBuffer;if(!e||t.props?.flags?.isUnicode)return t.path;const r=ft.decode(e);return!r||r.includes("\uFFFD")?t.path:r}async function V(t){const e=t.autodrain?.();e&&await new Promise((r,i)=>{e.on("close",r),e.on("end",r),e.on("finish",r),e.on("error",i)})}function A(t){if(t.entries+=1,t.entries>y.maxEntries)throw new Error(`Archive contains too many entries. Limit: ${y.maxEntries}`)}function X(t,e){if(t.totalBytes+=e,e>y.maxFileBytes)throw new Error(`Archive entry exceeds max size. Limit: ${y.maxFileBytes} bytes`);if(t.totalBytes>y.maxTotalBytes)throw new Error(`Archive extraction exceeds total size. Limit: ${y.maxTotalBytes} bytes`)}async function Y(t,e,r){let i=0;t.on("data",a=>{const n=Buffer.isBuffer(a)?a.length:Buffer.byteLength(a);i+=n,(i>y.maxFileBytes||r.totalBytes+i>y.maxTotalBytes)&&t instanceof st&&t.destroy(new Error("Archive extraction size limit exceeded"))}),await ct(t,ot(e)),X(r,i)}async function J(t){try{return await o.access(t),!0}catch(e){if((typeof e=="object"&&e!==null?Reflect.get(e,"code"):void 0)==="ENOENT")return!1;throw e}}async function W({workspacePath:t,filePath:e}){const{requestedRoot:r,workspaceRoot:i}=await k(t),a=String(e||"").trim();if(!a)throw new Error("filePath is required");return{workspaceRoot:i,resolvedFilePath:z(r,i,a)}}async function Ot(t){const{workspaceRoot:e,resolvedTargetPath:r}=await $(t);if(!(await o.stat(r)).isDirectory())throw new Error(`Path is not a directory: ${r}`);const a=await o.readdir(r,{withFileTypes:!0}),n=await Promise.all(a.map(async s=>{const c=d.join(r,s.name),u=s.isFile()?(await o.stat(c)).size:void 0;return{name:s.name,path:h(c),isDirectory:s.isDirectory(),size:u}}));return{currentPath:h(r),workspacePath:h(e),items:n}}async function Ut(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t),i=await x(e,r);if(!(await o.stat(i)).isFile())throw new Error(`Path is not a file: ${i}`);const n=await o.readFile(i,"utf-8");return{workspacePath:h(e),filePath:h(i),content:n}}const Q={maxEntries:1e5,maxDepth:32};async function Rt(t,e){let r=0,i=0;async function a(n,s){if(s>=Q.maxDepth)return;let c;try{c=await o.readdir(n,{withFileTypes:!0})}catch{return}for(const u of c){if(i+=1,i>Q.maxEntries)return;if(u.isSymbolicLink())continue;const l=p(t,d.join(n,u.name));try{if(u.isDirectory())await a(l,s+1);else if(u.isFile()){const f=await o.stat(l);r+=f.size}}catch{}}}return await a(e,0),r}async function jt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await S(t,{allowWorkspaceRoot:!0}),[i,a]=await Promise.all([o.stat(r),o.lstat(r)]),n=i.isDirectory(),s=i.isFile()?await St(r):void 0,c=n?await Rt(e,r):i.size;return{workspacePath:h(e),targetPath:h(r),name:d.basename(r),isDirectory:i.isDirectory(),isFile:i.isFile(),isSymbolicLink:a.isSymbolicLink(),size:c,mode:i.mode,modeOctal:_(i.mode),permissions:yt(i.mode),uid:i.uid,gid:i.gid,atimeMs:i.atimeMs,mtimeMs:i.mtimeMs,ctimeMs:i.ctimeMs,birthtimeMs:i.birthtimeMs,...s?{image:s}:{}}}async function qt(t){const e=gt(t.mode),r=!!t.recursive,{workspaceRoot:i,resolvedTargetPath:a}=await S(t),n=await G(i,a,r);for(const s of n)await vt(i,s),await o.chmod(s,e);return{ok:!0,workspacePath:h(i),targetPath:h(a),mode:e,modeOctal:_(e),recursive:r,changedCount:n.length}}async function _t(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t),i=await x(e,r),a=await o.stat(i);if(!a.isFile())throw new Error(`Path is not a file: ${i}`);const n=d.extname(i).toLowerCase();if(n===".doc")return{workspacePath:h(e),filePath:h(i),kind:"unsupported",content:"",message:"\u6682\u4E0D\u652F\u6301\u65E7\u7248 .doc \u683C\u5F0F\u9884\u89C8\uFF0C\u8BF7\u53E6\u5B58\u4E3A .docx \u540E\u518D\u6253\u5F00\u3002",size:a.size,mtimeMs:a.mtimeMs};if(n!==".docx")throw new Error("Document preview only supports .docx files");return{workspacePath:h(e),filePath:h(i),kind:"html",content:"",size:a.size,mtimeMs:a.mtimeMs}}async function Gt(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t);return await o.mkdir(d.dirname(r),{recursive:!0}),await v(e,r),await o.writeFile(r,String(t.content??""),"utf-8"),{ok:!0,workspacePath:h(e),filePath:h(r)}}async function Zt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await $(t),i=D(t.entryName),a=p(e,d.join(r,i));if(!(await o.stat(r)).isDirectory())throw new Error(`Path is not a directory: ${r}`);try{throw await o.access(a),new Error(`Path already exists: ${a}`)}catch(s){if((typeof s=="object"&&s!==null?Reflect.get(s,"code"):void 0)!=="ENOENT")throw s}return t.isDirectory?await o.mkdir(a,{recursive:!1}):(await o.mkdir(d.dirname(a),{recursive:!0}),await v(e,a),await o.writeFile(a,"","utf-8")),{ok:!0,workspacePath:h(e),targetPath:h(a),isDirectory:t.isDirectory}}async function Ht(t){const{workspaceRoot:e,resolvedTargetPath:r}=await S(t),i=D(t.newName),a=p(e,d.join(d.dirname(r),i));if(a===r)return{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(a)};await o.stat(r);try{throw await o.access(a),new Error(`Path already exists: ${a}`)}catch(n){if((typeof n=="object"&&n!==null?Reflect.get(n,"code"):void 0)!=="ENOENT")throw n}return await o.rename(r,a),{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(a)}}async function Kt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await S(t),i=await $({workspacePath:t.workspacePath,targetPath:t.destinationPath});if(!(await o.stat(i.resolvedTargetPath)).isDirectory())throw new Error(`Destination is not a directory: ${i.resolvedTargetPath}`);if((await o.stat(r)).isDirectory()){const c=d.relative(r,i.resolvedTargetPath);if(c===""||!c.startsWith("..")&&!d.isAbsolute(c))throw new Error("Cannot move a directory into itself or its descendant")}const s=p(e,d.join(i.resolvedTargetPath,d.basename(r)));if(s===r)return{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(s),destinationPath:h(i.resolvedTargetPath)};try{throw await o.access(s),new Error(`Path already exists: ${s}`)}catch(c){if((typeof c=="object"&&c!==null?Reflect.get(c,"code"):void 0)!=="ENOENT")throw c}return await o.rename(r,s),{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(s),destinationPath:h(i.resolvedTargetPath)}}async function Vt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await S(t);return(await o.stat(r)).isDirectory()?await o.rm(r,{recursive:!0,force:!1}):await o.unlink(r),{ok:!0,workspacePath:h(e),targetPath:h(r)}}async function Xt(t){if(!Array.isArray(t.files)||t.files.length===0)throw new Error("files are required");const{workspaceRoot:e,resolvedTargetPath:r}=await Z(t);if(!(await o.stat(r)).isDirectory())throw new Error(`Path is not a directory: ${r}`);const a=[];for(const n of t.files){const s=B(n.originalname),c=mt(n.relativePath,n.originalname),u=p(e,d.join(r,c));await o.mkdir(d.dirname(u),{recursive:!0}),await v(e,u),await o.copyFile(n.path,u);let l;t.extractArchives&&H(u)&&(l=await Wt({workspacePath:e,archivePath:u,outputPath:Ft(r,s)})),a.push({fileName:s,targetPath:h(u),size:n.size,extracted:l})}return{ok:!0,workspacePath:h(e),targetPath:h(r),files:a}}async function Yt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await S(t),i=await o.stat(r),a=d.basename(r);return{workspacePath:h(e),targetPath:h(r),resolvedTargetPath:r,fileName:i.isDirectory()?`${a||"workspace"}.zip`:a,contentType:i.isDirectory()?"application/zip":"application/octet-stream",isDirectory:i.isDirectory()}}async function Jt(t,e){const r=new wt({zlib:{level:9}}),i=new Promise((a,n)=>{e.on("close",a),e.on("finish",a),r.on("error",n),e.on("error",n)});r.pipe(e),r.directory(t,!1),await r.finalize(),await i}async function zt(t,e,r){let i=0,a;const n=U(t),s=n.pipe(dt.Parse({forceStream:!0}));try{for await(const c of s){if(a){await V(c);continue}const u=Tt(c);try{const l=I(e,u);if(A(r),c.type==="Directory"){await o.mkdir(l,{recursive:!0});continue}if(c.type!=="File")throw new Error(`Unsupported archive entry type: ${u}`);await o.mkdir(d.dirname(l),{recursive:!0}),await v(e,l),await Y(c,l,r),i+=1}catch(l){a=l,await V(c)}}}finally{n.destroy(),s.destroy()}if(a)throw a;return i}async function Dt(t,e,r,i){let a=0,n;const s=(c,u)=>{if(n)return!1;try{I(e,c),A(i);const l=String(u.type||"").toLowerCase();if(l==="symboliclink"||l==="link")throw new Error(`Archive links are not supported: ${c}`);if(l!=="file"&&l!=="oldfile"&&l!=="contiguousfile"&&l!=="directory")throw new Error(`Unsupported archive entry type: ${c}`);return typeof u.size=="number"&&X(i,u.size),l!=="directory"&&(a+=1),!0}catch(l){return n=l,!1}};if(await ut.x({file:t,cwd:e,gzip:r,strict:!0,filter:(c,u)=>s(c,u)}),n)throw n;return a}async function Lt(t,e,r){const i=K(d.basename(t)),a=I(e,i||"decompressed");return A(r),await o.mkdir(d.dirname(a),{recursive:!0}),await v(e,a),await Y(U(t).pipe(ht()),a,r),1}async function Wt(t){const{requestedRoot:e,workspaceRoot:r}=await k(t.workspacePath),{resolvedTargetPath:i}=await Z({workspacePath:t.workspacePath,targetPath:t.outputPath||""}),a=z(e,r,String(t.archivePath||"").trim()),n=await x(r,a);if(!(await o.stat(n)).isFile())throw new Error(`Archive path is not a file: ${n}`);if(await J(i)||await o.mkdir(i,{recursive:!0}),!(await o.stat(i)).isDirectory())throw new Error(`Output path is not a directory: ${i}`);const u=H(n);if(!u)throw new Error("Unsupported archive type. Supported: .zip, .tar, .tar.gz, .tgz, .gz");let l=0;const f={entries:0,totalBytes:0};return u==="zip"?l=await zt(n,i,f):u==="tar"||u==="tgz"?l=await Dt(n,i,u==="tgz",f):l=await Lt(n,i,f),{ok:!0,workspacePath:h(r),archivePath:h(n),targetPath:h(i),extractedEntries:l}}function tt(t){const e=t.match(/^(.*?)\{([^}]+)\}(.*)$/);if(!e)return[t];const[,r,i,a]=e;return i.split(",").flatMap(n=>tt(r+n.trim()+a))}function et(t,e){const r=String(e||"").trim();if(!r||r==="*"||r==="*.*")return!0;const i=t.toLowerCase();return tt(r.toLowerCase()).some(n=>{if(n==="*")return!0;const s=n.replace(/\./g,"\\.").replace(/\*\*/g,"<<GLOBSTAR>>").replace(/\*/g,"[^/]*").replace(/\?/g,"[^/]").replace(/<<GLOBSTAR>>/g,".*");return new RegExp(`^${s}$`).test(i)})}function rt(t){return t===".git"||t==="node_modules"||t===".svn"||t===".hg"}const it=10*1024*1024,$t=1e3;async function Qt(t){const{workspaceRoot:e}=await k(t.workspacePath),r=String(t.keyword||"").trim();if(!r)throw new Error("keyword is required");const i=!!t.ignoreCase,a=String(t.fileMask||"").trim(),n=typeof t.maxResults=="number"&&t.maxResults>0?t.maxResults:$t,s=i?r.toLowerCase():r,u=(t.mode==="filename"?"filename":"content")==="filename",l=[];let f=0,w=!1;async function m(E){if(w)return;let F;try{F=await o.readdir(E,{withFileTypes:!0})}catch{return}for(const g of F){if(w)return;const T=p(e,d.join(E,g.name));if(g.isSymbolicLink())continue;if(g.isDirectory()){if(rt(g.name))continue;await m(T);continue}if(!g.isFile()||a&&!et(g.name,a))continue;f+=1;let N;try{N=await o.stat(T)}catch{continue}if(N.size>it)continue;if(u){const P=(i?g.name.toLowerCase():g.name).indexOf(s);if(P!==-1&&(l.push({filePath:h(T),lineNumber:0,lineContent:g.name,matchStart:P,matchEnd:P+r.length}),l.length>=n)){w=!0;return}continue}let M;try{M=await o.readFile(T,"utf-8")}catch{continue}const b=M.split(/\r?\n/);for(let R=0;R<b.length;R+=1){const P=b[R],nt=i?P.toLowerCase():P;let O=0;for(;;){const L=nt.indexOf(s,O);if(L===-1)break;if(l.push({filePath:h(T),lineNumber:R+1,lineContent:P,matchStart:L,matchEnd:L+r.length}),l.length>=n){w=!0;return}O=L+1}}}}return await m(e),{workspacePath:h(e),keyword:r,totalFiles:f,totalMatches:l.length,matches:l,truncated:w}}async function at(t,e,r,i,a){let n;try{n=await o.readFile(e,"utf-8")}catch{return{changed:!1,count:0}}const s=n;let c=0;if(a){const u=r.toLowerCase();let l=0;for(;;){const w=n.toLowerCase().indexOf(u,l);if(w===-1)break;n=n.slice(0,w)+i+n.slice(w+r.length),c+=1;const m=i.length||1;l=w+m}}else{let u=0;for(;;){const l=n.indexOf(r,u);if(l===-1)break;n=n.slice(0,l)+i+n.slice(l+r.length),c+=1;const f=i.length||1;u=l+f}}return n===s?{changed:!1,count:0}:(await v(t,e),await o.writeFile(e,n,"utf-8"),{changed:!0,count:c})}async function te(t){const{workspaceRoot:e}=await k(t.workspacePath),r=String(t.keyword||"").trim();if(!r)throw new Error("keyword is required");const i=String(t.replacement??""),a=!!t.ignoreCase,n=String(t.fileMask||"").trim(),s=String(t.filePath||"").trim();let c=0,u=0;if(s){const{resolvedFilePath:f}=await W({workspacePath:t.workspacePath,filePath:s}),w=await at(e,f,r,i,a);return w.changed&&(c=1,u=w.count),{workspacePath:h(e),keyword:r,replacement:i,changedFiles:c,changedMatches:u}}async function l(f){let w;try{w=await o.readdir(f,{withFileTypes:!0})}catch{return}for(const m of w){const E=p(e,d.join(f,m.name));if(m.isSymbolicLink())continue;if(m.isDirectory()){if(rt(m.name))continue;await l(E);continue}if(!m.isFile()||n&&!et(m.name,n))continue;try{if((await o.stat(E)).size>it)continue}catch{continue}const F=await at(e,E,r,i,a);F.changed&&(c+=1,u+=F.count)}}return await l(e),{workspacePath:h(e),keyword:r,replacement:i,changedFiles:c,changedMatches:u}}export{qt as chmodWorkspaceEntry,Zt as createWorkspaceEntry,Vt as deleteWorkspaceEntry,Wt as extractWorkspaceArchive,jt as getWorkspaceEntryProperties,Ot as listWorkspaceDirectory,Kt as moveWorkspaceEntry,_t as previewWorkspaceDocument,Ut as readWorkspaceFile,Ht as renameWorkspaceEntry,te as replaceWorkspaceFiles,Yt as resolveWorkspaceDownloadTarget,Qt as searchWorkspaceFiles,Jt as streamWorkspaceDirectoryZip,Xt as uploadWorkspaceFiles,Gt as writeWorkspaceFile};
|
|
1
|
+
import{createReadStream as O,createWriteStream as ot,promises as o}from"node:fs";import d from"node:path";import{Readable as st}from"node:stream";import{pipeline as ct}from"node:stream/promises";import{TextDecoder as lt}from"node:util";import{createGunzip as ht}from"node:zlib";import*as ut from"tar";import dt from"unzipper";const{ZipArchive:wt}=await import("archiver"),y={maxEntries:1e4,maxFileBytes:512*1024*1024,maxTotalBytes:2*1024*1024*1024,maxPathDepth:64,maxPathLength:4096},ft=new lt("gbk");function h(t){return String(t||"").replace(/\\/g,"/")}function U(t){const e=d.resolve(String(t||"").trim());if(!e)throw new Error("workspacePath is required");return e}async function pt(t){const e=U(t),r=await o.realpath(e);if(!(await o.stat(r)).isDirectory())throw new Error(`Workspace path is not a directory: ${e}`);return r}async function k(t){return{requestedRoot:U(t),workspaceRoot:await pt(t)}}function p(t,e){const r=d.resolve(e),i=d.relative(t,r);if(i.startsWith("..")||d.isAbsolute(i))throw new Error(`Target path is outside workspace: ${r}`);return r}async function x(t,e){const r=await o.realpath(e);return p(t,r)}async function E(t,e){const r=await o.realpath(d.dirname(e));p(t,r);try{if((await o.lstat(e)).isSymbolicLink())throw new Error(`Refusing to write through symbolic link: ${e}`)}catch(i){if((typeof i=="object"&&i!==null?Reflect.get(i,"code"):void 0)!=="ENOENT")throw i}}function z(t,e,r){const i=d.resolve(r),a=d.relative(t,i);if(a.startsWith("..")||d.isAbsolute(a))throw new Error(`Target path is outside workspace: ${i}`);return p(e,d.join(e,a))}async function C({workspacePath:t,targetPath:e=""}){const{requestedRoot:r,workspaceRoot:i}=await k(t),a=String(e||"").trim(),n=a?z(r,i,a):i,s=await x(i,n);return{workspaceRoot:i,resolvedTargetPath:s}}function D(t){const e=String(t||"").trim();if(!e)throw new Error("entryName is required");if(e==="."||e==="..")throw new Error("entryName is invalid");if(e.includes("/")||e.includes("\\")||d.basename(e)!==e)throw new Error(`entryName must be a plain file or directory name: ${e}`);return e}function q(t){const e=String(t||"");if(!/[\u00c0-\u00ff]/.test(e))return e;const r=Buffer.from(e,"latin1").toString("utf8");return!r||r.includes("\uFFFD")?e:r}function $(t){const e=q(t);return D(d.basename(e.replace(/\\/g,"/")))}function mt(t,e){if(!t)return $(e);const i=q(String(t||e||"")).replace(/\\/g,"/").split("/").filter(Boolean).map(a=>D(a));return i.length===0?$(e):d.join(...i)}function _(t){return(t&4095).toString(8).padStart(4,"0")}function gt(t){const e=String(t||"").trim();if(!/^[0-7]{3,4}$/.test(e))throw new Error("mode must be a 3 or 4 digit octal string");return Number.parseInt(e,8)}function B(t,e,r,i,a,n,s){const c=t&e?"r":"-",u=t&r?"w":"-",l=(t&i)!==0,w=(t&a)!==0?l?n:s:l?"x":"-";return`${c}${u}${w}`}function yt(t){return[B(t,256,128,64,2048,"s","S"),B(t,32,16,8,1024,"s","S"),B(t,4,2,1,512,"t","T")].join("")}function Pt(t){if(!(t.length<24||t.toString("hex",0,8)!=="89504e470d0a1a0a"))return{format:"png",width:t.readUInt32BE(16),height:t.readUInt32BE(20)}}function kt(t){if(!(t.length<10||t.toString("ascii",0,6)!=="GIF87a"&&t.toString("ascii",0,6)!=="GIF89a"))return{format:"gif",width:t.readUInt16LE(6),height:t.readUInt16LE(8)}}function xt(t){if(t.length<4||t[0]!==255||t[1]!==216)return;let e=2;for(;e+9<t.length;){if(t[e]!==255){e+=1;continue}const r=t[e+1],i=t.readUInt16BE(e+2);if(i<2)return;if(r>=192&&r<=207&&![196,200,204].includes(r)&&e+8<t.length)return{format:"jpeg",height:t.readUInt16BE(e+5),width:t.readUInt16BE(e+7)};e+=2+i}}function vt(t){if(t.length<30||t.toString("ascii",0,4)!=="RIFF"||t.toString("ascii",8,12)!=="WEBP")return;const e=t.toString("ascii",12,16);if(e==="VP8X"&&t.length>=30)return{format:"webp",width:1+t.readUIntLE(24,3),height:1+t.readUIntLE(27,3)};if(e==="VP8 "&&t.length>=30)return{format:"webp",width:t.readUInt16LE(26)&16383,height:t.readUInt16LE(28)&16383};if(e==="VP8L"&&t.length>=25){const r=t.readUInt32LE(21);return{format:"webp",width:(r&16383)+1,height:(r>>14&16383)+1}}}async function G(t,e,r){if((await o.lstat(e)).isSymbolicLink())throw new Error(`Refusing to change permissions on symbolic link: ${e}`);const a=await o.stat(e);if(!r||!a.isDirectory())return[e];const n=await o.readdir(e),s=await Promise.all(n.map(c=>{const u=p(t,d.join(e,c));return G(t,u,!0)}));return[e,...s.flat()]}async function Et(t,e){if((await o.lstat(e)).isSymbolicLink())throw new Error(`Refusing to change permissions on symbolic link: ${e}`);await x(t,e)}async function St(t){const e=await o.open(t,"r");try{const r=Buffer.alloc(512),{bytesRead:i}=await e.read(r,0,r.length,0),a=r.subarray(0,i);return Pt(a)||kt(a)||xt(a)||vt(a)}finally{await e.close()}}async function S({workspacePath:t,targetPath:e},r={}){const{requestedRoot:i,workspaceRoot:a}=await k(t),n=String(e||"").trim();if(!n)throw new Error("targetPath is required");const s=z(i,a,n),c=await x(a,s);if(!r.allowWorkspaceRoot&&c===a)throw new Error("Workspace root cannot be modified");return{workspaceRoot:a,resolvedTargetPath:c}}async function Z(t){const{requestedRoot:e,workspaceRoot:r}=await k(t.workspacePath),i=String(t.targetPath||"").trim();if(!i)return{workspaceRoot:r,resolvedTargetPath:r};const a=z(e,r,i);if(await J(a))return{workspaceRoot:r,resolvedTargetPath:await x(r,a)};const n=await o.realpath(d.dirname(a));return p(r,n),{workspaceRoot:r,resolvedTargetPath:a}}function H(t){const e=t.toLowerCase();return e.endsWith(".zip")?"zip":e.endsWith(".tar.gz")||e.endsWith(".tgz")?"tgz":e.endsWith(".tar")?"tar":e.endsWith(".gz")?"gz":null}function K(t){return t.replace(/\.tar\.gz$/i,"").replace(/\.tgz$/i,"").replace(/\.zip$/i,"").replace(/\.tar$/i,"").replace(/\.gz$/i,"")}function Ft(t,e){const r=D(K(e)||"extracted");return d.join(t,r)}function I(t,e){const r=String(e||"").replace(/\\/g,"/"),i=r.split("/").filter(Boolean);if(!r||r.startsWith("/")||/^[A-Za-z]:/.test(r))throw new Error(`Archive entry path is invalid: ${e}`);if(r.length>y.maxPathLength||i.length>y.maxPathDepth)throw new Error(`Archive entry path is too deep or too long: ${e}`);return p(t,d.join(t,r))}function Tt(t){const e=t.props?.pathBuffer;if(!e||t.props?.flags?.isUnicode)return t.path;const r=ft.decode(e);return!r||r.includes("\uFFFD")?t.path:r}async function V(t){const e=t.autodrain?.();e&&await new Promise((r,i)=>{e.on("close",r),e.on("end",r),e.on("finish",r),e.on("error",i)})}function A(t){if(t.entries+=1,t.entries>y.maxEntries)throw new Error(`Archive contains too many entries. Limit: ${y.maxEntries}`)}function X(t,e){if(t.totalBytes+=e,e>y.maxFileBytes)throw new Error(`Archive entry exceeds max size. Limit: ${y.maxFileBytes} bytes`);if(t.totalBytes>y.maxTotalBytes)throw new Error(`Archive extraction exceeds total size. Limit: ${y.maxTotalBytes} bytes`)}async function Y(t,e,r){let i=0;t.on("data",a=>{const n=Buffer.isBuffer(a)?a.length:Buffer.byteLength(a);i+=n,(i>y.maxFileBytes||r.totalBytes+i>y.maxTotalBytes)&&t instanceof st&&t.destroy(new Error("Archive extraction size limit exceeded"))}),await ct(t,ot(e)),X(r,i)}async function J(t){try{return await o.access(t),!0}catch(e){if((typeof e=="object"&&e!==null?Reflect.get(e,"code"):void 0)==="ENOENT")return!1;throw e}}async function W({workspacePath:t,filePath:e}){const{requestedRoot:r,workspaceRoot:i}=await k(t),a=String(e||"").trim();if(!a)throw new Error("filePath is required");return{workspaceRoot:i,resolvedFilePath:z(r,i,a)}}async function Ot(t){const{workspaceRoot:e,resolvedTargetPath:r}=await C(t);if(!(await o.stat(r)).isDirectory())throw new Error(`Path is not a directory: ${r}`);const a=await o.readdir(r,{withFileTypes:!0}),n=await Promise.all(a.map(async s=>{const c=d.join(r,s.name),u=s.isFile()?(await o.stat(c)).size:void 0;return{name:s.name,path:h(c),isDirectory:s.isDirectory(),size:u}}));return{currentPath:h(r),workspacePath:h(e),items:n}}async function Ut(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t),i=await x(e,r);if(!(await o.stat(i)).isFile())throw new Error(`Path is not a file: ${i}`);const n=await o.readFile(i,"utf-8");return{workspacePath:h(e),filePath:h(i),content:n}}const Q={maxEntries:1e5,maxDepth:32};async function Rt(t,e){let r=0,i=0;async function a(n,s){if(s>=Q.maxDepth)return;let c;try{c=await o.readdir(n,{withFileTypes:!0})}catch{return}for(const u of c){if(i+=1,i>Q.maxEntries)return;if(u.isSymbolicLink())continue;const l=p(t,d.join(n,u.name));try{if(u.isDirectory())await a(l,s+1);else if(u.isFile()){const f=await o.stat(l);r+=f.size}}catch{}}}return await a(e,0),r}async function qt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await S(t,{allowWorkspaceRoot:!0}),[i,a]=await Promise.all([o.stat(r),o.lstat(r)]),n=i.isDirectory(),s=i.isFile()?await St(r):void 0,c=n?await Rt(e,r):i.size;return{workspacePath:h(e),targetPath:h(r),name:d.basename(r),isDirectory:i.isDirectory(),isFile:i.isFile(),isSymbolicLink:a.isSymbolicLink(),size:c,mode:i.mode,modeOctal:_(i.mode),permissions:yt(i.mode),uid:i.uid,gid:i.gid,atimeMs:i.atimeMs,mtimeMs:i.mtimeMs,ctimeMs:i.ctimeMs,birthtimeMs:i.birthtimeMs,...s?{image:s}:{}}}async function _t(t){const e=gt(t.mode),r=!!t.recursive,{workspaceRoot:i,resolvedTargetPath:a}=await S(t),n=await G(i,a,r);for(const s of n)await Et(i,s),await o.chmod(s,e);return{ok:!0,workspacePath:h(i),targetPath:h(a),mode:e,modeOctal:_(e),recursive:r,changedCount:n.length}}async function Gt(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t),i=await x(e,r),a=await o.stat(i);if(!a.isFile())throw new Error(`Path is not a file: ${i}`);const n=d.extname(i).toLowerCase();if(n===".doc")return{workspacePath:h(e),filePath:h(i),kind:"unsupported",content:"",message:"\u6682\u4E0D\u652F\u6301\u65E7\u7248 .doc \u683C\u5F0F\u9884\u89C8\uFF0C\u8BF7\u53E6\u5B58\u4E3A .docx \u540E\u518D\u6253\u5F00\u3002",size:a.size,mtimeMs:a.mtimeMs};if(n!==".docx")throw new Error("Document preview only supports .docx files");return{workspacePath:h(e),filePath:h(i),kind:"html",content:"",size:a.size,mtimeMs:a.mtimeMs}}async function Zt(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t);return await o.mkdir(d.dirname(r),{recursive:!0}),await E(e,r),await o.writeFile(r,String(t.content??""),"utf-8"),{ok:!0,workspacePath:h(e),filePath:h(r)}}async function Ht(t){const{workspaceRoot:e,resolvedTargetPath:r}=await C(t),i=D(t.entryName),a=p(e,d.join(r,i));if(!(await o.stat(r)).isDirectory())throw new Error(`Path is not a directory: ${r}`);try{throw await o.access(a),new Error(`Path already exists: ${a}`)}catch(s){if((typeof s=="object"&&s!==null?Reflect.get(s,"code"):void 0)!=="ENOENT")throw s}return t.isDirectory?await o.mkdir(a,{recursive:!1}):(await o.mkdir(d.dirname(a),{recursive:!0}),await E(e,a),await o.writeFile(a,"","utf-8")),{ok:!0,workspacePath:h(e),targetPath:h(a),isDirectory:t.isDirectory}}async function Kt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await S(t),i=D(t.newName),a=p(e,d.join(d.dirname(r),i));if(a===r)return{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(a)};await o.stat(r);try{throw await o.access(a),new Error(`Path already exists: ${a}`)}catch(n){if((typeof n=="object"&&n!==null?Reflect.get(n,"code"):void 0)!=="ENOENT")throw n}return await o.rename(r,a),{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(a)}}async function Vt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await S(t),i=await C({workspacePath:t.workspacePath,targetPath:t.destinationPath});if(!(await o.stat(i.resolvedTargetPath)).isDirectory())throw new Error(`Destination is not a directory: ${i.resolvedTargetPath}`);if((await o.stat(r)).isDirectory()){const c=d.relative(r,i.resolvedTargetPath);if(c===""||!c.startsWith("..")&&!d.isAbsolute(c))throw new Error("Cannot move a directory into itself or its descendant")}const s=p(e,d.join(i.resolvedTargetPath,d.basename(r)));if(s===r)return{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(s),destinationPath:h(i.resolvedTargetPath)};try{throw await o.access(s),new Error(`Path already exists: ${s}`)}catch(c){if((typeof c=="object"&&c!==null?Reflect.get(c,"code"):void 0)!=="ENOENT")throw c}return await o.rename(r,s),{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(s),destinationPath:h(i.resolvedTargetPath)}}async function Xt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await S(t);return(await o.stat(r)).isDirectory()?await o.rm(r,{recursive:!0,force:!1}):await o.unlink(r),{ok:!0,workspacePath:h(e),targetPath:h(r)}}async function Yt(t){if(!Array.isArray(t.files)||t.files.length===0)throw new Error("files are required");const{workspaceRoot:e,resolvedTargetPath:r}=await Z(t);if(!(await o.stat(r)).isDirectory())throw new Error(`Path is not a directory: ${r}`);const a=[];for(const n of t.files){const s=$(n.originalname),c=mt(n.relativePath,n.originalname),u=p(e,d.join(r,c));await o.mkdir(d.dirname(u),{recursive:!0}),await E(e,u),await o.copyFile(n.path,u);let l;t.extractArchives&&H(u)&&(l=await Ct({workspacePath:e,archivePath:u,outputPath:Ft(r,s)})),a.push({fileName:s,targetPath:h(u),size:n.size,extracted:l})}return{ok:!0,workspacePath:h(e),targetPath:h(r),files:a}}async function Jt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await S(t),i=await o.stat(r),a=d.basename(r);return{workspacePath:h(e),targetPath:h(r),resolvedTargetPath:r,fileName:i.isDirectory()?`${a||"workspace"}.zip`:a,contentType:i.isDirectory()?"application/zip":zt(r),isDirectory:i.isDirectory()}}function zt(t){const e=d.extname(t).toLowerCase();return{".svg":"image/svg+xml",".svgz":"image/svg+xml",".ico":"image/x-icon",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".bmp":"image/bmp",".avif":"image/avif",".txt":"text/plain; charset=utf-8",".json":"application/json; charset=utf-8",".xml":"application/xml; charset=utf-8",".html":"text/html; charset=utf-8",".htm":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".js":"text/javascript; charset=utf-8",".md":"text/markdown; charset=utf-8",".csv":"text/csv; charset=utf-8",".pdf":"application/pdf",".zip":"application/zip",".mp3":"audio/mpeg",".wav":"audio/wav",".mp4":"video/mp4",".webm":"video/webm"}[e]||"application/octet-stream"}async function Qt(t,e){const r=new wt({zlib:{level:9}}),i=new Promise((a,n)=>{e.on("close",a),e.on("finish",a),r.on("error",n),e.on("error",n)});r.pipe(e),r.directory(t,!1),await r.finalize(),await i}async function Dt(t,e,r){let i=0,a;const n=O(t),s=n.pipe(dt.Parse({forceStream:!0}));try{for await(const c of s){if(a){await V(c);continue}const u=Tt(c);try{const l=I(e,u);if(A(r),c.type==="Directory"){await o.mkdir(l,{recursive:!0});continue}if(c.type!=="File")throw new Error(`Unsupported archive entry type: ${u}`);await o.mkdir(d.dirname(l),{recursive:!0}),await E(e,l),await Y(c,l,r),i+=1}catch(l){a=l,await V(c)}}}finally{n.destroy(),s.destroy()}if(a)throw a;return i}async function Lt(t,e,r,i){let a=0,n;const s=(c,u)=>{if(n)return!1;try{I(e,c),A(i);const l=String(u.type||"").toLowerCase();if(l==="symboliclink"||l==="link")throw new Error(`Archive links are not supported: ${c}`);if(l!=="file"&&l!=="oldfile"&&l!=="contiguousfile"&&l!=="directory")throw new Error(`Unsupported archive entry type: ${c}`);return typeof u.size=="number"&&X(i,u.size),l!=="directory"&&(a+=1),!0}catch(l){return n=l,!1}};if(await ut.x({file:t,cwd:e,gzip:r,strict:!0,filter:(c,u)=>s(c,u)}),n)throw n;return a}async function Wt(t,e,r){const i=K(d.basename(t)),a=I(e,i||"decompressed");return A(r),await o.mkdir(d.dirname(a),{recursive:!0}),await E(e,a),await Y(O(t).pipe(ht()),a,r),1}async function Ct(t){const{requestedRoot:e,workspaceRoot:r}=await k(t.workspacePath),{resolvedTargetPath:i}=await Z({workspacePath:t.workspacePath,targetPath:t.outputPath||""}),a=z(e,r,String(t.archivePath||"").trim()),n=await x(r,a);if(!(await o.stat(n)).isFile())throw new Error(`Archive path is not a file: ${n}`);if(await J(i)||await o.mkdir(i,{recursive:!0}),!(await o.stat(i)).isDirectory())throw new Error(`Output path is not a directory: ${i}`);const u=H(n);if(!u)throw new Error("Unsupported archive type. Supported: .zip, .tar, .tar.gz, .tgz, .gz");let l=0;const f={entries:0,totalBytes:0};return u==="zip"?l=await Dt(n,i,f):u==="tar"||u==="tgz"?l=await Lt(n,i,u==="tgz",f):l=await Wt(n,i,f),{ok:!0,workspacePath:h(r),archivePath:h(n),targetPath:h(i),extractedEntries:l}}function tt(t){const e=t.match(/^(.*?)\{([^}]+)\}(.*)$/);if(!e)return[t];const[,r,i,a]=e;return i.split(",").flatMap(n=>tt(r+n.trim()+a))}function et(t,e){const r=String(e||"").trim();if(!r||r==="*"||r==="*.*")return!0;const i=t.toLowerCase();return tt(r.toLowerCase()).some(n=>{if(n==="*")return!0;const s=n.replace(/\./g,"\\.").replace(/\*\*/g,"<<GLOBSTAR>>").replace(/\*/g,"[^/]*").replace(/\?/g,"[^/]").replace(/<<GLOBSTAR>>/g,".*");return new RegExp(`^${s}$`).test(i)})}function rt(t){return t===".git"||t==="node_modules"||t===".svn"||t===".hg"}const it=10*1024*1024,$t=1e3;async function te(t){const{workspaceRoot:e}=await k(t.workspacePath),r=String(t.keyword||"").trim();if(!r)throw new Error("keyword is required");const i=!!t.ignoreCase,a=String(t.fileMask||"").trim(),n=typeof t.maxResults=="number"&&t.maxResults>0?t.maxResults:$t,s=i?r.toLowerCase():r,u=(t.mode==="filename"?"filename":"content")==="filename",l=[];let f=0,w=!1;async function m(v){if(w)return;let F;try{F=await o.readdir(v,{withFileTypes:!0})}catch{return}for(const g of F){if(w)return;const T=p(e,d.join(v,g.name));if(g.isSymbolicLink())continue;if(g.isDirectory()){if(rt(g.name))continue;await m(T);continue}if(!g.isFile()||a&&!et(g.name,a))continue;f+=1;let N;try{N=await o.stat(T)}catch{continue}if(N.size>it)continue;if(u){const P=(i?g.name.toLowerCase():g.name).indexOf(s);if(P!==-1&&(l.push({filePath:h(T),lineNumber:0,lineContent:g.name,matchStart:P,matchEnd:P+r.length}),l.length>=n)){w=!0;return}continue}let b;try{b=await o.readFile(T,"utf-8")}catch{continue}const M=b.split(/\r?\n/);for(let R=0;R<M.length;R+=1){const P=M[R],nt=i?P.toLowerCase():P;let j=0;for(;;){const L=nt.indexOf(s,j);if(L===-1)break;if(l.push({filePath:h(T),lineNumber:R+1,lineContent:P,matchStart:L,matchEnd:L+r.length}),l.length>=n){w=!0;return}j=L+1}}}}return await m(e),{workspacePath:h(e),keyword:r,totalFiles:f,totalMatches:l.length,matches:l,truncated:w}}async function at(t,e,r,i,a){let n;try{n=await o.readFile(e,"utf-8")}catch{return{changed:!1,count:0}}const s=n;let c=0;if(a){const u=r.toLowerCase();let l=0;for(;;){const w=n.toLowerCase().indexOf(u,l);if(w===-1)break;n=n.slice(0,w)+i+n.slice(w+r.length),c+=1;const m=i.length||1;l=w+m}}else{let u=0;for(;;){const l=n.indexOf(r,u);if(l===-1)break;n=n.slice(0,l)+i+n.slice(l+r.length),c+=1;const f=i.length||1;u=l+f}}return n===s?{changed:!1,count:0}:(await E(t,e),await o.writeFile(e,n,"utf-8"),{changed:!0,count:c})}async function ee(t){const{workspaceRoot:e}=await k(t.workspacePath),r=String(t.keyword||"").trim();if(!r)throw new Error("keyword is required");const i=String(t.replacement??""),a=!!t.ignoreCase,n=String(t.fileMask||"").trim(),s=String(t.filePath||"").trim();let c=0,u=0;if(s){const{resolvedFilePath:f}=await W({workspacePath:t.workspacePath,filePath:s}),w=await at(e,f,r,i,a);return w.changed&&(c=1,u=w.count),{workspacePath:h(e),keyword:r,replacement:i,changedFiles:c,changedMatches:u}}async function l(f){let w;try{w=await o.readdir(f,{withFileTypes:!0})}catch{return}for(const m of w){const v=p(e,d.join(f,m.name));if(m.isSymbolicLink())continue;if(m.isDirectory()){if(rt(m.name))continue;await l(v);continue}if(!m.isFile()||n&&!et(m.name,n))continue;try{if((await o.stat(v)).size>it)continue}catch{continue}const F=await at(e,v,r,i,a);F.changed&&(c+=1,u+=F.count)}}return await l(e),{workspacePath:h(e),keyword:r,replacement:i,changedFiles:c,changedMatches:u}}export{_t as chmodWorkspaceEntry,Ht as createWorkspaceEntry,Xt as deleteWorkspaceEntry,Ct as extractWorkspaceArchive,qt as getWorkspaceEntryProperties,Ot as listWorkspaceDirectory,Vt as moveWorkspaceEntry,Gt as previewWorkspaceDocument,Ut as readWorkspaceFile,Kt as renameWorkspaceEntry,ee as replaceWorkspaceFiles,Jt as resolveWorkspaceDownloadTarget,te as searchWorkspaceFiles,Qt as streamWorkspaceDirectoryZip,Yt as uploadWorkspaceFiles,Zt as writeWorkspaceFile};
|
|
2
2
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import type { ACodeBuiltInTool } from "./built-in-file-tools.js";
|
|
3
|
+
import type { AwaitBgCommandResult } from "./background-command-manager.js";
|
|
4
|
+
export interface AwaitCompleteSubAgentResult {
|
|
5
|
+
subId: string;
|
|
6
|
+
status: string;
|
|
7
|
+
output: string;
|
|
8
|
+
error?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ACodeAwaitCompleteDeps {
|
|
11
|
+
agentId: string;
|
|
12
|
+
|
|
13
|
+
awaitSubAgents: ((subIds: string[], timeoutMs?: number) => Promise<AwaitCompleteSubAgentResult[]>) | null;
|
|
14
|
+
|
|
15
|
+
awaitBgCommands: (taskIds: string[], timeoutMs?: number) => Promise<Array<AwaitBgCommandResult | null>>;
|
|
16
|
+
}
|
|
17
|
+
export declare function createAwaitCompleteTool(deps: ACodeAwaitCompleteDeps): ACodeBuiltInTool;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const p=`Block and wait for one or more sub-agents AND/OR background commands to complete.
|
|
2
|
+
|
|
3
|
+
This is the unified replacement for the old await_sub_agents: it can wait for BOTH
|
|
4
|
+
sub-agents (spawned via sub_agent) and background commands (started via Bash with
|
|
5
|
+
wait_seconds=0 or n) in a single call.
|
|
6
|
+
|
|
7
|
+
All specified items must reach a terminal state before this returns (JOIN semantics):
|
|
8
|
+
- sub-agent: completed / failed / cancelled
|
|
9
|
+
- background command: completed / failed / killed
|
|
10
|
+
|
|
11
|
+
Returns a structured result with each item's outcome. For background commands only a
|
|
12
|
+
short status + exitCode is returned; use ReadBackgroundOutput(task_id, mode="tail")
|
|
13
|
+
to fetch full output.
|
|
14
|
+
|
|
15
|
+
Guidelines:
|
|
16
|
+
- Pass sub-agent IDs in 'sub_agent_ids' and/or background command task_ids in 'bg_cmd_ids'
|
|
17
|
+
- At least one of the two arrays must be non-empty
|
|
18
|
+
- Use timeout_ms to avoid waiting forever (0 = no timeout, default 0)
|
|
19
|
+
- After this returns, call poll_message to receive any pending messages`;function h(o){return{kind:"builtin",toolName:"await_complete",exposedName:"await_complete",description:p,inputSchema:{type:"object",properties:{sub_agent_ids:{type:"array",items:{type:"string"},description:"Array of sub-agent IDs to wait for (from sub_agent). Empty if none."},bg_cmd_ids:{type:"array",items:{type:"string"},description:"Array of background command task_ids to wait for (from Bash wait_seconds or ListBackgroundCommands). Empty if none."},timeout_ms:{type:"number",description:"Maximum time to wait in milliseconds, applied to the whole JOIN. 0 = no timeout (wait forever). Default: 0."}},additionalProperties:!1},async execute(i){const l=typeof i.timeout_ms=="number"?i.timeout_ms:0,m=i.sub_agent_ids,c=i.bg_cmd_ids,n=Array.isArray(m)?m.filter(t=>typeof t=="string"&&t.trim().length>0):[],u=Array.isArray(c)?c.filter(t=>typeof t=="string"&&t.trim().length>0):[];if(n.length===0&&u.length===0)return{title:"await_complete validation error",output:"Invalid input: provide at least one of 'sub_agent_ids' or 'bg_cmd_ids'.",metadata:{error:!0}};if(n.length>0&&!o.awaitSubAgents)return{title:"await_complete error",output:"sub_agent_ids provided but sub-agent manager is not enabled for this agent.",metadata:{error:!0}};try{let t=[];n.length>0&&o.awaitSubAgents&&(t=await o.awaitSubAgents(n,l)??[]);let a=[];u.length>0&&(a=await o.awaitBgCommands(u,l));const e=[],g=[],d=[];if(t.length>0){e.push(`=== ${t.length} sub-agent(s) ===`);for(const s of t)e.push(`[${s.status}] ${s.subId}`),s.error?(e.push("<task_error>"),e.push(s.error),e.push("</task_error>")):(e.push("<task_result>"),e.push(s.output||"(empty output)"),e.push("</task_result>")),e.push(""),g.push(s)}if(a.length>0){e.push(`=== ${a.length} background command(s) ===`);for(const s of a){if(!s){e.push("[not_found] (unknown task_id)"),e.push(""),d.push(null);continue}const r=[];s.timedOut&&r.push("timed_out"),s.aborted&&r.push("aborted"),e.push(`[${s.status}] ${s.taskId} exit=${s.exitCode??"?"}`+(r.length?` (${r.join(",")})`:"")),e.push(""),d.push(s)}}return{title:`awaited ${t.length+a.length} item(s)`,output:e.join(`
|
|
20
|
+
`),metadata:{total:t.length+a.length,sub_agents:g,bg_cmds:d}}}catch(t){return{title:"await_complete error",output:`Failed to await: ${t instanceof Error?t.message:String(t)}`,metadata:{error:!0}}}}}}export{h as createAwaitCompleteTool};
|
|
21
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
|
|
2
|
+
import { type BackgroundTaskStatus } from "./background-command-store.js";
|
|
3
|
+
export type { BackgroundTaskRecord, BackgroundTaskStatus } from "./background-command-store.js";
|
|
4
|
+
|
|
5
|
+
export interface BackgroundCommandResult {
|
|
6
|
+
taskId: string;
|
|
7
|
+
exitCode: number | null;
|
|
8
|
+
signal: string | null;
|
|
9
|
+
timedOut: boolean;
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
durationMs: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AwaitBgCommandResult {
|
|
16
|
+
taskId: string;
|
|
17
|
+
|
|
18
|
+
status: BackgroundTaskStatus;
|
|
19
|
+
exitCode: number | null;
|
|
20
|
+
signal: string | null;
|
|
21
|
+
timedOut: boolean;
|
|
22
|
+
|
|
23
|
+
aborted: boolean;
|
|
24
|
+
durationMs: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface StartCommandInput {
|
|
28
|
+
commandText: string;
|
|
29
|
+
agentId: string;
|
|
30
|
+
workspaceRoot: string;
|
|
31
|
+
cwd: string;
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
onOutput?: (event: {
|
|
34
|
+
stream: "stdout" | "stderr";
|
|
35
|
+
text: string;
|
|
36
|
+
}) => void;
|
|
37
|
+
|
|
38
|
+
onCompleted?: (event: BackgroundCompletedEvent) => void;
|
|
39
|
+
}
|
|
40
|
+
export interface BackgroundCompletedEvent {
|
|
41
|
+
taskId: string;
|
|
42
|
+
agentId: string;
|
|
43
|
+
status: BackgroundTaskStatus;
|
|
44
|
+
exitCode: number | null;
|
|
45
|
+
signal: string | null;
|
|
46
|
+
commandPreview: string;
|
|
47
|
+
outputLineCount: number;
|
|
48
|
+
outputBytes: number;
|
|
49
|
+
outputPath: string;
|
|
50
|
+
finishedAt: number;
|
|
51
|
+
killedReason?: string | null;
|
|
52
|
+
}
|
|
53
|
+
export interface TaskSummary {
|
|
54
|
+
taskId: string;
|
|
55
|
+
status: BackgroundTaskStatus;
|
|
56
|
+
command: string;
|
|
57
|
+
commandPreview: string;
|
|
58
|
+
cwd: string;
|
|
59
|
+
startedAt: number;
|
|
60
|
+
finishedAt: number | null;
|
|
61
|
+
exitCode: number | null;
|
|
62
|
+
signal: string | null;
|
|
63
|
+
outputLineCount: number;
|
|
64
|
+
outputBytes: number;
|
|
65
|
+
}
|
|
66
|
+
export interface ReadOutputArgs {
|
|
67
|
+
task_id: string;
|
|
68
|
+
mode?: "head" | "tail" | "offset" | "grep";
|
|
69
|
+
lines?: number;
|
|
70
|
+
offset?: number;
|
|
71
|
+
pattern?: string;
|
|
72
|
+
include_metadata?: boolean;
|
|
73
|
+
}
|
|
74
|
+
export interface ReadOutputResult {
|
|
75
|
+
taskId: string;
|
|
76
|
+
status: BackgroundTaskStatus;
|
|
77
|
+
mode: string;
|
|
78
|
+
lines: string[];
|
|
79
|
+
lineCount: number;
|
|
80
|
+
metadata?: {
|
|
81
|
+
totalLines: number;
|
|
82
|
+
totalBytes: number;
|
|
83
|
+
returnedBytes: number;
|
|
84
|
+
truncated: boolean;
|
|
85
|
+
hasMore: boolean;
|
|
86
|
+
outputFile: string;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export interface KillResult {
|
|
90
|
+
taskId: string;
|
|
91
|
+
status: BackgroundTaskStatus;
|
|
92
|
+
signal?: string;
|
|
93
|
+
exitCode?: number | null;
|
|
94
|
+
error?: string;
|
|
95
|
+
reason?: string;
|
|
96
|
+
}
|
|
97
|
+
export declare class BackgroundCommandManager {
|
|
98
|
+
private tasksByAgent;
|
|
99
|
+
private store;
|
|
100
|
+
|
|
101
|
+
private globalCount;
|
|
102
|
+
|
|
103
|
+
startCommand(input: StartCommandInput): {
|
|
104
|
+
taskId: string;
|
|
105
|
+
completion: Promise<BackgroundCommandResult>;
|
|
106
|
+
};
|
|
107
|
+
private spawnAndAttach;
|
|
108
|
+
private onOutput;
|
|
109
|
+
private appendToFile;
|
|
110
|
+
private finalizeTask;
|
|
111
|
+
|
|
112
|
+
private evictTask;
|
|
113
|
+
listTasks(agentId: string, statusFilter?: string): TaskSummary[];
|
|
114
|
+
private toSummary;
|
|
115
|
+
readOutput(agentId: string, args: ReadOutputArgs): Promise<ReadOutputResult>;
|
|
116
|
+
|
|
117
|
+
private readFromFile;
|
|
118
|
+
|
|
119
|
+
awaitCompletion(agentId: string, taskIds: string[], timeoutMs?: number): Promise<Array<AwaitBgCommandResult | null>>;
|
|
120
|
+
private awaitOne;
|
|
121
|
+
private taskToAwaitResult;
|
|
122
|
+
|
|
123
|
+
interruptAwaits(agentId: string, taskIds: Iterable<string>): void;
|
|
124
|
+
killTask(agentId: string, taskId: string): Promise<KillResult>;
|
|
125
|
+
|
|
126
|
+
private killProcessGroup;
|
|
127
|
+
|
|
128
|
+
disposeAgent(agentId: string): Promise<void>;
|
|
129
|
+
|
|
130
|
+
disposeAll(): Promise<void>;
|
|
131
|
+
|
|
132
|
+
reconcileOrphans(agentId: string): Promise<void>;
|
|
133
|
+
|
|
134
|
+
readSessionState(agentId: string): Promise<import("./background-command-store.js").BackgroundSessionState | null>;
|
|
135
|
+
|
|
136
|
+
markNotified(agentId: string, taskIds: string[]): Promise<void>;
|
|
137
|
+
private getOrCreateBucket;
|
|
138
|
+
private getTask;
|
|
139
|
+
private generateTaskId;
|
|
140
|
+
private persistTask;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export declare class BackgroundTaskError extends Error {
|
|
144
|
+
readonly code: string;
|
|
145
|
+
constructor(code: string, message: string);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export declare const backgroundCommandManager: BackgroundCommandManager;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import{spawn as S}from"node:child_process";import{promises as g}from"node:fs";import{createInterface as P}from"node:readline";import{randomBytes as T}from"node:crypto";import{prepareShellCommand as I,shellExecutable as L}from"./builtins/shellCommandPreparation.js";import{createShellOutputDecoder as w,decodeShellOutputChunk as p}from"./builtins/shellOutputDecoder.js";import{BackgroundOutputRingBuffer as O}from"./background-output-ringbuffer.js";import{BackgroundCommandStore as R}from"./background-command-store.js";const b=1e3,A=10*60*1e3,B=50*1024*1024,y=16,C=256,x=256*1024,_=500,v=5e3,D=256,k=5*60*1e3;class z{constructor(){this.tasksByAgent=new Map,this.store=new R}globalCount(){let t=0;for(const i of this.tasksByAgent.values())t+=i.size;return t}startCommand(t){const i=t.agentId,e=this.getOrCreateBucket(i);if(e.size>=y)throw new M("too_many_tasks",`Agent ${i} has ${e.size} background tasks (limit ${y}). Kill or wait for completion first.`);if(this.globalCount()>=C)throw new M("global_limit_reached",`Global background task limit ${C} reached.`);const n=this.generateTaskId(e),o=Math.min(t.timeoutMs??A,A),s=this.store.outputPathFor(i,n),u=t.commandText.length>80?`${t.commandText.slice(0,77)}...`:t.commandText,r={taskId:n,agentId:i,command:t.commandText,commandPreview:u,cwd:t.cwd,status:"running",startedAt:Date.now(),finishedAt:null,exitCode:null,signal:null,killedReason:null,timeoutMs:o,child:null,ringBuffer:new O,outputPath:s,outputWriteChain:Promise.resolve(),outputTruncated:!1,outputLineCount:0,outputBytes:0,notified:!1,completionWaiters:[],onCompleted:t.onCompleted,onOutput:t.onOutput,timeoutTimer:null,killEscalationTimer:null,retentionTimer:null,finalized:!1,stdoutDecoder:w(),stderrDecoder:w()},l=new Promise(a=>{r.completionResolve=a});return e.set(n,r),this.spawnAndAttach(r,t).catch(a=>{r.ringBuffer.push(`[ACode] spawn failed: ${a?.message??String(a)}
|
|
2
|
+
`),this.finalizeTask(r,-1,null,"spawn_error")}),this.persistTask(r),{taskId:n,completion:l}}async spawnAndAttach(t,i){const e=L(),n=await I(i.commandText,i.workspaceRoot,e),o=process.platform==="win32",s=S(e.command,[...e.argsPrefix,n.commandText],{cwd:i.cwd,env:process.env,detached:!o,stdio:["ignore","pipe","pipe"],windowsVerbatimArguments:o,windowsHide:!0});t.child=s,s.stdout?.on("data",u=>{const r=p(t.stdoutDecoder,u);this.onOutput(t,"stdout",r)}),s.stderr?.on("data",u=>{const r=p(t.stderrDecoder,u);this.onOutput(t,"stderr",r)}),s.on("error",u=>{this.onOutput(t,"stderr",`[ACode] child error: ${u.message}
|
|
3
|
+
`),t.finalized||this.finalizeTask(t,-1,null,"child_error")}),s.on("close",(u,r)=>{const l=p(t.stdoutDecoder,void 0,!0),a=p(t.stderrDecoder,void 0,!0);if(l&&this.onOutput(t,"stdout",l),a&&this.onOutput(t,"stderr",a),t.ringBuffer.flush(),!t.finalized){const c=t.killedReason??null;this.finalizeTask(t,u,r,c??void 0)}}),t.timeoutTimer=setTimeout(()=>{t.finalized||(t.killedReason="timeout",this.killProcessGroup(s))},t.timeoutMs),t.timeoutTimer.unref?.()}onOutput(t,i,e){if(!e)return;if(t.outputBytes>=B){if(!t.outputTruncated){t.outputTruncated=!0;const o=`
|
|
4
|
+
[ACode] output truncated at 50MB
|
|
5
|
+
`;t.ringBuffer.push(o),this.appendToFile(t,o)}t.ringBuffer.push(e);return}t.ringBuffer.push(e),t.onOutput?.({stream:i,text:e});const n=(e.match(/\n/g)??[]).length;t.outputLineCount+=n,t.outputBytes+=Buffer.byteLength(e,"utf-8"),this.appendToFile(t,e)}appendToFile(t,i){return t.outputBytes>B?Promise.resolve():(t.outputWriteChain=t.outputWriteChain.then(()=>g.appendFile(t.outputPath,i,"utf-8")).catch(e=>{t.ringBuffer.push(`[ACode] output write failed: ${e?.message??e}
|
|
6
|
+
`)}),t.outputWriteChain)}finalizeTask(t,i,e,n){if(t.finalized)return;t.finalized=!0,t.timeoutTimer&&(clearTimeout(t.timeoutTimer),t.timeoutTimer=null),t.killEscalationTimer&&(clearTimeout(t.killEscalationTimer),t.killEscalationTimer=null),t.child=null,t.finishedAt=Date.now();let o;n?(o="killed",t.killedReason=n):i===0?o="completed":o="failed",t.status=o,t.exitCode=i,t.signal=e;const s=t.ringBuffer.tail(1e3),u={taskId:t.taskId,exitCode:i,signal:e,timedOut:n==="timeout",stdout:s.join(`
|
|
7
|
+
`),stderr:"",durationMs:t.finishedAt-t.startedAt};t.completionResolve?.(u);const r={taskId:t.taskId,status:o,exitCode:i,signal:e,timedOut:n==="timeout",aborted:!1,durationMs:t.finishedAt-t.startedAt},l=t.completionWaiters;t.completionWaiters=[];for(const a of l)a(r);this.persistTask(t),t.onCompleted?.({taskId:t.taskId,agentId:t.agentId,status:o,exitCode:i,signal:e,commandPreview:t.commandPreview,outputLineCount:t.outputLineCount,outputBytes:t.outputBytes,outputPath:t.outputPath,finishedAt:t.finishedAt,killedReason:t.killedReason}),t.retentionTimer=setTimeout(()=>{this.evictTask(t.agentId,t.taskId)},k),t.retentionTimer.unref?.()}evictTask(t,i){const e=this.tasksByAgent.get(t);if(!e)return;const n=e.get(i);n&&(g.unlink(n.outputPath).catch(()=>{}),e.delete(i),e.size===0&&this.tasksByAgent.delete(t))}listTasks(t,i){const e=this.tasksByAgent.get(t);if(!e)return[];const n=[];for(const o of e.values())i&&i!=="all"&&o.status!==i||n.push(this.toSummary(o));return n.sort((o,s)=>s.startedAt-o.startedAt)}toSummary(t){return{taskId:t.taskId,status:t.status,command:t.command,commandPreview:t.commandPreview,cwd:t.cwd,startedAt:t.startedAt,finishedAt:t.finishedAt,exitCode:t.exitCode,signal:t.signal,outputLineCount:t.outputLineCount,outputBytes:t.outputBytes}}async readOutput(t,i){const e=String(i.task_id??""),n=this.getTask(t,e),o=i.mode??"tail",s=Math.min(Math.max(1,i.lines??50),_);if(!n)return{taskId:e,status:"killed",mode:o,lines:[],lineCount:0,metadata:{totalLines:0,totalBytes:0,returnedBytes:0,truncated:!1,hasMore:!1,outputFile:""}};let u=[],r=!1;if(o==="head")u=n.ringBuffer.head(s);else if(o==="tail")u=n.ringBuffer.tail(s);else if(o==="offset"){const d=Math.max(0,i.offset??0),f=n.ringBuffer.offset(d,s);if(f.length>0||n.ringBuffer.hasLine(d))u=f;else{const h=await this.readFromFile(n,"offset",d,s,void 0);u=h.lines,r=h.hasMore}}else if(o==="grep"){const d=String(i.pattern??"");if(d.length>D)return{taskId:e,status:n.status,mode:o,lines:[],lineCount:0,metadata:{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:0,truncated:!1,hasMore:!1,outputFile:n.outputPath}};let f;try{f=new RegExp(d,"i")}catch{return{taskId:e,status:n.status,mode:o,lines:[],lineCount:0,metadata:{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:0,truncated:!1,hasMore:!1,outputFile:n.outputPath}}}const h=await this.readFromFile(n,"grep",0,s,f);u=h.lines,r=h.hasMore}let l=0;const a=[];let c=!1;for(const d of u){if(a.length>=_){c=!0,r=!0;break}const f=Buffer.byteLength(d,"utf-8")+1;if(l+f>x){c=!0,r=!0;break}a.push(d),l+=f}const m=i.include_metadata!==!1;return{taskId:e,status:n.status,mode:o,lines:a,lineCount:a.length,metadata:m?{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:l,truncated:c,hasMore:r,outputFile:n.outputPath}:void 0}}async readFromFile(t,i,e,n,o){const s=[];let u=!1,r=0,l=0;try{const a=await g.open(t.outputPath,"r"),c=P({input:a.createReadStream({encoding:"utf-8"}),crlfDelay:1/0});for await(const m of c){if(i==="grep"&&s.length>=v){u=!0;break}if(i==="offset"){if(r<e){r++;continue}if(l>=n){u=!0;break}s.push(m),l++,r++}else{if(o.test(m)){if(l>=n){u=!0;break}s.push(m),l++}r++}}c.close(),await a.close()}catch{return{lines:[],hasMore:!1}}return{lines:s,hasMore:u}}async awaitCompletion(t,i,e){return Promise.all(i.map(n=>this.awaitOne(t,n,e)))}async awaitOne(t,i,e){const n=this.getTask(t,i);if(n)return n.status!=="running"?this.taskToAwaitResult(n):new Promise(u=>{let r=null;const l=a=>{r&&clearTimeout(r),u(a)};n.completionWaiters.push(l),e&&e>0&&(r=setTimeout(()=>{n.completionWaiters=n.completionWaiters.filter(a=>a!==l),u({taskId:i,status:"running",exitCode:null,signal:null,timedOut:!0,aborted:!1,durationMs:Date.now()-n.startedAt})},e),r.unref?.())});const s=(await this.store.readSession(t))?.tasks.find(u=>u.taskId===i);return s?s.status!=="running"?{taskId:i,status:s.status,exitCode:s.exitCode,signal:s.signal,timedOut:s.killedReason==="timeout",aborted:!1,durationMs:(s.finishedAt??Date.now())-s.startedAt}:{taskId:i,status:"killed",exitCode:null,signal:null,timedOut:!1,aborted:!1,durationMs:(s.finishedAt??Date.now())-s.startedAt}:null}taskToAwaitResult(t){return{taskId:t.taskId,status:t.status,exitCode:t.exitCode,signal:t.signal,timedOut:t.killedReason==="timeout",aborted:!1,durationMs:(t.finishedAt??Date.now())-t.startedAt}}interruptAwaits(t,i){const e=this.tasksByAgent.get(t);if(e)for(const n of i){const o=e.get(n);if(!o)continue;const s=o.completionWaiters;if(s.length===0)continue;o.completionWaiters=[];const u={taskId:n,status:"running",exitCode:null,signal:null,timedOut:!1,aborted:!0,durationMs:Date.now()-o.startedAt};for(const r of s)r(u)}}async killTask(t,i){const e=this.getTask(t,i);return e?e.status!=="running"?{taskId:i,status:e.status,exitCode:e.exitCode??void 0}:e.child?(e.killedReason="user_kill",this.killProcessGroup(e.child)?(e.killEscalationTimer&&clearTimeout(e.killEscalationTimer),e.killEscalationTimer=setTimeout(()=>{e.child&&!e.finalized&&this.killProcessGroup(e.child,!0)},b),e.killEscalationTimer.unref?.(),{taskId:i,status:"killed",signal:"SIGTERM"}):{taskId:i,status:e.status,error:"kill_failed",reason:"permission_denied"}):{taskId:i,status:e.status,error:"kill_failed",reason:"no_child"}:{taskId:i,status:"killed",error:"task_not_found"}}killProcessGroup(t,i=!1){const e=t.pid;if(!e)return!1;try{if(process.platform==="win32"){const n="/F",{spawnSync:o}=require("node:child_process");return o("taskkill",["/PID",String(e),"/T",n],{windowsHide:!0}),!0}try{process.kill(-e,i?"SIGKILL":"SIGTERM")}catch{process.kill(e,i?"SIGKILL":"SIGTERM")}return!0}catch{return!1}}async disposeAgent(t){const i=this.tasksByAgent.get(t);if(i){for(const e of i.values())e.status==="running"&&e.child&&(e.killedReason="session_disposed",this.killProcessGroup(e.child,!0)),e.timeoutTimer&&clearTimeout(e.timeoutTimer),e.killEscalationTimer&&clearTimeout(e.killEscalationTimer),e.retentionTimer&&clearTimeout(e.retentionTimer);this.tasksByAgent.delete(t)}await this.store.deleteAgent(t)}async disposeAll(){for(const[t,i]of this.tasksByAgent){for(const e of i.values())e.status==="running"&&e.child&&(e.killedReason="process_exit",this.killProcessGroup(e.child,!0)),e.timeoutTimer&&clearTimeout(e.timeoutTimer),e.killEscalationTimer&&clearTimeout(e.killEscalationTimer),e.retentionTimer&&clearTimeout(e.retentionTimer);this.tasksByAgent.delete(t)}}async reconcileOrphans(t){const i=await this.store.readSession(t);if(!i||i.tasks.length===0)return;let e=!1;for(const n of i.tasks)n.status==="running"&&(n.status="killed",n.killedReason="runtime_crashed",n.finishedAt=Date.now(),n.notified=!0,e=!0);e&&await this.store.persistSession(t,i.tasks)}async readSessionState(t){return this.store.readSession(t)}async markNotified(t,i){await this.store.markNotified(t,i)}getOrCreateBucket(t){let i=this.tasksByAgent.get(t);return i||(i=new Map,this.tasksByAgent.set(t,i)),i}getTask(t,i){const e=this.tasksByAgent.get(t);if(e&&/^[A-Za-z0-9]{8}$/.test(i))return e.get(i)}generateTaskId(t){for(let i=0;i<3;i++){const e=T(4).toString("hex").slice(0,8);if(!t.has(e))return e}return T(6).toString("hex").slice(0,8)}async persistTask(t){const i=await this.store.readSession(t.agentId)??{agentId:t.agentId,updatedAt:0,tasks:[]},e={taskId:t.taskId,agentId:t.agentId,command:t.command,commandPreview:t.commandPreview,cwd:t.cwd,status:t.status,startedAt:t.startedAt,finishedAt:t.finishedAt,exitCode:t.exitCode,signal:t.signal,outputPath:t.outputPath,outputLineCount:t.outputLineCount,outputBytes:t.outputBytes,notified:t.notified,killedReason:t.killedReason},n=i.tasks.findIndex(s=>s.taskId===t.taskId);n>=0?i.tasks[n]=e:i.tasks.push(e);const o=Date.now();i.tasks=i.tasks.filter(s=>s.status==="running"||!s.finishedAt||o-s.finishedAt<k),await this.store.persistSession(t.agentId,i.tasks)}}class M extends Error{constructor(t,i){super(i),this.name="BackgroundTaskError",this.code=t}}const Y=new z;export{z as BackgroundCommandManager,M as BackgroundTaskError,Y as backgroundCommandManager};
|
|
8
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
export type BackgroundTaskStatus = "running" | "completed" | "failed" | "killed";
|
|
3
|
+
|
|
4
|
+
export interface BackgroundTaskRecord {
|
|
5
|
+
taskId: string;
|
|
6
|
+
agentId: string;
|
|
7
|
+
command: string;
|
|
8
|
+
commandPreview: string;
|
|
9
|
+
cwd: string;
|
|
10
|
+
status: BackgroundTaskStatus;
|
|
11
|
+
startedAt: number;
|
|
12
|
+
finishedAt: number | null;
|
|
13
|
+
exitCode: number | null;
|
|
14
|
+
signal: string | null;
|
|
15
|
+
outputPath: string;
|
|
16
|
+
outputLineCount: number;
|
|
17
|
+
outputBytes: number;
|
|
18
|
+
|
|
19
|
+
notified: boolean;
|
|
20
|
+
|
|
21
|
+
killedReason?: string | null;
|
|
22
|
+
}
|
|
23
|
+
export interface BackgroundSessionState {
|
|
24
|
+
agentId: string;
|
|
25
|
+
updatedAt: number;
|
|
26
|
+
tasks: BackgroundTaskRecord[];
|
|
27
|
+
}
|
|
28
|
+
export declare class BackgroundCommandStore {
|
|
29
|
+
|
|
30
|
+
private writeChains;
|
|
31
|
+
private chain;
|
|
32
|
+
private setChain;
|
|
33
|
+
|
|
34
|
+
readSession(agentId: string): Promise<BackgroundSessionState | null>;
|
|
35
|
+
|
|
36
|
+
persistSession(agentId: string, tasks: BackgroundTaskRecord[]): Promise<void>;
|
|
37
|
+
|
|
38
|
+
markNotified(agentId: string, taskIds: string[]): Promise<void>;
|
|
39
|
+
|
|
40
|
+
outputPathFor(agentId: string, taskId: string): string;
|
|
41
|
+
|
|
42
|
+
deleteAgent(agentId: string): Promise<void>;
|
|
43
|
+
|
|
44
|
+
listAgents(): Promise<string[]>;
|
|
45
|
+
private backupCorrupt;
|
|
46
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{promises as a}from"node:fs";import f from"node:os";import c from"node:path";import{renameWithRetry as w}from"./fs-utils.js";const p=c.join(f.homedir(),".acode","bg-tasks");function m(s){return String(s).replace(/[^a-zA-Z0-9_-]/g,"_")}function u(s){return c.join(p,m(s))}function h(s){return c.join(u(s),"state.json")}class S{constructor(){this.writeChains=new Map}chain(t){return this.writeChains.get(t)??Promise.resolve()}setChain(t,r){this.writeChains.set(t,r.catch(()=>{}))}async readSession(t){try{const r=await a.readFile(h(t),"utf-8"),e=JSON.parse(r);return{agentId:t,updatedAt:typeof e.updatedAt=="number"?e.updatedAt:0,tasks:Array.isArray(e.tasks)?e.tasks:[]}}catch(r){if(r?.code==="ENOENT")return null;if(r instanceof SyntaxError)return await this.backupCorrupt(t).catch(()=>{}),null;throw r}}async persistSession(t,r){const e=h(t),n=this.chain(t).then(async()=>{await a.mkdir(u(t),{recursive:!0});const o={agentId:t,updatedAt:Date.now(),tasks:r},i=`${e}.tmp`;await a.writeFile(i,JSON.stringify(o,null,2),"utf-8"),await w(i,e)});this.setChain(t,n),await n}async markNotified(t,r){const e=await this.readSession(t);if(!e)return;const n=new Set(r);let o=!1;for(const i of e.tasks)n.has(i.taskId)&&!i.notified&&(i.notified=!0,o=!0);o&&await this.persistSession(t,e.tasks)}outputPathFor(t,r){return c.join(u(t),`${r}.out`)}async deleteAgent(t){const r=this.chain(t).then(()=>a.rm(u(t),{recursive:!0,force:!0}));this.setChain(t,r),await r.catch(()=>{})}async listAgents(){try{return(await a.readdir(p,{withFileTypes:!0})).filter(r=>r.isDirectory()).map(r=>r.name)}catch(t){if(t?.code==="ENOENT")return[];throw t}}async backupCorrupt(t){const r=h(t),e=`${r}.corrupt-${Date.now()}`;await a.copyFile(r,e).catch(()=>{})}}export{S as BackgroundCommandStore};
|
|
2
|
+
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
|
|
2
|
+
import type { ACodeBuiltInTool, BackgroundToolDeps } from "./built-in-file-tools.js";
|
|
3
|
+
export declare function createListBackgroundCommandsTool(agentId: string, deps: BackgroundToolDeps): ACodeBuiltInTool;
|
|
4
|
+
export declare function createKillBackgroundCommandTool(agentId: string, deps: BackgroundToolDeps): ACodeBuiltInTool;
|
|
5
|
+
export declare function createReadBackgroundOutputTool(agentId: string, deps: BackgroundToolDeps): ACodeBuiltInTool;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const s=`List all background commands for the current agent, including running and recently completed ones.
|
|
2
|
+
|
|
3
|
+
Returns task_id, status, command (preview), startedAt, finishedAt, exitCode, outputLineCount, outputBytes.
|
|
4
|
+
Does NOT include output content (use read_background_output to fetch output).`,d=`Terminate a running background command by task_id.
|
|
5
|
+
|
|
6
|
+
Sends SIGTERM to the process group, then SIGKILL after 1s if still alive.
|
|
7
|
+
No-op (idempotent) if the task already finished.
|
|
8
|
+
Cross-agent task_id returns task_not_found (does not leak existence).`,r=`Read the output (stdout+stderr merged, interleaved in arrival order) of a background command.
|
|
9
|
+
|
|
10
|
+
Query modes:
|
|
11
|
+
- head: first N lines
|
|
12
|
+
- tail (default): last N lines (fastest, in-memory)
|
|
13
|
+
- offset: from line X (0-based) take N lines (reads output file, bypasses memory cap)
|
|
14
|
+
- grep: filter lines by regex (JS syntax, case-insensitive)
|
|
15
|
+
|
|
16
|
+
Output capped at 256KB / 500 lines per call; truncated=true means more is available.`;function u(a,o){return{kind:"builtin",toolName:"ListBackgroundCommands",exposedName:"ListBackgroundCommands",description:s,inputSchema:{type:"object",properties:{status_filter:{type:"string",enum:["running","completed","failed","killed","all"],description:"Filter by status. Defaults to 'all'.",default:"all"}},additionalProperties:!1},async execute(t){const e=typeof t.status_filter=="string"?t.status_filter:"all",i=o.manager.listTasks(a,e);return{title:`${i.length} background commands`,output:JSON.stringify(i.map(n=>({taskId:n.taskId,status:n.status,command:n.commandPreview,cwd:n.cwd,startedAt:new Date(n.startedAt).toISOString(),finishedAt:n.finishedAt?new Date(n.finishedAt).toISOString():null,exitCode:n.exitCode,outputLineCount:n.outputLineCount,outputBytes:n.outputBytes})),null,2),metadata:{tasks:i,count:i.length}}}}}function l(a,o){return{kind:"builtin",toolName:"KillBackgroundCommand",exposedName:"KillBackgroundCommand",description:d,inputSchema:{type:"object",properties:{task_id:{type:"string",description:"The task_id returned by Bash(wait_seconds=...) or ListBackgroundCommands."}},required:["task_id"],additionalProperties:!1},async execute(t){const e=typeof t.task_id=="string"?t.task_id:"",i=await o.manager.killTask(a,e);return{title:`kill ${e}: ${i.status}`,output:JSON.stringify(i,null,2),metadata:i}}}}function p(a,o){return{kind:"builtin",toolName:"ReadBackgroundOutput",exposedName:"ReadBackgroundOutput",description:r,inputSchema:{type:"object",properties:{task_id:{type:"string",description:"The task_id to read output from."},mode:{type:"string",enum:["head","tail","offset","grep"],description:"head=first N, tail=last N (default), offset=from line X take N, grep=regex filter.",default:"tail"},lines:{type:"integer",description:"Number of lines (head/tail/offset). Default 50, max 500.",default:50,minimum:1,maximum:500},offset:{type:"integer",description:"Starting line number (0-based) for offset mode.",minimum:0},pattern:{type:"string",description:"Regex pattern for grep mode (JS syntax, case-insensitive)."},include_metadata:{type:"boolean",description:"Include totalLines/totalBytes/truncated/hasMore/outputFile in response.",default:!0}},required:["task_id"],additionalProperties:!1},async execute(t){const e=await o.manager.readOutput(a,{task_id:typeof t.task_id=="string"?t.task_id:"",mode:t.mode==="head"||t.mode==="tail"||t.mode==="offset"||t.mode==="grep"?t.mode:"tail",lines:typeof t.lines=="number"?t.lines:50,offset:typeof t.offset=="number"?t.offset:0,pattern:typeof t.pattern=="string"?t.pattern:void 0,include_metadata:t.include_metadata!==!1});return{title:`read ${e.taskId} (${e.mode}): ${e.lineCount} lines`,output:e.lines.join(`
|
|
17
|
+
`),metadata:e}}}}export{l as createKillBackgroundCommandTool,u as createListBackgroundCommandsTool,p as createReadBackgroundOutputTool};
|
|
18
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
export declare class BackgroundOutputRingBuffer {
|
|
3
|
+
private lines;
|
|
4
|
+
private bytes;
|
|
5
|
+
private partialLine;
|
|
6
|
+
|
|
7
|
+
push(text: string): void;
|
|
8
|
+
|
|
9
|
+
flush(): void;
|
|
10
|
+
private enforceLimits;
|
|
11
|
+
|
|
12
|
+
head(n: number): string[];
|
|
13
|
+
|
|
14
|
+
tail(n: number): string[];
|
|
15
|
+
|
|
16
|
+
offset(offset: number, limit: number): string[];
|
|
17
|
+
|
|
18
|
+
getLineCount(): number;
|
|
19
|
+
|
|
20
|
+
getByteCount(): number;
|
|
21
|
+
|
|
22
|
+
hasLine(lineIndex: number): boolean;
|
|
23
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const n=1e3,h=262144;class r{constructor(){this.lines=[],this.bytes=0,this.partialLine=""}push(t){if(!t)return;this.partialLine+=t;const i=this.partialLine.split(`
|
|
2
|
+
`);this.partialLine=i.pop()??"";for(const s of i)this.lines.push(s),this.bytes+=Buffer.byteLength(s,"utf-8");this.enforceLimits()}flush(){this.partialLine&&(this.lines.push(this.partialLine),this.bytes+=Buffer.byteLength(this.partialLine,"utf-8"),this.partialLine="",this.enforceLimits())}enforceLimits(){for(;this.lines.length>1e3;){const t=this.lines.shift();t!==void 0&&(this.bytes-=Buffer.byteLength(t,"utf-8"))}for(;this.bytes>262144&&this.lines.length>1;){const t=this.lines.shift();t!==void 0&&(this.bytes-=Buffer.byteLength(t,"utf-8"))}this.bytes<0&&(this.bytes=0)}head(t){return this.lines.slice(0,Math.max(0,t))}tail(t){const i=Math.max(0,this.lines.length-t);return this.lines.slice(i)}offset(t,i){const s=Math.max(0,t);return this.lines.slice(s,s+Math.max(0,i))}getLineCount(){return this.lines.length}getByteCount(){return this.bytes+Buffer.byteLength(this.partialLine,"utf-8")}hasLine(t){return t>=0&&t<this.lines.length}}export{r as BackgroundOutputRingBuffer};
|
|
3
|
+
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { type CommandOutputSink } from "./builtins/shellCommandRunner.js";
|
|
2
|
+
import type { BackgroundCommandManager, BackgroundCompletedEvent } from "./background-command-manager.js";
|
|
3
|
+
|
|
4
|
+
export interface BackgroundToolDeps {
|
|
5
|
+
manager: BackgroundCommandManager;
|
|
6
|
+
|
|
7
|
+
emitCompleted?: (event: BackgroundCompletedEvent) => void;
|
|
8
|
+
}
|
|
2
9
|
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
3
10
|
[key: string]: JsonValue;
|
|
4
11
|
};
|
|
@@ -34,4 +41,4 @@ export interface ResolvedWorkspaceTarget {
|
|
|
34
41
|
export declare function ensureInsideWorkspace(workspaceRoot: string, targetPath: string): string;
|
|
35
42
|
|
|
36
43
|
export declare function resolveWorkspaceTarget(workingDirectory: string, rawFilePath: string): Promise<ResolvedWorkspaceTarget>;
|
|
37
|
-
export declare function createBuiltInFileTools(workingDirectory: string, agentId?: string, onFileChange?: OnAgentFileChange): ACodeBuiltInTool[];
|
|
44
|
+
export declare function createBuiltInFileTools(workingDirectory: string, agentId?: string, onFileChange?: OnAgentFileChange, backgroundDeps?: BackgroundToolDeps): ACodeBuiltInTool[];
|