aws-runtime-bridge 1.9.185 → 1.9.189

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +1767 -1640
  2. package/README.md +256 -256
  3. package/dist/adapter/AcodeSdkAdapter.js +3 -3
  4. package/dist/adapter/types.js +1 -1
  5. package/dist/browser/browser-pool.d.ts +2 -0
  6. package/dist/browser/browser-pool.js +1 -1
  7. package/dist/config.d.ts +12 -0
  8. package/dist/config.js +2 -2
  9. package/dist/index.js +1 -1
  10. package/dist/remote-desktop/win32-api.js +1 -1
  11. package/dist/routes/background-tasks.js +4 -4
  12. package/dist/routes/dashboard.js +17 -17
  13. package/dist/routes/file-browser.js +1 -1
  14. package/dist/routes/terminal.js +19 -19
  15. package/dist/services/acode-bg-manager.js +1 -1
  16. package/dist/services/auto-register.js +1 -1
  17. package/dist/services/instance-features.d.ts +9 -0
  18. package/dist/services/instance-features.js +1 -1
  19. package/dist/services/launch-manager.d.ts +33 -0
  20. package/dist/services/launch-manager.js +7 -7
  21. package/dist/services/launch-streams.d.ts +2 -0
  22. package/dist/services/launch-streams.js +4 -4
  23. package/dist/services/panel-auth.d.ts +4 -0
  24. package/dist/services/panel-auth.js +1 -1
  25. package/dist/services/plugin-handler-adapter.js +2 -2
  26. package/dist/services/port-detector.js +5 -5
  27. package/dist/services/workspace-files.d.ts +4 -0
  28. package/dist/services/workspace-files.js +1 -1
  29. package/dist/utils/dynamic-import.d.ts +31 -0
  30. package/dist/utils/dynamic-import.js +2 -0
  31. package/dist/utils/sdk-package-loader.js +1 -1
  32. package/node_modules/playwright/cli.js +0 -0
  33. package/node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh +0 -0
  34. package/node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh +0 -0
  35. package/node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh +0 -0
  36. package/node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh +0 -0
  37. package/node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh +0 -0
  38. package/node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh +0 -0
  39. package/node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh +0 -0
  40. package/node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh +0 -0
  41. package/node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh +0 -0
  42. package/node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh +0 -0
  43. package/node_modules/playwright-core/cli.js +0 -0
  44. package/node_modules/playwright-core/lib/webp_codec.wasm +0 -0
  45. package/node_modules/playwright-core/lib/xdg-open +0 -0
  46. package/package/acode/dist/await-complete-tool.js +3 -3
  47. package/package/acode/dist/mcpToolNames.js +1 -1
  48. package/package/acode/dist/runtime.d.ts +9 -0
  49. package/package/acode/dist/runtime.js +20 -21
  50. package/package/acode/dist/sub-agent-manager.d.ts +33 -0
  51. package/package/acode/dist/sub-agent-manager.js +9 -1
  52. package/package/acode/dist/sub-agent-tools.d.ts +4 -0
  53. package/package/acode/dist/sub-agent-tools.js +27 -12
  54. package/package/acode/dist/subagent-handback.d.ts +16 -0
  55. package/package/acode/dist/subagent-handback.js +7 -0
  56. package/package/acode/dist/tool-allocation.js +1 -1
  57. package/package/acode/package.json +38 -38
  58. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +14 -5
  59. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  60. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +31 -1
  61. package/package/aws-client-agent-mcp/dist/mcp-server.js +16 -16
  62. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +23 -1
  63. package/package/aws-client-agent-mcp/dist/mcp-tools.js +35 -19
  64. package/package/aws-client-agent-mcp/dist/message-buffer.d.ts +10 -0
  65. package/package/aws-client-agent-mcp/dist/message-buffer.js +1 -1
  66. package/package/aws-client-agent-mcp/dist/status-reporter.js +1 -1
  67. package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
  68. package/package/aws-client-agent-mcp/dist/types.d.ts +84 -6
  69. package/package/aws-client-agent-mcp/package.json +53 -53
  70. package/package.json +134 -132
  71. /package/package/acode/dist/grammars/{grammars/tree-sitter-bash.wasm → tree-sitter-bash.wasm} +0 -0
  72. /package/package/acode/dist/grammars/{grammars/tree-sitter-c-sharp.wasm → tree-sitter-c-sharp.wasm} +0 -0
  73. /package/package/acode/dist/grammars/{grammars/tree-sitter-c.wasm → tree-sitter-c.wasm} +0 -0
  74. /package/package/acode/dist/grammars/{grammars/tree-sitter-cpp.wasm → tree-sitter-cpp.wasm} +0 -0
  75. /package/package/acode/dist/grammars/{grammars/tree-sitter-go.wasm → tree-sitter-go.wasm} +0 -0
  76. /package/package/acode/dist/grammars/{grammars/tree-sitter-java.wasm → tree-sitter-java.wasm} +0 -0
  77. /package/package/acode/dist/grammars/{grammars/tree-sitter-javascript.wasm → tree-sitter-javascript.wasm} +0 -0
  78. /package/package/acode/dist/grammars/{grammars/tree-sitter-jsx.wasm → tree-sitter-jsx.wasm} +0 -0
  79. /package/package/acode/dist/grammars/{grammars/tree-sitter-lua.wasm → tree-sitter-lua.wasm} +0 -0
  80. /package/package/acode/dist/grammars/{grammars/tree-sitter-php.wasm → tree-sitter-php.wasm} +0 -0
  81. /package/package/acode/dist/grammars/{grammars/tree-sitter-python.wasm → tree-sitter-python.wasm} +0 -0
  82. /package/package/acode/dist/grammars/{grammars/tree-sitter-ruby.wasm → tree-sitter-ruby.wasm} +0 -0
  83. /package/package/acode/dist/grammars/{grammars/tree-sitter-rust.wasm → tree-sitter-rust.wasm} +0 -0
  84. /package/package/acode/dist/grammars/{grammars/tree-sitter-tsx.wasm → tree-sitter-tsx.wasm} +0 -0
  85. /package/package/acode/dist/grammars/{grammars/tree-sitter-typescript.wasm → tree-sitter-typescript.wasm} +0 -0
@@ -1,2 +1,2 @@
1
- import{getAgentOwner as P}from"./agent-ownership.js";import{getEffective as N,hasAnyDefault as D}from"./capability-config.js";const j=new Set(["disabled","collapsed","expanded"]);function v(e){if(e===!0)return"expanded";if(e===!1)return"disabled";if(typeof e=="string"&&j.has(e))return e}const b={},se="desktop",I="browser",S="agentSys.launchItem",x="agentSys.hire",O="agentSys.skillInstall",R="agentSys.abilityDev",z="pencil",G="draw",H="office",k="collaboration",h="collaboration.task",m="collaboration.meeting",L="collaboration.debug",U="collaboration.fileHistory",J="email",V=new Set,W=new Set([I,z,G,H,S,x,O,R,h,m,L,U,J]),X=[["agentSys","agentSys."],[k,"collaboration."]],q=new Map([["task",h],["meeting",m],["debug",L],["fileHistory",U],["launch",S],["hire",x],["abilityMarket",O],["abilityDev",R]]);function le(e){return q.get(e)??e}function w(e){for(const[t,n]of X)if(e.startsWith(n))return t}const Q=new Set,y=new Map,_=new Map,a=new Map,Z=["fileReadOutside","commandExecution","fileModification","fileModificationOutside"],$=new Set(["allow","ask","deny"]);function ee(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;const t=e,n={};let o=!1;for(const r of Z){const i=t[r];typeof i=="string"&&$.has(i)?(n[r]=i,o=!0):n[r]="allow"}return o?n:null}function K(e){if(e==null)return{...b};let t=e;if(typeof e=="string")try{t=JSON.parse(e)}catch{t=null}if(typeof t!="object"||t===null||Array.isArray(t))return{...b};const n={};for(const[o,r]of Object.entries(t)){if(Q.has(o))continue;const i=v(r);i!==void 0&&(n[o]=i)}return n}function ue(e,t){if(!e)return;y.set(e,K(t));let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n=="object"&&n!==null&&!Array.isArray(n)){const o=ee(n.toolPermissions);o?a.set(e,o):a.delete(e)}else a.delete(e)}function te(e){return y.get(e)??{...b}}function ce(e,t){if(!e)return;if(t==null){_.delete(e);return}const n=K(t);if(Object.keys(n).length===0){_.delete(e);return}_.set(e,n)}function ne(e){return _.get(e)??{}}function oe(e,t){const n=te(e),o=ne(e),r=w(t);if(r&&(n[r]??o[r])==="disabled")return"disabled";const i=n[t]??o[t];return i!==void 0?i:V.has(t)?"expanded":W.has(t)?"collapsed":"disabled"}function fe(e,t){return oe(e,t)!=="disabled"}function ae(e){y.delete(e),a.delete(e),f.delete(e),T.delete(e)}function pe(e){return a.get(e)??null}function Ee(e){return a.get(e)??{fileReadOutside:"allow",commandExecution:"allow",fileModification:"allow",fileModificationOutside:"allow"}}const M=["skills","mcp","plugins"],f=new Map,T=new Map;function Y(e){if(typeof e!="object"||e===null||Array.isArray(e))return;const t={};for(const[n,o]of Object.entries(e))n.trim()&&typeof o=="boolean"&&(t[n.trim()]=o);return t}function Ae(e,t){if(!e)return;if(t==null){f.delete(e);return}let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n!="object"||n===null||Array.isArray(n)){f.delete(e);return}const o=n,r={};let i=!1;for(const A of M){const l=Y(o[A]);l&&(r[A]=l,i=!0)}i?f.set(e,r):f.delete(e);const s=o.plugins,u={};let E=!1;if(typeof s=="object"&&s!==null&&!Array.isArray(s))for(const[A,l]of Object.entries(s)){const d=A.trim();if(d){if(typeof l=="boolean"){const c=r.plugins??{};c[d]=l,r.plugins=c,i=!0;continue}if(l!==null&&typeof l=="object"&&!Array.isArray(l)){const c=l,B=c.enabled!==!1,g=typeof c.url=="string"?c.url:void 0,C=typeof c.sha256=="string"?c.sha256:void 0,F=r.plugins??{};F[d]=B,r.plugins=F,i=!0,g&&(u[d]={url:g,sha256:C},E=!0)}}}E?T.set(e,u):T.delete(e)}function de(e){return f.get(e)??null}const p=new Map;function ye(e,t){if(!e)return;if(t==null){p.delete(e);return}let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n!="object"||n===null||Array.isArray(n)){p.delete(e);return}const o=n,r={};let i=!1;for(const s of M){const u=Y(o[s]);u&&(r[s]=u,i=!0)}i?p.set(e,r):p.delete(e)}function _e(e){return p.get(e)??null}function Te(e){return T.get(e)??null}function be(e,t,n){const o=P(e);if(D(o,t))return N(o,e,t,n);const i=p.get(e)?.[t]?.[n];if(i!==void 0)return i;const s=f.get(e);if(!s)return!0;const u=s[t];if(!u)return!0;const E=u[n];return E===void 0?!0:E}function ge(){return y.size}export{R as ABILITY_DEV_FEATURE_KEY,I as BROWSER_FEATURE_KEY,M as CAPABILITY_TYPES,L as COLLABORATION_DEBUG_FEATURE_KEY,k as COLLABORATION_FEATURE_KEY,U as COLLABORATION_FILE_HISTORY_FEATURE_KEY,m as COLLABORATION_MEETING_FEATURE_KEY,h as COLLABORATION_TASK_FEATURE_KEY,se as DESKTOP_FEATURE_KEY,G as DRAW_FEATURE_KEY,J as EMAIL_FEATURE_KEY,q as GROUP_KEY_TO_FEATURE,x as HIRE_FEATURE_KEY,S as LAUNCH_ITEM_FEATURE_KEY,H as OFFICE_FEATURE_KEY,z as PENCIL_FEATURE_KEY,O as SKILL_INSTALL_FEATURE_KEY,ae as clearAgentFeatures,de as getAgentCapabilities,_e as getAgentCapabilitiesInherited,te as getAgentFeatures,ne as getAgentInheritedFeatures,Te as getAgentPluginSources,pe as getAgentToolPermissions,oe as getFeatureState,ge as instanceFeaturesCacheSize,be as isCapabilityEnabled,fe as isFeatureEnabled,v as normalizeFeatureState,Ee as resolveAgentToolPermissions,le as resolveGroupFeatureKey,Ae as setAgentCapabilities,ye as setAgentCapabilitiesInherited,ue as setAgentFeatures,ce as setAgentInheritedFeatures};
1
+ import{getAgentOwner as P}from"./agent-ownership.js";import{getEffective as D,hasAnyDefault as v}from"./capability-config.js";const j=new Set(["disabled","collapsed","expanded"]);function I(e){if(e===!0)return"expanded";if(e===!1)return"disabled";if(typeof e=="string"&&j.has(e))return e}const b={},le="desktop",z="browser",F="agentSys.launchItem",x="agentSys.hire",S="agentSys.skillInstall",R="agentSys.abilityDev",G="pencil",H="draw",k="office",V="collaboration",L="collaboration.task",h="collaboration.meeting",m="collaboration.debug",U="collaboration.fileHistory",J="email",K="collaboration.voice",W=new Set,X=new Set([z,G,H,k,F,x,S,R,L,h,m,U,J,K]),q=[["agentSys","agentSys."],[V,"collaboration."]],w=new Map([["task",L],["meeting",h],["debug",m],["fileHistory",U],["voice",K],["launch",F],["hire",x],["abilityMarket",S],["abilityDev",R]]);function ue(e){return w.get(e)??e}function Q(e){for(const[t,n]of q)if(e.startsWith(n))return t}const Z=new Set,y=new Map,_=new Map,a=new Map,$=["fileReadOutside","commandExecution","fileModification","fileModificationOutside"],ee=new Set(["allow","ask","deny"]);function te(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;const t=e,n={};let o=!1;for(const r of $){const i=t[r];typeof i=="string"&&ee.has(i)?(n[r]=i,o=!0):n[r]="allow"}return o?n:null}function Y(e){if(e==null)return{...b};let t=e;if(typeof e=="string")try{t=JSON.parse(e)}catch{t=null}if(typeof t!="object"||t===null||Array.isArray(t))return{...b};const n={};for(const[o,r]of Object.entries(t)){if(Z.has(o))continue;const i=I(r);i!==void 0&&(n[o]=i)}return n}function ce(e,t){if(!e)return;y.set(e,Y(t));let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n=="object"&&n!==null&&!Array.isArray(n)){const o=te(n.toolPermissions);o?a.set(e,o):a.delete(e)}else a.delete(e)}function ne(e){return y.get(e)??{...b}}function fe(e,t){if(!e)return;if(t==null){_.delete(e);return}const n=Y(t);if(Object.keys(n).length===0){_.delete(e);return}_.set(e,n)}function oe(e){return _.get(e)??{}}function re(e,t){const n=ne(e),o=oe(e),r=Q(t);if(r&&(n[r]??o[r])==="disabled")return"disabled";const i=n[t]??o[t];return i!==void 0?i:W.has(t)?"expanded":X.has(t)?"collapsed":"disabled"}function ae(e,t){return re(e,t)!=="disabled"}function pe(e){y.delete(e),a.delete(e),f.delete(e),T.delete(e)}function Ee(e){return a.get(e)??null}function Ae(e){return a.get(e)??{fileReadOutside:"allow",commandExecution:"allow",fileModification:"allow",fileModificationOutside:"allow"}}const C=["skills","mcp","plugins"],f=new Map,T=new Map;function M(e){if(typeof e!="object"||e===null||Array.isArray(e))return;const t={};for(const[n,o]of Object.entries(e))n.trim()&&typeof o=="boolean"&&(t[n.trim()]=o);return t}function de(e,t){if(!e)return;if(t==null){f.delete(e);return}let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n!="object"||n===null||Array.isArray(n)){f.delete(e);return}const o=n,r={};let i=!1;for(const A of C){const l=M(o[A]);l&&(r[A]=l,i=!0)}i?f.set(e,r):f.delete(e);const s=o.plugins,u={};let E=!1;if(typeof s=="object"&&s!==null&&!Array.isArray(s))for(const[A,l]of Object.entries(s)){const d=A.trim();if(d){if(typeof l=="boolean"){const c=r.plugins??{};c[d]=l,r.plugins=c,i=!0;continue}if(l!==null&&typeof l=="object"&&!Array.isArray(l)){const c=l,B=c.enabled!==!1,O=typeof c.url=="string"?c.url:void 0,N=typeof c.sha256=="string"?c.sha256:void 0,g=r.plugins??{};g[d]=B,r.plugins=g,i=!0,O&&(u[d]={url:O,sha256:N},E=!0)}}}E?T.set(e,u):T.delete(e)}function ye(e){return f.get(e)??null}const p=new Map;function _e(e,t){if(!e)return;if(t==null){p.delete(e);return}let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n!="object"||n===null||Array.isArray(n)){p.delete(e);return}const o=n,r={};let i=!1;for(const s of C){const u=M(o[s]);u&&(r[s]=u,i=!0)}i?p.set(e,r):p.delete(e)}function Te(e){return p.get(e)??null}function be(e){return T.get(e)??null}function Oe(e,t,n){const o=P(e);if(v(o,t))return D(o,e,t,n);const i=p.get(e)?.[t]?.[n];if(i!==void 0)return i;const s=f.get(e);if(!s)return!0;const u=s[t];if(!u)return!0;const E=u[n];return E===void 0?!0:E}function ge(){return y.size}export{R as ABILITY_DEV_FEATURE_KEY,z as BROWSER_FEATURE_KEY,C as CAPABILITY_TYPES,m as COLLABORATION_DEBUG_FEATURE_KEY,V as COLLABORATION_FEATURE_KEY,U as COLLABORATION_FILE_HISTORY_FEATURE_KEY,h as COLLABORATION_MEETING_FEATURE_KEY,L as COLLABORATION_TASK_FEATURE_KEY,K as COLLABORATION_VOICE_FEATURE_KEY,le as DESKTOP_FEATURE_KEY,H as DRAW_FEATURE_KEY,J as EMAIL_FEATURE_KEY,w as GROUP_KEY_TO_FEATURE,x as HIRE_FEATURE_KEY,F as LAUNCH_ITEM_FEATURE_KEY,k as OFFICE_FEATURE_KEY,G as PENCIL_FEATURE_KEY,S as SKILL_INSTALL_FEATURE_KEY,pe as clearAgentFeatures,ye as getAgentCapabilities,Te as getAgentCapabilitiesInherited,ne as getAgentFeatures,oe as getAgentInheritedFeatures,be as getAgentPluginSources,Ee as getAgentToolPermissions,re as getFeatureState,ge as instanceFeaturesCacheSize,Oe as isCapabilityEnabled,ae as isFeatureEnabled,I as normalizeFeatureState,Ae as resolveAgentToolPermissions,ue as resolveGroupFeatureKey,de as setAgentCapabilities,_e as setAgentCapabilitiesInherited,ce as setAgentFeatures,fe as setAgentInheritedFeatures};
2
2
 
@@ -199,6 +199,25 @@ export declare class LaunchManager {
199
199
  private restored;
200
200
 
201
201
  private readonly portsProbeInflight;
202
+
203
+
204
+
205
+
206
+
207
+
208
+
209
+ private readonly knownPorts;
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+ private readonly portReprobeTimers;
218
+
219
+ private readonly portReprobeTokens;
220
+ private portReprobeSeq;
202
221
  private constructor();
203
222
  static getInstance(): LaunchManager;
204
223
 
@@ -277,6 +296,7 @@ export declare class LaunchManager {
277
296
 
278
297
 
279
298
 
299
+
280
300
  listRuns(options?: {
281
301
  withPorts?: boolean;
282
302
  }): Promise<LaunchRunSummary[]>;
@@ -293,6 +313,7 @@ export declare class LaunchManager {
293
313
 
294
314
 
295
315
 
316
+
296
317
  publishRunningPorts(): Promise<void>;
297
318
 
298
319
 
@@ -327,8 +348,20 @@ export declare class LaunchManager {
327
348
 
328
349
 
329
350
 
351
+
352
+
353
+
330
354
  private publishRunStatus;
331
355
 
356
+ private buildStatusFrame;
357
+
358
+
359
+
360
+
361
+ private schedulePortReprobe;
362
+
363
+ private clearPortReprobe;
364
+
332
365
 
333
366
 
334
367
  private persist;
@@ -1,12 +1,12 @@
1
- import{exec as _,spawn as z}from"node:child_process";import{promises as F}from"node:fs";import A from"node:os";import M from"node:path";import{promisify as J}from"node:util";import{atomicWriteJsonFile as U,withFileLock as G}from"../utils/file-utils.js";import{createLogger as V}from"../utils/logger.js";import{LaunchMetricsMonitor as X}from"./launch-metrics.js";import{getLaunchStreamHub as P}from"./launch-streams.js";import{getListeningPortsForProcessTrees as k}from"./port-detector.js";import{isProcessRunning as L,terminateProcessTree as E}from"./process-detector.js";import{RingBuffer as O}from"./ring-buffer.js";const C=J(_),m=V("launch-manager"),D=5e3,B=4096,K=1500,Y=20;class H extends Error{constructor(t){super(`\u542F\u52A8\u9879\u5DF2\u5728\u8FD0\u884C: pid=${t.pid}`),this.name="LaunchAlreadyRunningError",this.existing=t}}function N(){return M.join(A.tmpdir(),"agentswork-runtime-bridge","launch-runs.json")}function Z(l,t){return l.replace(/\$\{([^}]+)\}/g,(e,s)=>{const r=s.trim(),i=r.toUpperCase();if(i==="WORKSPACE")return t.workspacePath||"";if(i==="JAVA_HOME")return t.jdkPath||process.env.JAVA_HOME||"";if(i==="HOME")return A.homedir();if(t.env&&t.env[r]!==void 0)return t.env[r];if(t.env){for(const[n,a]of Object.entries(t.env))if(n.toUpperCase()===i)return a}return e})}function Q(l){const t={...process.env};l.env&&Object.assign(t,l.env);for(const e of Object.keys(t))if(e.toUpperCase()==="PATH"&&e!=="PATH"){const s=t[e];delete t[e],t.PATH===void 0&&typeof s=="string"&&(t.PATH=s)}if(l.jdkPath){t.JAVA_HOME=l.jdkPath;const e=M.join(l.jdkPath,"bin"),s=M.delimiter;t.PATH=t.PATH?`${e}${s}${t.PATH}`:e}return t}const q=256,tt=120;class W{constructor(t=()=>{}){this.utf8Probe=new TextDecoder("utf-8",{fatal:!0}),this.utf8=new TextDecoder("utf-8"),this.gbk=new TextDecoder("gbk"),this.mode=null,this.buffered=[],this.bufferedSize=0,this.flushTimer=null,this.onFlush=t}decode(t){return this.mode!==null?(this.mode==="gbk"?this.gbk:this.utf8).decode(t,{stream:!0}):(this.buffered.push(t),this.bufferedSize+=t.length,this.bufferedSize>=q?this.commit():(this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.onFlush(this.commit())},tt)),""))}finalize(){return this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.mode===null?this.commit():(this.mode==="gbk"?this.gbk:this.utf8).decode()}commit(){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.mode!==null)return"";const t=Buffer.concat(this.buffered,this.bufferedSize);this.buffered=[],this.bufferedSize=0;try{return this.utf8Probe.decode(t),this.mode="utf8",this.utf8.decode(t)}catch{return this.mode="gbk",this.gbk.decode(t)}}}function et(l){const t=l.length>0&&!l.endsWith(`
2
- `)?l+`
3
- `:l;return t.length>B?t.slice(-B):t}async function st(l){const t=A.platform();for(let e=0;e<6;e+=1){try{if(t==="win32"){const s=`Get-CimInstance Win32_Process -Filter "ParentProcessId = ${l} AND Name <> 'conhost.exe'" | Select-Object -First 1 ProcessId | ConvertTo-Json -Compress`,r=Buffer.from(s,"utf16le").toString("base64"),{stdout:i}=await C(`powershell -NoProfile -NonInteractive -EncodedCommand ${r}`,{encoding:"utf8",timeout:5e3,windowsHide:!0}),n=i.replace(/#\s*<\s*CLIXML[\s\S]*?(?=\{|\[|$)/g,"").trim(),a=JSON.parse(n||"null"),h=Number(a?.ProcessId);if(Number.isFinite(h)&&h>0)return h}else{const{stdout:s}=await C(`pgrep -P ${l} | head -n 1`,{encoding:"utf8",timeout:3e3}),r=Number(s.trim());if(Number.isFinite(r)&&r>0)return r}}catch{}await new Promise(s=>setTimeout(s,300))}return null}class S{constructor(){this.runs=new Map,this.logs=new Map,this.startupWaiters=new Map,this.readinessMatchers=new Map,this.logListeners=new Map,this.metricsMonitor=new X(()=>this.runningRefs()),this.restored=!1,this.portsProbeInflight=new Map}static getInstance(){return S.instance===null&&(S.instance=new S),S.instance}runningRefs(){const t=[];for(const e of this.runs.values())e.state==="running"&&e.pid>0&&t.push({configId:e.configId,pid:e.pid});return t}async start(t){const e=t.configId;if(!e||!e.trim())throw new Error("configId is required");if(!t.command||!t.command.trim())throw new Error("command is required");let s=null;if(t.readinessPattern&&t.readinessPattern.trim())try{s=new RegExp(t.readinessPattern.trim())}catch(o){throw new Error(`readinessPattern \u6B63\u5219\u8BED\u6CD5\u65E0\u6548: ${o.message}`)}const r=t.startedBy?.trim()||void 0;await this.ensureRestored();const i=this.runs.get(e);if(i&&i.state==="running"&&await L(i.pid))throw new H(i);const n=Z(t.command,{workspacePath:t.workspacePath,jdkPath:t.jdkPath,env:t.env}),a=t.cwd||t.workspacePath||process.cwd(),h=Q(t);m.info(`[start] \u542F\u52A8\u547D\u4EE4: configId=${e}, cwd=${a}, command=${n}`);let g;try{g=z(n,{cwd:a,env:h,shell:!0,windowsHide:!0})}catch(o){const c=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${o.message}`;throw m.error(`[start] spawn \u5931\u8D25: configId=${e}, error=${c}`),new Error(c)}const w=g.pid??0,T={configId:e,pid:w,state:"running",startedAt:new Date().toISOString(),command:n,cwd:a,...r?{startedBy:r}:{}};this.runs.set(e,T),this.publishRunStatus(e,!0),this.metricsMonitor.clear(e),this.metricsMonitor.ensureRunning();let p=this.logs.get(e);p||(p=new O(D),this.logs.set(e,p));const I=p.getSinceIndex(-1).nextIndex;s?this.readinessMatchers.set(e,{pattern:s,fromIndex:I+1}):this.readinessMatchers.delete(e);const b=p.append({stream:"stdout",text:`> ${n}
4
- `});P().publish(e,"logs",b.index,b.data);let R=null;(async()=>{const o=await st(w),c=this.runs.get(e);o&&c?.pid===w&&(R=o,this.runs.set(e,{...c,pid:o}),await this.persist(),this.publishRunStatus(e))})();const y=o=>o!==void 0&&(o.pid===w||o.pid===R),u=new W(o=>{f("stdout",o)}),d=new W(o=>{f("stderr",o)}),f=(o,c)=>{const x=et(c);if(x){const $=p.append({stream:o,text:x});P().publish(e,"logs",$.index,$.data);const v=this.logListeners.get(e);if(v&&v.size>0)for(const j of v)try{j($)}catch{}}};return g.stdout.on("data",o=>{f("stdout",u.decode(o))}),g.stderr.on("data",o=>{f("stderr",d.decode(o))}),g.on("error",o=>{f("stderr",`[\u542F\u52A8\u5931\u8D25] ${o.message}
5
- `);const c=this.runs.get(e);c&&y(c)&&c.state==="running"&&(this.runs.set(e,{...c,state:"exited",exitedAt:new Date().toISOString(),exitCode:-1}),P().publishState(e,{configId:e,state:"exited",exitCode:-1}),this.publishRunStatus(e),this.persist(),this.resolveStartupWaiters(e,"exited",-1))}),g.on("exit",(o,c)=>{f("stdout",u.finalize()),f("stderr",d.finalize()),f("stderr",`
1
+ import{exec as H,spawn as j}from"node:child_process";import{promises as z}from"node:fs";import A from"node:os";import $ from"node:path";import{promisify as F}from"node:util";import{atomicWriteJsonFile as J,withFileLock as U}from"../utils/file-utils.js";import{createLogger as V}from"../utils/logger.js";import{LaunchMetricsMonitor as G}from"./launch-metrics.js";import{getLaunchStreamHub as w}from"./launch-streams.js";import{getListeningPortsForProcessTrees as X}from"./port-detector.js";import{isProcessRunning as E,terminateProcessTree as v}from"./process-detector.js";import{RingBuffer as L}from"./ring-buffer.js";const O=F(H),P=V("launch-manager"),_=5e3,D=4096,Y=1500,K=2e3,Z=5e3,Q=12e4,q=20;class C extends Error{constructor(t){super(`\u542F\u52A8\u9879\u5DF2\u5728\u8FD0\u884C: pid=${t.pid}`),this.name="LaunchAlreadyRunningError",this.existing=t}}function B(){return $.join(A.tmpdir(),"agentswork-runtime-bridge","launch-runs.json")}function tt(p,t){return p.replace(/\$\{([^}]+)\}/g,(e,s)=>{const r=s.trim(),n=r.toUpperCase();if(n==="WORKSPACE")return t.workspacePath||"";if(n==="JAVA_HOME")return t.jdkPath||process.env.JAVA_HOME||"";if(n==="HOME")return A.homedir();if(t.env&&t.env[r]!==void 0)return t.env[r];if(t.env){for(const[i,a]of Object.entries(t.env))if(i.toUpperCase()===n)return a}return e})}function et(p){const t={...process.env};p.env&&Object.assign(t,p.env);for(const e of Object.keys(t))if(e.toUpperCase()==="PATH"&&e!=="PATH"){const s=t[e];delete t[e],t.PATH===void 0&&typeof s=="string"&&(t.PATH=s)}if(p.jdkPath){t.JAVA_HOME=p.jdkPath;const e=$.join(p.jdkPath,"bin"),s=$.delimiter;t.PATH=t.PATH?`${e}${s}${t.PATH}`:e}return t}const st=256,rt=120;class N{constructor(t=()=>{}){this.utf8Probe=new TextDecoder("utf-8",{fatal:!0}),this.utf8=new TextDecoder("utf-8"),this.gbk=new TextDecoder("gbk"),this.mode=null,this.buffered=[],this.bufferedSize=0,this.flushTimer=null,this.onFlush=t}decode(t){return this.mode!==null?(this.mode==="gbk"?this.gbk:this.utf8).decode(t,{stream:!0}):(this.buffered.push(t),this.bufferedSize+=t.length,this.bufferedSize>=st?this.commit():(this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.onFlush(this.commit())},rt)),""))}finalize(){return this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.mode===null?this.commit():(this.mode==="gbk"?this.gbk:this.utf8).decode()}commit(){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.mode!==null)return"";const t=Buffer.concat(this.buffered,this.bufferedSize);this.buffered=[],this.bufferedSize=0;try{return this.utf8Probe.decode(t),this.mode="utf8",this.utf8.decode(t)}catch{return this.mode="gbk",this.gbk.decode(t)}}}function nt(p){const t=p.length>0&&!p.endsWith(`
2
+ `)?p+`
3
+ `:p;return t.length>D?t.slice(-D):t}async function it(p){const t=A.platform();for(let e=0;e<6;e+=1){try{if(t==="win32"){const s=`Get-CimInstance Win32_Process -Filter "ParentProcessId = ${p} AND Name <> 'conhost.exe'" | Select-Object -First 1 ProcessId | ConvertTo-Json -Compress`,r=Buffer.from(s,"utf16le").toString("base64"),{stdout:n}=await O(`powershell -NoProfile -NonInteractive -EncodedCommand ${r}`,{encoding:"utf8",timeout:5e3,windowsHide:!0}),i=n.replace(/#\s*<\s*CLIXML[\s\S]*?(?=\{|\[|$)/g,"").trim(),a=JSON.parse(i||"null"),u=Number(a?.ProcessId);if(Number.isFinite(u)&&u>0)return u}else{const{stdout:s}=await O(`pgrep -P ${p} | head -n 1`,{encoding:"utf8",timeout:3e3}),r=Number(s.trim());if(Number.isFinite(r)&&r>0)return r}}catch{}await new Promise(s=>setTimeout(s,300))}return null}class y{constructor(){this.runs=new Map,this.logs=new Map,this.startupWaiters=new Map,this.readinessMatchers=new Map,this.logListeners=new Map,this.metricsMonitor=new G(()=>this.runningRefs()),this.restored=!1,this.portsProbeInflight=new Map,this.knownPorts=new Map,this.portReprobeTimers=new Map,this.portReprobeTokens=new Map,this.portReprobeSeq=0}static getInstance(){return y.instance===null&&(y.instance=new y),y.instance}runningRefs(){const t=[];for(const e of this.runs.values())e.state==="running"&&e.pid>0&&t.push({configId:e.configId,pid:e.pid});return t}async start(t){const e=t.configId;if(!e||!e.trim())throw new Error("configId is required");if(!t.command||!t.command.trim())throw new Error("command is required");let s=null;if(t.readinessPattern&&t.readinessPattern.trim())try{s=new RegExp(t.readinessPattern.trim())}catch(o){throw new Error(`readinessPattern \u6B63\u5219\u8BED\u6CD5\u65E0\u6548: ${o.message}`)}const r=t.startedBy?.trim()||void 0;await this.ensureRestored();const n=this.runs.get(e);if(n&&n.state==="running"&&await E(n.pid))throw new C(n);const i=tt(t.command,{workspacePath:t.workspacePath,jdkPath:t.jdkPath,env:t.env}),a=t.cwd||t.workspacePath||process.cwd(),u=et(t);P.info(`[start] \u542F\u52A8\u547D\u4EE4: configId=${e}, cwd=${a}, command=${i}`);let l;try{l=j(i,{cwd:a,env:u,shell:!0,windowsHide:!0})}catch(o){const c=`\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${o.message}`;throw P.error(`[start] spawn \u5931\u8D25: configId=${e}, error=${c}`),new Error(c)}const f=l.pid??0,b={configId:e,pid:f,state:"running",startedAt:new Date().toISOString(),command:i,cwd:a,...r?{startedBy:r}:{}};this.runs.set(e,b),this.knownPorts.delete(e),this.clearPortReprobe(e),this.publishRunStatus(e,!0),this.metricsMonitor.clear(e),this.metricsMonitor.ensureRunning();let m=this.logs.get(e);m||(m=new L(_),this.logs.set(e,m));const k=m.getSinceIndex(-1).nextIndex;s?this.readinessMatchers.set(e,{pattern:s,fromIndex:k+1}):this.readinessMatchers.delete(e);const R=m.append({stream:"stdout",text:`> ${i}
4
+ `});w().publish(e,"logs",R.index,R.data);let x=null;(async()=>{const o=await it(f),c=this.runs.get(e);o&&c?.pid===f&&(x=o,this.runs.set(e,{...c,pid:o}),await this.persist(),this.publishRunStatus(e))})();const T=o=>o!==void 0&&(o.pid===f||o.pid===x),d=new N(o=>{g("stdout",o)}),h=new N(o=>{g("stderr",o)}),g=(o,c)=>{const S=nt(c);if(S){const I=m.append({stream:o,text:S});w().publish(e,"logs",I.index,I.data);const M=this.logListeners.get(e);if(M&&M.size>0)for(const W of M)try{W(I)}catch{}}};return l.stdout.on("data",o=>{g("stdout",d.decode(o))}),l.stderr.on("data",o=>{g("stderr",h.decode(o))}),l.on("error",o=>{g("stderr",`[\u542F\u52A8\u5931\u8D25] ${o.message}
5
+ `);const c=this.runs.get(e);c&&T(c)&&c.state==="running"&&(this.runs.set(e,{...c,state:"exited",exitedAt:new Date().toISOString(),exitCode:-1}),this.knownPorts.delete(e),this.clearPortReprobe(e),w().publishState(e,{configId:e,state:"exited",exitCode:-1}),this.publishRunStatus(e),this.persist(),this.resolveStartupWaiters(e,"exited",-1))}),l.on("exit",(o,c)=>{g("stdout",d.finalize()),g("stderr",h.finalize()),g("stderr",`
6
6
  [\u8FDB\u7A0B\u9000\u51FA] code=${o??"-"}${c?` signal=${c}`:""}
7
- `);const x=this.runs.get(e);x&&y(x)&&x.state==="running"&&(this.runs.set(e,{...x,state:"exited",exitedAt:new Date().toISOString(),exitCode:o}),P().publishState(e,{configId:e,state:"exited",exitCode:o}),this.publishRunStatus(e),this.persist(),this.resolveStartupWaiters(e,"exited",o))}),await this.persist(),T}async stop(t,e="manual",s){await this.ensureRestored();const r=this.runs.get(t);if(!r||r.state!=="running")return{success:!1,message:"\u542F\u52A8\u9879\u672A\u5728\u8FD0\u884C",pid:r?.pid};const i=s?.trim()||void 0;m.info(`[stop] \u7EC8\u6B62\u8FDB\u7A0B\u6811: configId=${t}, pid=${r.pid}, reason=${e}${i?`, actor=${i}`:""}`),this.runs.set(t,{...r,state:"stopped",exitedAt:new Date().toISOString(),...i?{stoppedBy:i}:{}});const n=await E(r.pid),a=e==="shutdown"?`
7
+ `);const S=this.runs.get(e);S&&T(S)&&S.state==="running"&&(this.runs.set(e,{...S,state:"exited",exitedAt:new Date().toISOString(),exitCode:o}),this.knownPorts.delete(e),this.clearPortReprobe(e),w().publishState(e,{configId:e,state:"exited",exitCode:o}),this.publishRunStatus(e),this.persist(),this.resolveStartupWaiters(e,"exited",o))}),await this.persist(),b}async stop(t,e="manual",s){await this.ensureRestored();const r=this.runs.get(t);if(!r||r.state!=="running")return{success:!1,message:"\u542F\u52A8\u9879\u672A\u5728\u8FD0\u884C",pid:r?.pid};const n=s?.trim()||void 0;P.info(`[stop] \u7EC8\u6B62\u8FDB\u7A0B\u6811: configId=${t}, pid=${r.pid}, reason=${e}${n?`, actor=${n}`:""}`),this.runs.set(t,{...r,state:"stopped",exitedAt:new Date().toISOString(),...n?{stoppedBy:n}:{}}),this.knownPorts.delete(t),this.clearPortReprobe(t);const i=await v(r.pid),a=e==="shutdown"?`
8
8
  [bridge \u505C\u6B62\uFF0C\u8FDB\u7A0B\u5DF2\u8054\u52A8\u7EC8\u6B62]
9
9
  `:`
10
10
  [\u5DF2\u624B\u52A8\u505C\u6B62]
11
- `,h=this.logs.get(t)?.append({stream:"stderr",text:a});return h&&P().publish(t,"logs",h.index,h.data),P().publishState(t,{configId:t,state:"stopped"}),this.publishRunStatus(t),await this.persist(),this.resolveStartupWaiters(t,"stopped",void 0),{success:n.failed===0,message:n.failed===0?"\u8FDB\u7A0B\u5DF2\u505C\u6B62":`\u90E8\u5206\u8FDB\u7A0B\u672A\u80FD\u7EC8\u6B62\uFF08terminated=${n.terminated}, failed=${n.failed}\uFF09`,pid:r.pid}}async restart(t){await this.ensureRestored();const e=this.runs.get(t.configId);return e&&e.state==="running"&&await this.stop(t.configId,"manual",t.startedBy),await this.start(t)}async startBatch(t,e){await this.ensureRestored();const s=await Promise.all(t.map(async i=>{try{const n=await this.start(i);return{configId:i.configId,ok:!0,run:n}}catch(n){return n instanceof H?{configId:i.configId,ok:!0,skipped:!0,message:"\u5F53\u524D\u5DF2\u5904\u4E8E\u542F\u52A8/\u6B63\u5728\u542F\u52A8\u72B6\u6001\uFF0C\u8DF3\u8FC7",run:n.existing}:{configId:i.configId,ok:!1,error:n.message}}}));if(e>0){const i=await Promise.all(s.map(async n=>{if(!n.ok||n.skipped)return n;try{const a=await this.waitStartupResult(n.configId,e);return{...n,wait:a}}catch(a){return{...n,error:a.message}}}));s.splice(0,s.length,...i)}const r={total:s.length,started:0,skipped:0,failed:0,ready:0,exited:0,stopped:0,timeout:0};for(const i of s){if(!i.ok){r.failed+=1;continue}if(i.skipped){r.skipped+=1;continue}r.started+=1,i.wait&&(r[i.wait.outcome]+=1)}return{items:s,summary:r}}async stopAll(){await this.ensureRestored();const t=Array.from(this.runs.values()).filter(s=>s.state==="running");let e=0;for(const s of t)try{const r=await this.stop(s.configId,"shutdown");r.success?e++:m.warn(`[stopAll] \u542F\u52A8\u9879\u672A\u80FD\u5B8C\u5168\u7EC8\u6B62: configId=${s.configId}, message=${r.message}`)}catch(r){m.warn(`[stopAll] \u505C\u6B62\u542F\u52A8\u9879\u5931\u8D25: configId=${s.configId}, error=${r.message}`)}return{running:t.length,stopped:e}}async waitStartupResult(t,e){const s=this.runs.get(t);if(!s)throw new Error("launch run not found");const r=Date.now(),i=()=>(this.logs.get(t)?.getLastN(Y)??[]).map(a=>a.data);if(s.state!=="running")return{outcome:s.state==="stopped"?"stopped":"exited",waitedMs:0,...s.state==="exited"?{exitCode:s.exitCode??null}:{},logTail:i()};const n=this.readinessMatchers.get(t);if(n){const a=this.scanReadinessMatch(t,n);if(a!==null)return{outcome:"ready",waitedMs:0,matchedLine:a,logTail:i()}}return await new Promise(a=>{let h=!1,g=null,w=null,T=!1,p=null;const I=()=>{g!==null&&(clearInterval(g),g=null),w!==null&&(clearTimeout(w),w=null);const u=this.startupWaiters.get(t);if(u&&(u.delete(R),u.size===0&&this.startupWaiters.delete(t)),p!==null){const d=this.logListeners.get(t);d&&(d.delete(p),d.size===0&&this.logListeners.delete(t)),p=null}},b=u=>{h||(h=!0,I(),a(u))},R=(u,d)=>{b({outcome:u==="stopped"?"stopped":"exited",waitedMs:Date.now()-r,...u==="exited"?{exitCode:d??null}:{},logTail:i()})};let y=this.startupWaiters.get(t);if(y||(y=new Set,this.startupWaiters.set(t,y)),y.add(R),n){p=d=>{if(!(h||d.index<n.fromIndex)){for(const f of d.data.text.split(/\r?\n/))if(f&&n.pattern.test(f)){b({outcome:"ready",waitedMs:Date.now()-r,matchedLine:f.trim(),logTail:i()});return}}};let u=this.logListeners.get(t);u||(u=new Set,this.logListeners.set(t,u)),u.add(p)}else{const u=async()=>{if(h||T)return;const d=this.runs.get(t);if(!(!d||d.state!=="running"||d.pid<=0)){T=!0;try{const o=(await k([d.pid])).get(d.pid)??[];if(o.length>0&&!h){const c=this.runs.get(t);c?.state==="running"&&c.pid===d.pid&&b({outcome:"ready",waitedMs:Date.now()-r,ports:o,logTail:i()})}}catch{}finally{T=!1}}};g=setInterval(()=>{u()},K),u()}w=setTimeout(()=>{b({outcome:"timeout",waitedMs:Date.now()-r,logTail:i()})},e)})}scanReadinessMatch(t,e){const s=this.logs.get(t);if(!s)return null;for(const r of s.getSinceIndex(e.fromIndex-1).entries)for(const i of r.data.text.split(/\r?\n/))if(i&&e.pattern.test(i))return i.trim();return null}resolveStartupWaiters(t,e,s){const r=this.startupWaiters.get(t);if(!(!r||r.size===0)){this.startupWaiters.delete(t);for(const i of r)try{i(e,s)}catch{}}}async listRuns(t){await this.ensureRestored();const s=t?.withPorts??!0?Array.from(this.runs.values()).filter(n=>n.state==="running"&&n.pid>0).map(n=>n.pid):[];let r=new Map;if(s.length>0)try{r=await this.probePorts(s)}catch(n){m.debug(`[listRuns] \u7AEF\u53E3\u63A2\u6D4B\u5931\u8D25: ${n.message}`)}const i=[];for(const n of this.runs.values()){const a=this.logs.get(n.configId);i.push({...n,logTail:a?a.getLastN(20).map(h=>h.data):[],nextLogIndex:a?a.getSinceIndex(-1).nextIndex:0,ports:n.state==="running"?r.get(n.pid)??[]:[],metrics:this.metricsMonitor.getLatest(n.configId)??void 0})}return i}async probePorts(t){const e=[...t].sort((i,n)=>i-n).join(","),s=this.portsProbeInflight.get(e);if(s)return s;const r=k(t).finally(()=>{this.portsProbeInflight.get(e)===r&&this.portsProbeInflight.delete(e)});return this.portsProbeInflight.set(e,r),r}async publishRunningPorts(){const t=this.runningRefs();if(t.length===0)return;let e=new Map;try{e=await this.probePorts(t.map(s=>s.pid))}catch(s){m.debug(`[publishRunningPorts] \u7AEF\u53E3\u63A2\u6D4B\u5931\u8D25: ${s.message}`);return}for(const s of t){const r=this.runs.get(s.configId);!r||r.state!=="running"||r.pid!==s.pid||P().publishStatusRun({...r,ports:e.get(s.pid)??[]})}}async getLogs(t,e){await this.ensureRestored();const s=this.runs.get(t);if(!s)return null;const r=this.logs.get(t);if(!r)return{configId:t,state:s.state,entries:[],nextIndex:0,oldestIndex:0};const{entries:i,nextIndex:n,oldestIndex:a}=r.getSinceIndex(e);return{configId:t,state:s.state,entries:i,nextIndex:n,oldestIndex:a}}getRun(t){return this.runs.get(t)}getMetrics(t,e){return this.metricsMonitor.getHistory(t,e)}getMetricsSince(t,e,s){return this.metricsMonitor.getHistoryEntriesSince(t,e,s)}async ensureRestored(){if(!this.restored){this.restored=!0;try{const t=await F.readFile(N(),"utf-8"),e=JSON.parse(t);for(const s of e){const r=s.pid>0&&await L(s.pid);if(r){m.warn(`[restore] \u68C0\u6D4B\u5230\u4E0A\u6B21 bridge \u975E\u4F18\u96C5\u9000\u51FA\u540E\u7684\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u8054\u52A8\u7EC8\u6B62: configId=${s.configId}, pid=${s.pid}`);try{await E(s.pid)}catch(i){m.warn(`[restore] \u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B\u5931\u8D25: configId=${s.configId}, pid=${s.pid}, error=${i.message}`)}}this.runs.set(s.configId,{...s,state:"exited",...r?{exitedAt:new Date().toISOString()}:{}}),this.logs.set(s.configId,new O(D))}m.info(`[restore] \u5DF2\u6062\u590D ${e.length} \u6761\u542F\u52A8\u9879\u8FD0\u884C\u8BB0\u5F55`)}catch{}}}publishRunStatus(t,e=!1){const s=this.runs.get(t);s&&(P().publishStatusRun({...s}),!(!e||s.state!=="running"||s.pid<=0)&&setTimeout(()=>{const r=this.runs.get(t);!r||r.state!=="running"||r.pid<=0||(async()=>{let i=[];try{i=(await this.probePorts([r.pid])).get(r.pid)??[]}catch{}const n=this.runs.get(t);n&&n.state==="running"&&n.pid===r.pid&&P().publishStatusRun({...n,ports:i})})()},2e3))}async persist(){const t=N();try{const e=Array.from(this.runs.values());await G(t,async()=>{await U(t,e)})}catch(e){m.warn(`[persist] \u6301\u4E45\u5316\u5931\u8D25: ${e.message}`)}}}S.instance=null;function gt(){return S.getInstance()}export{H as LaunchAlreadyRunningError,S as LaunchManager,W as StreamDecoder,gt as getLaunchManager,Z as resolvePlaceholders};
11
+ `,u=this.logs.get(t)?.append({stream:"stderr",text:a});return u&&w().publish(t,"logs",u.index,u.data),w().publishState(t,{configId:t,state:"stopped"}),this.publishRunStatus(t),await this.persist(),this.resolveStartupWaiters(t,"stopped",void 0),{success:i.failed===0,message:i.failed===0?"\u8FDB\u7A0B\u5DF2\u505C\u6B62":`\u90E8\u5206\u8FDB\u7A0B\u672A\u80FD\u7EC8\u6B62\uFF08terminated=${i.terminated}, failed=${i.failed}\uFF09`,pid:r.pid}}async restart(t){await this.ensureRestored();const e=this.runs.get(t.configId);return e&&e.state==="running"&&await this.stop(t.configId,"manual",t.startedBy),await this.start(t)}async startBatch(t,e){await this.ensureRestored();const s=await Promise.all(t.map(async n=>{try{const i=await this.start(n);return{configId:n.configId,ok:!0,run:i}}catch(i){return i instanceof C?{configId:n.configId,ok:!0,skipped:!0,message:"\u5F53\u524D\u5DF2\u5904\u4E8E\u542F\u52A8/\u6B63\u5728\u542F\u52A8\u72B6\u6001\uFF0C\u8DF3\u8FC7",run:i.existing}:{configId:n.configId,ok:!1,error:i.message}}}));if(e>0){const n=await Promise.all(s.map(async i=>{if(!i.ok||i.skipped)return i;try{const a=await this.waitStartupResult(i.configId,e);return{...i,wait:a}}catch(a){return{...i,error:a.message}}}));s.splice(0,s.length,...n)}const r={total:s.length,started:0,skipped:0,failed:0,ready:0,exited:0,stopped:0,timeout:0};for(const n of s){if(!n.ok){r.failed+=1;continue}if(n.skipped){r.skipped+=1;continue}r.started+=1,n.wait&&(r[n.wait.outcome]+=1)}return{items:s,summary:r}}async stopAll(){await this.ensureRestored();const t=Array.from(this.runs.values()).filter(s=>s.state==="running");let e=0;for(const s of t)try{const r=await this.stop(s.configId,"shutdown");r.success?e++:P.warn(`[stopAll] \u542F\u52A8\u9879\u672A\u80FD\u5B8C\u5168\u7EC8\u6B62: configId=${s.configId}, message=${r.message}`)}catch(r){P.warn(`[stopAll] \u505C\u6B62\u542F\u52A8\u9879\u5931\u8D25: configId=${s.configId}, error=${r.message}`)}return{running:t.length,stopped:e}}async waitStartupResult(t,e){const s=this.runs.get(t);if(!s)throw new Error("launch run not found");const r=Date.now(),n=()=>(this.logs.get(t)?.getLastN(q)??[]).map(a=>a.data);if(s.state!=="running")return{outcome:s.state==="stopped"?"stopped":"exited",waitedMs:0,...s.state==="exited"?{exitCode:s.exitCode??null}:{},logTail:n()};const i=this.readinessMatchers.get(t);if(i){const a=this.scanReadinessMatch(t,i);if(a!==null)return{outcome:"ready",waitedMs:0,matchedLine:a,logTail:n()}}return await new Promise(a=>{let u=!1,l=null,f=null,b=!1,m=null;const k=()=>{l!==null&&(clearInterval(l),l=null),f!==null&&(clearTimeout(f),f=null);const d=this.startupWaiters.get(t);if(d&&(d.delete(x),d.size===0&&this.startupWaiters.delete(t)),m!==null){const h=this.logListeners.get(t);h&&(h.delete(m),h.size===0&&this.logListeners.delete(t)),m=null}},R=d=>{u||(u=!0,k(),a(d))},x=(d,h)=>{R({outcome:d==="stopped"?"stopped":"exited",waitedMs:Date.now()-r,...d==="exited"?{exitCode:h??null}:{},logTail:n()})};let T=this.startupWaiters.get(t);if(T||(T=new Set,this.startupWaiters.set(t,T)),T.add(x),i){m=h=>{if(!(u||h.index<i.fromIndex)){for(const g of h.data.text.split(/\r?\n/))if(g&&i.pattern.test(g)){R({outcome:"ready",waitedMs:Date.now()-r,matchedLine:g.trim(),logTail:n()});return}}};let d=this.logListeners.get(t);d||(d=new Set,this.logListeners.set(t,d)),d.add(m)}else{const d=async()=>{if(u||b)return;const h=this.runs.get(t);if(!(!h||h.state!=="running"||h.pid<=0)){b=!0;try{const o=(await this.probePorts([h.pid])).get(h.pid)??[];if(o.length>0&&!u){const c=this.runs.get(t);c?.state==="running"&&c.pid===h.pid&&(this.knownPorts.set(t,o),w().publishStatusRun({...c,ports:o}),R({outcome:"ready",waitedMs:Date.now()-r,ports:o,logTail:n()}))}}catch{}finally{b=!1}}};l=setInterval(()=>{d()},Y),d()}f=setTimeout(()=>{R({outcome:"timeout",waitedMs:Date.now()-r,logTail:n()})},e)})}scanReadinessMatch(t,e){const s=this.logs.get(t);if(!s)return null;for(const r of s.getSinceIndex(e.fromIndex-1).entries)for(const n of r.data.text.split(/\r?\n/))if(n&&e.pattern.test(n))return n.trim();return null}resolveStartupWaiters(t,e,s){const r=this.startupWaiters.get(t);if(!(!r||r.size===0)){this.startupWaiters.delete(t);for(const n of r)try{n(e,s)}catch{}}}async listRuns(t){await this.ensureRestored();const s=t?.withPorts??!0?Array.from(this.runs.values()).filter(i=>i.state==="running"&&i.pid>0).map(i=>i.pid):[];let r=new Map;if(s.length>0)try{r=await this.probePorts(s)}catch(i){P.debug(`[listRuns] \u7AEF\u53E3\u63A2\u6D4B\u5931\u8D25: ${i.message}`)}const n=[];for(const i of this.runs.values()){const a=this.logs.get(i.configId),u=i.state==="running"?r.get(i.pid)??[]:[];u.length>0&&this.knownPorts.set(i.configId,u),n.push({...i,logTail:a?a.getLastN(20).map(l=>l.data):[],nextLogIndex:a?a.getSinceIndex(-1).nextIndex:0,ports:i.state==="running"?u.length>0?u:this.knownPorts.get(i.configId)??[]:[],metrics:this.metricsMonitor.getLatest(i.configId)??void 0})}return n}async probePorts(t){const e=[...t].sort((n,i)=>n-i).join(","),s=this.portsProbeInflight.get(e);if(s)return s;const r=X(t).finally(()=>{this.portsProbeInflight.get(e)===r&&this.portsProbeInflight.delete(e)});return this.portsProbeInflight.set(e,r),r}async publishRunningPorts(){const t=this.runningRefs();if(t.length===0)return;let e=new Map;try{e=await this.probePorts(t.map(s=>s.pid))}catch(s){P.debug(`[publishRunningPorts] \u7AEF\u53E3\u63A2\u6D4B\u5931\u8D25: ${s.message}`);return}for(const s of t){const r=this.runs.get(s.configId);if(!r||r.state!=="running"||r.pid!==s.pid)continue;const n=e.get(s.pid)??[];n.length>0?this.knownPorts.set(s.configId,n):this.portReprobeTimers.has(s.configId)||this.schedulePortReprobe(s.configId),w().publishStatusRun({...r,ports:n.length>0?n:this.knownPorts.get(s.configId)??[]})}}async getLogs(t,e){await this.ensureRestored();const s=this.runs.get(t);if(!s)return null;const r=this.logs.get(t);if(!r)return{configId:t,state:s.state,entries:[],nextIndex:0,oldestIndex:0};const{entries:n,nextIndex:i,oldestIndex:a}=r.getSinceIndex(e);return{configId:t,state:s.state,entries:n,nextIndex:i,oldestIndex:a}}getRun(t){return this.runs.get(t)}getMetrics(t,e){return this.metricsMonitor.getHistory(t,e)}getMetricsSince(t,e,s){return this.metricsMonitor.getHistoryEntriesSince(t,e,s)}async ensureRestored(){if(!this.restored){this.restored=!0;try{const t=await z.readFile(B(),"utf-8"),e=JSON.parse(t);for(const s of e){const r=s.pid>0&&await E(s.pid);if(r){P.warn(`[restore] \u68C0\u6D4B\u5230\u4E0A\u6B21 bridge \u975E\u4F18\u96C5\u9000\u51FA\u540E\u7684\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u8054\u52A8\u7EC8\u6B62: configId=${s.configId}, pid=${s.pid}`);try{await v(s.pid)}catch(n){P.warn(`[restore] \u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B\u5931\u8D25: configId=${s.configId}, pid=${s.pid}, error=${n.message}`)}}this.runs.set(s.configId,{...s,state:"exited",...r?{exitedAt:new Date().toISOString()}:{}}),this.logs.set(s.configId,new L(_))}P.info(`[restore] \u5DF2\u6062\u590D ${e.length} \u6761\u542F\u52A8\u9879\u8FD0\u884C\u8BB0\u5F55`)}catch{}}}publishRunStatus(t,e=!1){const s=this.runs.get(t);s&&(w().publishStatusRun(this.buildStatusFrame(s)),!(!e||s.state!=="running"||s.pid<=0)&&this.schedulePortReprobe(t))}buildStatusFrame(t){return{...t,ports:t.state==="running"?this.knownPorts.get(t.configId)??[]:[]}}schedulePortReprobe(t){this.clearPortReprobe(t);const e=Date.now(),s=++this.portReprobeSeq;this.portReprobeTokens.set(t,s);const r=(n,i)=>{const a=setTimeout(()=>{if(this.portReprobeTokens.get(t)!==s||(this.portReprobeTimers.delete(t),i&&!w().hasStatusSubscribers()))return;const u=this.runs.get(t);!u||u.state!=="running"||u.pid<=0||(this.knownPorts.get(t)?.length??0)>0||(async()=>{let l=[];try{l=(await this.probePorts([u.pid])).get(u.pid)??[]}catch{}if(this.portReprobeTokens.get(t)!==s)return;const f=this.runs.get(t);if(!(!f||f.state!=="running"||f.pid!==u.pid)){if(l.length>0){this.knownPorts.set(t,l),w().publishStatusRun({...f,ports:l});return}Date.now()-e<Q&&r(Z,!0)}})()},n);a.unref?.(),this.portReprobeTimers.set(t,a)};r(K,!1)}clearPortReprobe(t){const e=this.portReprobeTimers.get(t);e!==void 0&&(clearTimeout(e),this.portReprobeTimers.delete(t)),this.portReprobeTokens.delete(t)}async persist(){const t=B();try{const e=Array.from(this.runs.values());await U(t,async()=>{await J(t,e)})}catch(e){P.warn(`[persist] \u6301\u4E45\u5316\u5931\u8D25: ${e.message}`)}}}y.instance=null;function Pt(){return y.getInstance()}export{C as LaunchAlreadyRunningError,y as LaunchManager,N as StreamDecoder,Pt as getLaunchManager,tt as resolvePlaceholders};
12
12
 
@@ -33,6 +33,8 @@ export declare class LaunchStreamHub {
33
33
 
34
34
  subscribeStatus(send: (frame: string) => void): () => void;
35
35
 
36
+ hasStatusSubscribers(): boolean;
37
+
36
38
  publishStatusRun(run: unknown): void;
37
39
 
38
40
  publish(configId: string, kind: LaunchStreamKind, id: number, data: unknown): void;
@@ -1,11 +1,11 @@
1
- class i{constructor(){this.subscribers=new Map,this.statusSubscribers=new Set}static getInstance(){return i.instance===null&&(i.instance=new i),i.instance}subscribe(s,t,n){const r=b(s,t);let e=this.subscribers.get(r);e||(e=new Set,this.subscribers.set(r,e));const c={configId:s,kind:t,send:n};return e.add(c),()=>{const u=this.subscribers.get(r);u&&(u.delete(c),u.size===0&&this.subscribers.delete(r))}}subscriberCount(s,t){return this.subscribers.get(b(s,t))?.size??0}subscribeStatus(s){const t={send:s};return this.statusSubscribers.add(t),()=>{this.statusSubscribers.delete(t)}}publishStatusRun(s){if(this.statusSubscribers.size===0)return;const t=`event: run_upsert
1
+ class n{constructor(){this.subscribers=new Map,this.statusSubscribers=new Set}static getInstance(){return n.instance===null&&(n.instance=new n),n.instance}subscribe(s,t,i){const r=b(s,t);let e=this.subscribers.get(r);e||(e=new Set,this.subscribers.set(r,e));const c={configId:s,kind:t,send:i};return e.add(c),()=>{const u=this.subscribers.get(r);u&&(u.delete(c),u.size===0&&this.subscribers.delete(r))}}subscriberCount(s,t){return this.subscribers.get(b(s,t))?.size??0}subscribeStatus(s){const t={send:s};return this.statusSubscribers.add(t),()=>{this.statusSubscribers.delete(t)}}hasStatusSubscribers(){return this.statusSubscribers.size>0}publishStatusRun(s){if(this.statusSubscribers.size===0)return;const t=`event: run_upsert
2
2
  data: ${JSON.stringify({run:s})}
3
3
 
4
- `;for(const n of[...this.statusSubscribers])try{n.send(t)}catch{}}publish(s,t,n,r){const e=this.subscribers.get(b(s,t));if(!e||e.size===0)return;const c=`id: ${n}
4
+ `;for(const i of[...this.statusSubscribers])try{i.send(t)}catch{}}publish(s,t,i,r){const e=this.subscribers.get(b(s,t));if(!e||e.size===0)return;const c=`id: ${i}
5
5
  data: ${JSON.stringify(r)}
6
6
 
7
- `;for(const u of[...e])try{u.send(c)}catch{}}publishState(s,t){const n=`event: run_state
7
+ `;for(const u of[...e])try{u.send(c)}catch{}}publishState(s,t){const i=`event: run_state
8
8
  data: ${JSON.stringify(t)}
9
9
 
10
- `;for(const r of["logs","metrics"]){const e=this.subscribers.get(b(s,r));if(!(!e||e.size===0))for(const c of[...e])try{c.send(n)}catch{}}}}i.instance=null;function b(a,s){return`${a}:${s}`}function o(){return i.getInstance()}export{i as LaunchStreamHub,o as getLaunchStreamHub};
10
+ `;for(const r of["logs","metrics"]){const e=this.subscribers.get(b(s,r));if(!(!e||e.size===0))for(const c of[...e])try{c.send(i)}catch{}}}}n.instance=null;function b(a,s){return`${a}:${s}`}function o(){return n.getInstance()}export{n as LaunchStreamHub,o as getLaunchStreamHub};
11
11
 
@@ -7,6 +7,10 @@
7
7
 
8
8
 
9
9
 
10
+
11
+
12
+ export declare const SESSION_COOKIE_MAX_AGE_SEC: number;
13
+
10
14
  export declare function createSession(): string;
11
15
 
12
16
  export declare function validateSession(token: string | undefined | null): boolean;
@@ -1,2 +1,2 @@
1
- import{randomUUID as _,randomBytes as $,scryptSync as S,timingSafeEqual as I}from"node:crypto";import{existsSync as f,mkdirSync as w,readFileSync as u,writeFileSync as y}from"node:fs";import{homedir as v}from"node:os";import g from"node:path";import{getAutoRegisterConfigFilePath as D}from"../config.js";import{runExclusiveConfigWrite as x}from"../utils/config-write-queue.js";import{logger as i}from"../utils/logger.js";const C=24*60*60*1e3,M=60*60*1e3,a=new Map;let p=null;function F(){p||(p=setInterval(()=>{const e=Date.now();let t=0;for(const[n,o]of a)e-o.lastUsedAt>C&&(a.delete(n),t++);t>0&&i.info(`[panel-auth] \u5DF2\u6E05\u7406 ${t} \u4E2A\u8FC7\u671F\u9762\u677F\u4F1A\u8BDD`)},M),p.unref())}function K(){F();const e=_(),t=Date.now();return a.set(e,{token:e,createdAt:t,lastUsedAt:t}),e}function ee(e){if(!e)return!1;const t=a.get(e);if(!t)return!1;const n=Date.now();return n-t.lastUsedAt>C?(a.delete(e),!1):(t.lastUsedAt=n,!0)}function te(e){a.delete(e)}function ne(){return Array.from(a.values())}function re(){return a.size}const P="scrypt$",A=64;function m(e){return e.startsWith(P)}function k(e){const t=$(16),n=S(e,t,A);return`${P}${t.toString("hex")}$${n.toString("hex")}`}function J(e,t){if(e.length!==t.length)return!1;try{return I(Buffer.from(e,"hex"),Buffer.from(t,"hex"))}catch{return!1}}function U(e,t){if(m(t)){const n=t.split("$");if(n.length!==3)return!1;const o=Buffer.from(n[1],"hex");if(o.length===0)return!1;const s=S(e,o,A).toString("hex");return J(s,n[2])}return e===t}const T=5,h=15*60*1e3,L=10*60*1e3,c=new Map;function R(){const e=Date.now();for(const[t,n]of c)n.lockedUntil<=e&&e-n.windowStart>h&&c.delete(t)}function oe(e){const t=Date.now(),n=c.get(e);return n?n.lockedUntil>t?{allowed:!1,retryAfterSec:Math.ceil((n.lockedUntil-t)/1e3)}:(t-n.windowStart>h&&c.delete(e),{allowed:!0,retryAfterSec:0}):{allowed:!0,retryAfterSec:0}}function se(e){const t=Date.now();R();const n=c.get(e);if(!n||t-n.windowStart>h){c.set(e,{failures:1,windowStart:t,lockedUntil:0});return}n.failures+=1,n.failures>=T&&(n.lockedUntil=t+L,i.warn(`[panel-auth] \u767B\u5F55\u5931\u8D25\u6B21\u6570\u8FC7\u591A\uFF0C\u5DF2\u4E34\u65F6\u9501\u5B9A\u6765\u6E90 ${e}\uFF08${L/6e4} \u5206\u949F\uFF09`))}function ae(e){c.delete(e)}let l=null;function d(){return D()}function B(){const e=d();if(!f(e))return null;try{const t=u(e,"utf-8"),n=JSON.parse(t),o=String(n.panelUsername||"").trim(),s=String(n.panelPassword||"").trim();if(o&&s)return{username:o,password:s}}catch{}return null}function N(){if(l)return l;const e=B();return e?(l=e,e):(q(),l={username:"root",password:"root"},l)}function ie(e,t){const n=N();return e!==n.username||!U(t,n.password)?!1:(!m(n.password)&&H()&&W(n.username,t).then(()=>{i.info("[panel-auth] \u5DF2\u5C06\u660E\u6587\u9762\u677F\u5BC6\u7801\u81EA\u52A8\u8FC1\u79FB\u4E3A scrypt \u54C8\u5E0C\u5B58\u50A8")}).catch(()=>{}),!0)}function O(){l=null}function H(){const e=d();if(!f(e))return!1;try{const t=u(e,"utf-8"),n=JSON.parse(t);return!!(n.panelUsername&&n.panelPassword)}catch{return!1}}function ce(){const e=N();return e.username==="root"&&U("root",e.password)}async function W(e,t){const n=d();O(),await x(n,()=>{const o=g.dirname(n);let s={};if(f(n))try{s=JSON.parse(u(n,"utf-8"))}catch{}s.panelUsername=e,s.panelPassword=m(t)?t:k(t);try{w(o,{recursive:!0})}catch{}y(n,JSON.stringify(s,null,2),"utf-8"),i.info("[panel-auth] \u9762\u677F\u51ED\u636E\u5DF2\u66F4\u65B0")})}let E=!1;function G(){return g.join(v(),".aws-bridge","config.json")}async function j(){const e=d(),t=G();if(t===e||!f(t))return!1;let n="",o="";try{const r=JSON.parse(u(t,"utf-8"));n=String(r.panelUsername??"").trim(),o=String(r.panelPassword??"").trim()}catch(r){return i.warn(`[panel-auth] \u65E7\u914D\u7F6E\u4E0D\u53EF\u89E3\u6790\uFF0C\u8DF3\u8FC7\u9762\u677F\u51ED\u636E\u8FC1\u79FB: ${r instanceof Error?r.message:String(r)}`),!1}if(!n||!o)return!1;let s=!1;return await x(e,()=>{let r={};if(f(e))try{r=JSON.parse(u(e,"utf-8"))}catch{r={}}if(!(String(r.panelUsername??"").trim()&&String(r.panelPassword??"").trim())){r.panelUsername=n,r.panelPassword=o;try{w(g.dirname(e),{recursive:!0})}catch{}y(e,JSON.stringify(r,null,2),"utf-8"),s=!0,i.info(`[panel-auth] \u5DF2\u4ECE ${t} \u8FC1\u79FB\u9762\u677F\u51ED\u636E`)}}),s}function q(){E||(E=!0,j().then(e=>{e&&O()}).catch(e=>{i.warn(`[panel-auth] \u65E7\u9762\u677F\u51ED\u636E\u8FC1\u79FB\u5931\u8D25\uFF08\u5FFD\u7565\uFF09: ${e instanceof Error?e.message:String(e)}`)}))}export{oe as checkLoginAllowed,O as clearCredentialsCache,K as createSession,te as destroySession,re as getActiveSessionCount,ne as getAllSessions,N as getPanelCredentials,H as hasConfiguredCredentials,ce as isDefaultCredentials,j as migrateLegacyPanelCredentials,se as recordLoginFailure,ae as recordLoginSuccess,W as setPanelCredentials,ie as validateCredentials,ee as validateSession};
1
+ import{randomUUID as T,randomBytes as b,scryptSync as E,timingSafeEqual as j}from"node:crypto";import{existsSync as f,mkdirSync as h,readFileSync as l,writeFileSync as w}from"node:fs";import{homedir as H}from"node:os";import u from"node:path";import{getAutoRegisterConfigFilePath as O}from"../config.js";import{runExclusiveConfigWrite as L}from"../utils/config-write-queue.js";import{logger as a}from"../utils/logger.js";const y=30*24*60*60*1e3,fe=30*24*60*60,R=60*60*1e3,B=500,i=new Map;let A=null,p=null;function _(){return u.join(u.dirname(O()),"panel-sessions.json")}function G(){const e=_();if(f(e))try{const t=JSON.parse(l(e,"utf-8")),n=Date.now();let r=0;if(t.sessions&&typeof t.sessions=="object")for(const[o,s]of Object.entries(t.sessions)){const N=Number(s?.createdAt),m=Number(s?.lastUsedAt);typeof o!="string"||!Number.isFinite(N)||!Number.isFinite(m)||n-m>y||(i.set(o,{token:o,createdAt:N,lastUsedAt:m}),r++)}r>0&&a.info(`[panel-auth] \u5DF2\u4ECE\u78C1\u76D8\u6062\u590D ${r} \u4E2A\u9762\u677F\u4F1A\u8BDD`)}catch(t){a.warn(`[panel-auth] \u9762\u677F\u4F1A\u8BDD\u6587\u4EF6\u4E0D\u53EF\u8BFB\uFF08\u5FFD\u7565\uFF09: ${t instanceof Error?t.message:String(t)}`)}}let x=!1;function C(){x||(x=!0,G())}function F(){const e=_();try{h(u.dirname(e),{recursive:!0});const t={version:1,sessions:Object.fromEntries(Array.from(i.values()).map(n=>[n.token,{createdAt:n.createdAt,lastUsedAt:n.lastUsedAt}]))};w(e,JSON.stringify(t,null,2),{encoding:"utf-8",mode:384})}catch(t){a.warn(`[panel-auth] \u9762\u677F\u4F1A\u8BDD\u843D\u76D8\u5931\u8D25\uFF08\u5FFD\u7565\uFF09: ${t instanceof Error?t.message:String(t)}`)}}function g(){p||(p=setTimeout(()=>{p=null,F()},B),p.unref())}function W(){A||(A=setInterval(()=>{const e=Date.now();let t=0;for(const[n,r]of i)e-r.lastUsedAt>y&&(i.delete(n),t++);t>0&&(a.info(`[panel-auth] \u5DF2\u6E05\u7406 ${t} \u4E2A\u8FC7\u671F\u9762\u677F\u4F1A\u8BDD`),g())},R),A.unref())}process.on("exit",()=>{x&&i.size>0&&F()});function le(){C(),W();const e=T(),t=Date.now();return i.set(e,{token:e,createdAt:t,lastUsedAt:t}),g(),e}function ue(e){if(!e)return!1;C();const t=i.get(e);if(!t)return!1;const n=Date.now();return n-t.lastUsedAt>y?(i.delete(e),g(),!1):(t.lastUsedAt=n,!0)}function de(e){C(),i.delete(e)&&g()}function pe(){return Array.from(i.values())}function ge(){return i.size}const $="scrypt$",I=64;function P(e){return e.startsWith($)}function X(e){const t=b(16),n=E(e,t,I);return`${$}${t.toString("hex")}$${n.toString("hex")}`}function Y(e,t){if(e.length!==t.length)return!1;try{return j(Buffer.from(e,"hex"),Buffer.from(t,"hex"))}catch{return!1}}function v(e,t){if(P(t)){const n=t.split("$");if(n.length!==3)return!1;const r=Buffer.from(n[1],"hex");if(r.length===0)return!1;const o=E(e,r,I).toString("hex");return Y(o,n[2])}return e===t}const q=5,U=15*60*1e3,D=10*60*1e3,c=new Map;function z(){const e=Date.now();for(const[t,n]of c)n.lockedUntil<=e&&e-n.windowStart>U&&c.delete(t)}function Se(e){const t=Date.now(),n=c.get(e);return n?n.lockedUntil>t?{allowed:!1,retryAfterSec:Math.ceil((n.lockedUntil-t)/1e3)}:(t-n.windowStart>U&&c.delete(e),{allowed:!0,retryAfterSec:0}):{allowed:!0,retryAfterSec:0}}function me(e){const t=Date.now();z();const n=c.get(e);if(!n||t-n.windowStart>U){c.set(e,{failures:1,windowStart:t,lockedUntil:0});return}n.failures+=1,n.failures>=q&&(n.lockedUntil=t+D,a.warn(`[panel-auth] \u767B\u5F55\u5931\u8D25\u6B21\u6570\u8FC7\u591A\uFF0C\u5DF2\u4E34\u65F6\u9501\u5B9A\u6765\u6E90 ${e}\uFF08${D/6e4} \u5206\u949F\uFF09`))}function he(e){c.delete(e)}let d=null;function S(){return O()}function V(){const e=S();if(!f(e))return null;try{const t=l(e,"utf-8"),n=JSON.parse(t),r=String(n.panelUsername||"").trim(),o=String(n.panelPassword||"").trim();if(r&&o)return{username:r,password:o}}catch{}return null}function M(){if(d)return d;const e=V();return e?(d=e,e):(te(),d={username:"root",password:"root"},d)}function we(e,t){const n=M();return e!==n.username||!v(t,n.password)?!1:(!P(n.password)&&K()&&Q(n.username,t).then(()=>{a.info("[panel-auth] \u5DF2\u5C06\u660E\u6587\u9762\u677F\u5BC6\u7801\u81EA\u52A8\u8FC1\u79FB\u4E3A scrypt \u54C8\u5E0C\u5B58\u50A8")}).catch(()=>{}),!0)}function k(){d=null}function K(){const e=S();if(!f(e))return!1;try{const t=l(e,"utf-8"),n=JSON.parse(t);return!!(n.panelUsername&&n.panelPassword)}catch{return!1}}function ye(){const e=M();return e.username==="root"&&v("root",e.password)}async function Q(e,t){const n=S();k(),await L(n,()=>{const r=u.dirname(n);let o={};if(f(n))try{o=JSON.parse(l(n,"utf-8"))}catch{}o.panelUsername=e,o.panelPassword=P(t)?t:X(t);try{h(r,{recursive:!0})}catch{}w(n,JSON.stringify(o,null,2),"utf-8"),a.info("[panel-auth] \u9762\u677F\u51ED\u636E\u5DF2\u66F4\u65B0")})}let J=!1;function Z(){return u.join(H(),".aws-bridge","config.json")}async function ee(){const e=S(),t=Z();if(t===e||!f(t))return!1;let n="",r="";try{const s=JSON.parse(l(t,"utf-8"));n=String(s.panelUsername??"").trim(),r=String(s.panelPassword??"").trim()}catch(s){return a.warn(`[panel-auth] \u65E7\u914D\u7F6E\u4E0D\u53EF\u89E3\u6790\uFF0C\u8DF3\u8FC7\u9762\u677F\u51ED\u636E\u8FC1\u79FB: ${s instanceof Error?s.message:String(s)}`),!1}if(!n||!r)return!1;let o=!1;return await L(e,()=>{let s={};if(f(e))try{s=JSON.parse(l(e,"utf-8"))}catch{s={}}if(!(String(s.panelUsername??"").trim()&&String(s.panelPassword??"").trim())){s.panelUsername=n,s.panelPassword=r;try{h(u.dirname(e),{recursive:!0})}catch{}w(e,JSON.stringify(s,null,2),"utf-8"),o=!0,a.info(`[panel-auth] \u5DF2\u4ECE ${t} \u8FC1\u79FB\u9762\u677F\u51ED\u636E`)}}),o}function te(){J||(J=!0,ee().then(e=>{e&&k()}).catch(e=>{a.warn(`[panel-auth] \u65E7\u9762\u677F\u51ED\u636E\u8FC1\u79FB\u5931\u8D25\uFF08\u5FFD\u7565\uFF09: ${e instanceof Error?e.message:String(e)}`)}))}export{fe as SESSION_COOKIE_MAX_AGE_SEC,Se as checkLoginAllowed,k as clearCredentialsCache,le as createSession,de as destroySession,ge as getActiveSessionCount,pe as getAllSessions,M as getPanelCredentials,K as hasConfiguredCredentials,ye as isDefaultCredentials,ee as migrateLegacyPanelCredentials,me as recordLoginFailure,he as recordLoginSuccess,Q as setPanelCredentials,we as validateCredentials,ue as validateSession};
2
2
 
@@ -1,3 +1,3 @@
1
- import{spawn as T}from"node:child_process";import{join as _}from"node:path";import{pathToFileURL as O}from"node:url";import{BLOCKED_ENV_KEYS as P}from"../utils/env-safety.js";import{createLogger as A}from"../utils/logger.js";import{renderCommandArgv as v,truncate as C}from"./plugin-manifest.js";const N=A("plugin-manager"),g=256*1024,h=6e4,S=/^[A-Za-z_][A-Za-z0-9_]*$/;async function G(t,e,s,a,o){const n=Date.now(),r=s.handler??{type:"process"};try{return r.type==="mcp"?{ok:!1,error:"handler.type=mcp \u5C06\u5728\u540E\u7EED\u7248\u672C\u652F\u6301\uFF0C\u8BF7\u6539\u7528 process/module handler"}:r.type==="module"?{ok:!0,result:await b(e,r,a,t,o),durationMs:Date.now()-n}:!r.command||!r.command.trim()?{ok:!1,error:`\u5DE5\u5177 ${s.name} \u7684 process handler \u7F3A\u5C11 command`}:{ok:!0,result:await $(e,r,a,t,o),durationMs:Date.now()-n}}catch(i){return{ok:!1,error:i instanceof Error?i.message:String(i),durationMs:Date.now()-n}}}async function $(t,e,s,a,o){const n=e.command??"";if(e.shell===!0&&/\{\{.+?\}\}/.test(n))throw new Error('shell:true \u7684 handler \u4E0D\u652F\u6301 {{params.*}} \u63D2\u503C\uFF08\u547D\u4EE4\u6CE8\u5165\u98CE\u9669\uFF09\uFF1B\u8BF7\u6539\u7528 shell:false \u7684 argv \u6A21\u5F0F\u6216 stdin:"params"');const r=v(n,{params:s});if(r.length===0)throw new Error("process handler command \u4E3A\u7A7A");const i=typeof e.timeoutMs=="number"&&e.timeoutMs>0?e.timeoutMs:h,u=new AbortController,d=()=>u.abort();o?.signal?.addEventListener("abort",d,{once:!0});const E=setTimeout(()=>u.abort(),i);try{return await new Promise((l,w)=>{N.info("[plugin:%s] spawn: %s",t.name,r.join(" "));const c=T(r[0],r.slice(1),{cwd:t.dir,env:k(t,a),shell:e.shell===!0,windowsHide:!0,signal:u.signal});let f="",y="";c.stdin?.on("error",()=>{}),c.stdout?.on("data",m=>{f.length<g&&(f+=m.toString("utf8"))}),c.stderr?.on("data",m=>{y.length<g&&(y+=m.toString("utf8"))}),c.on("error",m=>{w(new Error(`\u63D2\u4EF6\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${m.message}`))}),c.on("close",m=>{const p=f.trim();if(m!==0){const M=C(y.trim()||p||"(\u65E0\u8F93\u51FA)",600);w(new Error(u.signal.aborted?`\u63D2\u4EF6\u8FDB\u7A0B\u8D85\u65F6(${i}ms)\u6216\u88AB\u4E2D\u6B62`:`\u63D2\u4EF6\u8FDB\u7A0B\u9000\u51FA\u7801 ${m}: ${M}`));return}if(!p){l({ok:!0});return}try{l(JSON.parse(p))}catch{l(p)}});try{e.stdin==="params"?c.stdin?.end(`${JSON.stringify(s)}
2
- `):c.stdin?.end()}catch{}})}finally{clearTimeout(E),o?.signal?.removeEventListener("abort",d)}}async function b(t,e,s,a,o){if(!e.module)throw new Error("module handler \u7F3A\u5C11 module \u8DEF\u5F84");const n=_(t.dir,e.module);let r=t.moduleCache.get(n);r||(r=await import(`${O(n).href}?acode_nonce=${t.importNonce}`),t.moduleCache.set(n,r));const i=e.export||"default",d=r[i];if(typeof d!="function")throw new Error(`\u6A21\u5757 ${e.module} \u672A\u5BFC\u51FA\u51FD\u6570 ${i}`);const E=typeof e.timeoutMs=="number"&&e.timeoutMs>0?e.timeoutMs:h;let l;const w=Promise.resolve().then(()=>d(s,{agentId:a,signal:o?.signal,pluginRoot:t.dir}));try{return await Promise.race([w,new Promise((c,f)=>{l=setTimeout(()=>f(new Error(`\u63D2\u4EF6\u6A21\u5757\u6267\u884C\u8D85\u65F6(${E}ms)`)),E)})])}finally{clearTimeout(l)}}function k(t,e){const s={};for(const o of["PATH","HOME","USERPROFILE","SystemRoot","COMSPEC","TEMP","TMP","LANG","TZ"]){const n=process.env[o];n!==void 0&&(s[o]=n)}s.ACODE_PLUGIN_ROOT=t.dir,s.ACODE_AGENT_ID=e,s.ACODE_PLUGIN_NAME=t.name;const a=new Set((t.userConfig??[]).map(o=>o.key));for(const[o,n]of Object.entries(t.configValues))a.has(o)&&(!S.test(o)||P.has(o.toUpperCase())||(s[o]=n));return s}export{k as buildPluginEnv,G as executeHandler};
1
+ import{spawn as T}from"node:child_process";import{join as _}from"node:path";import{pathToFileURL as O}from"node:url";import{loadDynamicModule as P}from"../utils/dynamic-import.js";import{BLOCKED_ENV_KEYS as A}from"../utils/env-safety.js";import{createLogger as v}from"../utils/logger.js";import{renderCommandArgv as C,truncate as N}from"./plugin-manifest.js";const S=v("plugin-manager"),g=256*1024,h=6e4,b=/^[A-Za-z_][A-Za-z0-9_]*$/;async function K(t,e,s,a,o){const n=Date.now(),r=s.handler??{type:"process"};try{return r.type==="mcp"?{ok:!1,error:"handler.type=mcp \u5C06\u5728\u540E\u7EED\u7248\u672C\u652F\u6301\uFF0C\u8BF7\u6539\u7528 process/module handler"}:r.type==="module"?{ok:!0,result:await D(e,r,a,t,o),durationMs:Date.now()-n}:!r.command||!r.command.trim()?{ok:!1,error:`\u5DE5\u5177 ${s.name} \u7684 process handler \u7F3A\u5C11 command`}:{ok:!0,result:await k(e,r,a,t,o),durationMs:Date.now()-n}}catch(i){return{ok:!1,error:i instanceof Error?i.message:String(i),durationMs:Date.now()-n}}}async function k(t,e,s,a,o){const n=e.command??"";if(e.shell===!0&&/\{\{.+?\}\}/.test(n))throw new Error('shell:true \u7684 handler \u4E0D\u652F\u6301 {{params.*}} \u63D2\u503C\uFF08\u547D\u4EE4\u6CE8\u5165\u98CE\u9669\uFF09\uFF1B\u8BF7\u6539\u7528 shell:false \u7684 argv \u6A21\u5F0F\u6216 stdin:"params"');const r=C(n,{params:s});if(r.length===0)throw new Error("process handler command \u4E3A\u7A7A");const i=typeof e.timeoutMs=="number"&&e.timeoutMs>0?e.timeoutMs:h,u=new AbortController,d=()=>u.abort();o?.signal?.addEventListener("abort",d,{once:!0});const E=setTimeout(()=>u.abort(),i);try{return await new Promise((l,w)=>{S.info("[plugin:%s] spawn: %s",t.name,r.join(" "));const c=T(r[0],r.slice(1),{cwd:t.dir,env:L(t,a),shell:e.shell===!0,windowsHide:!0,signal:u.signal});let f="",y="";c.stdin?.on("error",()=>{}),c.stdout?.on("data",m=>{f.length<g&&(f+=m.toString("utf8"))}),c.stderr?.on("data",m=>{y.length<g&&(y+=m.toString("utf8"))}),c.on("error",m=>{w(new Error(`\u63D2\u4EF6\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25: ${m.message}`))}),c.on("close",m=>{const p=f.trim();if(m!==0){const M=N(y.trim()||p||"(\u65E0\u8F93\u51FA)",600);w(new Error(u.signal.aborted?`\u63D2\u4EF6\u8FDB\u7A0B\u8D85\u65F6(${i}ms)\u6216\u88AB\u4E2D\u6B62`:`\u63D2\u4EF6\u8FDB\u7A0B\u9000\u51FA\u7801 ${m}: ${M}`));return}if(!p){l({ok:!0});return}try{l(JSON.parse(p))}catch{l(p)}});try{e.stdin==="params"?c.stdin?.end(`${JSON.stringify(s)}
2
+ `):c.stdin?.end()}catch{}})}finally{clearTimeout(E),o?.signal?.removeEventListener("abort",d)}}async function D(t,e,s,a,o){if(!e.module)throw new Error("module handler \u7F3A\u5C11 module \u8DEF\u5F84");const n=_(t.dir,e.module);let r=t.moduleCache.get(n);r||(r=await P(O(n).href,{freshInstanceQuery:`acode_nonce=${t.importNonce}`}),t.moduleCache.set(n,r));const i=e.export||"default",d=r[i];if(typeof d!="function")throw new Error(`\u6A21\u5757 ${e.module} \u672A\u5BFC\u51FA\u51FD\u6570 ${i}`);const E=typeof e.timeoutMs=="number"&&e.timeoutMs>0?e.timeoutMs:h;let l;const w=Promise.resolve().then(()=>d(s,{agentId:a,signal:o?.signal,pluginRoot:t.dir}));try{return await Promise.race([w,new Promise((c,f)=>{l=setTimeout(()=>f(new Error(`\u63D2\u4EF6\u6A21\u5757\u6267\u884C\u8D85\u65F6(${E}ms)`)),E)})])}finally{clearTimeout(l)}}function L(t,e){const s={};for(const o of["PATH","HOME","USERPROFILE","SystemRoot","COMSPEC","TEMP","TMP","LANG","TZ"]){const n=process.env[o];n!==void 0&&(s[o]=n)}s.ACODE_PLUGIN_ROOT=t.dir,s.ACODE_AGENT_ID=e,s.ACODE_PLUGIN_NAME=t.name;const a=new Set((t.userConfig??[]).map(o=>o.key));for(const[o,n]of Object.entries(t.configValues))a.has(o)&&(!b.test(o)||A.has(o.toUpperCase())||(s[o]=n));return s}export{L as buildPluginEnv,K as executeHandler};
3
3
 
@@ -1,6 +1,6 @@
1
- import{exec as N}from"node:child_process";import g from"node:os";import{promisify as P}from"node:util";import{createLogger as w}from"../utils/logger.js";const l=P(N),m=w("port-detector");function I(s){return s.replace(/#\s*<\s*CLIXML[\s\S]*?(?=#<\s*CLIXML|$)/g,"").trim()}function b(s){return s==null?[]:Array.isArray(s)?s:[s]}function y(s,o){const i=new Set([s]),t=[s];for(;t.length>0;){const n=t.shift();if(n===void 0)break;for(const e of o.get(n)??[])i.has(e)||(i.add(e),t.push(e))}return i}function M(s){const o=new Map;for(const i of s.split(`
2
- `)){const t=i.trim().split(/\s+/);if(t.length<2)continue;const n=Number.parseInt(t[0],10),e=Number.parseInt(t[1],10);if(!Number.isFinite(n)||!Number.isFinite(e))continue;const r=o.get(e);r?r.push(n):o.set(e,[n])}return o}async function S(){const i=Buffer.from("$conns = Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | Select-Object LocalPort, OwningProcess; $procs = Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId; @{Connections = $conns; Processes = $procs} | ConvertTo-Json -Compress -Depth 3","utf16le").toString("base64"),{stdout:t}=await l(`powershell -NoProfile -NonInteractive -EncodedCommand ${i}`,{encoding:"utf8",timeout:15e3,windowsHide:!0,maxBuffer:10*1024*1024}),n=new Map,e=new Map,r=I(t),d=r.search(/[[{]/);if(d<0)return{portsByPid:n,childrenMap:e};const u=JSON.parse(r.slice(d));for(const c of b(u.Connections)){const a=typeof c?.LocalPort=="number"?c.LocalPort:Number.NaN,p=typeof c?.OwningProcess=="number"?c.OwningProcess:Number.NaN;if(!Number.isFinite(a)||!Number.isFinite(p)||a<=0||p<=0)continue;const f=n.get(p);f?f.push(a):n.set(p,[a])}for(const c of b(u.Processes)){const a=typeof c?.ProcessId=="number"?c.ProcessId:Number.NaN,p=typeof c?.ParentProcessId=="number"?c.ParentProcessId:Number.NaN;if(!Number.isFinite(a)||!Number.isFinite(p))continue;const f=e.get(p);f?f.push(a):e.set(p,[a])}return{portsByPid:n,childrenMap:e}}function h(s,o,i){const t=s.get(o);t?t.push(i):s.set(o,[i])}function L(s,o){for(const i of s.split(`
3
- `)){if(!i.includes("LISTEN"))continue;const t=i.trim().split(/\s+/);if(t.length<5)continue;const n=t[3].match(/:(\d+)$/);if(!n)continue;const e=Number.parseInt(n[1],10);for(const r of t[t.length-1].matchAll(/pid=(\d+)/g))h(o,Number.parseInt(r[1],10),e)}}function C(s,o){for(const i of s.split(`
4
- `)){const t=i.trim().split(/\s+/);if(t.length<7||!t[0].startsWith("tcp")||t[5]!=="LISTEN")continue;const n=t[3].match(/:(\d+)$/);if(!n)continue;const e=t[6].match(/^(\d+)\//);e&&h(o,Number.parseInt(e[1],10),Number.parseInt(n[1],10))}}function T(s,o){for(const i of s.split(`
5
- `)){if(!i.includes("(LISTEN)"))continue;const t=i.trim().split(/\s+/);if(t.length<9)continue;const n=Number.parseInt(t[1],10),e=i.match(/:(\d+)\s+\(LISTEN\)/);!Number.isFinite(n)||!e||h(o,n,Number.parseInt(e[1],10))}}async function $(s){const o=new Map,{stdout:i}=await l("ps -axo pid=,ppid=",{encoding:"utf8",timeout:5e3}),t=M(i);if(s){try{const{stdout:n}=await l("lsof -nP -iTCP -sTCP:LISTEN",{encoding:"utf8",timeout:8e3});T(n,o)}catch(n){m.debug(`[collectUnix] lsof failed: ${n.message}`)}return{portsByPid:o,childrenMap:t}}try{const{stdout:n}=await l("ss -ltnp",{encoding:"utf8",timeout:5e3});L(n,o)}catch(n){m.debug(`[collectUnix] ss failed, fallback to netstat: ${n.message}`);try{const{stdout:e}=await l("netstat -ltnp",{encoding:"utf8",timeout:5e3});C(e,o)}catch(e){m.debug(`[collectUnix] netstat failed: ${e.message}`)}}return{portsByPid:o,childrenMap:t}}async function A(s){const o=new Map,i=s.filter(r=>Number.isFinite(r)&&r>0);if(i.length===0)return o;const t=g.platform();let n,e;if(t==="win32"){const r=await S();n=r.portsByPid,e=r.childrenMap}else{const r=await $(t==="darwin");n=r.portsByPid,e=r.childrenMap}for(const r of i){const d=y(r,e),u=new Set;for(const c of d)for(const a of n.get(c)??[])u.add(a);u.size>0&&o.set(r,[...u].sort((c,a)=>c-a))}return o}export{A as getListeningPortsForProcessTrees};
1
+ import{exec as P}from"node:child_process";import g from"node:os";import{promisify as w}from"node:util";import{createLogger as I}from"../utils/logger.js";const l=w(P),m=I("port-detector");function y(o){return o.replace(/#\s*<\s*CLIXML[\s\S]*?(?=#<\s*CLIXML|$)/g,"").trim()}function b(o){return o==null?[]:Array.isArray(o)?o:[o]}function M(o,s){const i=new Set([o]),t=[o];for(;t.length>0;){const e=t.shift();if(e===void 0)break;for(const n of s.get(e)??[])i.has(n)||(i.add(n),t.push(n))}return i}function S(o){const s=new Map;for(const i of o.split(`
2
+ `)){const t=i.trim().split(/\s+/);if(t.length<2)continue;const e=Number.parseInt(t[0],10),n=Number.parseInt(t[1],10);if(!Number.isFinite(e)||!Number.isFinite(n))continue;const r=s.get(n);r?r.push(e):s.set(n,[e])}return s}async function C(){const i=Buffer.from("$conns = Get-NetTCPConnection -ErrorAction SilentlyContinue | Select-Object LocalPort, RemotePort, OwningProcess; $procs = Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId; @{Connections = $conns; Processes = $procs} | ConvertTo-Json -Compress -Depth 3","utf16le").toString("base64"),{stdout:t}=await l(`powershell -NoProfile -NonInteractive -EncodedCommand ${i}`,{encoding:"utf8",timeout:15e3,windowsHide:!0,maxBuffer:20*1024*1024}),e=new Map,n=new Map,r=y(t),d=r.search(/[[{]/);if(d<0)return{portsByPid:e,childrenMap:n};const p=JSON.parse(r.slice(d));for(const c of b(p.Connections)){const u=typeof c?.LocalPort=="number"?c.LocalPort:Number.NaN,f=typeof c?.RemotePort=="number"?c.RemotePort:Number.NaN,a=typeof c?.OwningProcess=="number"?c.OwningProcess:Number.NaN;if(!Number.isFinite(u)||f!==0||!Number.isFinite(a)||u<=0||a<=0)continue;const N=e.get(a);N?N.push(u):e.set(a,[u])}for(const c of b(p.Processes)){const u=typeof c?.ProcessId=="number"?c.ProcessId:Number.NaN,f=typeof c?.ParentProcessId=="number"?c.ParentProcessId:Number.NaN;if(!Number.isFinite(u)||!Number.isFinite(f))continue;const a=n.get(f);a?a.push(u):n.set(f,[u])}return{portsByPid:e,childrenMap:n}}function h(o,s,i){const t=o.get(s);t?t.push(i):o.set(s,[i])}function L(o,s){for(const i of o.split(`
3
+ `)){if(!i.includes("LISTEN"))continue;const t=i.trim().split(/\s+/);if(t.length<5)continue;const e=t[3].match(/:(\d+)$/);if(!e)continue;const n=Number.parseInt(e[1],10);for(const r of t[t.length-1].matchAll(/pid=(\d+)/g))h(s,Number.parseInt(r[1],10),n)}}function T(o,s){for(const i of o.split(`
4
+ `)){const t=i.trim().split(/\s+/);if(t.length<7||!t[0].startsWith("tcp")||t[5]!=="LISTEN")continue;const e=t[3].match(/:(\d+)$/);if(!e)continue;const n=t[6].match(/^(\d+)\//);n&&h(s,Number.parseInt(n[1],10),Number.parseInt(e[1],10))}}function $(o,s){for(const i of o.split(`
5
+ `)){if(!i.includes("(LISTEN)"))continue;const t=i.trim().split(/\s+/);if(t.length<9)continue;const e=Number.parseInt(t[1],10),n=i.match(/:(\d+)\s+\(LISTEN\)/);!Number.isFinite(e)||!n||h(s,e,Number.parseInt(n[1],10))}}async function x(o){const s=new Map,{stdout:i}=await l("ps -axo pid=,ppid=",{encoding:"utf8",timeout:5e3}),t=S(i);if(o){try{const{stdout:e}=await l("lsof -nP -iTCP -sTCP:LISTEN",{encoding:"utf8",timeout:8e3});$(e,s)}catch(e){m.debug(`[collectUnix] lsof failed: ${e.message}`)}return{portsByPid:s,childrenMap:t}}try{const{stdout:e}=await l("ss -ltnp",{encoding:"utf8",timeout:5e3});L(e,s)}catch(e){m.debug(`[collectUnix] ss failed, fallback to netstat: ${e.message}`);try{const{stdout:n}=await l("netstat -ltnp",{encoding:"utf8",timeout:5e3});T(n,s)}catch(n){m.debug(`[collectUnix] netstat failed: ${n.message}`)}}return{portsByPid:s,childrenMap:t}}async function B(o){const s=new Map,i=o.filter(r=>Number.isFinite(r)&&r>0);if(i.length===0)return s;const t=g.platform();let e,n;if(t==="win32"){const r=await C();e=r.portsByPid,n=r.childrenMap}else{const r=await x(t==="darwin");e=r.portsByPid,n=r.childrenMap}for(const r of i){const d=M(r,n),p=new Set;for(const c of d)for(const u of e.get(c)??[])p.add(u);p.size>0&&s.set(r,[...p].sort((c,u)=>c-u))}return s}export{B as getListeningPortsForProcessTrees};
6
6
 
@@ -96,6 +96,8 @@ interface ChmodWorkspaceEntryParams extends WorkspacePathParams {
96
96
  }
97
97
  export interface SearchWorkspaceFilesParams {
98
98
  workspacePath: string;
99
+
100
+ rootPath?: string;
99
101
  keyword: string;
100
102
  fileMask?: string;
101
103
  ignoreCase?: boolean;
@@ -141,6 +143,8 @@ export interface SearchWorkspaceFilesResult {
141
143
  }
142
144
  export interface ReplaceWorkspaceFilesParams {
143
145
  workspacePath: string;
146
+
147
+ rootPath?: string;
144
148
  keyword: string;
145
149
  replacement: string;
146
150
  fileMask?: string;
@@ -1,2 +1,2 @@
1
- import{createReadStream as q,createWriteStream as O,promises as s}from"node:fs";import lt from"node:os";import w from"node:path";import{Readable as ht}from"node:stream";import{pipeline as ut}from"node:stream/promises";import{TextDecoder as wt}from"node:util";import{createGunzip as dt}from"node:zlib";import*as ft from"tar";import pt from"unzipper";const{ZipArchive:_}=await import("archiver"),x={maxEntries:1e4,maxFileBytes:512*1024*1024,maxTotalBytes:2*1024*1024*1024,maxPathDepth:64,maxPathLength:4096},mt=new wt("gbk");function u(t){return String(t||"").replace(/\\/g,"/")}function Z(t){const e=w.resolve(String(t||"").trim());if(!e)throw new Error("workspacePath is required");return e}async function yt(t){const e=Z(t),r=await s.realpath(e);if(!(await s.stat(r)).isDirectory())throw new Error(`Workspace path is not a directory: ${e}`);return r}async function v(t){return{requestedRoot:Z(t),workspaceRoot:await yt(t)}}function C(t,e){const r=w.resolve(e),i=w.relative(t,r);if(i.startsWith("..")||w.isAbsolute(i))throw new Error(`Target path is outside workspace: ${r}`);return r}async function D(t){return s.realpath(t)}async function F(t){await s.realpath(w.dirname(t));try{if((await s.lstat(t)).isSymbolicLink())throw new Error(`Refusing to write through symbolic link: ${t}`)}catch(e){if((typeof e=="object"&&e!==null?Reflect.get(e,"code"):void 0)!=="ENOENT")throw e}}function L(t,e,r){const i=w.resolve(t,r),o=w.relative(t,i);return o.startsWith("..")||w.isAbsolute(o)?i:C(e,w.join(e,o))}async function b({workspacePath:t,targetPath:e=""}){const{requestedRoot:r,workspaceRoot:i}=await v(t),o=String(e||"").trim(),a=o?L(r,i,o):i,c=await D(a);return{workspaceRoot:i,resolvedTargetPath:c}}function $(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("\\")||w.basename(e)!==e)throw new Error(`entryName must be a plain file or directory name: ${e}`);return e}function G(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=G(t);return $(w.basename(e.replace(/\\/g,"/")))}function gt(t,e){if(!t)return B(e);const i=G(String(t||e||"")).replace(/\\/g,"/").split("/").filter(Boolean).map(o=>$(o));return i.length===0?B(e):w.join(...i)}function H(t){return(t&4095).toString(8).padStart(4,"0")}function Pt(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 I(t,e,r,i,o,a,c){const n=t&e?"r":"-",h=t&r?"w":"-",l=(t&i)!==0,d=(t&o)!==0?l?a:c:l?"x":"-";return`${n}${h}${d}`}function kt(t){return[I(t,256,128,64,2048,"s","S"),I(t,32,16,8,1024,"s","S"),I(t,4,2,1,512,"t","T")].join("")}function xt(t){if(!(t.length<24||t.toString("hex",0,8)!=="89504e470d0a1a0a"))return{format:"png",width:t.readUInt32BE(16),height:t.readUInt32BE(20)}}function vt(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 Et(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 St(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 K(t,e){if((await s.lstat(t)).isSymbolicLink())throw new Error(`Refusing to change permissions on symbolic link: ${t}`);const i=await s.stat(t);if(!e||!i.isDirectory())return[t];const o=await s.readdir(t),a=await Promise.all(o.map(c=>{const n=w.join(t,c);return K(n,!0)}));return[t,...a.flat()]}async function Rt(t){if((await s.lstat(t)).isSymbolicLink())throw new Error(`Refusing to change permissions on symbolic link: ${t}`);await D(t)}async function Dt(t){const e=await s.open(t,"r");try{const r=Buffer.alloc(512),{bytesRead:i}=await e.read(r,0,r.length,0),o=r.subarray(0,i);return xt(o)||vt(o)||Et(o)||St(o)}finally{await e.close()}}async function T({workspacePath:t,targetPath:e},r={}){const{requestedRoot:i,workspaceRoot:o}=await v(t),a=String(e||"").trim();if(!a)throw new Error("targetPath is required");const c=L(i,o,a),n=await D(c);if(!r.allowWorkspaceRoot&&n===o)throw new Error("Workspace root cannot be modified");return{workspaceRoot:o,resolvedTargetPath:n}}async function X(t){const{requestedRoot:e,workspaceRoot:r}=await v(t.workspacePath),i=String(t.targetPath||"").trim();if(!i)return{workspaceRoot:r,resolvedTargetPath:r};const o=L(e,r,i);return await et(o)?{workspaceRoot:r,resolvedTargetPath:await s.realpath(o)}:(await s.realpath(w.dirname(o)),{workspaceRoot:r,resolvedTargetPath:o})}function V(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 Y(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=$(Y(e)||"extracted");return w.join(t,r)}function M(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>x.maxPathLength||i.length>x.maxPathDepth)throw new Error(`Archive entry path is too deep or too long: ${e}`);return C(t,w.join(t,r))}function Tt(t){const e=t.props?.pathBuffer;if(!e||t.props?.flags?.isUnicode)return t.path;const r=mt.decode(e);return!r||r.includes("\uFFFD")?t.path:r}async function J(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 N(t){if(t.entries+=1,t.entries>x.maxEntries)throw new Error(`Archive contains too many entries. Limit: ${x.maxEntries}`)}function Q(t,e){if(t.totalBytes+=e,e>x.maxFileBytes)throw new Error(`Archive entry exceeds max size. Limit: ${x.maxFileBytes} bytes`);if(t.totalBytes>x.maxTotalBytes)throw new Error(`Archive extraction exceeds total size. Limit: ${x.maxTotalBytes} bytes`)}async function tt(t,e,r){let i=0;t.on("data",o=>{const a=Buffer.isBuffer(o)?o.length:Buffer.byteLength(o);i+=a,(i>x.maxFileBytes||r.totalBytes+i>x.maxTotalBytes)&&t instanceof ht&&t.destroy(new Error("Archive extraction size limit exceeded"))}),await ut(t,O(e)),Q(r,i)}async function et(t){try{return await s.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 v(t),o=String(e||"").trim();if(!o)throw new Error("filePath is required");return{workspaceRoot:i,resolvedFilePath:L(r,i,o)}}async function Gt(t){const{workspaceRoot:e}=await v(t.workspacePath),r=String(t.targetPath||"").trim();if(!r){const{resolvedTargetPath:h}=await b(t);return rt(e,h)}const i=w.resolve(r);let o;try{o=await s.realpath(i)}catch{throw new Error(`Path not found: ${i}`)}if(!(await s.stat(o)).isDirectory())throw new Error(`Path is not a directory: ${i}`);const c=w.relative(e,o),n=c===""||!c.startsWith("..")&&!w.isAbsolute(c);return rt(e,n?o:i)}async function rt(t,e){if(!(await s.stat(e)).isDirectory())throw new Error(`Path is not a directory: ${e}`);const i=await s.readdir(e,{withFileTypes:!0}),o=await Promise.all(i.map(async a=>{const c=w.join(e,a.name),n=a.isFile()?(await s.stat(c)).size:void 0;return{name:a.name,path:u(c),isDirectory:a.isDirectory(),size:n}}));return{currentPath:u(e),workspacePath:u(t),items:o}}async function Ht(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t),i=await D(r),o=await s.stat(i);if(!o.isFile())throw new Error(`Path is not a file: ${i}`);const a=await s.readFile(i,"utf-8");return{workspacePath:u(e),filePath:u(i),content:a,mtimeMs:o.mtimeMs}}const it={maxEntries:1e5,maxDepth:32};async function zt(t){let e=0,r=0;async function i(o,a){if(a>=it.maxDepth)return;let c;try{c=await s.readdir(o,{withFileTypes:!0})}catch{return}for(const n of c){if(r+=1,r>it.maxEntries)return;if(n.isSymbolicLink())continue;const h=w.join(o,n.name);try{if(n.isDirectory())await i(h,a+1);else if(n.isFile()){const l=await s.stat(h);e+=l.size}}catch{}}}return await i(t,0),e}async function Kt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await T(t,{allowWorkspaceRoot:!0}),[i,o]=await Promise.all([s.stat(r),s.lstat(r)]),a=i.isDirectory(),c=i.isFile()?await Dt(r):void 0,n=a?await zt(r):i.size;return{workspacePath:u(e),targetPath:u(r),name:w.basename(r),isDirectory:i.isDirectory(),isFile:i.isFile(),isSymbolicLink:o.isSymbolicLink(),size:n,mode:i.mode,modeOctal:H(i.mode),permissions:kt(i.mode),uid:i.uid,gid:i.gid,atimeMs:i.atimeMs,mtimeMs:i.mtimeMs,ctimeMs:i.ctimeMs,birthtimeMs:i.birthtimeMs,...c?{image:c}:{}}}async function Xt(t){const e=Pt(t.mode),r=!!t.recursive,{workspaceRoot:i,resolvedTargetPath:o}=await T(t),a=await K(o,r);for(const c of a)await Rt(c),await s.chmod(c,e);return{ok:!0,workspacePath:u(i),targetPath:u(o),mode:e,modeOctal:H(e),recursive:r,changedCount:a.length}}async function Vt(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t),i=await D(r),o=await s.stat(i);if(!o.isFile())throw new Error(`Path is not a file: ${i}`);const a=w.extname(i).toLowerCase();if(a===".doc"||a===".xls"||a===".ppt")return{workspacePath:u(e),filePath:u(i),kind:"unsupported",content:"",message:`\u65E7\u7248 ${a} \u683C\u5F0F\u5C06\u7531\u670D\u52A1\u7AEF\u8F6C\u6362\u4E3A\u73B0\u4EE3\u683C\u5F0F\u540E\u6253\u5F00\uFF08\u539F\u6587\u4EF6\u4E0D\u53D8\uFF09\u3002`,size:o.size,mtimeMs:o.mtimeMs};if(!/\.(docx|docm|xlsx|xlsm|pptx|pptm)$/.test(a))throw new Error("Document preview only supports docx/xlsx/pptx files");return{workspacePath:u(e),filePath:u(i),kind:"html",content:"",size:o.size,mtimeMs:o.mtimeMs}}async function Yt(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t);await s.mkdir(w.dirname(r),{recursive:!0}),await F(r),await s.writeFile(r,String(t.content??""),"utf-8");const i=await s.stat(r);return{ok:!0,workspacePath:u(e),filePath:u(r),mtimeMs:i.mtimeMs}}async function Jt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await b(t),i=$(t.entryName),o=w.join(r,i);if(!(await s.stat(r)).isDirectory())throw new Error(`Path is not a directory: ${r}`);try{throw await s.access(o),new Error(`Path already exists: ${o}`)}catch(c){if((typeof c=="object"&&c!==null?Reflect.get(c,"code"):void 0)!=="ENOENT")throw c}return t.isDirectory?await s.mkdir(o,{recursive:!1}):(await s.mkdir(w.dirname(o),{recursive:!0}),await F(o),await s.writeFile(o,"","utf-8")),{ok:!0,workspacePath:u(e),targetPath:u(o),isDirectory:t.isDirectory}}async function Qt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await T(t),i=$(t.newName),o=w.join(w.dirname(r),i);if(o===r)return{ok:!0,workspacePath:u(e),sourcePath:u(r),targetPath:u(o)};await s.stat(r);try{throw await s.access(o),new Error(`Path already exists: ${o}`)}catch(a){if((typeof a=="object"&&a!==null?Reflect.get(a,"code"):void 0)!=="ENOENT")throw a}return await s.rename(r,o),{ok:!0,workspacePath:u(e),sourcePath:u(r),targetPath:u(o)}}async function te(t){const{workspaceRoot:e,resolvedTargetPath:r}=await T(t),i=await b({workspacePath:t.workspacePath,targetPath:t.destinationPath});if(!(await s.stat(i.resolvedTargetPath)).isDirectory())throw new Error(`Destination is not a directory: ${i.resolvedTargetPath}`);if((await s.stat(r)).isDirectory()){const n=w.relative(r,i.resolvedTargetPath);if(n===""||!n.startsWith("..")&&!w.isAbsolute(n))throw new Error("Cannot move a directory into itself or its descendant")}const c=w.join(i.resolvedTargetPath,w.basename(r));if(c===r)return{ok:!0,workspacePath:u(e),sourcePath:u(r),targetPath:u(c),destinationPath:u(i.resolvedTargetPath)};try{throw await s.access(c),new Error(`Path already exists: ${c}`)}catch(n){if((typeof n=="object"&&n!==null?Reflect.get(n,"code"):void 0)!=="ENOENT")throw n}return await s.rename(r,c),{ok:!0,workspacePath:u(e),sourcePath:u(r),targetPath:u(c),destinationPath:u(i.resolvedTargetPath)}}async function ee(t){const{workspaceRoot:e,resolvedTargetPath:r}=await T(t),i=await s.stat(r),o=w.parse(r).root;if(r===o)throw new Error("Filesystem root cannot be deleted");return i.isDirectory()?await s.rm(r,{recursive:!0,force:!1}):await s.unlink(r),{ok:!0,workspacePath:u(e),targetPath:u(r)}}async function re(t){if(!Array.isArray(t.files)||t.files.length===0)throw new Error("files are required");const{workspaceRoot:e,resolvedTargetPath:r}=await X(t);if(!(await s.stat(r)).isDirectory())throw new Error(`Path is not a directory: ${r}`);const o=[];for(const a of t.files){const c=B(a.originalname),n=gt(a.relativePath,a.originalname),h=w.join(r,n);await s.mkdir(w.dirname(h),{recursive:!0}),await F(h),await s.copyFile(a.path,h);let l;t.extractArchives&&V(h)&&(l=await Wt({workspacePath:e,archivePath:h,outputPath:Ft(r,c)})),o.push({fileName:c,targetPath:u(h),size:a.size,extracted:l})}return{ok:!0,workspacePath:u(e),targetPath:u(r),files:o}}async function ie(t){const{workspaceRoot:e,resolvedTargetPath:r}=await T(t),i=await s.stat(r),o=w.basename(r);return{workspacePath:u(e),targetPath:u(r),resolvedTargetPath:r,fileName:i.isDirectory()?`${o||"workspace"}.zip`:o,contentType:i.isDirectory()?"application/zip":Lt(r),isDirectory:i.isDirectory(),size:i.isDirectory()?void 0:i.size}}function Lt(t){const e=w.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 oe(t,e){const r=new _({zlib:{level:9}}),i=new Promise((o,a)=>{e.on("close",o),e.on("finish",o),r.on("error",a),e.on("error",a)});r.pipe(e),r.directory(t,!1),await r.finalize(),await i}async function ae(t,e,r,i){const o=w.join(lt.tmpdir(),"agentswork-bridge-downloads");await s.mkdir(o,{recursive:!0});const a=(e||"workspace.zip").replace(/[^\w.-]/g,"_").replace(/\.zip$/i,"")||"workspace",c=w.join(o,`${a}-${Date.now()}-${Math.random().toString(36).slice(2,8)}.zip`),n=new _({zlib:{level:9}}),h=()=>n.pointer(),l=()=>n.abort(),f=O(c),d=new Promise((m,g)=>{f.on("close",m),f.on("finish",m),n.on("error",g),f.on("error",g)});d.catch(()=>{}),n.pipe(f);const y=setInterval(()=>{try{if(i?.()){l();return}r?.(h())}catch{}},200);try{return n.on("progress",()=>{i?.()&&l()}),n.directory(t,!1),i?.()&&l(),await n.finalize(),await d,r?.(h()),c}catch(m){throw await s.rm(c,{force:!0}).catch(()=>{}),m}finally{clearInterval(y)}}async function $t(t,e,r){let i=0,o;const a=q(t),c=a.pipe(pt.Parse({forceStream:!0}));try{for await(const n of c){if(o){await J(n);continue}const h=Tt(n);try{const l=M(e,h);if(N(r),n.type==="Directory"){await s.mkdir(l,{recursive:!0});continue}if(n.type!=="File")throw new Error(`Unsupported archive entry type: ${h}`);await s.mkdir(w.dirname(l),{recursive:!0}),await F(l),await tt(n,l,r),i+=1}catch(l){o=l,await J(n)}}}finally{a.destroy(),c.destroy()}if(o)throw o;return i}async function At(t,e,r,i){let o=0,a;const c=(n,h)=>{if(a)return!1;try{M(e,n),N(i);const l=String(h.type||"").toLowerCase();if(l==="symboliclink"||l==="link")throw new Error(`Archive links are not supported: ${n}`);if(l!=="file"&&l!=="oldfile"&&l!=="contiguousfile"&&l!=="directory")throw new Error(`Unsupported archive entry type: ${n}`);return typeof h.size=="number"&&Q(i,h.size),l!=="directory"&&(o+=1),!0}catch(l){return a=l,!1}};if(await ft.x({file:t,cwd:e,gzip:r,strict:!0,filter:(n,h)=>c(n,h)}),a)throw a;return o}async function Ct(t,e,r){const i=Y(w.basename(t)),o=M(e,i||"decompressed");return N(r),await s.mkdir(w.dirname(o),{recursive:!0}),await F(o),await tt(q(t).pipe(dt()),o,r),1}async function Wt(t){const{requestedRoot:e,workspaceRoot:r}=await v(t.workspacePath),{resolvedTargetPath:i}=await X({workspacePath:t.workspacePath,targetPath:t.outputPath||""}),o=L(e,r,String(t.archivePath||"").trim()),a=await D(o);if(!(await s.stat(a)).isFile())throw new Error(`Archive path is not a file: ${a}`);if(await et(i)||await s.mkdir(i,{recursive:!0}),!(await s.stat(i)).isDirectory())throw new Error(`Output path is not a directory: ${i}`);const h=V(a);if(!h)throw new Error("Unsupported archive type. Supported: .zip, .tar, .tar.gz, .tgz, .gz");let l=0;const f={entries:0,totalBytes:0};return h==="zip"?l=await $t(a,i,f):h==="tar"||h==="tgz"?l=await At(a,i,h==="tgz",f):l=await Ct(a,i,f),{ok:!0,workspacePath:u(r),archivePath:u(a),targetPath:u(i),extractedEntries:l}}function ot(t){const e=t.match(/^(.*?)\{([^}]+)\}(.*)$/);if(!e)return[t];const[,r,i,o]=e;return i.split(",").flatMap(a=>ot(r+a.trim()+o))}function at(t,e){const r=String(e||"").trim();if(!r||r==="*"||r==="*.*")return!0;const i=t.toLowerCase();return ot(r.toLowerCase()).some(a=>{if(a==="*")return!0;const c=a.replace(/\./g,"\\.").replace(/\*\*/g,"<<GLOBSTAR>>").replace(/\*/g,"[^/]*").replace(/\?/g,"[^/]").replace(/<<GLOBSTAR>>/g,".*");return new RegExp(`^${c}$`).test(i)})}function j(t){return t===".git"||t==="node_modules"||t===".svn"||t===".hg"}const nt=10*1024*1024,bt=1e3;async function ne(t){const{workspaceRoot:e}=await v(t.workspacePath),r=String(t.keyword||"").trim();if(!r)throw new Error("keyword is required");const i=!!t.ignoreCase,o=String(t.fileMask||"").trim(),a=typeof t.maxResults=="number"&&t.maxResults>0?t.maxResults:bt,c=i?r.toLowerCase():r,h=(t.mode==="filename"?"filename":"content")==="filename",l=[];let f=0,d=!1;async function y(m){if(d)return;let g;try{g=await s.readdir(m,{withFileTypes:!0})}catch{return}for(const p of g){if(d)return;const P=C(e,w.join(m,p.name));if(p.isSymbolicLink())continue;if(p.isDirectory()){if(j(p.name))continue;await y(P);continue}if(!p.isFile()||o&&!at(p.name,o))continue;f+=1;let k;try{k=await s.stat(P)}catch{continue}if(k.size>nt)continue;if(h){const E=(i?p.name.toLowerCase():p.name).indexOf(c);if(E!==-1&&(l.push({filePath:u(P),lineNumber:0,lineContent:p.name,matchStart:E,matchEnd:E+r.length}),l.length>=a)){d=!0;return}continue}let S;try{S=await s.readFile(P,"utf-8")}catch{continue}const z=S.split(/\r?\n/);for(let R=0;R<z.length;R+=1){const E=z[R],ct=i?E.toLowerCase():E;let U=0;for(;;){const A=ct.indexOf(c,U);if(A===-1)break;if(l.push({filePath:u(P),lineNumber:R+1,lineContent:E,matchStart:A,matchEnd:A+r.length}),l.length>=a){d=!0;return}U=A+1}}}}return await y(e),{workspacePath:u(e),keyword:r,totalFiles:f,totalMatches:l.length,matches:l,truncated:d}}const Bt=100,It=120;async function se(t){const{workspaceRoot:e}=await v(t.workspacePath),r=String(t.keyword||"").trim();if(!r)throw new Error("keyword is required");const i=!!t.ignoreCase,o=i?r.toLowerCase():r,a=typeof t.maxResults=="number"&&t.maxResults>0?t.maxResults:Bt,c=typeof t.maxDirectories=="number"&&t.maxDirectories>0?t.maxDirectories:It,n=String(t.rootPath||"").trim(),h=n?w.resolve(/^[A-Za-z]:$/.test(n)?`${n}/`:n):e;let l;try{l=await s.realpath(h)}catch{throw new Error(`Path not found: ${h}`)}if(!(await s.stat(l)).isDirectory())throw new Error(`Path is not a directory: ${h}`);const d=[],y=[l];let m=0,g=!1;for(;y.length>0&&d.length<a&&m<c;){const p=y.shift();m+=1;let P;try{P=await s.readdir(p,{withFileTypes:!0})}catch{continue}for(const k of P){if(d.length>=a){g=!0;break}if(k.isSymbolicLink())continue;const S=w.join(p,k.name);if(k.isDirectory()&&j(k.name))continue;const z=w.relative(l,S).replace(/\\/g,"/");(i?z.toLowerCase():z).includes(o)&&d.push({name:k.name,path:u(S),isDirectory:k.isDirectory()}),k.isDirectory()&&m<c&&y.push(S)}}return(m>=c||d.length>=a)&&(g=!0),d.sort((p,P)=>p.isDirectory===P.isDirectory?p.name.localeCompare(P.name):p.isDirectory?-1:1),{workspacePath:u(e),rootPath:u(l),keyword:r,items:d,truncated:g}}async function st(t,e,r,i){let o;try{o=await s.readFile(t,"utf-8")}catch{return{changed:!1,count:0}}const a=o;let c=0;if(i){const n=e.toLowerCase();let h=0;for(;;){const f=o.toLowerCase().indexOf(n,h);if(f===-1)break;o=o.slice(0,f)+r+o.slice(f+e.length),c+=1;const d=r.length||1;h=f+d}}else{let n=0;for(;;){const h=o.indexOf(e,n);if(h===-1)break;o=o.slice(0,h)+r+o.slice(h+e.length),c+=1;const l=r.length||1;n=h+l}}return o===a?{changed:!1,count:0}:(await F(t),await s.writeFile(t,o,"utf-8"),{changed:!0,count:c})}async function ce(t){const{workspaceRoot:e}=await v(t.workspacePath),r=String(t.keyword||"").trim();if(!r)throw new Error("keyword is required");const i=String(t.replacement??""),o=!!t.ignoreCase,a=String(t.fileMask||"").trim(),c=String(t.filePath||"").trim();let n=0,h=0;if(c){const{resolvedFilePath:f}=await W({workspacePath:t.workspacePath,filePath:c}),d=await st(f,r,i,o);return d.changed&&(n=1,h=d.count),{workspacePath:u(e),keyword:r,replacement:i,changedFiles:n,changedMatches:h}}async function l(f){let d;try{d=await s.readdir(f,{withFileTypes:!0})}catch{return}for(const y of d){const m=C(e,w.join(f,y.name));if(y.isSymbolicLink())continue;if(y.isDirectory()){if(j(y.name))continue;await l(m);continue}if(!y.isFile()||a&&!at(y.name,a))continue;try{if((await s.stat(m)).size>nt)continue}catch{continue}const g=await st(m,r,i,o);g.changed&&(n+=1,h+=g.count)}}return await l(e),{workspacePath:u(e),keyword:r,replacement:i,changedFiles:n,changedMatches:h}}export{Xt as chmodWorkspaceEntry,Jt as createWorkspaceEntry,ee as deleteWorkspaceEntry,Wt as extractWorkspaceArchive,Kt as getWorkspaceEntryProperties,Gt as listWorkspaceDirectory,te as moveWorkspaceEntry,Vt as previewWorkspaceDocument,Ht as readWorkspaceFile,Qt as renameWorkspaceEntry,ce as replaceWorkspaceFiles,ie as resolveWorkspaceDownloadTarget,ne as searchWorkspaceFiles,se as searchWorkspacePaths,oe as streamWorkspaceDirectoryZip,re as uploadWorkspaceFiles,Yt as writeWorkspaceFile,ae as zipWorkspaceDirectoryToTemp};
1
+ import{createReadStream as _,createWriteStream as Z,promises as s}from"node:fs";import wt from"node:os";import w from"node:path";import{Readable as dt}from"node:stream";import{pipeline as ft}from"node:stream/promises";import{TextDecoder as pt}from"node:util";import{createGunzip as mt}from"node:zlib";import*as yt from"tar";import gt from"unzipper";let B;async function G(){return B||(B=await import("archiver")),B}const x={maxEntries:1e4,maxFileBytes:512*1024*1024,maxTotalBytes:2*1024*1024*1024,maxPathDepth:64,maxPathLength:4096},Pt=new pt("gbk");function h(t){return String(t||"").replace(/\\/g,"/")}function H(t){const e=w.resolve(String(t||"").trim());if(!e)throw new Error("workspacePath is required");return e}async function kt(t){const e=H(t),r=await s.realpath(e);if(!(await s.stat(r)).isDirectory())throw new Error(`Workspace path is not a directory: ${e}`);return r}async function v(t){return{requestedRoot:H(t),workspaceRoot:await kt(t)}}function C(t,e){const r=w.resolve(e),i=w.relative(t,r);if(i.startsWith("..")||w.isAbsolute(i))throw new Error(`Target path is outside workspace: ${r}`);return r}async function R(t){return s.realpath(t)}async function D(t){await s.realpath(w.dirname(t));try{if((await s.lstat(t)).isSymbolicLink())throw new Error(`Refusing to write through symbolic link: ${t}`)}catch(e){if((typeof e=="object"&&e!==null?Reflect.get(e,"code"):void 0)!=="ENOENT")throw e}}function $(t,e,r){const i=w.resolve(t,r),o=w.relative(t,i);return o.startsWith("..")||w.isAbsolute(o)?i:C(e,w.join(e,o))}async function I({workspacePath:t,targetPath:e=""}){const{requestedRoot:r,workspaceRoot:i}=await v(t),o=String(e||"").trim(),a=o?$(r,i,o):i,n=await R(a);return{workspaceRoot:i,resolvedTargetPath:n}}function L(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("\\")||w.basename(e)!==e)throw new Error(`entryName must be a plain file or directory name: ${e}`);return e}function K(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 M(t){const e=K(t);return L(w.basename(e.replace(/\\/g,"/")))}function xt(t,e){if(!t)return M(e);const i=K(String(t||e||"")).replace(/\\/g,"/").split("/").filter(Boolean).map(o=>L(o));return i.length===0?M(e):w.join(...i)}function X(t){return(t&4095).toString(8).padStart(4,"0")}function vt(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 N(t,e,r,i,o,a,n){const c=t&e?"r":"-",l=t&r?"w":"-",u=(t&i)!==0,f=(t&o)!==0?u?a:n:u?"x":"-";return`${c}${l}${f}`}function Et(t){return[N(t,256,128,64,2048,"s","S"),N(t,32,16,8,1024,"s","S"),N(t,4,2,1,512,"t","T")].join("")}function St(t){if(!(t.length<24||t.toString("hex",0,8)!=="89504e470d0a1a0a"))return{format:"png",width:t.readUInt32BE(16),height:t.readUInt32BE(20)}}function Rt(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 Dt(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 Ft(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 V(t,e){if((await s.lstat(t)).isSymbolicLink())throw new Error(`Refusing to change permissions on symbolic link: ${t}`);const i=await s.stat(t);if(!e||!i.isDirectory())return[t];const o=await s.readdir(t),a=await Promise.all(o.map(n=>{const c=w.join(t,n);return V(c,!0)}));return[t,...a.flat()]}async function zt(t){if((await s.lstat(t)).isSymbolicLink())throw new Error(`Refusing to change permissions on symbolic link: ${t}`);await R(t)}async function Tt(t){const e=await s.open(t,"r");try{const r=Buffer.alloc(512),{bytesRead:i}=await e.read(r,0,r.length,0),o=r.subarray(0,i);return St(o)||Rt(o)||Dt(o)||Ft(o)}finally{await e.close()}}async function F({workspacePath:t,targetPath:e},r={}){const{requestedRoot:i,workspaceRoot:o}=await v(t),a=String(e||"").trim();if(!a)throw new Error("targetPath is required");const n=$(i,o,a),c=await R(n);if(!r.allowWorkspaceRoot&&c===o)throw new Error("Workspace root cannot be modified");return{workspaceRoot:o,resolvedTargetPath:c}}async function Y(t){const{requestedRoot:e,workspaceRoot:r}=await v(t.workspacePath),i=String(t.targetPath||"").trim();if(!i)return{workspaceRoot:r,resolvedTargetPath:r};const o=$(e,r,i);return await it(o)?{workspaceRoot:r,resolvedTargetPath:await s.realpath(o)}:(await s.realpath(w.dirname(o)),{workspaceRoot:r,resolvedTargetPath:o})}function J(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 Q(t){return t.replace(/\.tar\.gz$/i,"").replace(/\.tgz$/i,"").replace(/\.zip$/i,"").replace(/\.tar$/i,"").replace(/\.gz$/i,"")}function $t(t,e){const r=L(Q(e)||"extracted");return w.join(t,r)}function j(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>x.maxPathLength||i.length>x.maxPathDepth)throw new Error(`Archive entry path is too deep or too long: ${e}`);return C(t,w.join(t,r))}function Lt(t){const e=t.props?.pathBuffer;if(!e||t.props?.flags?.isUnicode)return t.path;const r=Pt.decode(e);return!r||r.includes("\uFFFD")?t.path:r}async function tt(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 U(t){if(t.entries+=1,t.entries>x.maxEntries)throw new Error(`Archive contains too many entries. Limit: ${x.maxEntries}`)}function et(t,e){if(t.totalBytes+=e,e>x.maxFileBytes)throw new Error(`Archive entry exceeds max size. Limit: ${x.maxFileBytes} bytes`);if(t.totalBytes>x.maxTotalBytes)throw new Error(`Archive extraction exceeds total size. Limit: ${x.maxTotalBytes} bytes`)}async function rt(t,e,r){let i=0;t.on("data",o=>{const a=Buffer.isBuffer(o)?o.length:Buffer.byteLength(o);i+=a,(i>x.maxFileBytes||r.totalBytes+i>x.maxTotalBytes)&&t instanceof dt&&t.destroy(new Error("Archive extraction size limit exceeded"))}),await ft(t,Z(e)),et(r,i)}async function it(t){try{return await s.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 v(t),o=String(e||"").trim();if(!o)throw new Error("filePath is required");return{workspaceRoot:i,resolvedFilePath:$(r,i,o)}}async function Xt(t){const{workspaceRoot:e}=await v(t.workspacePath),r=String(t.targetPath||"").trim();if(!r){const{resolvedTargetPath:l}=await I(t);return ot(e,l)}const i=w.resolve(r);let o;try{o=await s.realpath(i)}catch{throw new Error(`Path not found: ${i}`)}if(!(await s.stat(o)).isDirectory())throw new Error(`Path is not a directory: ${i}`);const n=w.relative(e,o),c=n===""||!n.startsWith("..")&&!w.isAbsolute(n);return ot(e,c?o:i)}async function ot(t,e){if(!(await s.stat(e)).isDirectory())throw new Error(`Path is not a directory: ${e}`);const i=await s.readdir(e,{withFileTypes:!0}),o=await Promise.all(i.map(async a=>{const n=w.join(e,a.name);let c;if(a.isFile())try{c=(await s.stat(n)).size}catch{c=void 0}return{name:a.name,path:h(n),isDirectory:a.isDirectory(),size:c}}));return{currentPath:h(e),workspacePath:h(t),items:o}}async function Vt(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t),i=await R(r),o=await s.stat(i);if(!o.isFile())throw new Error(`Path is not a file: ${i}`);const a=await s.readFile(i,"utf-8");return{workspacePath:h(e),filePath:h(i),content:a,mtimeMs:o.mtimeMs}}const at={maxEntries:1e5,maxDepth:32};async function At(t){let e=0,r=0;async function i(o,a){if(a>=at.maxDepth)return;let n;try{n=await s.readdir(o,{withFileTypes:!0})}catch{return}for(const c of n){if(r+=1,r>at.maxEntries)return;if(c.isSymbolicLink())continue;const l=w.join(o,c.name);try{if(c.isDirectory())await i(l,a+1);else if(c.isFile()){const u=await s.stat(l);e+=u.size}}catch{}}}return await i(t,0),e}async function Yt(t){const{workspaceRoot:e,resolvedTargetPath:r}=await F(t,{allowWorkspaceRoot:!0}),[i,o]=await Promise.all([s.stat(r),s.lstat(r)]),a=i.isDirectory(),n=i.isFile()?await Tt(r):void 0,c=a?await At(r):i.size;return{workspacePath:h(e),targetPath:h(r),name:w.basename(r),isDirectory:i.isDirectory(),isFile:i.isFile(),isSymbolicLink:o.isSymbolicLink(),size:c,mode:i.mode,modeOctal:X(i.mode),permissions:Et(i.mode),uid:i.uid,gid:i.gid,atimeMs:i.atimeMs,mtimeMs:i.mtimeMs,ctimeMs:i.ctimeMs,birthtimeMs:i.birthtimeMs,...n?{image:n}:{}}}async function Jt(t){const e=vt(t.mode),r=!!t.recursive,{workspaceRoot:i,resolvedTargetPath:o}=await F(t),a=await V(o,r);for(const n of a)await zt(n),await s.chmod(n,e);return{ok:!0,workspacePath:h(i),targetPath:h(o),mode:e,modeOctal:X(e),recursive:r,changedCount:a.length}}async function Qt(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t),i=await R(r),o=await s.stat(i);if(!o.isFile())throw new Error(`Path is not a file: ${i}`);const a=w.extname(i).toLowerCase();if(a===".doc"||a===".xls"||a===".ppt")return{workspacePath:h(e),filePath:h(i),kind:"unsupported",content:"",message:`\u65E7\u7248 ${a} \u683C\u5F0F\u5C06\u7531\u670D\u52A1\u7AEF\u8F6C\u6362\u4E3A\u73B0\u4EE3\u683C\u5F0F\u540E\u6253\u5F00\uFF08\u539F\u6587\u4EF6\u4E0D\u53D8\uFF09\u3002`,size:o.size,mtimeMs:o.mtimeMs};if(!/\.(docx|docm|xlsx|xlsm|pptx|pptm)$/.test(a))throw new Error("Document preview only supports docx/xlsx/pptx files");return{workspacePath:h(e),filePath:h(i),kind:"html",content:"",size:o.size,mtimeMs:o.mtimeMs}}async function te(t){const{workspaceRoot:e,resolvedFilePath:r}=await W(t);await s.mkdir(w.dirname(r),{recursive:!0}),await D(r),await s.writeFile(r,String(t.content??""),"utf-8");const i=await s.stat(r);return{ok:!0,workspacePath:h(e),filePath:h(r),mtimeMs:i.mtimeMs}}async function ee(t){const{workspaceRoot:e,resolvedTargetPath:r}=await I(t),i=L(t.entryName),o=w.join(r,i);if(!(await s.stat(r)).isDirectory())throw new Error(`Path is not a directory: ${r}`);try{throw await s.access(o),new Error(`Path already exists: ${o}`)}catch(n){if((typeof n=="object"&&n!==null?Reflect.get(n,"code"):void 0)!=="ENOENT")throw n}return t.isDirectory?await s.mkdir(o,{recursive:!1}):(await s.mkdir(w.dirname(o),{recursive:!0}),await D(o),await s.writeFile(o,"","utf-8")),{ok:!0,workspacePath:h(e),targetPath:h(o),isDirectory:t.isDirectory}}async function re(t){const{workspaceRoot:e,resolvedTargetPath:r}=await F(t),i=L(t.newName),o=w.join(w.dirname(r),i);if(o===r)return{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(o)};await s.stat(r);try{throw await s.access(o),new Error(`Path already exists: ${o}`)}catch(a){if((typeof a=="object"&&a!==null?Reflect.get(a,"code"):void 0)!=="ENOENT")throw a}return await s.rename(r,o),{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(o)}}async function ie(t){const{workspaceRoot:e,resolvedTargetPath:r}=await F(t),i=await I({workspacePath:t.workspacePath,targetPath:t.destinationPath});if(!(await s.stat(i.resolvedTargetPath)).isDirectory())throw new Error(`Destination is not a directory: ${i.resolvedTargetPath}`);if((await s.stat(r)).isDirectory()){const c=w.relative(r,i.resolvedTargetPath);if(c===""||!c.startsWith("..")&&!w.isAbsolute(c))throw new Error("Cannot move a directory into itself or its descendant")}const n=w.join(i.resolvedTargetPath,w.basename(r));if(n===r)return{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(n),destinationPath:h(i.resolvedTargetPath)};try{throw await s.access(n),new Error(`Path already exists: ${n}`)}catch(c){if((typeof c=="object"&&c!==null?Reflect.get(c,"code"):void 0)!=="ENOENT")throw c}return await s.rename(r,n),{ok:!0,workspacePath:h(e),sourcePath:h(r),targetPath:h(n),destinationPath:h(i.resolvedTargetPath)}}async function oe(t){const{workspaceRoot:e,resolvedTargetPath:r}=await F(t),i=await s.stat(r),o=w.parse(r).root;if(r===o)throw new Error("Filesystem root cannot be deleted");return i.isDirectory()?await s.rm(r,{recursive:!0,force:!1}):await s.unlink(r),{ok:!0,workspacePath:h(e),targetPath:h(r)}}async function ae(t){if(!Array.isArray(t.files)||t.files.length===0)throw new Error("files are required");const{workspaceRoot:e,resolvedTargetPath:r}=await Y(t);if(!(await s.stat(r)).isDirectory())throw new Error(`Path is not a directory: ${r}`);const o=[];for(const a of t.files){const n=M(a.originalname),c=xt(a.relativePath,a.originalname),l=w.join(r,c);await s.mkdir(w.dirname(l),{recursive:!0}),await D(l),await s.copyFile(a.path,l);let u;t.extractArchives&&J(l)&&(u=await It({workspacePath:e,archivePath:l,outputPath:$t(r,n)})),o.push({fileName:n,targetPath:h(l),size:a.size,extracted:u})}return{ok:!0,workspacePath:h(e),targetPath:h(r),files:o}}async function ne(t){const{workspaceRoot:e,resolvedTargetPath:r}=await F(t),i=await s.stat(r),o=w.basename(r);return{workspacePath:h(e),targetPath:h(r),resolvedTargetPath:r,fileName:i.isDirectory()?`${o||"workspace"}.zip`:o,contentType:i.isDirectory()?"application/zip":Ct(r),isDirectory:i.isDirectory(),size:i.isDirectory()?void 0:i.size}}function Ct(t){const e=w.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 se(t,e){const{ZipArchive:r}=await G(),i=new r({zlib:{level:9}}),o=new Promise((a,n)=>{e.on("close",a),e.on("finish",a),i.on("error",n),e.on("error",n)});i.pipe(e),i.directory(t,!1),await i.finalize(),await o}async function ce(t,e,r,i){const o=w.join(wt.tmpdir(),"agentswork-bridge-downloads");await s.mkdir(o,{recursive:!0});const a=(e||"workspace.zip").replace(/[^\w.-]/g,"_").replace(/\.zip$/i,"")||"workspace",n=w.join(o,`${a}-${Date.now()}-${Math.random().toString(36).slice(2,8)}.zip`),{ZipArchive:c}=await G(),l=new c({zlib:{level:9}}),u=()=>l.pointer(),d=()=>l.abort(),f=Z(n),p=new Promise((g,P)=>{f.on("close",g),f.on("finish",g),l.on("error",P),f.on("error",P)});p.catch(()=>{}),l.pipe(f);const m=setInterval(()=>{try{if(i?.()){d();return}r?.(u())}catch{}},200);try{return l.on("progress",()=>{i?.()&&d()}),l.directory(t,!1),i?.()&&d(),await l.finalize(),await p,r?.(u()),n}catch(g){throw await s.rm(n,{force:!0}).catch(()=>{}),g}finally{clearInterval(m)}}async function Wt(t,e,r){let i=0,o;const a=_(t),n=a.pipe(gt.Parse({forceStream:!0}));try{for await(const c of n){if(o){await tt(c);continue}const l=Lt(c);try{const u=j(e,l);if(U(r),c.type==="Directory"){await s.mkdir(u,{recursive:!0});continue}if(c.type!=="File")throw new Error(`Unsupported archive entry type: ${l}`);await s.mkdir(w.dirname(u),{recursive:!0}),await D(u),await rt(c,u,r),i+=1}catch(u){o=u,await tt(c)}}}finally{a.destroy(),n.destroy()}if(o)throw o;return i}async function bt(t,e,r,i){let o=0,a;const n=(c,l)=>{if(a)return!1;try{j(e,c),U(i);const u=String(l.type||"").toLowerCase();if(u==="symboliclink"||u==="link")throw new Error(`Archive links are not supported: ${c}`);if(u!=="file"&&u!=="oldfile"&&u!=="contiguousfile"&&u!=="directory")throw new Error(`Unsupported archive entry type: ${c}`);return typeof l.size=="number"&&et(i,l.size),u!=="directory"&&(o+=1),!0}catch(u){return a=u,!1}};if(await yt.x({file:t,cwd:e,gzip:r,strict:!0,filter:(c,l)=>n(c,l)}),a)throw a;return o}async function Bt(t,e,r){const i=Q(w.basename(t)),o=j(e,i||"decompressed");return U(r),await s.mkdir(w.dirname(o),{recursive:!0}),await D(o),await rt(_(t).pipe(mt()),o,r),1}async function It(t){const{requestedRoot:e,workspaceRoot:r}=await v(t.workspacePath),{resolvedTargetPath:i}=await Y({workspacePath:t.workspacePath,targetPath:t.outputPath||""}),o=$(e,r,String(t.archivePath||"").trim()),a=await R(o);if(!(await s.stat(a)).isFile())throw new Error(`Archive path is not a file: ${a}`);if(await it(i)||await s.mkdir(i,{recursive:!0}),!(await s.stat(i)).isDirectory())throw new Error(`Output path is not a directory: ${i}`);const l=J(a);if(!l)throw new Error("Unsupported archive type. Supported: .zip, .tar, .tar.gz, .tgz, .gz");let u=0;const d={entries:0,totalBytes:0};return l==="zip"?u=await Wt(a,i,d):l==="tar"||l==="tgz"?u=await bt(a,i,l==="tgz",d):u=await Bt(a,i,d),{ok:!0,workspacePath:h(r),archivePath:h(a),targetPath:h(i),extractedEntries:u}}function nt(t){const e=t.match(/^(.*?)\{([^}]+)\}(.*)$/);if(!e)return[t];const[,r,i,o]=e;return i.split(",").flatMap(a=>nt(r+a.trim()+o))}function st(t,e){const r=String(e||"").trim();if(!r||r==="*"||r==="*.*")return!0;const i=t.toLowerCase();return nt(r.toLowerCase()).some(a=>{if(a==="*")return!0;const n=a.replace(/\./g,"\\.").replace(/\*\*/g,"<<GLOBSTAR>>").replace(/\*/g,"[^/]*").replace(/\?/g,"[^/]").replace(/<<GLOBSTAR>>/g,".*");return new RegExp(`^${n}$`).test(i)})}function q(t){return t===".git"||t==="node_modules"||t===".svn"||t===".hg"}const ct=10*1024*1024,Mt=1e3;async function lt(t,e){const{workspaceRoot:r}=await v(t),i=String(e||"").trim();if(!i)return{workspaceRoot:r,searchRoot:r};const o=w.resolve(/^[A-Za-z]:$/.test(i)?`${i}/`:i);let a;try{a=await s.realpath(o)}catch{throw new Error(`Path not found: ${o}`)}if(!(await s.stat(a)).isDirectory())throw new Error(`Path is not a directory: ${o}`);return{workspaceRoot:r,searchRoot:a}}async function le(t){const{workspaceRoot:e,searchRoot:r}=await lt(t.workspacePath,t.rootPath),i=String(t.keyword||"").trim();if(!i)throw new Error("keyword is required");const o=!!t.ignoreCase,a=String(t.fileMask||"").trim(),n=typeof t.maxResults=="number"&&t.maxResults>0?t.maxResults:Mt,c=o?i.toLowerCase():i,u=(t.mode==="filename"?"filename":"content")==="filename",d=[];let f=0,p=!1;async function m(g){if(p)return;let P;try{P=await s.readdir(g,{withFileTypes:!0})}catch{return}for(const y of P){if(p)return;const k=C(r,w.join(g,y.name));if(y.isSymbolicLink())continue;if(y.isDirectory()){if(q(y.name))continue;await m(k);continue}if(!y.isFile()||a&&!st(y.name,a))continue;f+=1;let S;try{S=await s.stat(k)}catch{continue}if(S.size>ct)continue;if(u){const E=(o?y.name.toLowerCase():y.name).indexOf(c);if(E!==-1&&(d.push({filePath:h(k),lineNumber:0,lineContent:y.name,matchStart:E,matchEnd:E+i.length}),d.length>=n)){p=!0;return}continue}let z;try{z=await s.readFile(k,"utf-8")}catch{continue}const b=z.split(/\r?\n/);for(let T=0;T<b.length;T+=1){const E=b[T],ut=o?E.toLowerCase():E;let O=0;for(;;){const A=ut.indexOf(c,O);if(A===-1)break;if(d.push({filePath:h(k),lineNumber:T+1,lineContent:E,matchStart:A,matchEnd:A+i.length}),d.length>=n){p=!0;return}O=A+1}}}}return await m(r),{workspacePath:h(e),keyword:i,totalFiles:f,totalMatches:d.length,matches:d,truncated:p}}const Nt=100,jt=120;async function he(t){const{workspaceRoot:e}=await v(t.workspacePath),r=String(t.keyword||"").trim();if(!r)throw new Error("keyword is required");const i=!!t.ignoreCase,o=i?r.toLowerCase():r,a=typeof t.maxResults=="number"&&t.maxResults>0?t.maxResults:Nt,n=typeof t.maxDirectories=="number"&&t.maxDirectories>0?t.maxDirectories:jt,c=String(t.rootPath||"").trim(),l=c?w.resolve(/^[A-Za-z]:$/.test(c)?`${c}/`:c):e;let u;try{u=await s.realpath(l)}catch{throw new Error(`Path not found: ${l}`)}if(!(await s.stat(u)).isDirectory())throw new Error(`Path is not a directory: ${l}`);const f=[],p=[u];let m=0,g=!1;for(;p.length>0&&f.length<a&&m<n;){const P=p.shift();m+=1;let y;try{y=await s.readdir(P,{withFileTypes:!0})}catch{continue}for(const k of y){if(f.length>=a){g=!0;break}if(k.isSymbolicLink())continue;const S=w.join(P,k.name);if(k.isDirectory()&&q(k.name))continue;const z=w.relative(u,S).replace(/\\/g,"/");(i?z.toLowerCase():z).includes(o)&&f.push({name:k.name,path:h(S),isDirectory:k.isDirectory()}),k.isDirectory()&&m<n&&p.push(S)}}return(m>=n||f.length>=a)&&(g=!0),f.sort((P,y)=>P.isDirectory===y.isDirectory?P.name.localeCompare(y.name):P.isDirectory?-1:1),{workspacePath:h(e),rootPath:h(u),keyword:r,items:f,truncated:g}}async function ht(t,e,r,i){let o;try{o=await s.readFile(t,"utf-8")}catch{return{changed:!1,count:0}}const a=o;let n=0;if(i){const c=e.toLowerCase();let l=0;for(;;){const d=o.toLowerCase().indexOf(c,l);if(d===-1)break;o=o.slice(0,d)+r+o.slice(d+e.length),n+=1;const f=r.length||1;l=d+f}}else{let c=0;for(;;){const l=o.indexOf(e,c);if(l===-1)break;o=o.slice(0,l)+r+o.slice(l+e.length),n+=1;const u=r.length||1;c=l+u}}return o===a?{changed:!1,count:0}:(await D(t),await s.writeFile(t,o,"utf-8"),{changed:!0,count:n})}async function ue(t){const{workspaceRoot:e,searchRoot:r}=await lt(t.workspacePath,t.rootPath),i=String(t.keyword||"").trim();if(!i)throw new Error("keyword is required");const o=String(t.replacement??""),a=!!t.ignoreCase,n=String(t.fileMask||"").trim(),c=String(t.filePath||"").trim();let l=0,u=0;if(c){const{resolvedFilePath:f}=await W({workspacePath:t.workspacePath,filePath:c}),p=await ht(f,i,o,a);return p.changed&&(l=1,u=p.count),{workspacePath:h(e),keyword:i,replacement:o,changedFiles:l,changedMatches:u}}async function d(f){let p;try{p=await s.readdir(f,{withFileTypes:!0})}catch{return}for(const m of p){const g=C(r,w.join(f,m.name));if(m.isSymbolicLink())continue;if(m.isDirectory()){if(q(m.name))continue;await d(g);continue}if(!m.isFile()||n&&!st(m.name,n))continue;try{if((await s.stat(g)).size>ct)continue}catch{continue}const P=await ht(g,i,o,a);P.changed&&(l+=1,u+=P.count)}}return await d(r),{workspacePath:h(e),keyword:i,replacement:o,changedFiles:l,changedMatches:u}}export{Jt as chmodWorkspaceEntry,ee as createWorkspaceEntry,oe as deleteWorkspaceEntry,It as extractWorkspaceArchive,Yt as getWorkspaceEntryProperties,Xt as listWorkspaceDirectory,ie as moveWorkspaceEntry,Qt as previewWorkspaceDocument,Vt as readWorkspaceFile,re as renameWorkspaceEntry,ue as replaceWorkspaceFiles,ne as resolveWorkspaceDownloadTarget,le as searchWorkspaceFiles,he as searchWorkspacePaths,se as streamWorkspaceDirectoryZip,ae as uploadWorkspaceFiles,te as writeWorkspaceFile,ce as zipWorkspaceDirectoryToTemp};
2
2
 
@@ -0,0 +1,31 @@
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+ export interface LoadDynamicModuleOptions {
28
+
29
+ freshInstanceQuery?: string;
30
+ }
31
+ export declare function loadDynamicModule<T = unknown>(specifier: string, options?: LoadDynamicModuleOptions): Promise<T>;
@@ -0,0 +1,2 @@
1
+ import{copyFileSync as u,rmSync as s}from"node:fs";import{fileURLToPath as l}from"node:url";async function i(e,t){if(typeof require=="function"&&typeof require.cache=="object"&&require.cache!==null){const o=require,r=e.startsWith("file://")?l(e):e;if(t?.freshInstanceQuery){if(/\.m[jt]s$/i.test(r)){const c=t.freshInstanceQuery.replace(/[^A-Za-z0-9._-]/g,"_"),n=r.match(/\.[^.]+$/)?.[0]??".mjs",a=`${r}.acode-fresh-${c}${n}`;try{return u(r,a),o(a)}finally{try{s(a,{force:!0})}catch{}}}try{const c=o.resolve(r),n=require.cache;n&&c&&delete n[c]}catch{}}return o(r)}return import(t?.freshInstanceQuery?`${e}${e.includes("?")?"&":"?"}${t.freshInstanceQuery}`:e)}export{i as loadDynamicModule};
2
+
@@ -1,2 +1,2 @@
1
- import{access as p,readFile as m}from"node:fs/promises";import o from"node:path";import{fileURLToPath as l,pathToFileURL as y}from"node:url";const d=(()=>{const r=String(process.env.AWS_BRIDGE_PACKAGE_ROOT||"").trim();return r?o.resolve(r):o.resolve(o.dirname(l(import.meta.url)),"..","..")})();function c(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function E(r,t){return o.join(t,"node_modules",...r.split("/"))}function e(r){if(typeof r=="string")return r;if(!c(r))return null;for(const t of["import","module","default","node"]){const n=e(r[t]);if(n)return n}return null}function g(r){return typeof r=="string"?r:c(r)?e(r["."])??e(r):null}function P(r){const t=g(r.exports);return t||(typeof r.module=="string"?r.module:typeof r.main=="string"?r.main:"index.js")}async function h(r,t=d){const n=E(r,t),a=o.join(n,"package.json"),s=await m(a,"utf8"),f=JSON.parse(s),u=P(f),i=o.resolve(n,u);return await p(i),i}async function A(r){try{const t=await h(r);return await import(y(t).href)}catch(t){if(t instanceof Error&&"code"in t&&t.code==="ENOENT")return await import(r);throw t}}export{d as BRIDGE_PACKAGE_ROOT,A as importBridgeSdkPackage,h as resolveBridgePackageEntryPath};
1
+ import{access as l,readFile as m}from"node:fs/promises";import o from"node:path";import{fileURLToPath as y,pathToFileURL as d}from"node:url";import{loadDynamicModule as c}from"./dynamic-import.js";const E=(()=>{const r=String(process.env.AWS_BRIDGE_PACKAGE_ROOT||"").trim();return r?o.resolve(r):o.resolve(o.dirname(y(import.meta.url)),"..","..")})();function a(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function g(r,t){return o.join(t,"node_modules",...r.split("/"))}function e(r){if(typeof r=="string")return r;if(!a(r))return null;for(const t of["import","module","default","node"]){const n=e(r[t]);if(n)return n}return null}function P(r){return typeof r=="string"?r:a(r)?e(r["."])??e(r):null}function h(r){const t=P(r.exports);return t||(typeof r.module=="string"?r.module:typeof r.main=="string"?r.main:"index.js")}async function R(r,t=E){const n=g(r,t),s=o.join(n,"package.json"),f=await m(s,"utf8"),u=JSON.parse(f),p=h(u),i=o.resolve(n,p);return await l(i),i}async function O(r){try{const t=await R(r);return await c(d(t).href)}catch(t){if(t instanceof Error&&"code"in t&&t.code==="ENOENT")return await c(r);throw t}}export{E as BRIDGE_PACKAGE_ROOT,O as importBridgeSdkPackage,R as resolveBridgePackageEntryPath};
2
2
 
File without changes
File without changes
File without changes
File without changes