aws-runtime-bridge 1.9.186 → 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 (75) hide show
  1. package/CHANGELOG.md +1767 -1673
  2. package/README.md +256 -256
  3. package/dist/adapter/AcodeSdkAdapter.js +3 -3
  4. package/dist/browser/browser-pool.d.ts +2 -0
  5. package/dist/browser/browser-pool.js +1 -1
  6. package/dist/config.d.ts +12 -0
  7. package/dist/config.js +2 -2
  8. package/dist/index.js +1 -1
  9. package/dist/remote-desktop/win32-api.js +1 -1
  10. package/dist/routes/background-tasks.js +4 -4
  11. package/dist/routes/dashboard.js +17 -17
  12. package/dist/routes/terminal.js +19 -19
  13. package/dist/services/acode-bg-manager.js +1 -1
  14. package/dist/services/auto-register.js +1 -1
  15. package/dist/services/instance-features.d.ts +9 -0
  16. package/dist/services/instance-features.js +1 -1
  17. package/dist/services/panel-auth.d.ts +4 -0
  18. package/dist/services/panel-auth.js +1 -1
  19. package/dist/services/plugin-handler-adapter.js +2 -2
  20. package/dist/services/workspace-files.js +1 -1
  21. package/dist/utils/dynamic-import.d.ts +31 -0
  22. package/dist/utils/dynamic-import.js +2 -0
  23. package/dist/utils/sdk-package-loader.js +1 -1
  24. package/node_modules/playwright/cli.js +0 -0
  25. package/node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh +0 -0
  26. package/node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh +0 -0
  27. package/node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh +0 -0
  28. package/node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh +0 -0
  29. package/node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh +0 -0
  30. package/node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh +0 -0
  31. package/node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh +0 -0
  32. package/node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh +0 -0
  33. package/node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh +0 -0
  34. package/node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh +0 -0
  35. package/node_modules/playwright-core/cli.js +0 -0
  36. package/node_modules/playwright-core/lib/webp_codec.wasm +0 -0
  37. package/node_modules/playwright-core/lib/xdg-open +0 -0
  38. package/package/acode/dist/await-complete-tool.js +3 -3
  39. package/package/acode/dist/runtime.d.ts +9 -0
  40. package/package/acode/dist/runtime.js +20 -21
  41. package/package/acode/dist/sub-agent-manager.d.ts +33 -0
  42. package/package/acode/dist/sub-agent-manager.js +9 -1
  43. package/package/acode/dist/sub-agent-tools.d.ts +4 -0
  44. package/package/acode/dist/sub-agent-tools.js +27 -12
  45. package/package/acode/dist/subagent-handback.d.ts +16 -0
  46. package/package/acode/dist/subagent-handback.js +7 -0
  47. package/package/acode/dist/tool-allocation.js +1 -1
  48. package/package/acode/package.json +38 -38
  49. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +10 -5
  50. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  51. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +27 -0
  52. package/package/aws-client-agent-mcp/dist/mcp-server.js +16 -16
  53. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +19 -0
  54. package/package/aws-client-agent-mcp/dist/mcp-tools.js +35 -19
  55. package/package/aws-client-agent-mcp/dist/message-buffer.d.ts +10 -0
  56. package/package/aws-client-agent-mcp/dist/message-buffer.js +1 -1
  57. package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
  58. package/package/aws-client-agent-mcp/dist/types.d.ts +81 -3
  59. package/package/aws-client-agent-mcp/package.json +53 -53
  60. package/package.json +134 -132
  61. /package/package/acode/dist/grammars/{grammars/tree-sitter-bash.wasm → tree-sitter-bash.wasm} +0 -0
  62. /package/package/acode/dist/grammars/{grammars/tree-sitter-c-sharp.wasm → tree-sitter-c-sharp.wasm} +0 -0
  63. /package/package/acode/dist/grammars/{grammars/tree-sitter-c.wasm → tree-sitter-c.wasm} +0 -0
  64. /package/package/acode/dist/grammars/{grammars/tree-sitter-cpp.wasm → tree-sitter-cpp.wasm} +0 -0
  65. /package/package/acode/dist/grammars/{grammars/tree-sitter-go.wasm → tree-sitter-go.wasm} +0 -0
  66. /package/package/acode/dist/grammars/{grammars/tree-sitter-java.wasm → tree-sitter-java.wasm} +0 -0
  67. /package/package/acode/dist/grammars/{grammars/tree-sitter-javascript.wasm → tree-sitter-javascript.wasm} +0 -0
  68. /package/package/acode/dist/grammars/{grammars/tree-sitter-jsx.wasm → tree-sitter-jsx.wasm} +0 -0
  69. /package/package/acode/dist/grammars/{grammars/tree-sitter-lua.wasm → tree-sitter-lua.wasm} +0 -0
  70. /package/package/acode/dist/grammars/{grammars/tree-sitter-php.wasm → tree-sitter-php.wasm} +0 -0
  71. /package/package/acode/dist/grammars/{grammars/tree-sitter-python.wasm → tree-sitter-python.wasm} +0 -0
  72. /package/package/acode/dist/grammars/{grammars/tree-sitter-ruby.wasm → tree-sitter-ruby.wasm} +0 -0
  73. /package/package/acode/dist/grammars/{grammars/tree-sitter-rust.wasm → tree-sitter-rust.wasm} +0 -0
  74. /package/package/acode/dist/grammars/{grammars/tree-sitter-tsx.wasm → tree-sitter-tsx.wasm} +0 -0
  75. /package/package/acode/dist/grammars/{grammars/tree-sitter-typescript.wasm → tree-sitter-typescript.wasm} +0 -0
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{existsSync as T,readFileSync as D}from"node:fs";import M from"node:os";import S from"node:path";import{pathToFileURL as E}from"node:url";import{sweepExpiredJournals as x}from"@agentswork/acode";import F from"cors";import P from"express";import{adapterRegistry as L}from"./adapter/index.js";import{attachBrowserWebSocketServer as G}from"./browser/browser-ws-bridge.js";import{getAcodeDataHome as O,getActiveBridgeHttpPort as $,getAutoRegisterConfigFilePath as j,getBridgeDataHome as K,getBridgeListenHost as N,getBridgeRuntimePropertiesFilePath as _,getBridgeTemplateConfigFile as H,reserveBridgeListenPort as W,validateProductionToken as U,writeBridgeRuntimePropertiesFile as J}from"./config.js";import{attachRemoteDesktopWebSocketServer as z}from"./remote-desktop/index.js";import{acodeTodosRouter as Y}from"./routes/acode-todos.js";import{agentStateRouter as Z}from"./routes/agent-state.js";import{aiSourcesRouter as q}from"./routes/ai-sources.js";import{backgroundTasksRouter as Q}from"./routes/background-tasks.js";import{bridgeTempFilesRouter as V}from"./routes/bridge-temp-files.js";import{browserListenersRouter as X}from"./routes/browser-listeners.js";import{browserSessionsRouter as ee}from"./routes/browser-sessions.js";import{capabilitiesRouter as re}from"./routes/capabilities.js";import{computerRouter as te}from"./routes/computer.js";import{dashboardRouter as ie}from"./routes/dashboard.js";import{debugMountRouter as oe}from"./routes/debug-mount.js";import{desktopControlRouter as ne}from"./routes/desktop-control.js";import{eventsRouter as se}from"./routes/events.js";import{fileBrowserRouter as ae}from"./routes/file-browser.js";import{fileChangeDiffRouter as me}from"./routes/file-change-diff.js";import{fileDiffRollbackRouter as ue}from"./routes/file-diff-rollback.js";import{fileSnapshotRouter as ce}from"./routes/file-snapshot.js";import{gitRouter as de}from"./routes/git.js";import{instanceRouter as ge,setGracefulShutdownFn as pe}from"./routes/instance.js";import{jdksRouter as fe}from"./routes/jdks.js";import{launchRouter as le}from"./routes/launch.js";import{lspProvidersRouter as be}from"./routes/lsp-providers.js";import{attachLspWebSocketServer as he}from"./routes/lsp.js";import{ltrRouter as we}from"./routes/ltr.js";import{mcpExtraRouter as Re}from"./routes/mcp-extra.js";import{mcpRouter as Se}from"./routes/mcp.js";import{pluginsRouter as Pe}from"./routes/plugins.js";import{processesRouter as $e}from"./routes/processes.js";import{propertiesRouter as ye}from"./routes/properties.js";import{attachPtyWebSocketServer as Ie,closeAllPtySessions as ke,ptyRouter as Ce,ptySessions as Ae}from"./routes/pty.js";import{runtimeBindingRouter as ve,logRuntimeBindingStartupState as Be}from"./routes/runtime-binding.js";import{sessionsRouter as Te}from"./routes/sessions.js";import{skillsRouter as De}from"./routes/skills.js";import{subAgentsRouter as Me}from"./routes/sub-agents.js";import{systemMetricsRouter as Ee}from"./routes/system-metrics.js";import{taskContextRouter as xe}from"./routes/task-context.js";import{techStackRouter as Fe}from"./routes/tech-stack.js";import{terminalRouter as Le,sdkSessions as w}from"./routes/terminal.js";import{workspaceIndexRouter as Ge}from"./routes/workspace-index.js";import{ymlRouter as Oe}from"./routes/yml.js";import{accessControlMiddleware as je}from"./services/access-control.js";import{ensureAcodePackageReleased as Ke,getReleasedAcodeEntryPath as Ne}from"./services/acode-package.js";import{getAgentProcessManager as y}from"./services/agent-process-manager.js";import{autoRegister as _e,unregister as He,bridgeRestartCleanup as We,cancelBackgroundRegisterRetries as Ue}from"./services/auto-register.js";import{ensureAwsClientAgentMcpReleased as Je}from"./services/aws-client-agent-mcp.js";import{disposeBrowserSessionManager as ze}from"./services/browser-session-manager.js";import{handleCliCommand as Ye}from"./services/cli-commands.js";import{disposeDesktopMcpManager as Ze}from"./services/desktop-mcp-manager.js";import{getLaunchManager as qe}from"./services/launch-manager.js";import{migrateOldPathsOnStartup as Qe}from"./services/legacy-path-migration.js";import{deliverPendingBridgeLifecycleNotifications as Ve}from"./services/lifecycle-state.js";import{startLogRetention as Xe}from"./services/log-retention.js";import{startOrphanMonitor as er,stopOrphanMonitor as rr}from"./services/orphan-monitor.js";import{pluginManager as tr}from"./services/plugin-manager.js";import{detectOrphanProcesses as ir}from"./services/process-detector.js";import{buildGracefulShutdownPlan as or,shouldCleanupPersistedSessionsOnStartup as nr}from"./services/runtime-lifecycle-policy.js";import{ensureStartupConfig as sr}from"./services/startup-config-wizard.js";import{subAgentStore as ar}from"./services/sub-agent-manager-instance.js";import{loadPersistedSessions as I,savePersistedSessions as k}from"./services/terminal-persistence.js";import{stopTunnelClient as mr}from"./services/tunnel-client.js";import{logger as e}from"./utils/logger.js";const C=await Ye();C.handled&&process.exit(C.exitCode),await sr(),U(),Je(),Ke(),Qe(),Be(),await W(),J(),e.info(`[runtime-bridge] \u5DF2\u5199\u5165\u8FD0\u884C\u65F6\u914D\u7F6E ${_()}\uFF08port=${$()}\uFF09`),e.info(`[runtime-bridge] ACode \u6570\u636E\u76EE\u5F55(\u7528\u6237): ${O()}`),e.info(`[runtime-bridge] Bridge \u6570\u636E\u76EE\u5F55: ${K()}`),e.info(`[runtime-bridge] \u6A21\u677F\u914D\u7F6E: ${H()}`),x().then(r=>{r>0&&e.info(`[runtime-bridge] \u5DF2\u6E05\u626B ${r} \u4E2A\u8D85\u671F\u4F11\u7720 journal`)}).catch(()=>{});async function ur(){try{if(await _e())e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6210\u529F");else{const{loadConfig:n}=await import("./services/auto-register.js"),o=n();!!o.userKey&&o.enabled?e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6682\u65F6\u5931\u8D25\uFF0C\u5C06\u5728\u540E\u53F0\u6301\u7EED\u91CD\u8BD5\u76F4\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3\u5EFA\u7ACB\u8FDE\u63A5"):(e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u672A\u914D\u7F6E\uFF0C\u7EE7\u7EED\u542F\u52A8\u670D\u52A1"),e.info(`[runtime-bridge] \u8981\u542F\u7528\u81EA\u52A8\u6CE8\u518C\uFF0C\u8BF7\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6 ${j()}`))}}catch(r){const n=r;e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u51FA\u9519:",n.message)}}ur().then(()=>cr()).then(()=>Ve()).then(()=>{e.info("[runtime-bridge] Bridge \u751F\u547D\u5468\u671F\u901A\u77E5\u540C\u6B65\u5B8C\u6210")}).catch(r=>{e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6216\u6E05\u7406\u51FA\u9519:",r)}),import("./services/update-notifier.js").then(({startUpdateNotifier:r})=>r()).catch(r=>{e.warn("[runtime-bridge] \u7248\u672C\u68C0\u67E5\u670D\u52A1\u542F\u52A8\u5931\u8D25:",r.message)});async function cr(){try{if(process.env.AWS_BRIDGE_RESTART_CLEANUP!=="true"){e.info("[runtime-bridge] \u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406\uFF0C\u4FDD\u7559 Agent \u72B6\u6001\u4F9B\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D");return}const{getRegistrationState:r}=await import("./services/auto-register.js"),n=r();if(!n.registered||!n.instanceId){e.info("[runtime-bridge] \u5B9E\u4F8B\u672A\u6CE8\u518C\uFF0C\u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406");return}e.info("[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5DF2\u663E\u5F0F\u542F\u7528\uFF0C\u6B63\u5728\u901A\u77E5\u8C03\u5EA6\u4E2D\u5FC3\u6E05\u7406 Agent \u72B6\u6001...");const o=await We();o.success?e.info(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u6210\u529F\uFF0C\u6E05\u7406\u4E86 ${o.agentCount||0} \u4E2A Agent`):e.warn(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5931\u8D25: ${o.error}`)}catch(r){const n=r;e.warn("[runtime-bridge] Bridge \u91CD\u542F\u6E05\u7406\u51FA\u9519:",n.message)}}async function dr(){try{const r=await I();if(r.length===0){e.info("[runtime-bridge] \u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u8DF3\u8FC7\u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA");return}await y().rebuildRegistry(r.map(o=>({agentId:o.agentId,sessionId:o.sessionId,pid:o.pid,workspacePath:o.workspacePath,command:o.command,mode:"sdk"}))),e.info(`[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5B8C\u6210: ${r.length} \u6761\u8BB0\u5F55`)}catch(r){const n=r;e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",n.message)}}dr().catch(r=>{e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",r)}),import(E(S.join(Ne(),"..","background-command-manager.js")).href).then(async r=>{const n=r.backgroundCommandManager;if(!n||typeof n.reconcileAllAgents!="function"){e.warn("[runtime-bridge] \u540E\u53F0\u547D\u4EE4\u7BA1\u7406\u5668\u4E0D\u53EF\u7528\uFF0C\u8DF3\u8FC7\u542F\u52A8\u5B64\u513F\u5BF9\u8D26");return}const o=await n.reconcileAllAgents();o>0&&e.info(`[runtime-bridge] \u2605 \u542F\u52A8\u5B64\u513F\u5BF9\u8D26\u5B8C\u6210\uFF1A\u4FEE\u590D ${o} \u6761\u540E\u53F0\u547D\u4EE4\u72B6\u6001`)}).catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u5BF9\u8D26\u5931\u8D25:",r.message)});async function gr(){try{const r=await import("node:fs/promises"),n=await import("node:path"),o=await import("node:os"),d=n.join(o.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");let u=!1;try{const t=await r.readFile(d,"utf-8");u=JSON.parse(t).preserveSessions===!0,await r.unlink(d),e.info(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\uFF0CpreserveSessions=${u}`)}catch{}const a=await I();if(a.length===0){e.info("[runtime-bridge] \u542F\u52A8\u65F6\u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u65E0\u9700\u68C0\u6D4B\u5B64\u513F\u8FDB\u7A0B");return}if(!nr(u)){e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u5E76\u91CD\u5EFA\u8FDB\u7A0B\u6CE8\u518C\u8868`),await y().rebuildRegistry(a.map(s=>({agentId:s.agentId,sessionId:s.sessionId,pid:s.pid,workspacePath:s.workspacePath,command:s.command,mode:"sdk"})));return}e.info(`[runtime-bridge] \u2605 \u5DF2\u663E\u5F0F\u542F\u7528\u542F\u52A8\u6E05\u7406\uFF0C\u68C0\u6D4B ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u7684\u5B64\u513F\u8FDB\u7A0B...`);const g=await ir(a.map(t=>({agentId:t.agentId,pid:t.pid,workspacePath:t.workspacePath,command:t.command})));if(g.length>0){e.warn(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 ${g.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF1A`);for(const t of g)e.warn(` - agentId=${t.agentId}, pid=${t.process.pid}, command=${t.process.command?.slice(0,50)}`);e.info("[runtime-bridge] \u6B63\u5728\u81EA\u52A8\u6E05\u7406\u6240\u6709\u5B64\u513F\u8FDB\u7A0B...");for(const t of g)try{if(t.process.pid)if(process.platform==="win32"){const{execSync:s}=await import("node:child_process");s(`taskkill /PID ${t.process.pid} /T /F`,{encoding:"utf8",timeout:3e3}),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}else process.kill(t.process.pid,"SIGKILL"),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}catch(s){const c=s;e.warn(`[runtime-bridge] \u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B\u5931\u8D25: agentId=${t.agentId}, PID=${t.process.pid}, error=${c.message}`)}await new Promise(t=>setTimeout(t,1e3))}await k([]),e.info(`[runtime-bridge] \u2605 \u542F\u52A8\u6E05\u7406\u5B8C\u6210\uFF0C\u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD\uFF08\u6E05\u7406\u4E86 ${g.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\uFF09`)}catch(r){const n=r;e.warn("[runtime-bridge] \u542F\u52A8\u65F6\u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u5931\u8D25:",n.message)}}gr().catch(r=>{e.warn("[runtime-bridge] \u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u51FA\u9519:",r)}),er().catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5931\u8D25:",r)});const i=P();i.use(je),i.use(F()),i.use(P.json({limit:"1mb"})),i.use("/runtime",ve),i.use("/runtime",ye),i.use("/runtime",Oe),i.use("/runtime",ge),i.use("/runtime",De),i.use("/runtime",Se),i.use("/runtime",re),i.use("/runtime",Le),i.use("/runtime",Te),i.use("/runtime",$e),i.use("/runtime",le),i.use("/runtime",fe),i.use("/runtime",Fe),i.use("/runtime",Ee),i.use("/runtime",se),i.use("/runtime",de),i.use("/runtime",ce),i.use("/runtime",Y),i.use("/runtime",Z),i.use("/runtime",Q),i.use("/runtime",Me),i.use("/runtime",ee),i.use("/runtime",ne),i.use("/runtime",X),i.use("/runtime",Pe),i.use("/runtime",Re),i.use("/runtime",oe),i.use("/runtime",q),i.use("/runtime",xe),i.use("/runtime",ue),i.use("/runtime",me),i.use("/runtime",be),i.use("/runtime/computer",te),i.use("/pty",Ce),i.use("/",ie),i.use("/api/file-browser",ae),i.use("/api",Ge),i.use("/api/ltr",we),i.use("/api/bridge-temp-files",V);function pr(){const r=$(),n=N(),o=n?i.listen(r,n,()=>{e.info(`[runtime-bridge] listening on ${n}:${r}`)}):i.listen(r,()=>{e.info(`[runtime-bridge] listening on ${r}`)});return Ie(o),z(o),G(o),he(o),o.on("error",d=>{if(d.code==="EADDRINUSE"){e.error(`[runtime-bridge] port ${r} became unavailable after reservation (another process grabbed it concurrently). Set AWS_RUNTIME_BRIDGE_PORT to a free port and restart.`),process.exitCode=1;return}e.error("[runtime-bridge] failed to start server:",d),process.exitCode=1}),o}let A=!1;async function b(r,n,o=!1){if(A){e.info(`[runtime-bridge] \u5DF2\u5728\u5173\u95ED\u4E2D\uFF0C\u5FFD\u7565 ${r}`);return}A=!0,o||R()&&(o=!0,e.info("[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 .preserve-sessions \u6807\u8BB0\u6587\u4EF6\uFF0C\u81EA\u52A8\u5347\u7EA7\u4E3A\u4FDD\u7559\u4F1A\u8BDD\u6A21\u5F0F")),e.info(`[runtime-bridge] \u6536\u5230 ${r} \u4FE1\u53F7\uFF0C\u5F00\u59CB\u4F18\u96C5\u5173\u95ED... (preserveSessions=${o})`);const d=Date.now(),u=or(o);try{const a=w.size;if(u.terminateSdkSessions){e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${a} \u4E2A SDK \u4F1A\u8BDD...`);for(const[t,s]of w.entries())try{const c=s.providerId||"claude-code",p=L.get(c);let f="";try{const m=p.getSessionPid?.(t);m&&(f=` (PID: ${m})`)}catch{}await p.terminateSession(t),e.info(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u5DF2\u7EC8\u6B62${f}`),w.delete(t)}catch(c){const p=c;e.error(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u7EC8\u6B62\u5931\u8D25:`,p.message),w.delete(t)}}else e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a} \u4E2A SDK \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u7EC8\u6B62 Agent \u8FDB\u7A0B`);const l=Ae.size;u.closePtySessions?(e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${l} \u4E2A PTY \u4F1A\u8BDD...`),ke("shutdown")):e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${l} \u4E2A PTY \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u5173\u95ED\u7EC8\u7AEF\u8FDB\u7A0B`);try{const{running:t,stopped:s}=await qe().stopAll();t>0&&e.info(`[runtime-bridge] \u542F\u52A8\u9879\u8FDB\u7A0B\u5DF2\u505C\u6B62: running=${t}, stopped=${s}`)}catch(t){e.warn("[runtime-bridge] \u505C\u6B62\u542F\u52A8\u9879\u8FDB\u7A0B\u5931\u8D25:",t.message)}e.info("[runtime-bridge] \u6B63\u5728\u505C\u6B62\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7...");try{const c=(await import("file://"+S.join(import.meta.dirname,"..","package","acode","dist","background-command-manager.js")).catch(()=>({backgroundCommandManager:null}))).backgroundCommandManager;c&&(e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7406\u540E\u53F0\u547D\u4EE4..."),await c.disposeAll())}catch(t){e.warn("[runtime-bridge] \u540E\u53F0\u547D\u4EE4\u6E05\u7406\u5931\u8D25: %s",t?.message)}if(rr(),u.terminateResidualProcesses&&(e.info("[runtime-bridge] \u7B49\u5F85\u8FDB\u7A0B\u5B8C\u5168\u7EC8\u6B62..."),await new Promise(t=>setTimeout(t,1e3))),u.terminateResidualProcesses)try{const{detectOrphanProcesses:t,terminateProcessTree:s}=await import("./services/process-detector.js"),{loadPersistedSessions:c}=await import("./services/terminal-persistence.js"),p=await c();if(p.length>0){const f=await t(p.map(m=>({agentId:m.agentId,pid:m.pid,workspacePath:m.workspacePath,command:m.command})));if(f.length>0){e.warn(`[runtime-bridge] \u68C0\u6D4B\u5230 ${f.length} \u4E2A\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u6B63\u5728\u5F3A\u5236\u7EC8\u6B62...`);for(const m of f)if(m.process.pid){const B=await s(m.process.pid);e.info(`[runtime-bridge] \u5DF2\u5F3A\u5236\u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B\u6811\uFF1AagentId=${m.agentId}, PID=${m.process.pid}, \u7EC8\u6B62\u4E86 ${B.terminated} \u4E2A\u8FDB\u7A0B`)}}}}catch(t){const s=t;e.warn("[runtime-bridge] \u6B8B\u7559\u8FDB\u7A0B\u68C0\u67E5\u5931\u8D25:",s.message)}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u6B8B\u7559\u8FDB\u7A0B\u5F3A\u5236\u7EC8\u6B62\uFF0C\u7B49\u5F85\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D\u4F1A\u8BDD");if(u.unregisterInstance){e.info("[runtime-bridge] \u6B63\u5728\u6CE8\u9500\u5B9E\u4F8B...");try{await He()}catch(t){const s=t;e.error("[runtime-bridge] \u6CE8\u9500\u5B9E\u4F8B\u5931\u8D25:",s.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u5B9E\u4F8B\u6CE8\u9500\uFF0C\u907F\u514D\u8C03\u5EA6\u4E2D\u5FC3\u5C06 Agent \u6807\u8BB0\u4E3A stopped");if(Ue(),u.stopTunnelClient&&(e.info("[runtime-bridge] \u6B63\u5728\u5173\u95ED\u96A7\u9053\u5BA2\u6237\u7AEF..."),mr()),u.clearPersistedSessions){e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7A7A\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001...");try{await k([])}catch(t){const s=t;e.error("[runtime-bridge] \u6E05\u7A7A\u6301\u4E45\u5316\u72B6\u6001\u5931\u8D25:",s.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001\uFF08aws-mcp-server \u91CD\u542F\u6062\u590D\u573A\u666F\uFF09");try{await ze(),e.info("[runtime-bridge] browser \u5DE5\u5177\u6808\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] browser \u5DE5\u5177\u6808\u6E05\u7406\u5931\u8D25:",t.message)}try{await Ze(),e.info("[runtime-bridge] desktop \u5DE5\u5177\u6808\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] desktop \u5DE5\u5177\u6808\u6E05\u7406\u5931\u8D25:",t.message)}try{await tr.stopAll(),e.info("[runtime-bridge] \u63D2\u4EF6\u76D1\u542C\u8FDB\u7A0B\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] \u63D2\u4EF6\u76D1\u542C\u8FDB\u7A0B\u6E05\u7406\u5931\u8D25:",t.message)}const g=Date.now()-d;e.info(`[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u5B8C\u6210 (\u8017\u65F6 ${g}ms)\uFF0C\u505C\u6B62 ${a} SDK \u4F1A\u8BDD`),n.close(()=>{e.info("[runtime-bridge] HTTP \u670D\u52A1\u5668\u5DF2\u5173\u95ED"),process.exit(process.exitCode||0)}),setTimeout(()=>{e.warn("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8D85\u65F6\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)},15e3)}catch(a){const l=a;e.error("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",l),process.exit(1)}}ar.reconcileZombies().then(r=>{r>0&&e.info(`[runtime-bridge] \u5DF2\u6E05\u7406 ${r} \u4E2A\u50F5\u5C38 sub-agent \u8BB0\u5F55`)}).catch(r=>{e.warn("[runtime-bridge] \u6E05\u7406\u50F5\u5C38 sub-agent \u8BB0\u5F55\u5931\u8D25:",r.message)});const h=pr();Xe();const v=S.join(M.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");function R(){try{if(T(v)){const r=D(v,"utf-8");return JSON.parse(r).preserveSessions===!0}}catch{}return!1}pe(async(r,n)=>{await b(r,h,n)}),process.on("SIGTERM",()=>{const r=R();b("SIGTERM",h,r)}),process.on("SIGINT",()=>{const r=R();b("SIGINT",h,r)}),process.platform==="win32"&&process.on("SIGBREAK",()=>{const r=R();b("SIGBREAK",h,r)}),process.on("uncaughtException",r=>{e.error("[runtime-bridge] \u672A\u6355\u83B7\u5F02\u5E38:",r),b("uncaughtException",h)}),process.on("unhandledRejection",r=>{e.error("[runtime-bridge] \u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD:",r)});
2
+ import{existsSync as L,readFileSync as G}from"node:fs";import O from"node:os";import P from"node:path";import{pathToFileURL as j}from"node:url";import{sweepExpiredJournals as K}from"@agentswork/acode";import N from"cors";import I from"express";import{adapterRegistry as _}from"./adapter/index.js";import{attachBrowserWebSocketServer as H}from"./browser/browser-ws-bridge.js";import{getAcodeDataHome as W,getActiveBridgeHttpPort as k,getAutoRegisterConfigFilePath as U,getBridgeDataHome as J,getBridgeListenHost as z,getBridgeRuntimePropertiesFilePath as Y,getBridgeTemplateConfigFile as Z,reserveBridgeListenPort as q,validateProductionToken as Q,writeBridgeRuntimePropertiesFile as V}from"./config.js";import{attachRemoteDesktopWebSocketServer as X}from"./remote-desktop/index.js";import{acodeTodosRouter as ee}from"./routes/acode-todos.js";import{agentStateRouter as re}from"./routes/agent-state.js";import{aiSourcesRouter as te}from"./routes/ai-sources.js";import{backgroundTasksRouter as ie}from"./routes/background-tasks.js";import{bridgeTempFilesRouter as oe}from"./routes/bridge-temp-files.js";import{browserListenersRouter as ne}from"./routes/browser-listeners.js";import{browserSessionsRouter as se}from"./routes/browser-sessions.js";import{capabilitiesRouter as ae}from"./routes/capabilities.js";import{computerRouter as me}from"./routes/computer.js";import{dashboardRouter as ue}from"./routes/dashboard.js";import{debugMountRouter as ce}from"./routes/debug-mount.js";import{desktopControlRouter as de}from"./routes/desktop-control.js";import{eventsRouter as ge}from"./routes/events.js";import{fileBrowserRouter as pe}from"./routes/file-browser.js";import{fileChangeDiffRouter as fe}from"./routes/file-change-diff.js";import{fileDiffRollbackRouter as le}from"./routes/file-diff-rollback.js";import{fileSnapshotRouter as be}from"./routes/file-snapshot.js";import{gitRouter as he}from"./routes/git.js";import{instanceRouter as we,setGracefulShutdownFn as Re}from"./routes/instance.js";import{jdksRouter as Se}from"./routes/jdks.js";import{launchRouter as Pe}from"./routes/launch.js";import{lspProvidersRouter as ye}from"./routes/lsp-providers.js";import{attachLspWebSocketServer as $e}from"./routes/lsp.js";import{ltrRouter as Ie}from"./routes/ltr.js";import{mcpExtraRouter as ke}from"./routes/mcp-extra.js";import{mcpRouter as Ce}from"./routes/mcp.js";import{pluginsRouter as Ae}from"./routes/plugins.js";import{processesRouter as ve}from"./routes/processes.js";import{propertiesRouter as Be}from"./routes/properties.js";import{attachPtyWebSocketServer as Te,closeAllPtySessions as De,ptyRouter as Me,ptySessions as Ee}from"./routes/pty.js";import{runtimeBindingRouter as xe,logRuntimeBindingStartupState as Fe}from"./routes/runtime-binding.js";import{sessionsRouter as Le}from"./routes/sessions.js";import{skillsRouter as Ge}from"./routes/skills.js";import{subAgentsRouter as Oe}from"./routes/sub-agents.js";import{systemMetricsRouter as je}from"./routes/system-metrics.js";import{taskContextRouter as Ke}from"./routes/task-context.js";import{techStackRouter as Ne}from"./routes/tech-stack.js";import{terminalRouter as _e,sdkSessions as S}from"./routes/terminal.js";import{workspaceIndexRouter as He}from"./routes/workspace-index.js";import{ymlRouter as We}from"./routes/yml.js";import{accessControlMiddleware as Ue}from"./services/access-control.js";import{ensureAcodePackageReleased as Je,getReleasedAcodeEntryPath as ze}from"./services/acode-package.js";import{getAgentProcessManager as C}from"./services/agent-process-manager.js";import{autoRegister as Ye,unregister as Ze,bridgeRestartCleanup as qe,cancelBackgroundRegisterRetries as Qe}from"./services/auto-register.js";import{ensureAwsClientAgentMcpReleased as Ve}from"./services/aws-client-agent-mcp.js";import{disposeBrowserSessionManager as Xe}from"./services/browser-session-manager.js";import{handleCliCommand as er}from"./services/cli-commands.js";import{disposeDesktopMcpManager as rr}from"./services/desktop-mcp-manager.js";import{getLaunchManager as tr}from"./services/launch-manager.js";import{migrateOldPathsOnStartup as ir}from"./services/legacy-path-migration.js";import{deliverPendingBridgeLifecycleNotifications as or}from"./services/lifecycle-state.js";import{startLogRetention as nr}from"./services/log-retention.js";import{startOrphanMonitor as sr,stopOrphanMonitor as ar}from"./services/orphan-monitor.js";import{pluginManager as mr}from"./services/plugin-manager.js";import{detectOrphanProcesses as ur}from"./services/process-detector.js";import{buildGracefulShutdownPlan as cr,shouldCleanupPersistedSessionsOnStartup as dr}from"./services/runtime-lifecycle-policy.js";import{ensureStartupConfig as gr}from"./services/startup-config-wizard.js";import{subAgentStore as pr}from"./services/sub-agent-manager-instance.js";import{loadPersistedSessions as A,savePersistedSessions as v}from"./services/terminal-persistence.js";import{stopTunnelClient as fr}from"./services/tunnel-client.js";import{loadDynamicModule as B}from"./utils/dynamic-import.js";import{logger as e}from"./utils/logger.js";async function lr(){const w=await er();w.handled&&process.exit(w.exitCode),await gr(),Q(),Ve(),Je(),ir(),Fe(),await q(),V(),e.info(`[runtime-bridge] \u5DF2\u5199\u5165\u8FD0\u884C\u65F6\u914D\u7F6E ${Y()}\uFF08port=${k()}\uFF09`),e.info(`[runtime-bridge] ACode \u6570\u636E\u76EE\u5F55(\u7528\u6237): ${W()}`),e.info(`[runtime-bridge] Bridge \u6570\u636E\u76EE\u5F55: ${J()}`),e.info(`[runtime-bridge] \u6A21\u677F\u914D\u7F6E: ${Z()}`),K().then(r=>{r>0&&e.info(`[runtime-bridge] \u5DF2\u6E05\u626B ${r} \u4E2A\u8D85\u671F\u4F11\u7720 journal`)}).catch(()=>{});async function T(){try{if(await Ye())e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6210\u529F");else{const{loadConfig:n}=await import("./services/auto-register.js"),o=n();!!o.userKey&&o.enabled?e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6682\u65F6\u5931\u8D25\uFF0C\u5C06\u5728\u540E\u53F0\u6301\u7EED\u91CD\u8BD5\u76F4\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3\u5EFA\u7ACB\u8FDE\u63A5"):(e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u672A\u914D\u7F6E\uFF0C\u7EE7\u7EED\u542F\u52A8\u670D\u52A1"),e.info(`[runtime-bridge] \u8981\u542F\u7528\u81EA\u52A8\u6CE8\u518C\uFF0C\u8BF7\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6 ${U()}`))}}catch(r){const n=r;e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u51FA\u9519:",n.message)}}T().then(()=>D()).then(()=>or()).then(()=>{e.info("[runtime-bridge] Bridge \u751F\u547D\u5468\u671F\u901A\u77E5\u540C\u6B65\u5B8C\u6210")}).catch(r=>{e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6216\u6E05\u7406\u51FA\u9519:",r)}),import("./services/update-notifier.js").then(({startUpdateNotifier:r})=>r()).catch(r=>{e.warn("[runtime-bridge] \u7248\u672C\u68C0\u67E5\u670D\u52A1\u542F\u52A8\u5931\u8D25:",r.message)});async function D(){try{if(process.env.AWS_BRIDGE_RESTART_CLEANUP!=="true"){e.info("[runtime-bridge] \u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406\uFF0C\u4FDD\u7559 Agent \u72B6\u6001\u4F9B\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D");return}const{getRegistrationState:r}=await import("./services/auto-register.js"),n=r();if(!n.registered||!n.instanceId){e.info("[runtime-bridge] \u5B9E\u4F8B\u672A\u6CE8\u518C\uFF0C\u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406");return}e.info("[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5DF2\u663E\u5F0F\u542F\u7528\uFF0C\u6B63\u5728\u901A\u77E5\u8C03\u5EA6\u4E2D\u5FC3\u6E05\u7406 Agent \u72B6\u6001...");const o=await qe();o.success?e.info(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u6210\u529F\uFF0C\u6E05\u7406\u4E86 ${o.agentCount||0} \u4E2A Agent`):e.warn(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5931\u8D25: ${o.error}`)}catch(r){const n=r;e.warn("[runtime-bridge] Bridge \u91CD\u542F\u6E05\u7406\u51FA\u9519:",n.message)}}async function M(){try{const r=await A();if(r.length===0){e.info("[runtime-bridge] \u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u8DF3\u8FC7\u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA");return}await C().rebuildRegistry(r.map(o=>({agentId:o.agentId,sessionId:o.sessionId,pid:o.pid,workspacePath:o.workspacePath,command:o.command,mode:"sdk"}))),e.info(`[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5B8C\u6210: ${r.length} \u6761\u8BB0\u5F55`)}catch(r){const n=r;e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",n.message)}}M().catch(r=>{e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",r)}),B(j(P.join(ze(),"..","background-command-manager.js")).href).then(async r=>{const n=r.backgroundCommandManager;if(!n||typeof n.reconcileAllAgents!="function"){e.warn("[runtime-bridge] \u540E\u53F0\u547D\u4EE4\u7BA1\u7406\u5668\u4E0D\u53EF\u7528\uFF0C\u8DF3\u8FC7\u542F\u52A8\u5B64\u513F\u5BF9\u8D26");return}const o=await n.reconcileAllAgents();o>0&&e.info(`[runtime-bridge] \u2605 \u542F\u52A8\u5B64\u513F\u5BF9\u8D26\u5B8C\u6210\uFF1A\u4FEE\u590D ${o} \u6761\u540E\u53F0\u547D\u4EE4\u72B6\u6001`)}).catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u5BF9\u8D26\u5931\u8D25:",r.message)});async function E(){try{const r=await import("node:fs/promises"),n=await import("node:path"),o=await import("node:os"),d=n.join(o.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");let u=!1;try{const t=await r.readFile(d,"utf-8");u=JSON.parse(t).preserveSessions===!0,await r.unlink(d),e.info(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\uFF0CpreserveSessions=${u}`)}catch{}const a=await A();if(a.length===0){e.info("[runtime-bridge] \u542F\u52A8\u65F6\u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u65E0\u9700\u68C0\u6D4B\u5B64\u513F\u8FDB\u7A0B");return}if(!dr(u)){e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u5E76\u91CD\u5EFA\u8FDB\u7A0B\u6CE8\u518C\u8868`),await C().rebuildRegistry(a.map(s=>({agentId:s.agentId,sessionId:s.sessionId,pid:s.pid,workspacePath:s.workspacePath,command:s.command,mode:"sdk"})));return}e.info(`[runtime-bridge] \u2605 \u5DF2\u663E\u5F0F\u542F\u7528\u542F\u52A8\u6E05\u7406\uFF0C\u68C0\u6D4B ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u7684\u5B64\u513F\u8FDB\u7A0B...`);const g=await ur(a.map(t=>({agentId:t.agentId,pid:t.pid,workspacePath:t.workspacePath,command:t.command})));if(g.length>0){e.warn(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 ${g.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF1A`);for(const t of g)e.warn(` - agentId=${t.agentId}, pid=${t.process.pid}, command=${t.process.command?.slice(0,50)}`);e.info("[runtime-bridge] \u6B63\u5728\u81EA\u52A8\u6E05\u7406\u6240\u6709\u5B64\u513F\u8FDB\u7A0B...");for(const t of g)try{if(t.process.pid)if(process.platform==="win32"){const{execSync:s}=await import("node:child_process");s(`taskkill /PID ${t.process.pid} /T /F`,{encoding:"utf8",timeout:3e3}),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}else process.kill(t.process.pid,"SIGKILL"),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}catch(s){const c=s;e.warn(`[runtime-bridge] \u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B\u5931\u8D25: agentId=${t.agentId}, PID=${t.process.pid}, error=${c.message}`)}await new Promise(t=>setTimeout(t,1e3))}await v([]),e.info(`[runtime-bridge] \u2605 \u542F\u52A8\u6E05\u7406\u5B8C\u6210\uFF0C\u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD\uFF08\u6E05\u7406\u4E86 ${g.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\uFF09`)}catch(r){const n=r;e.warn("[runtime-bridge] \u542F\u52A8\u65F6\u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u5931\u8D25:",n.message)}}E().catch(r=>{e.warn("[runtime-bridge] \u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u51FA\u9519:",r)}),sr().catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5931\u8D25:",r)});const i=I();i.use(Ue),i.use(N()),i.use(I.json({limit:"1mb"})),i.use("/runtime",xe),i.use("/runtime",Be),i.use("/runtime",We),i.use("/runtime",we),i.use("/runtime",Ge),i.use("/runtime",Ce),i.use("/runtime",ae),i.use("/runtime",_e),i.use("/runtime",Le),i.use("/runtime",ve),i.use("/runtime",Pe),i.use("/runtime",Se),i.use("/runtime",Ne),i.use("/runtime",je),i.use("/runtime",ge),i.use("/runtime",he),i.use("/runtime",be),i.use("/runtime",ee),i.use("/runtime",re),i.use("/runtime",ie),i.use("/runtime",Oe),i.use("/runtime",se),i.use("/runtime",de),i.use("/runtime",ne),i.use("/runtime",Ae),i.use("/runtime",ke),i.use("/runtime",ce),i.use("/runtime",te),i.use("/runtime",Ke),i.use("/runtime",le),i.use("/runtime",fe),i.use("/runtime",ye),i.use("/runtime/computer",me),i.use("/pty",Me),i.use("/",ue),i.use("/api/file-browser",pe),i.use("/api",He),i.use("/api/ltr",Ie),i.use("/api/bridge-temp-files",oe);function x(){const r=k(),n=z(),o=n?i.listen(r,n,()=>{e.info(`[runtime-bridge] listening on ${n}:${r}`)}):i.listen(r,()=>{e.info(`[runtime-bridge] listening on ${r}`)});return Te(o),X(o),H(o),$e(o),o.on("error",d=>{if(d.code==="EADDRINUSE"){e.error(`[runtime-bridge] port ${r} became unavailable after reservation (another process grabbed it concurrently). Set AWS_RUNTIME_BRIDGE_PORT to a free port and restart.`),process.exitCode=1;return}e.error("[runtime-bridge] failed to start server:",d),process.exitCode=1}),o}let y=!1;async function l(r,n,o=!1){if(y){e.info(`[runtime-bridge] \u5DF2\u5728\u5173\u95ED\u4E2D\uFF0C\u5FFD\u7565 ${r}`);return}y=!0,o||R()&&(o=!0,e.info("[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 .preserve-sessions \u6807\u8BB0\u6587\u4EF6\uFF0C\u81EA\u52A8\u5347\u7EA7\u4E3A\u4FDD\u7559\u4F1A\u8BDD\u6A21\u5F0F")),e.info(`[runtime-bridge] \u6536\u5230 ${r} \u4FE1\u53F7\uFF0C\u5F00\u59CB\u4F18\u96C5\u5173\u95ED... (preserveSessions=${o})`);const d=Date.now(),u=cr(o);try{const a=S.size;if(u.terminateSdkSessions){e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${a} \u4E2A SDK \u4F1A\u8BDD...`);for(const[t,s]of S.entries())try{const c=s.providerId||"claude-code",p=_.get(c);let f="";try{const m=p.getSessionPid?.(t);m&&(f=` (PID: ${m})`)}catch{}await p.terminateSession(t),e.info(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u5DF2\u7EC8\u6B62${f}`),S.delete(t)}catch(c){const p=c;e.error(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u7EC8\u6B62\u5931\u8D25:`,p.message),S.delete(t)}}else e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a} \u4E2A SDK \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u7EC8\u6B62 Agent \u8FDB\u7A0B`);const h=Ee.size;u.closePtySessions?(e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${h} \u4E2A PTY \u4F1A\u8BDD...`),De("shutdown")):e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${h} \u4E2A PTY \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u5173\u95ED\u7EC8\u7AEF\u8FDB\u7A0B`);try{const{running:t,stopped:s}=await tr().stopAll();t>0&&e.info(`[runtime-bridge] \u542F\u52A8\u9879\u8FDB\u7A0B\u5DF2\u505C\u6B62: running=${t}, stopped=${s}`)}catch(t){e.warn("[runtime-bridge] \u505C\u6B62\u542F\u52A8\u9879\u8FDB\u7A0B\u5931\u8D25:",t.message)}e.info("[runtime-bridge] \u6B63\u5728\u505C\u6B62\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7...");try{const t="file://"+P.join(import.meta.dirname,"..","package","acode","dist","background-command-manager.js"),c=(await B(t).catch(()=>({backgroundCommandManager:null}))).backgroundCommandManager;c&&(e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7406\u540E\u53F0\u547D\u4EE4..."),await c.disposeAll())}catch(t){e.warn("[runtime-bridge] \u540E\u53F0\u547D\u4EE4\u6E05\u7406\u5931\u8D25: %s",t?.message)}if(ar(),u.terminateResidualProcesses&&(e.info("[runtime-bridge] \u7B49\u5F85\u8FDB\u7A0B\u5B8C\u5168\u7EC8\u6B62..."),await new Promise(t=>setTimeout(t,1e3))),u.terminateResidualProcesses)try{const{detectOrphanProcesses:t,terminateProcessTree:s}=await import("./services/process-detector.js"),{loadPersistedSessions:c}=await import("./services/terminal-persistence.js"),p=await c();if(p.length>0){const f=await t(p.map(m=>({agentId:m.agentId,pid:m.pid,workspacePath:m.workspacePath,command:m.command})));if(f.length>0){e.warn(`[runtime-bridge] \u68C0\u6D4B\u5230 ${f.length} \u4E2A\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u6B63\u5728\u5F3A\u5236\u7EC8\u6B62...`);for(const m of f)if(m.process.pid){const F=await s(m.process.pid);e.info(`[runtime-bridge] \u5DF2\u5F3A\u5236\u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B\u6811\uFF1AagentId=${m.agentId}, PID=${m.process.pid}, \u7EC8\u6B62\u4E86 ${F.terminated} \u4E2A\u8FDB\u7A0B`)}}}}catch(t){const s=t;e.warn("[runtime-bridge] \u6B8B\u7559\u8FDB\u7A0B\u68C0\u67E5\u5931\u8D25:",s.message)}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u6B8B\u7559\u8FDB\u7A0B\u5F3A\u5236\u7EC8\u6B62\uFF0C\u7B49\u5F85\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D\u4F1A\u8BDD");if(u.unregisterInstance){e.info("[runtime-bridge] \u6B63\u5728\u6CE8\u9500\u5B9E\u4F8B...");try{await Ze()}catch(t){const s=t;e.error("[runtime-bridge] \u6CE8\u9500\u5B9E\u4F8B\u5931\u8D25:",s.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u5B9E\u4F8B\u6CE8\u9500\uFF0C\u907F\u514D\u8C03\u5EA6\u4E2D\u5FC3\u5C06 Agent \u6807\u8BB0\u4E3A stopped");if(Qe(),u.stopTunnelClient&&(e.info("[runtime-bridge] \u6B63\u5728\u5173\u95ED\u96A7\u9053\u5BA2\u6237\u7AEF..."),fr()),u.clearPersistedSessions){e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7A7A\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001...");try{await v([])}catch(t){const s=t;e.error("[runtime-bridge] \u6E05\u7A7A\u6301\u4E45\u5316\u72B6\u6001\u5931\u8D25:",s.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001\uFF08aws-mcp-server \u91CD\u542F\u6062\u590D\u573A\u666F\uFF09");try{await Xe(),e.info("[runtime-bridge] browser \u5DE5\u5177\u6808\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] browser \u5DE5\u5177\u6808\u6E05\u7406\u5931\u8D25:",t.message)}try{await rr(),e.info("[runtime-bridge] desktop \u5DE5\u5177\u6808\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] desktop \u5DE5\u5177\u6808\u6E05\u7406\u5931\u8D25:",t.message)}try{await mr.stopAll(),e.info("[runtime-bridge] \u63D2\u4EF6\u76D1\u542C\u8FDB\u7A0B\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] \u63D2\u4EF6\u76D1\u542C\u8FDB\u7A0B\u6E05\u7406\u5931\u8D25:",t.message)}const g=Date.now()-d;e.info(`[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u5B8C\u6210 (\u8017\u65F6 ${g}ms)\uFF0C\u505C\u6B62 ${a} SDK \u4F1A\u8BDD`),n.close(()=>{e.info("[runtime-bridge] HTTP \u670D\u52A1\u5668\u5DF2\u5173\u95ED"),process.exit(process.exitCode||0)}),setTimeout(()=>{e.warn("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8D85\u65F6\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)},15e3)}catch(a){const h=a;e.error("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",h),process.exit(1)}}pr.reconcileZombies().then(r=>{r>0&&e.info(`[runtime-bridge] \u5DF2\u6E05\u7406 ${r} \u4E2A\u50F5\u5C38 sub-agent \u8BB0\u5F55`)}).catch(r=>{e.warn("[runtime-bridge] \u6E05\u7406\u50F5\u5C38 sub-agent \u8BB0\u5F55\u5931\u8D25:",r.message)});const b=x();nr();const $=P.join(O.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");function R(){try{if(L($)){const r=G($,"utf-8");return JSON.parse(r).preserveSessions===!0}}catch{}return!1}Re(async(r,n)=>{await l(r,b,n)}),process.on("SIGTERM",()=>{const r=R();l("SIGTERM",b,r)}),process.on("SIGINT",()=>{const r=R();l("SIGINT",b,r)}),process.platform==="win32"&&process.on("SIGBREAK",()=>{const r=R();l("SIGBREAK",b,r)}),process.on("uncaughtException",r=>{e.error("[runtime-bridge] \u672A\u6355\u83B7\u5F02\u5E38:",r),l("uncaughtException",b)}),process.on("unhandledRejection",r=>{e.error("[runtime-bridge] \u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD:",r)})}lr().catch(w=>{e.error("[runtime-bridge] \u542F\u52A8\u5931\u8D25:",w),process.exitCode=1});
3
3
 
@@ -1,2 +1,2 @@
1
- let e=null;try{e=(await import("koffi")).default}catch{e=null}const g=1,N=2,v=4,P=8,_=16,O=2048,S=4096,W=2,x=["Edit","RichEdit","RICHEDIT","ComboBox","ComboBoxEx32","WindowsForms10.EDIT","DirectUIHWND","Chrome_RenderWidgetHostHWND"];function C(r){return r?x.some(t=>r===t||r.startsWith(t)):!1}let o;function U(){if(o!==void 0)return o;if(process.platform!=="win32"||!e)return o=null,o;try{e.struct("POINT",{x:"long",y:"long"}),e.struct("RECT",{left:"long",top:"long",right:"long",bottom:"long"}),e.struct("GUITHREADINFO",{cbSize:"uint32",flags:"uint32",hwndActive:"void*",hwndFocus:"void*",hwndCapture:"void*",hwndMenuOwner:"void*",hwndMoveSize:"void*",hwndCaret:"void*",rcCaret:"RECT"});const r=e.sizeof("GUITHREADINFO"),t=e.load("user32.dll"),l=t.func("int SetProcessDPIAware(void)"),E=t.func("int SetCursorPos(int X, int Y)"),f=t.func("int GetCursorPos(_Out_ POINT *lpPoint)"),F=t.func("void mouse_event(uint dwFlags, int dx, int dy, int dwData, int64 dwExtraInfo)"),h=t.func("void keybd_event(uint8 bVk, uint8 bScan, uint dwFlags, int64 dwExtraInfo)"),I=t.func("void* GetForegroundWindow(void)"),T=t.func("uint32 GetWindowThreadProcessId(void* hWnd, _Out_ uint32 *lpdwProcessId)"),p=t.func("int GetGUIThreadInfo(uint32 idThread, _Inout_ GUITHREADINFO *lpGUI)"),w=t.func("int GetClassNameW(void* hWnd, char16_t *lpClassName, int nMaxCount)");l(),o={setCursorPos:(n,i)=>E(Math.round(n),Math.round(i))===1,getCursorPos:()=>{const n={};return f(n)===0?null:{x:n.x??0,y:n.y??0}},mouseEvent:(n,i,u,s)=>F(n,Math.round(i),Math.round(u),s,0),keybdEvent:(n,i)=>h(n,0,i,0),isInputFocused:()=>{try{const n=I();if(!n)return!1;const u=T(n,[0]);if(!u)return!1;const s={cbSize:r};if(p(u,s)===0)return!1;if(s.hwndCaret)return!0;const d=new Uint16Array(256);if(w(s.hwndFocus,d,256)===0)return!1;let a="";for(let c=0;c<d.length&&d[c]!==0;c++)a+=String.fromCharCode(d[c]);return C(a)}catch{return!1}}}}catch(r){console.warn("[remote-desktop] Win32 FFI init failed, falling back to PowerShell:",r.message),o=null}return o}function m(){o=void 0}export{W as KEYEVENTF_KEYUP,S as MOUSEEVENTF_HWHEEL,N as MOUSEEVENTF_LEFTDOWN,v as MOUSEEVENTF_LEFTUP,g as MOUSEEVENTF_MOVE,P as MOUSEEVENTF_RIGHTDOWN,_ as MOUSEEVENTF_RIGHTUP,O as MOUSEEVENTF_WHEEL,U as initWin32Api,C as isInputControlClassName,m as resetWin32ApiForTest};
1
+ import{createRequire as C}from"node:module";const g=C(import.meta.url);let f;function N(){if(f===void 0)try{const t=g("koffi");f=t.default??t}catch{f=null}return f}const _=1,O=2,S=4,W=8,U=16,M=2048,R=4096,b=2,m=["Edit","RichEdit","RICHEDIT","ComboBox","ComboBoxEx32","WindowsForms10.EDIT","DirectUIHWND","Chrome_RenderWidgetHostHWND"];function v(t){return t?m.some(r=>t===r||t.startsWith(r)):!1}let o;function D(){if(o!==void 0)return o;if(process.platform!=="win32")return o=null,o;const t=N();if(!t)return o=null,o;try{t.struct("POINT",{x:"long",y:"long"}),t.struct("RECT",{left:"long",top:"long",right:"long",bottom:"long"}),t.struct("GUITHREADINFO",{cbSize:"uint32",flags:"uint32",hwndActive:"void*",hwndFocus:"void*",hwndCapture:"void*",hwndMenuOwner:"void*",hwndMoveSize:"void*",hwndCaret:"void*",rcCaret:"RECT"});const r=t.sizeof("GUITHREADINFO"),e=t.load("user32.dll"),l=e.func("int SetProcessDPIAware(void)"),E=e.func("int SetCursorPos(int X, int Y)"),F=e.func("int GetCursorPos(_Out_ POINT *lpPoint)"),h=e.func("void mouse_event(uint dwFlags, int dx, int dy, int dwData, int64 dwExtraInfo)"),I=e.func("void keybd_event(uint8 bVk, uint8 bScan, uint dwFlags, int64 dwExtraInfo)"),T=e.func("void* GetForegroundWindow(void)"),p=e.func("uint32 GetWindowThreadProcessId(void* hWnd, _Out_ uint32 *lpdwProcessId)"),x=e.func("int GetGUIThreadInfo(uint32 idThread, _Inout_ GUITHREADINFO *lpGUI)"),w=e.func("int GetClassNameW(void* hWnd, char16_t *lpClassName, int nMaxCount)");l(),o={setCursorPos:(n,i)=>E(Math.round(n),Math.round(i))===1,getCursorPos:()=>{const n={};return F(n)===0?null:{x:n.x??0,y:n.y??0}},mouseEvent:(n,i,u,s)=>h(n,Math.round(i),Math.round(u),s,0),keybdEvent:(n,i)=>I(n,0,i,0),isInputFocused:()=>{try{const n=T();if(!n)return!1;const u=p(n,[0]);if(!u)return!1;const s={cbSize:r};if(x(u,s)===0)return!1;if(s.hwndCaret)return!0;const d=new Uint16Array(256);if(w(s.hwndFocus,d,256)===0)return!1;let a="";for(let c=0;c<d.length&&d[c]!==0;c++)a+=String.fromCharCode(d[c]);return v(a)}catch{return!1}}}}catch(r){console.warn("[remote-desktop] Win32 FFI init failed, falling back to PowerShell:",r.message),o=null}return o}function G(){o=void 0}export{b as KEYEVENTF_KEYUP,R as MOUSEEVENTF_HWHEEL,O as MOUSEEVENTF_LEFTDOWN,S as MOUSEEVENTF_LEFTUP,_ as MOUSEEVENTF_MOVE,W as MOUSEEVENTF_RIGHTDOWN,U as MOUSEEVENTF_RIGHTUP,M as MOUSEEVENTF_WHEEL,D as initWin32Api,v as isInputControlClassName,G as resetWin32ApiForTest};
2
2
 
@@ -1,8 +1,8 @@
1
- import{promises as S}from"node:fs";import y from"node:path";import{pathToFileURL as C}from"node:url";import{Router as j}from"express";import{getAcodeDataHome as T}from"../config.js";import{validateToken as k}from"../middleware/auth.js";import{getAcodeBgManager as h}from"../services/acode-bg-manager.js";import{getReleasedAcodeEntryPath as B}from"../services/acode-package.js";import{createLogger as E}from"../utils/logger.js";import{noteDashboardActivity as _}from"./dashboard.js";import{listPtySessions as L}from"./pty.js";let m=null;function I(){return m||(m=(async()=>{try{const e=B(),t=y.join(y.dirname(e),"background-command-store.js"),d=await import(C(t).href);return d.BackgroundCommandStore?new d.BackgroundCommandStore:(l.warn("[acode-bg-tasks] BackgroundCommandStore \u4E0D\u53EF\u7528,\u78C1\u76D8\u515C\u5E95\u7981\u7528"),null)}catch(e){return l.warn("[acode-bg-tasks] \u52A0\u8F7D BackgroundCommandStore \u5931\u8D25: %s",e?.message),null}})().then(e=>(e||(m=null),e)),m)}const l=E("acode-bg-tasks"),p=j();function v(e){return String(e).replace(/[^a-zA-Z0-9_-]/g,"_")}function P(e){return y.join(T(),"bg-tasks",v(e),"state.json")}p.get("/acode-bg-tasks/:agentId",k,async(e,t)=>{const d=e.params.agentId,o=Array.isArray(d)?d[0]:d;if(!o||!String(o).trim()){t.status(400).json({ok:!1,error:"agentId is required"});return}try{const s=await h();if(s&&typeof s.listTasksWithReconcile=="function"){const r=e.query.status&&String(e.query.status)!=="all"?String(e.query.status):void 0,n=await s.listTasksWithReconcile(String(o),r);t.json({ok:!0,agentId:String(o),updatedAt:Date.now(),tasks:n});return}}catch(s){l.warn("[acode-bg-tasks] \u5185\u5B58\u5BF9\u8D26\u5217\u8868\u5931\u8D25\uFF0C\u964D\u7EA7\u78C1\u76D8\u8BFB\u53D6: %s",s?.message)}const i=P(String(o));try{const s=await S.readFile(i,"utf-8"),r=JSON.parse(s),u=(Array.isArray(r.tasks)?r.tasks:[]).map(c=>{const a=c;return{taskId:a.taskId,status:a.status,command:a.commandPreview??a.command,commandPreview:a.commandPreview,description:typeof a.description=="string"?a.description:void 0,cwd:a.cwd,startedAt:a.startedAt,finishedAt:a.finishedAt,exitCode:a.exitCode,signal:a.signal,outputLineCount:a.outputLineCount,outputBytes:a.outputBytes}});t.json({ok:!0,agentId:String(o),updatedAt:typeof r.updatedAt=="number"?r.updatedAt:null,tasks:u})}catch(s){if((typeof s=="object"&&s!==null?Reflect.get(s,"code"):void 0)==="ENOENT"){t.json({ok:!0,agentId:String(o),updatedAt:null,tasks:[]});return}if(s instanceof SyntaxError){l.warn("[acode-bg-tasks] \u6587\u4EF6\u635F\u574F\uFF08JSON \u89E3\u6790\u5931\u8D25\uFF09: %s",i),t.json({ok:!0,agentId:String(o),updatedAt:null,tasks:[]});return}const n=s;l.error("[acode-bg-tasks] \u8BFB\u53D6\u5931\u8D25: %s",n.message),t.status(500).json({ok:!1,error:n.message})}}),p.get("/acode-agent-pty-sessions/:agentId",k,(e,t)=>{const d=e.params.agentId,o=Array.isArray(d)?d[0]:d;if(!o||!String(o).trim()){t.status(400).json({ok:!1,error:"agentId is required"});return}const i=String(o),r=L().filter(n=>n.ownerUserId===i);t.json({ok:!0,agentId:i,sessions:r})});const N=15e3;function w(e){return{taskId:e.taskId,status:e.status,exitCode:e.exitCode,signal:e.signal,startedAt:e.startedAt,finishedAt:e.finishedAt,command:e.command,lines:e.lines,nextSeq:e.nextSeq,totalLines:e.totalLines,totalBytes:e.totalBytes,truncated:e.truncated}}async function x(e,t){let o=null;try{o=await S.open(e,"r")}catch(i){if(i?.code==="ENOENT")return{text:[],fileExists:!1,truncated:!1};throw i}try{const s=(await o.stat()).size;if(s===0)return{text:[],fileExists:!0,truncated:!1};const r=Math.min(s,2097152),n=s-r,u=Buffer.alloc(r);await o.read(u,0,r,n);const a=u.toString("utf-8").split(`
2
- `);return n>0&&a.shift(),{text:a.slice(-t),fileExists:!0,truncated:r<s}}finally{await o.close()}}p.get("/acode-bg-tasks/:agentId/:taskId/output",k,(e,t)=>{(async()=>{const d=String(e.params.agentId),o=String(e.params.taskId),i=Math.min(2e3,Math.max(100,Number(e.query.tailLines)||500));try{const s=await h();if(s){const r=s.getTaskOutputSnapshot(d,o);if(r){t.json({ok:!0,source:"memory",...w(r)});return}}}catch(s){l.warn("[acode-bg-tasks] \u5185\u5B58\u5FEB\u7167\u8BFB\u53D6\u5931\u8D25,\u964D\u7EA7\u8D70\u78C1\u76D8: %s",s?.message)}try{const s=await I();if(!s){t.status(503).json({ok:!1,error:"store unavailable"});return}const r=await s.readSession(d);if(!r){t.status(404).json({ok:!1,error:"task_not_found"});return}const n=r.tasks.find(f=>f.taskId===o);if(!n){t.status(404).json({ok:!1,error:"task_not_found"});return}const{text:u,fileExists:c,truncated:a}=await x(n.outputPath,i);t.json({ok:!0,source:"file",taskId:n.taskId,status:n.status,exitCode:n.exitCode,signal:n.signal,startedAt:n.startedAt,finishedAt:n.finishedAt,command:n.command,lines:u,nextSeq:0,totalLines:n.outputLineCount,totalBytes:n.outputBytes,truncated:a||!c})}catch(s){l.error("[acode-bg-tasks] \u78C1\u76D8\u515C\u5E95\u8BFB\u53D6\u5931\u8D25: %s",s?.message),t.status(500).json({ok:!1,error:"internal_error"})}})().catch(d=>{l.error("[acode-bg-tasks] output \u8BFB\u53D6\u5931\u8D25: %s",d?.message),t.status(500).json({ok:!1,error:"internal_error"})})}),p.get("/acode-bg-tasks/:agentId/:taskId/stream",k,(e,t)=>{_(),(async()=>{const d=String(e.params.agentId),o=String(e.params.taskId);t.status(200),t.set({"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),t.flushHeaders?.();const i=(u,c)=>{t.writableEnded||t.destroyed||(c!==void 0&&t.write(`id: ${c}
1
+ import{promises as S}from"node:fs";import y from"node:path";import{pathToFileURL as C}from"node:url";import{Router as j}from"express";import{getAcodeDataHome as T}from"../config.js";import{validateToken as k}from"../middleware/auth.js";import{getAcodeBgManager as h}from"../services/acode-bg-manager.js";import{getReleasedAcodeEntryPath as B}from"../services/acode-package.js";import{loadDynamicModule as E}from"../utils/dynamic-import.js";import{createLogger as _}from"../utils/logger.js";import{noteDashboardActivity as L}from"./dashboard.js";import{listPtySessions as v}from"./pty.js";let m=null;function I(){return m||(m=(async()=>{try{const e=B(),t=y.join(y.dirname(e),"background-command-store.js"),d=await E(C(t).href);return d.BackgroundCommandStore?new d.BackgroundCommandStore:(l.warn("[acode-bg-tasks] BackgroundCommandStore \u4E0D\u53EF\u7528,\u78C1\u76D8\u515C\u5E95\u7981\u7528"),null)}catch(e){return l.warn("[acode-bg-tasks] \u52A0\u8F7D BackgroundCommandStore \u5931\u8D25: %s",e?.message),null}})().then(e=>(e||(m=null),e)),m)}const l=_("acode-bg-tasks"),p=j();function P(e){return String(e).replace(/[^a-zA-Z0-9_-]/g,"_")}function N(e){return y.join(T(),"bg-tasks",P(e),"state.json")}p.get("/acode-bg-tasks/:agentId",k,async(e,t)=>{const d=e.params.agentId,o=Array.isArray(d)?d[0]:d;if(!o||!String(o).trim()){t.status(400).json({ok:!1,error:"agentId is required"});return}try{const n=await h();if(n&&typeof n.listTasksWithReconcile=="function"){const r=e.query.status&&String(e.query.status)!=="all"?String(e.query.status):void 0,s=await n.listTasksWithReconcile(String(o),r);t.json({ok:!0,agentId:String(o),updatedAt:Date.now(),tasks:s});return}}catch(n){l.warn("[acode-bg-tasks] \u5185\u5B58\u5BF9\u8D26\u5217\u8868\u5931\u8D25\uFF0C\u964D\u7EA7\u78C1\u76D8\u8BFB\u53D6: %s",n?.message)}const i=N(String(o));try{const n=await S.readFile(i,"utf-8"),r=JSON.parse(n),u=(Array.isArray(r.tasks)?r.tasks:[]).map(c=>{const a=c;return{taskId:a.taskId,status:a.status,command:a.commandPreview??a.command,commandPreview:a.commandPreview,description:typeof a.description=="string"?a.description:void 0,cwd:a.cwd,startedAt:a.startedAt,finishedAt:a.finishedAt,exitCode:a.exitCode,signal:a.signal,outputLineCount:a.outputLineCount,outputBytes:a.outputBytes}});t.json({ok:!0,agentId:String(o),updatedAt:typeof r.updatedAt=="number"?r.updatedAt:null,tasks:u})}catch(n){if((typeof n=="object"&&n!==null?Reflect.get(n,"code"):void 0)==="ENOENT"){t.json({ok:!0,agentId:String(o),updatedAt:null,tasks:[]});return}if(n instanceof SyntaxError){l.warn("[acode-bg-tasks] \u6587\u4EF6\u635F\u574F\uFF08JSON \u89E3\u6790\u5931\u8D25\uFF09: %s",i),t.json({ok:!0,agentId:String(o),updatedAt:null,tasks:[]});return}const s=n;l.error("[acode-bg-tasks] \u8BFB\u53D6\u5931\u8D25: %s",s.message),t.status(500).json({ok:!1,error:s.message})}}),p.get("/acode-agent-pty-sessions/:agentId",k,(e,t)=>{const d=e.params.agentId,o=Array.isArray(d)?d[0]:d;if(!o||!String(o).trim()){t.status(400).json({ok:!1,error:"agentId is required"});return}const i=String(o),r=v().filter(s=>s.ownerUserId===i);t.json({ok:!0,agentId:i,sessions:r})});const O=15e3;function w(e){return{taskId:e.taskId,status:e.status,exitCode:e.exitCode,signal:e.signal,startedAt:e.startedAt,finishedAt:e.finishedAt,command:e.command,lines:e.lines,nextSeq:e.nextSeq,totalLines:e.totalLines,totalBytes:e.totalBytes,truncated:e.truncated}}async function x(e,t){let o=null;try{o=await S.open(e,"r")}catch(i){if(i?.code==="ENOENT")return{text:[],fileExists:!1,truncated:!1};throw i}try{const n=(await o.stat()).size;if(n===0)return{text:[],fileExists:!0,truncated:!1};const r=Math.min(n,2097152),s=n-r,u=Buffer.alloc(r);await o.read(u,0,r,s);const a=u.toString("utf-8").split(`
2
+ `);return s>0&&a.shift(),{text:a.slice(-t),fileExists:!0,truncated:r<n}}finally{await o.close()}}p.get("/acode-bg-tasks/:agentId/:taskId/output",k,(e,t)=>{(async()=>{const d=String(e.params.agentId),o=String(e.params.taskId),i=Math.min(2e3,Math.max(100,Number(e.query.tailLines)||500));try{const n=await h();if(n){const r=n.getTaskOutputSnapshot(d,o);if(r){t.json({ok:!0,source:"memory",...w(r)});return}}}catch(n){l.warn("[acode-bg-tasks] \u5185\u5B58\u5FEB\u7167\u8BFB\u53D6\u5931\u8D25,\u964D\u7EA7\u8D70\u78C1\u76D8: %s",n?.message)}try{const n=await I();if(!n){t.status(503).json({ok:!1,error:"store unavailable"});return}const r=await n.readSession(d);if(!r){t.status(404).json({ok:!1,error:"task_not_found"});return}const s=r.tasks.find(f=>f.taskId===o);if(!s){t.status(404).json({ok:!1,error:"task_not_found"});return}const{text:u,fileExists:c,truncated:a}=await x(s.outputPath,i);t.json({ok:!0,source:"file",taskId:s.taskId,status:s.status,exitCode:s.exitCode,signal:s.signal,startedAt:s.startedAt,finishedAt:s.finishedAt,command:s.command,lines:u,nextSeq:0,totalLines:s.outputLineCount,totalBytes:s.outputBytes,truncated:a||!c})}catch(n){l.error("[acode-bg-tasks] \u78C1\u76D8\u515C\u5E95\u8BFB\u53D6\u5931\u8D25: %s",n?.message),t.status(500).json({ok:!1,error:"internal_error"})}})().catch(d=>{l.error("[acode-bg-tasks] output \u8BFB\u53D6\u5931\u8D25: %s",d?.message),t.status(500).json({ok:!1,error:"internal_error"})})}),p.get("/acode-bg-tasks/:agentId/:taskId/stream",k,(e,t)=>{L(),(async()=>{const d=String(e.params.agentId),o=String(e.params.taskId);t.status(200),t.set({"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),t.flushHeaders?.();const i=(u,c)=>{t.writableEnded||t.destroyed||(c!==void 0&&t.write(`id: ${c}
3
3
  `),t.write(`data: ${JSON.stringify(u)}
4
4
 
5
- `))};let s,r=null,n=null;try{s=await h(),s&&(r=s,n=s.getTaskOutputSnapshot(d,o))}catch(u){l.warn("[acode-bg-tasks] \u5185\u5B58\u8BFB\u53D6\u5931\u8D25,\u964D\u7EA7\u8D70\u78C1\u76D8: %s",u?.message)}if(n){if(!r){i({type:"done",status:"killed",exitCode:null,signal:null}),t.end();return}if(i({type:"snapshot",source:"memory",...w(n)}),n.status!=="running"){i({type:"done",status:n.status,exitCode:n.exitCode,signal:n.signal}),t.end();return}let u=null,c=!1;const a=()=>{c||(c=!0,u?.(),clearInterval(f))},f=setInterval(()=>{if(t.writableEnded||t.destroyed){a();return}try{t.write(`: ping
5
+ `))};let n,r=null,s=null;try{n=await h(),n&&(r=n,s=n.getTaskOutputSnapshot(d,o))}catch(u){l.warn("[acode-bg-tasks] \u5185\u5B58\u8BFB\u53D6\u5931\u8D25,\u964D\u7EA7\u8D70\u78C1\u76D8: %s",u?.message)}if(s){if(!r){i({type:"done",status:"killed",exitCode:null,signal:null}),t.end();return}if(i({type:"snapshot",source:"memory",...w(s)}),s.status!=="running"){i({type:"done",status:s.status,exitCode:s.exitCode,signal:s.signal}),t.end();return}let u=null,c=!1;const a=()=>{c||(c=!0,u?.(),clearInterval(f))},f=setInterval(()=>{if(t.writableEnded||t.destroyed){a();return}try{t.write(`: ping
6
6
 
7
- `)}catch{a()}},N);if(f.unref?.(),u=r.subscribeTaskOutput(d,o,{onLine:g=>i({type:"output",stream:g.stream,text:g.text,seq:g.seq},g.seq),onDone:g=>{i({type:"done",status:g.status,exitCode:g.exitCode,signal:g.signal}),a(),t.end()}}),!u){i({type:"done",status:n.status,exitCode:n.exitCode,signal:n.signal}),a(),t.end();return}e.on("close",()=>{a(),t.writableEnded||t.end()}),e.on("aborted",()=>a());return}try{const u=await I();if(!u){i({type:"done",status:"killed",exitCode:null,signal:null}),t.end();return}const c=await u.readSession(d);if(!c){i({type:"done",status:"killed",exitCode:null,signal:null}),t.end();return}const a=c.tasks.find(b=>b.taskId===o);if(!a){i({type:"done",status:"killed",exitCode:null,signal:null}),t.end();return}const{text:f,fileExists:g,truncated:A}=await x(a.outputPath,500);i({type:"snapshot",source:"file",taskId:a.taskId,status:a.status,exitCode:a.exitCode,signal:a.signal,startedAt:a.startedAt,finishedAt:a.finishedAt,command:a.command,lines:f,nextSeq:0,totalLines:a.outputLineCount,totalBytes:a.outputBytes,truncated:A||!g}),i({type:"done",status:a.status,exitCode:a.exitCode,signal:a.signal}),t.end()}catch(u){l.error("[acode-bg-tasks] \u78C1\u76D8\u515C\u5E95 stream \u5931\u8D25: %s",u?.message),t.headersSent?t.end():t.status(500).json({ok:!1,error:"internal_error"})}})().catch(d=>{l.error("[acode-bg-tasks] stream \u5EFA\u7ACB\u5931\u8D25: %s",d?.message),t.headersSent?t.end():t.status(500).json({ok:!1,error:"internal_error"})})});export{p as backgroundTasksRouter};
7
+ `)}catch{a()}},O);if(f.unref?.(),u=r.subscribeTaskOutput(d,o,{onLine:g=>i({type:"output",stream:g.stream,text:g.text,seq:g.seq},g.seq),onDone:g=>{i({type:"done",status:g.status,exitCode:g.exitCode,signal:g.signal}),a(),t.end()}}),!u){i({type:"done",status:s.status,exitCode:s.exitCode,signal:s.signal}),a(),t.end();return}e.on("close",()=>{a(),t.writableEnded||t.end()}),e.on("aborted",()=>a());return}try{const u=await I();if(!u){i({type:"done",status:"killed",exitCode:null,signal:null}),t.end();return}const c=await u.readSession(d);if(!c){i({type:"done",status:"killed",exitCode:null,signal:null}),t.end();return}const a=c.tasks.find(b=>b.taskId===o);if(!a){i({type:"done",status:"killed",exitCode:null,signal:null}),t.end();return}const{text:f,fileExists:g,truncated:A}=await x(a.outputPath,500);i({type:"snapshot",source:"file",taskId:a.taskId,status:a.status,exitCode:a.exitCode,signal:a.signal,startedAt:a.startedAt,finishedAt:a.finishedAt,command:a.command,lines:f,nextSeq:0,totalLines:a.outputLineCount,totalBytes:a.outputBytes,truncated:A||!g}),i({type:"done",status:a.status,exitCode:a.exitCode,signal:a.signal}),t.end()}catch(u){l.error("[acode-bg-tasks] \u78C1\u76D8\u515C\u5E95 stream \u5931\u8D25: %s",u?.message),t.headersSent?t.end():t.status(500).json({ok:!1,error:"internal_error"})}})().catch(d=>{l.error("[acode-bg-tasks] stream \u5EFA\u7ACB\u5931\u8D25: %s",d?.message),t.headersSent?t.end():t.status(500).json({ok:!1,error:"internal_error"})})});export{p as backgroundTasksRouter};
8
8
 
@@ -1,14 +1,14 @@
1
- import{execFile as re}from"node:child_process";import y from"node:fs";import B from"node:os";import $ from"node:path";import{Router as se}from"express";import{getBridgeVersion as oe,getRuntimeHomeDir as ie,getUserHomeDir as de}from"../config.js";import{getAccessControlEntries as le,isValidIpEntry as ce,parseAllowIps as ue,refreshAccessControlCache as ge}from"../services/access-control.js";import{getAgentProcessManager as P}from"../services/agent-process-manager.js";import{autoRegister as W,getRegistrationState as J,getAutoRegisterConfigFilePath as A}from"../services/auto-register.js";import{createSession as pe,getPanelCredentials as D,validateSession as H,destroySession as q,validateCredentials as G,hasConfiguredCredentials as R,isDefaultCredentials as fe,setPanelCredentials as me,getAllSessions as he,getActiveSessionCount as be,checkLoginAllowed as ve,recordLoginFailure as ye,recordLoginSuccess as xe}from"../services/panel-auth.js";import{getRuntimeBindingPublicState as Y,getRuntimePairingCode as we,normalizeSchedulerBaseUrl as ke}from"../services/runtime-binding.js";import{collectSystemMetrics as Se}from"../services/system-metrics.js";import{loadPersistedSessions as Ie}from"../services/terminal-persistence.js";import{runExclusiveConfigWrite as X}from"../utils/config-write-queue.js";import{createLogger as Be,getRecentLogs as Ce}from"../utils/logger.js";import{buildTargetKey as T}from"../utils/target-identity.js";import{DASHBOARD_FAVICON_DATA_URI as Q,DASHBOARD_FAVICON_LINK as O}from"./dashboard-icon.js";import{THEME_CSS as j,THEME_BOOT_SCRIPT as z,THEME_FAB_SCRIPT as Z}from"./dashboard-theme.js";import{sdkSessions as Ee}from"./terminal.js";const x=Be("dashboard");let N=null;const Ae=1e4;let M=null,U=null;const Te=3e4;async function F(){Se().then(t=>{M={data:t,ts:Date.now()}}).catch(()=>{}),P().discoverAllProcesses().then(t=>{U={data:t,ts:Date.now()}}).catch(()=>{}),P().cleanupStaleRegistry().catch(()=>{})}const Pe=12e4;let C=null,k=null;function Re(){k&&(clearTimeout(k),k=null),k=setTimeout(Ne,Pe),k.unref?.(),C===null&&(C=setInterval(F,Te),C.unref?.(),F())}function Ne(){C&&(clearInterval(C),C=null),k&&(clearTimeout(k),k=null)}const ee=oe();async function Ue(){const t=await import("node:fs/promises"),n=(await import("node:path")).join(ie(),".aws-bridge","lifecycle-state.json");try{const a=await t.readFile(n,"utf8"),o=JSON.parse(a),r=Array.isArray(o.operations)?o.operations:[];return r.length===0?null:(r.sort((s,d)=>new Date(d.updatedAt).getTime()-new Date(s.updatedAt).getTime()),r[0]||null)}catch{return null}}const p=se(),Le=["/runtime/login","/runtime/logout","/runtime/credentials-status","/runtime/change-credentials","/runtime/server-config","/runtime/access-control","/runtime/node-info","/runtime/logs","/runtime/re-register","/runtime/admin","/runtime/kill-process","/runtime/dashboard","/login","/setup"];function Ke(t){return t==="/"?!0:Le.some(e=>t===e||t.startsWith(`${e}/`))}p.use((t,e,n)=>{Ke(t.path)&&Re(),n()});const te="panel_sid";function De(t){const e={};if(!t)return e;for(const n of t.split(";")){const a=n.indexOf("=");if(a===-1)continue;const o=n.slice(0,a).trim(),r=n.slice(a+1).trim();o&&(e[o]=r)}return e}function L(t){return De(t.headers.cookie)[te]}function ne(t,e,n){const a=t.secure||t.headers["x-forwarded-proto"]==="https";return`${te}=${e}; HttpOnly; SameSite=Lax; Path=/${a?"; Secure":""}; Max-Age=${n}`}function v(t,e){const n=L(t);return n&&H(n)?!0:t.xhr||t.headers.accept?.includes("application/json")?(e.status(401).json({ok:!1,error:"unauthorized",needLogin:!0}),!1):(e.redirect("/login"),!1)}p.post("/runtime/login",(t,e)=>{const n=t.socket.remoteAddress||"unknown",a=ve(n);if(!a.allowed){e.status(429).set("Retry-After",String(a.retryAfterSec)).json({ok:!1,error:"too many failed login attempts, try again later",retryAfterSec:a.retryAfterSec});return}const{username:o,password:r}=t.body||{};if(!o||!r){e.status(400).json({ok:!1,error:"username and password required"});return}if(!G(String(o),String(r))){ye(n),e.status(401).json({ok:!1,error:"invalid credentials"});return}xe(n);const s=pe(),d=!R();e.setHeader("Set-Cookie",ne(t,s,86400)),e.json({ok:!0,needSetup:d})}),p.post("/runtime/logout",(t,e)=>{const n=L(t);n&&q(n),e.setHeader("Set-Cookie",ne(t,"",0)),e.json({ok:!0})}),p.get("/runtime/credentials-status",(t,e)=>{if(!v(t,e))return;const n=D();e.json({ok:!0,isDefault:fe(),configured:R(),username:n.username})}),p.post("/runtime/change-credentials",async(t,e)=>{if(!v(t,e))return;const{username:n,password:a,passwordConfirm:o,oldPassword:r}=t.body||{};if(a&&String(a).trim()){if(String(a)!==String(o)){e.status(400).json({ok:!1,error:"passwords do not match"});return}if(R()){if(!r){e.status(400).json({ok:!1,error:"old password required"});return}const d=D();if(!G(d.username,String(r))){e.status(403).json({ok:!1,error:"old password is incorrect"});return}}}if(!n||!String(n).trim()){e.status(400).json({ok:!1,error:"username required"});return}const s=a&&String(a).trim()?String(a).trim():D().password;try{await me(String(n).trim(),s),e.json({ok:!0})}catch(d){const l=d;x.error("Failed to change panel credentials:",l.message),e.status(500).json({ok:!1,error:l.message})}});function ae(t){const e=typeof t=="string"?t.trim():"";if(e)return e.length<8?"\u2022\u2022\u2022\u2022":"\u2022\u2022\u2022\u2022"+e.slice(-4)}function _(t){const e=Array.isArray(t.autoRegisterTargets)?t.autoRegisterTargets.filter(a=>!!(a&&typeof a=="object"&&!Array.isArray(a))):[];return e.length>0?e:["serverUrl","schedulerBaseUrl","userKey"].some(a=>!!String(t[a]??"").trim())?[t]:[]}const He=["enabled","serverUrl","schedulerBaseUrl","tenantId","userKey","connectionKey","password","instanceName","instanceId","projectId","roleName","workspacePath","registerAddr","registerIp","virtualIp","tunnel","preferSameLanIp","maxRetries","retryInterval"];function Oe(t){const e={};for(const n of He)t[n]!==void 0&&(e[n]=t[n]);return e}function je(t,e){const n=String(t.connectionKey??"").trim()||String(e??"").trim();return{serverUrl:String(t.serverUrl??t.schedulerBaseUrl??"").trim(),tenantId:String(t.tenantId??"").trim(),instanceName:String(t.instanceName??"").trim(),instanceId:String(t.instanceId??"").trim()||void 0,registerAddr:String(t.registerAddr??"").trim(),tunnel:typeof t.tunnel=="boolean"?t.tunnel:void 0,userKeyMasked:ae(t.userKey),userKeySet:!!String(t.userKey??"").trim(),connectionKeyMasked:ae(n),connectionKeySet:!!n,targetKey:T(String(t.serverUrl??t.schedulerBaseUrl??"").trim(),t.userKey)}}function ze(t){return ke(t)??String(t||"").trim()}p.get("/runtime/server-config",(t,e)=>{if(!v(t,e))return;const n=A();let a={};if(y.existsSync(n))try{a=JSON.parse(y.readFileSync(n,"utf-8"))}catch{e.status(500).json({ok:!1,error:"config.json is not valid JSON; fix it manually first"});return}const o=String(a.connectionKey??"").trim()||void 0,r=_(a).map(s=>je(s,o));e.json({ok:!0,targets:r})}),p.get("/runtime/server-config/connection-key",(t,e)=>{if(!v(t,e))return;const n=String((t.query||{}).targetKey??"").trim();if(!n){e.status(400).json({ok:!1,error:"targetKey is required"});return}const a=A();if(!y.existsSync(a)){e.status(404).json({ok:!1,error:"config.json not found"});return}let o;try{o=JSON.parse(y.readFileSync(a,"utf-8"))}catch{e.status(500).json({ok:!1,error:"config.json is not valid JSON"});return}const r=String(o.connectionKey??"").trim()||void 0,s=_(o).find(l=>T(String(l.serverUrl??l.schedulerBaseUrl??"").trim(),l.userKey)===n),d=String(s?.connectionKey??"").trim()||r||"";if(!d){e.status(404).json({ok:!1,error:"\u8BE5\u76EE\u6807\u5C1A\u672A\u914D\u7F6E\u8FDE\u63A5\u5BC6\u94A5\uFF1B\u542F\u52A8\u4E00\u6B21 Bridge \u4F1A\u81EA\u52A8\u751F\u6210\u5E76\u5199\u5165 config.json"});return}e.setHeader("Cache-Control","no-store"),e.json({ok:!0,connectionKey:d})});function K(t,e){const n=new Error(e);return n.status=t,n}p.post("/runtime/server-config",async(t,e)=>{if(!v(t,e))return;const n=(t.body||{}).targets;if(!Array.isArray(n)){e.status(400).json({ok:!1,error:"targets array is required"});return}const a=[];for(let o=0;o<n.length;o++){const r=n[o];if(!r||typeof r!="object"||Array.isArray(r)){e.status(400).json({ok:!1,error:`targets[${o}] must be an object`});return}const s=r,d=String(s.serverUrl??s.schedulerBaseUrl??"").trim();if(!d){e.status(400).json({ok:!1,error:`targets[${o}].serverUrl is required`});return}try{const w=new URL(d);if(!["http:","https:"].includes(w.protocol))throw new Error("protocol must be http or https")}catch{e.status(400).json({ok:!1,error:`targets[${o}].serverUrl must be a valid http(s) URL`});return}const l=s.tunnel;let m;if(l==="auto"||l===""||l===null||l===void 0)m=void 0;else if(l===!0||l==="true")m=!0;else if(l===!1||l==="false")m=!1;else{e.status(400).json({ok:!1,error:`targets[${o}].tunnel must be auto, true or false`});return}const h=String(s.originalServerUrl??"").trim();a.push({serverUrl:d,originalServerUrl:h&&h!==d?h:"",originalTargetKey:String(s.originalTargetKey??"").trim(),userKey:String(s.userKey??"").trim(),tenantId:String(s.tenantId??"").trim(),instanceName:String(s.instanceName??"").trim(),connectionKey:String(s.connectionKey??"").trim(),registerAddr:String(s.registerAddr??"").trim(),tunnel:m})}try{const o=A();await X(o,()=>{let r={};if(y.existsSync(o))try{r=JSON.parse(y.readFileSync(o,"utf-8"))}catch{throw K(500,"config.json is not valid JSON; fix it manually first")}const s=String(r.connectionKey??"").trim(),d=_(r),l=d.length>0&&d[0]===r,m=new Map;for(const i of d){const u=T(String(i.serverUrl??i.schedulerBaseUrl??"").trim(),i.userKey);m.set(u,l?Oe(i):i)}const h=[];for(const i of a){let u;const b=g=>{const c=m.get(g);return c&&m.delete(g),c},S=(g,c)=>T(g,c),E=g=>{const c=`${ze(g)}#`;return[...m.keys()].filter(I=>I.startsWith(c))};if(i.originalTargetKey&&(u=b(i.originalTargetKey)),!u&&i.originalServerUrl&&(u=b(S(i.originalServerUrl,i.userKey)),!u)){const g=E(i.originalServerUrl);g.length===1&&(u=b(g[0]))}if(u||(u=b(S(i.serverUrl,i.userKey))),!u){const g=E(i.serverUrl);g.length>=1&&(u=b(g[0]))}const f=u?{...u}:{};if(f.serverUrl=i.serverUrl,f.tenantId=i.tenantId,f.instanceName=i.instanceName,f.registerAddr=i.registerAddr,i.tunnel===void 0?delete f.tunnel:f.tunnel=i.tunnel,i.userKey)f.userKey=i.userKey;else if(!String(f.userKey??"").trim())throw K(400,`userKey is required for ${i.serverUrl} (new target without inheritable userKey)`);i.connectionKey?f.connectionKey=i.connectionKey:!String(f.connectionKey??"").trim()&&s&&(f.connectionKey=s),h.push(f)}const w=new Map;for(let i=0;i<h.length;i++){const u=h[i],b=T(String(u.serverUrl??u.schedulerBaseUrl??"").trim(),u.userKey),S=w.get(b);if(S!==void 0)throw K(400,`duplicate target: ${String(u.serverUrl??"")} appears in both targets[${S}] and targets[${i}] with the same API key; the same scheduler address can be added multiple times only with different API keys`);w.set(b,i)}r.autoRegisterTargets=h;for(const i of["enabled","serverUrl","schedulerBaseUrl","tenantId","userKey","connectionKey","password","instanceName","instanceId","registerAddr","registerIp","virtualIp","tunnel"])delete r[i];y.mkdirSync($.dirname(o),{recursive:!0}),y.writeFileSync(o,JSON.stringify(r,null,2),"utf-8")}),x.info("Server connection config updated via panel",{configPath:o,targetCount:a.length}),e.json({ok:!0})}catch(o){const r=o,s=Number(r.status)||500;s>=500&&x.error("Failed to save server connection config:",r.message),e.status(s).json({ok:!1,error:r.message})}}),p.get("/runtime/access-control",(t,e)=>{v(t,e)&&e.json({ok:!0,allowIps:le(),defaultAllowIps:["0.0.0.0"]})}),p.post("/runtime/access-control",async(t,e)=>{if(!v(t,e))return;const n=(t.body||{}).allowIps;if(typeof n!="string"&&!Array.isArray(n)){e.status(400).json({ok:!1,error:"allowIps must be a string or an array"});return}const a=ue(n),o=a.filter(r=>!ce(r));if(o.length>0){e.status(400).json({ok:!1,error:`invalid IP/CIDR entries: ${o.join(", ")}`});return}try{const r=A();await X(r,()=>{let s={};if(y.existsSync(r))try{s=JSON.parse(y.readFileSync(r,"utf-8"))}catch{throw K(500,"config.json is not valid JSON; fix it manually first")}const d=s.accessControl&&typeof s.accessControl=="object"&&!Array.isArray(s.accessControl)?{...s.accessControl}:{};d.allowIps=a,s.accessControl=d,y.mkdirSync($.dirname(r),{recursive:!0}),y.writeFileSync(r,JSON.stringify(s,null,2),"utf-8"),ge()}),x.info("Access control config updated via panel",{configPath:r,entryCount:a.length}),e.json({ok:!0,allowIps:a})}catch(r){const s=r,d=Number(s.status)||500;d>=500&&x.error("Failed to save access control config:",s.message),e.status(d).json({ok:!1,error:s.message})}}),p.get("/runtime/node-info",(t,e)=>{if(!v(t,e))return;const n=Y(),a=J();e.json({ok:!0,hostname:B.hostname(),platform:B.platform(),arch:B.arch(),uptime:Math.floor(process.uptime()),nodeVersion:process.version,bridgeVersion:ee,configPath:A(),homeDir:de(),bindingStatus:n.status,paired:n.paired,instanceId:n.instanceId||a.instanceId,schedulerBaseUrl:n.schedulerBaseUrl,registered:a.registered,pairingCode:n.pairingCode,activeSessions:be()})}),p.get("/runtime/logs",(t,e)=>{if(!v(t,e))return;const n=t.query.level||void 0,a=Math.min(Number(t.query.count)||200,500),r=n&&["debug","info","warn","error"].includes(n)?n:void 0,s=Ce(a,r);e.json({ok:!0,logs:s})}),p.post("/runtime/re-register",async(t,e)=>{if(v(t,e))try{const n=await W();e.json({ok:n})}catch(n){const a=n;e.status(500).json({ok:!1,error:a.message})}});let V=!1;function Me(t){const e=t.ip||t.socket.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}p.post("/runtime/pair-applied",(t,e)=>{if(!Me(t)){e.status(403).json({ok:!1,error:"loopback request required"});return}if(V){e.json({ok:!0,started:!1});return}V=!0,W().then(n=>{x.info(n?"[runtime-bridge] \u914D\u5BF9\u540E\u7ACB\u5373\u91CD\u6CE8\u518C\u6210\u529F":"[runtime-bridge] \u914D\u5BF9\u540E\u7ACB\u5373\u91CD\u6CE8\u518C\u672A\u6210\u529F\uFF08\u8BF7\u67E5\u770B AutoRegister \u65E5\u5FD7\uFF09")}).catch(n=>{x.warn("[runtime-bridge] \u914D\u5BF9\u540E\u7ACB\u5373\u91CD\u6CE8\u518C\u51FA\u9519:",n.message)}).finally(()=>{V=!1}),e.json({ok:!0,started:!0})}),p.get("/runtime/admin/sessions",(t,e)=>{if(!v(t,e))return;const n=he().map(a=>({token:a.token.slice(0,8)+"...",createdAt:new Date(a.createdAt).toISOString(),lastUsedAt:new Date(a.lastUsedAt).toISOString(),age:Math.floor((Date.now()-a.createdAt)/1e3)}));e.json({ok:!0,sessions:n})}),p.post("/runtime/admin/sessions/:token/destroy",(t,e)=>{v(t,e)&&(q(t.params.token),e.json({ok:!0}))});function Fe(t){return new Promise((e,n)=>{const a=B.platform()==="win32",o=a?"taskkill":"kill",r=a?["/PID",String(t),"/F"]:["-9",String(t)];re(o,r,{timeout:5e3},s=>s?n(s):e())})}p.post("/runtime/kill-process",async(t,e)=>{if(!v(t,e))return;const n=Number(t.body.pid);if(!n||!Number.isInteger(n)||n<=0){e.status(400).json({ok:!1,error:"Invalid PID"});return}const a=P(),o=()=>{const s=new Set,d=U?.data??[];for(const l of d)typeof l.pid=="number"&&s.add(l.pid);for(const l of a.getAllManagedProcesses())typeof l.pid=="number"&&s.add(l.pid);return s};let r=o();if(r.size===0)try{U={data:await a.discoverAllProcesses(),ts:Date.now()},r=o()}catch{}if(!r.has(n)){x.warn("Rejected kill-process for unrecognized PID",{pid:n}),e.status(404).json({ok:!1,error:"PID is not a bridge-discovered or registered agent process"});return}try{await Fe(n),x.info("Killed process",{pid:n}),e.json({ok:!0})}catch(s){const d=s;x.warn("Failed to kill process",{pid:n,error:d.message}),e.status(500).json({ok:!1,error:d.message})}}),p.get("/runtime/dashboard",async(t,e)=>{if(v(t,e)){if(N&&Date.now()-N.ts<Ae)return void e.json(N.data);try{const n=M?.data??null,a=U?.data??null;M||F();const[o,r,s]=await Promise.all([Promise.resolve(Y()),Promise.resolve(J()),Ie().catch(()=>[])]),l=P().getAllManagedProcesses(),m=Array.from(Ee.entries()).map(([f,g])=>({sessionId:f,agentId:g.agentId,workspacePath:g.workspacePath,runtimeStatus:g.currentRuntimeStatus||"running",runtimeActionType:g.currentRuntimeActionType,runtimeActionLabel:g.currentRuntimeActionLabel,providerId:g.providerId}));let h={managed:0,orphan:0,unknown:0},w=[];if(a){h={managed:a.filter(c=>c.managementStatus==="managed").length,orphan:a.filter(c=>c.managementStatus==="orphan").length,unknown:a.filter(c=>c.managementStatus==="unknown").length};const f=new Map(l.map(c=>[c.pid,c]));w=a.map(c=>{const I=f.get(c.pid);return{agentId:c.agentId||I?.agentId,pid:c.pid,managementStatus:c.managementStatus,sessionId:I?.sessionId,state:I?.state,command:c.command,cwd:c.cwd,startedAt:c.startedAt}});const g={managed:0,orphan:1,unknown:2};w.sort((c,I)=>(g[c.managementStatus]??9)-(g[I.managementStatus]??9))}const i=new Set(m.map(f=>f.sessionId)),u=s.filter(f=>!i.has(f.sessionId)),b=o,S=await Ue(),E={ok:!0,collectedAt:new Date().toISOString(),bridge:{version:ee,hostname:B.hostname(),platform:B.platform(),arch:B.arch(),uptime:Math.floor(process.uptime()),nodeVersion:process.version},binding:{status:b.status,paired:b.paired,instanceId:b.instanceId,userId:b.userId,schedulerBaseUrl:b.schedulerBaseUrl,pairingCode:we()},registration:{registered:r.registered,instanceId:r.instanceId,lastAttempt:r.lastAttempt?.toISOString(),error:r.error},metrics:n,sessions:{active:m,activeCount:m.length,persisted:u,persistedCount:u.length,total:m.length+u.length},processes:{...h,total:h.managed+h.orphan+h.unknown,list:w,registryCount:l.length},lifecycleOperation:S};N={data:E,ts:Date.now()},e.json(E)}catch(n){const a=n;x.error("Dashboard aggregation failed:",a.message),e.status(500).json({ok:!1,error:a.message})}}}),p.get("/login",(t,e)=>{e.type("text/html; charset=utf-8"),e.send(Ve)}),p.get("/",(t,e)=>{const n=L(t);if(!n||!H(n)){e.redirect("/login");return}if(!R()){e.redirect("/setup");return}const a=t.query.lang==="en"?"en":"zh";e.type("text/html; charset=utf-8"),e.send(_e.replace("{{LANG}}",a))}),p.get("/setup",(t,e)=>{const n=L(t);if(!n||!H(n)){e.redirect("/login");return}e.type("text/html; charset=utf-8"),e.send($e)});const _e=`<!DOCTYPE html>
1
+ import{execFile as le}from"node:child_process";import{timingSafeEqual as ce}from"node:crypto";import v from"node:fs";import k from"node:os";import G from"node:path";import{Router as ue}from"express";import{getBridgeVersion as Y,getRuntimeHomeDir as ge,getShellPairToken as pe,getUserHomeDir as fe}from"../config.js";import{getAccessControlEntries as me,isValidIpEntry as he,parseAllowIps as be,refreshAccessControlCache as ve}from"../services/access-control.js";import{getAgentProcessManager as R}from"../services/agent-process-manager.js";import{autoRegister as z,getRegistrationState as X,getAutoRegisterConfigFilePath as C}from"../services/auto-register.js";import{pairBridge as ye}from"../services/bridge-pairing.js";import{SESSION_COOKIE_MAX_AGE_SEC as xe,createSession as we,getPanelCredentials as M,validateSession as N,destroySession as Q,validateCredentials as Z,hasConfiguredCredentials as U,isDefaultCredentials as ke,setPanelCredentials as Se,getAllSessions as Ie,getActiveSessionCount as Be,checkLoginAllowed as Ce,recordLoginFailure as Ee,recordLoginSuccess as Ae}from"../services/panel-auth.js";import{getRuntimeBindingPublicState as ee,getRuntimePairingCode as Te,normalizeSchedulerBaseUrl as Pe}from"../services/runtime-binding.js";import{collectSystemMetrics as Re}from"../services/system-metrics.js";import{loadPersistedSessions as Ne}from"../services/terminal-persistence.js";import{runExclusiveConfigWrite as te}from"../utils/config-write-queue.js";import{createLogger as Ue,getRecentLogs as Le}from"../utils/logger.js";import{buildTargetKey as T}from"../utils/target-identity.js";import{DASHBOARD_FAVICON_DATA_URI as ne,DASHBOARD_FAVICON_LINK as F}from"./dashboard-icon.js";import{THEME_CSS as _,THEME_BOOT_SCRIPT as V,THEME_FAB_SCRIPT as re}from"./dashboard-theme.js";import{sdkSessions as Ke}from"./terminal.js";const x=Ue("dashboard");let L=null;const De=1e4;let $=null,K=null;const He=3e4;async function W(){Re().then(t=>{$={data:t,ts:Date.now()}}).catch(()=>{}),R().discoverAllProcesses().then(t=>{K={data:t,ts:Date.now()}}).catch(()=>{}),R().cleanupStaleRegistry().catch(()=>{})}const je=12e4;let E=null,S=null;function Oe(){S&&(clearTimeout(S),S=null),S=setTimeout(ze,je),S.unref?.(),E===null&&(E=setInterval(W,He),E.unref?.(),W())}function ze(){E&&(clearInterval(E),E=null),S&&(clearTimeout(S),S=null)}const ae=Y();async function Me(){const t=await import("node:fs/promises"),n=(await import("node:path")).join(ge(),".aws-bridge","lifecycle-state.json");try{const r=await t.readFile(n,"utf8"),o=JSON.parse(r),a=Array.isArray(o.operations)?o.operations:[];return a.length===0?null:(a.sort((s,i)=>new Date(i.updatedAt).getTime()-new Date(s.updatedAt).getTime()),a[0]||null)}catch{return null}}const u=ue(),Fe=["/runtime/login","/runtime/logout","/runtime/credentials-status","/runtime/change-credentials","/runtime/server-config","/runtime/access-control","/runtime/node-info","/runtime/logs","/runtime/re-register","/runtime/admin","/runtime/kill-process","/runtime/dashboard","/login","/setup"];function _e(t){return t==="/"?!0:Fe.some(e=>t===e||t.startsWith(`${e}/`))}u.use((t,e,n)=>{_e(t.path)&&Oe(),n()});const se="panel_sid";function Ve(t){const e={};if(!t)return e;for(const n of t.split(";")){const r=n.indexOf("=");if(r===-1)continue;const o=n.slice(0,r).trim(),a=n.slice(r+1).trim();o&&(e[o]=a)}return e}function P(t){return Ve(t.headers.cookie)[se]}function oe(t,e,n){const r=t.secure||t.headers["x-forwarded-proto"]==="https";return`${se}=${e}; HttpOnly; SameSite=Lax; Path=/${r?"; Secure":""}; Max-Age=${n}`}function $e(t,e){const n=P(t);return n&&N(n)?!0:t.xhr||t.headers.accept?.includes("application/json")?(e.status(401).json({ok:!1,error:"unauthorized",needLogin:!0}),!1):(e.redirect("/login"),!1)}function y(t,e){return O(t)?!0:$e(t,e)}u.post("/runtime/login",(t,e)=>{const n=t.socket.remoteAddress||"unknown",r=Ce(n);if(!r.allowed){e.status(429).set("Retry-After",String(r.retryAfterSec)).json({ok:!1,error:"too many failed login attempts, try again later",retryAfterSec:r.retryAfterSec});return}const{username:o,password:a}=t.body||{};if(!o||!a){e.status(400).json({ok:!1,error:"username and password required"});return}if(!Z(String(o),String(a))){Ee(n),e.status(401).json({ok:!1,error:"invalid credentials"});return}Ae(n);const s=we(),i=!U();e.setHeader("Set-Cookie",oe(t,s,xe)),e.json({ok:!0,needSetup:i})}),u.post("/runtime/logout",(t,e)=>{const n=P(t);n&&Q(n),e.setHeader("Set-Cookie",oe(t,"",0)),e.json({ok:!0})}),u.get("/runtime/credentials-status",(t,e)=>{if(!y(t,e))return;const n=M();e.json({ok:!0,isDefault:ke(),configured:U(),username:n.username})}),u.post("/runtime/change-credentials",async(t,e)=>{if(!y(t,e))return;const{username:n,password:r,passwordConfirm:o,oldPassword:a}=t.body||{};if(r&&String(r).trim()){if(String(r)!==String(o)){e.status(400).json({ok:!1,error:"passwords do not match"});return}if(U()){if(!a){e.status(400).json({ok:!1,error:"old password required"});return}const i=M();if(!Z(i.username,String(a))){e.status(403).json({ok:!1,error:"old password is incorrect"});return}}}if(!n||!String(n).trim()){e.status(400).json({ok:!1,error:"username required"});return}const s=r&&String(r).trim()?String(r).trim():M().password;try{await Se(String(n).trim(),s),e.json({ok:!0})}catch(i){const l=i;x.error("Failed to change panel credentials:",l.message),e.status(500).json({ok:!1,error:l.message})}});function ie(t){const e=typeof t=="string"?t.trim():"";if(e)return e.length<8?"\u2022\u2022\u2022\u2022":"\u2022\u2022\u2022\u2022"+e.slice(-4)}function D(t){const e=Array.isArray(t.autoRegisterTargets)?t.autoRegisterTargets.filter(r=>!!(r&&typeof r=="object"&&!Array.isArray(r))):[];return e.length>0?e:["serverUrl","schedulerBaseUrl","userKey"].some(r=>!!String(t[r]??"").trim())?[t]:[]}const We=["enabled","serverUrl","schedulerBaseUrl","tenantId","userKey","connectionKey","password","instanceName","instanceId","projectId","roleName","workspacePath","registerAddr","registerIp","virtualIp","tunnel","preferSameLanIp","maxRetries","retryInterval"];function Je(t){const e={};for(const n of We)t[n]!==void 0&&(e[n]=t[n]);return e}function qe(t,e){const n=String(t.connectionKey??"").trim()||String(e??"").trim();return{serverUrl:String(t.serverUrl??t.schedulerBaseUrl??"").trim(),tenantId:String(t.tenantId??"").trim(),instanceName:String(t.instanceName??"").trim(),instanceId:String(t.instanceId??"").trim()||void 0,registerAddr:String(t.registerAddr??"").trim(),tunnel:typeof t.tunnel=="boolean"?t.tunnel:void 0,userKeyMasked:ie(t.userKey),userKeySet:!!String(t.userKey??"").trim(),connectionKeyMasked:ie(n),connectionKeySet:!!n,targetKey:T(String(t.serverUrl??t.schedulerBaseUrl??"").trim(),t.userKey)}}function Ge(t){return Pe(t)??String(t||"").trim()}u.get("/runtime/server-config",(t,e)=>{if(!y(t,e))return;const n=C();let r={};if(v.existsSync(n))try{r=JSON.parse(v.readFileSync(n,"utf-8"))}catch{e.status(500).json({ok:!1,error:"config.json is not valid JSON; fix it manually first"});return}const o=String(r.connectionKey??"").trim()||void 0,a=D(r).map(s=>qe(s,o));e.json({ok:!0,targets:a})}),u.get("/runtime/server-config/connection-key",(t,e)=>{if(!y(t,e))return;const n=String((t.query||{}).targetKey??"").trim();if(!n){e.status(400).json({ok:!1,error:"targetKey is required"});return}const r=C();if(!v.existsSync(r)){e.status(404).json({ok:!1,error:"config.json not found"});return}let o;try{o=JSON.parse(v.readFileSync(r,"utf-8"))}catch{e.status(500).json({ok:!1,error:"config.json is not valid JSON"});return}const a=String(o.connectionKey??"").trim()||void 0,s=D(o).find(l=>T(String(l.serverUrl??l.schedulerBaseUrl??"").trim(),l.userKey)===n),i=String(s?.connectionKey??"").trim()||a||"";if(!i){e.status(404).json({ok:!1,error:"\u8BE5\u76EE\u6807\u5C1A\u672A\u914D\u7F6E\u8FDE\u63A5\u5BC6\u94A5\uFF1B\u542F\u52A8\u4E00\u6B21 Bridge \u4F1A\u81EA\u52A8\u751F\u6210\u5E76\u5199\u5165 config.json"});return}e.setHeader("Cache-Control","no-store"),e.json({ok:!0,connectionKey:i})});function H(t,e){const n=new Error(e);return n.status=t,n}u.post("/runtime/server-config",async(t,e)=>{if(!y(t,e))return;const n=(t.body||{}).targets;if(!Array.isArray(n)){e.status(400).json({ok:!1,error:"targets array is required"});return}const r=[];for(let o=0;o<n.length;o++){const a=n[o];if(!a||typeof a!="object"||Array.isArray(a)){e.status(400).json({ok:!1,error:`targets[${o}] must be an object`});return}const s=a,i=String(s.serverUrl??s.schedulerBaseUrl??"").trim();if(!i){e.status(400).json({ok:!1,error:`targets[${o}].serverUrl is required`});return}try{const w=new URL(i);if(!["http:","https:"].includes(w.protocol))throw new Error("protocol must be http or https")}catch{e.status(400).json({ok:!1,error:`targets[${o}].serverUrl must be a valid http(s) URL`});return}const l=s.tunnel;let m;if(l==="auto"||l===""||l===null||l===void 0)m=void 0;else if(l===!0||l==="true")m=!0;else if(l===!1||l==="false")m=!1;else{e.status(400).json({ok:!1,error:`targets[${o}].tunnel must be auto, true or false`});return}const h=String(s.originalServerUrl??"").trim();r.push({serverUrl:i,originalServerUrl:h&&h!==i?h:"",originalTargetKey:String(s.originalTargetKey??"").trim(),userKey:String(s.userKey??"").trim(),tenantId:String(s.tenantId??"").trim(),instanceName:String(s.instanceName??"").trim(),connectionKey:String(s.connectionKey??"").trim(),registerAddr:String(s.registerAddr??"").trim(),tunnel:m})}try{const o=C();await te(o,()=>{let a={};if(v.existsSync(o))try{a=JSON.parse(v.readFileSync(o,"utf-8"))}catch{throw H(500,"config.json is not valid JSON; fix it manually first")}const s=String(a.connectionKey??"").trim(),i=D(a),l=i.length>0&&i[0]===a,m=new Map;for(const d of i){const g=T(String(d.serverUrl??d.schedulerBaseUrl??"").trim(),d.userKey);m.set(g,l?Je(d):d)}const h=[];for(const d of r){let g;const b=p=>{const c=m.get(p);return c&&m.delete(p),c},I=(p,c)=>T(p,c),A=p=>{const c=`${Ge(p)}#`;return[...m.keys()].filter(B=>B.startsWith(c))};if(d.originalTargetKey&&(g=b(d.originalTargetKey)),!g&&d.originalServerUrl&&(g=b(I(d.originalServerUrl,d.userKey)),!g)){const p=A(d.originalServerUrl);p.length===1&&(g=b(p[0]))}if(g||(g=b(I(d.serverUrl,d.userKey))),!g){const p=A(d.serverUrl);p.length>=1&&(g=b(p[0]))}const f=g?{...g}:{};if(f.serverUrl=d.serverUrl,f.tenantId=d.tenantId,f.instanceName=d.instanceName,f.registerAddr=d.registerAddr,d.tunnel===void 0?delete f.tunnel:f.tunnel=d.tunnel,d.userKey)f.userKey=d.userKey;else if(!String(f.userKey??"").trim())throw H(400,`userKey is required for ${d.serverUrl} (new target without inheritable userKey)`);d.connectionKey?f.connectionKey=d.connectionKey:!String(f.connectionKey??"").trim()&&s&&(f.connectionKey=s),h.push(f)}const w=new Map;for(let d=0;d<h.length;d++){const g=h[d],b=T(String(g.serverUrl??g.schedulerBaseUrl??"").trim(),g.userKey),I=w.get(b);if(I!==void 0)throw H(400,`duplicate target: ${String(g.serverUrl??"")} appears in both targets[${I}] and targets[${d}] with the same API key; the same scheduler address can be added multiple times only with different API keys`);w.set(b,d)}a.autoRegisterTargets=h;for(const d of["enabled","serverUrl","schedulerBaseUrl","tenantId","userKey","connectionKey","password","instanceName","instanceId","registerAddr","registerIp","virtualIp","tunnel"])delete a[d];v.mkdirSync(G.dirname(o),{recursive:!0}),v.writeFileSync(o,JSON.stringify(a,null,2),"utf-8")}),x.info("Server connection config updated via panel",{configPath:o,targetCount:r.length}),e.json({ok:!0})}catch(o){const a=o,s=Number(a.status)||500;s>=500&&x.error("Failed to save server connection config:",a.message),e.status(s).json({ok:!1,error:a.message})}}),u.get("/runtime/access-control",(t,e)=>{y(t,e)&&e.json({ok:!0,allowIps:me(),defaultAllowIps:["0.0.0.0"]})}),u.post("/runtime/access-control",async(t,e)=>{if(!y(t,e))return;const n=(t.body||{}).allowIps;if(typeof n!="string"&&!Array.isArray(n)){e.status(400).json({ok:!1,error:"allowIps must be a string or an array"});return}const r=be(n),o=r.filter(a=>!he(a));if(o.length>0){e.status(400).json({ok:!1,error:`invalid IP/CIDR entries: ${o.join(", ")}`});return}try{const a=C();await te(a,()=>{let s={};if(v.existsSync(a))try{s=JSON.parse(v.readFileSync(a,"utf-8"))}catch{throw H(500,"config.json is not valid JSON; fix it manually first")}const i=s.accessControl&&typeof s.accessControl=="object"&&!Array.isArray(s.accessControl)?{...s.accessControl}:{};i.allowIps=r,s.accessControl=i,v.mkdirSync(G.dirname(a),{recursive:!0}),v.writeFileSync(a,JSON.stringify(s,null,2),"utf-8"),ve()}),x.info("Access control config updated via panel",{configPath:a,entryCount:r.length}),e.json({ok:!0,allowIps:r})}catch(a){const s=a,i=Number(s.status)||500;i>=500&&x.error("Failed to save access control config:",s.message),e.status(i).json({ok:!1,error:s.message})}}),u.get("/runtime/node-info",(t,e)=>{if(!y(t,e))return;const n=ee(),r=X();e.json({ok:!0,hostname:k.hostname(),platform:k.platform(),arch:k.arch(),uptime:Math.floor(process.uptime()),nodeVersion:process.version,bridgeVersion:ae,configPath:C(),homeDir:fe(),bindingStatus:n.status,paired:n.paired,instanceId:n.instanceId||r.instanceId,schedulerBaseUrl:n.schedulerBaseUrl,registered:r.registered,pairingCode:n.pairingCode,activeSessions:Be()})}),u.get("/runtime/logs",(t,e)=>{if(!y(t,e))return;const n=t.query.level||void 0,r=Math.min(Number(t.query.count)||200,500),a=n&&["debug","info","warn","error"].includes(n)?n:void 0,s=Le(r,a);e.json({ok:!0,logs:s})}),u.post("/runtime/re-register",async(t,e)=>{if(y(t,e))try{const n=await z();e.json({ok:n})}catch(n){const r=n;e.status(500).json({ok:!1,error:r.message})}});let J=!1;function j(t){const e=t.ip||t.socket.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}function O(t){const e=pe(),n=String(t.headers["x-shell-token"]??"").trim();if(!e||!n||!j(t))return!1;const r=Buffer.from(n,"utf8"),o=Buffer.from(e,"utf8");return r.length===o.length&&ce(r,o)}u.post("/runtime/pair-applied",(t,e)=>{if(!j(t)){e.status(403).json({ok:!1,error:"loopback request required"});return}if(J){e.json({ok:!0,started:!1});return}J=!0,z().then(n=>{x.info(n?"[runtime-bridge] \u914D\u5BF9\u540E\u7ACB\u5373\u91CD\u6CE8\u518C\u6210\u529F":"[runtime-bridge] \u914D\u5BF9\u540E\u7ACB\u5373\u91CD\u6CE8\u518C\u672A\u6210\u529F\uFF08\u8BF7\u67E5\u770B AutoRegister \u65E5\u5FD7\uFF09")}).catch(n=>{x.warn("[runtime-bridge] \u914D\u5BF9\u540E\u7ACB\u5373\u91CD\u6CE8\u518C\u51FA\u9519:",n.message)}).finally(()=>{J=!1}),e.json({ok:!0,started:!0})});function de(t,e){if(O(t))return!0;const n=P(t);return n&&N(n)?!0:(e.status(401).json({ok:!1,error:"unauthorized"}),!1)}u.get("/runtime/shell/status",(t,e)=>{if(!de(t,e))return;if(!j(t)){e.status(403).json({ok:!1,error:"loopback request required"});return}const n=C();let r={};if(v.existsSync(n))try{r=JSON.parse(v.readFileSync(n,"utf-8"))}catch{e.status(500).json({ok:!1,error:"config.json is not valid JSON"});return}const o=D(r).map(a=>({serverUrl:String(a.serverUrl??a.schedulerBaseUrl??"").trim(),instanceId:String(a.instanceId??"").trim(),instanceName:String(a.instanceName??"").trim()})).filter(a=>a.serverUrl);e.json({ok:!0,version:Y(),hostname:k.hostname(),targets:o})});let q=!1;u.post("/runtime/shell/pair",async(t,e)=>{if(!de(t,e))return;if(!j(t)){e.status(403).json({ok:!1,error:"loopback request required"});return}const n=t.body||{},r=String(n.pairingTicket??"").trim(),o=String(n.serverUrl??"").trim(),a=String(n.instanceName??"").trim(),s=String(n.instanceId??"").trim();if(!r||!o){e.status(400).json({ok:!1,error:"pairingTicket and serverUrl are required"});return}let i;try{i=await ye({ticket:r,serverUrl:o,...s?{instanceId:s}:{},...a?{instanceName:a}:{}})}catch(l){const m=l;e.status(500).json({ok:!1,error:m.message});return}if(!i.success){e.status(400).json({ok:!1,error:i.error||"pair failed"});return}q||(q=!0,z().catch(l=>{x.warn("[runtime-bridge] shell pair \u540E\u91CD\u6CE8\u518C\u51FA\u9519:",l.message)}).finally(()=>{q=!1})),e.json({ok:!0,instanceId:i.instanceId,serverUrl:i.serverUrl})}),u.get("/runtime/admin/sessions",(t,e)=>{if(!y(t,e))return;const n=Ie().map(r=>({token:r.token.slice(0,8)+"...",createdAt:new Date(r.createdAt).toISOString(),lastUsedAt:new Date(r.lastUsedAt).toISOString(),age:Math.floor((Date.now()-r.createdAt)/1e3)}));e.json({ok:!0,sessions:n})}),u.post("/runtime/admin/sessions/:token/destroy",(t,e)=>{y(t,e)&&(Q(t.params.token),e.json({ok:!0}))});function Ye(t){return new Promise((e,n)=>{const r=k.platform()==="win32",o=r?"taskkill":"kill",a=r?["/PID",String(t),"/F"]:["-9",String(t)];le(o,a,{timeout:5e3},s=>s?n(s):e())})}u.post("/runtime/kill-process",async(t,e)=>{if(!y(t,e))return;const n=Number(t.body.pid);if(!n||!Number.isInteger(n)||n<=0){e.status(400).json({ok:!1,error:"Invalid PID"});return}const r=R(),o=()=>{const s=new Set,i=K?.data??[];for(const l of i)typeof l.pid=="number"&&s.add(l.pid);for(const l of r.getAllManagedProcesses())typeof l.pid=="number"&&s.add(l.pid);return s};let a=o();if(a.size===0)try{K={data:await r.discoverAllProcesses(),ts:Date.now()},a=o()}catch{}if(!a.has(n)){x.warn("Rejected kill-process for unrecognized PID",{pid:n}),e.status(404).json({ok:!1,error:"PID is not a bridge-discovered or registered agent process"});return}try{await Ye(n),x.info("Killed process",{pid:n}),e.json({ok:!0})}catch(s){const i=s;x.warn("Failed to kill process",{pid:n,error:i.message}),e.status(500).json({ok:!1,error:i.message})}}),u.get("/runtime/dashboard",async(t,e)=>{if(y(t,e)){if(L&&Date.now()-L.ts<De)return void e.json(L.data);try{const n=$?.data??null,r=K?.data??null;$||W();const[o,a,s]=await Promise.all([Promise.resolve(ee()),Promise.resolve(X()),Ne().catch(()=>[])]),l=R().getAllManagedProcesses(),m=Array.from(Ke.entries()).map(([f,p])=>({sessionId:f,agentId:p.agentId,workspacePath:p.workspacePath,runtimeStatus:p.currentRuntimeStatus||"running",runtimeActionType:p.currentRuntimeActionType,runtimeActionLabel:p.currentRuntimeActionLabel,providerId:p.providerId}));let h={managed:0,orphan:0,unknown:0},w=[];if(r){h={managed:r.filter(c=>c.managementStatus==="managed").length,orphan:r.filter(c=>c.managementStatus==="orphan").length,unknown:r.filter(c=>c.managementStatus==="unknown").length};const f=new Map(l.map(c=>[c.pid,c]));w=r.map(c=>{const B=f.get(c.pid);return{agentId:c.agentId||B?.agentId,pid:c.pid,managementStatus:c.managementStatus,sessionId:B?.sessionId,state:B?.state,command:c.command,cwd:c.cwd,startedAt:c.startedAt}});const p={managed:0,orphan:1,unknown:2};w.sort((c,B)=>(p[c.managementStatus]??9)-(p[B.managementStatus]??9))}const d=new Set(m.map(f=>f.sessionId)),g=s.filter(f=>!d.has(f.sessionId)),b=o,I=await Me(),A={ok:!0,collectedAt:new Date().toISOString(),bridge:{version:ae,hostname:k.hostname(),platform:k.platform(),arch:k.arch(),uptime:Math.floor(process.uptime()),nodeVersion:process.version},binding:{status:b.status,paired:b.paired,instanceId:b.instanceId,userId:b.userId,schedulerBaseUrl:b.schedulerBaseUrl,pairingCode:Te()},registration:{registered:a.registered,instanceId:a.instanceId,lastAttempt:a.lastAttempt?.toISOString(),error:a.error},metrics:n,sessions:{active:m,activeCount:m.length,persisted:g,persistedCount:g.length,total:m.length+g.length},processes:{...h,total:h.managed+h.orphan+h.unknown,list:w,registryCount:l.length},lifecycleOperation:I};L={data:A,ts:Date.now()},e.json(A)}catch(n){const r=n;x.error("Dashboard aggregation failed:",r.message),e.status(500).json({ok:!1,error:r.message})}}}),u.get("/login",(t,e)=>{e.type("text/html; charset=utf-8"),e.send(Qe)}),u.get("/",(t,e)=>{const n=P(t),r=O(t);if((!n||!N(n))&&!r){e.redirect("/login");return}if(!U()){e.redirect("/setup");return}const o=t.query.lang==="en"?"en":"zh";e.type("text/html; charset=utf-8"),e.send(Xe.replace("{{LANG}}",o))}),u.get("/setup",(t,e)=>{const n=P(t),r=O(t);if((!n||!N(n))&&!r){e.redirect("/login");return}e.type("text/html; charset=utf-8"),e.send(Ze)});const Xe=`<!DOCTYPE html>
2
2
  <html lang="{{LANG}}">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Bridge Dashboard</title>
7
- ${O}
8
- ${z}
7
+ ${F}
8
+ ${V}
9
9
  <style>
10
10
  /* \u8BBE\u8BA1\u4EE4\u724C\u89C1 dashboard-theme.ts\uFF1A\u9ED8\u8BA4\u6DF1\u8272\uFF0Chtml.light-theme \u5207\u6D45\u8272 */
11
- ${j}
11
+ ${_}
12
12
 
13
13
  :root { --topbar-h: 56px; }
14
14
 
@@ -684,7 +684,7 @@ ${z}
684
684
  <!-- \u2550\u2550 \u9876\u680F\uFF1A\u54C1\u724C + \u8FD0\u884C\u5143\u4FE1\u606F + \u5168\u5C40\u64CD\u4F5C \u2550\u2550 -->
685
685
  <header class="topbar">
686
686
  <div class="brand">
687
- <img class="brand-mark" src="${Q}" alt="">
687
+ <img class="brand-mark" src="${ne}" alt="">
688
688
  <span>AgentsWorkStudio</span>
689
689
  </div>
690
690
  <div class="topbar-meta">
@@ -3425,17 +3425,17 @@ if (schedPrefill) {
3425
3425
  }
3426
3426
  </script>
3427
3427
  </body>
3428
- </html>`,Ve=`<!DOCTYPE html>
3428
+ </html>`,Qe=`<!DOCTYPE html>
3429
3429
  <html lang="zh-CN">
3430
3430
  <head>
3431
3431
  <meta charset="UTF-8">
3432
3432
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
3433
3433
  <title>Bridge Dashboard - Login</title>
3434
- ${O}
3435
- ${z}
3434
+ ${F}
3435
+ ${V}
3436
3436
  <style>
3437
3437
  /* \u4E0E\u4E3B\u9762\u677F\u5171\u7528\u540C\u4E00\u5957\u8BBE\u8BA1\u4EE4\u724C\uFF08\u9ED8\u8BA4\u6DF1\u8272\uFF0Chtml.light-theme \u5207\u6D45\u8272\uFF09 */
3438
- ${j}
3438
+ ${_}
3439
3439
 
3440
3440
  * { margin: 0; padding: 0; box-sizing: border-box; }
3441
3441
 
@@ -3551,7 +3551,7 @@ ${z}
3551
3551
  <button type="button" class="theme-fab" id="themeFab" onclick="toggleThemeFab()" title="\u5207\u6362\u4E3B\u9898">&#x263D;</button>
3552
3552
  <div class="login-card">
3553
3553
  <div class="login-brand">
3554
- <img class="brand-mark" src="${Q}" alt="AgentsWorkStudio Bridge">
3554
+ <img class="brand-mark" src="${ne}" alt="AgentsWorkStudio Bridge">
3555
3555
  <span class="login-brand-name">AgentsWorkStudio</span>
3556
3556
  </div>
3557
3557
  <h1>Bridge \u63A7\u5236\u53F0</h1>
@@ -3627,19 +3627,19 @@ document.getElementById("loginForm").addEventListener("keydown", function(e) {
3627
3627
  if (e.key === "Enter") doLogin(e);
3628
3628
  });
3629
3629
  </script>
3630
- ${Z}
3630
+ ${re}
3631
3631
  </body>
3632
- </html>`,$e=`<!DOCTYPE html>
3632
+ </html>`,Ze=`<!DOCTYPE html>
3633
3633
  <html lang="zh-CN">
3634
3634
  <head>
3635
3635
  <meta charset="UTF-8">
3636
3636
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
3637
3637
  <title>Bridge Dashboard - Setup</title>
3638
- ${O}
3639
- ${z}
3638
+ ${F}
3639
+ ${V}
3640
3640
  <style>
3641
3641
  /* \u4E0E\u4E3B\u9762\u677F\u5171\u7528\u8BBE\u8BA1\u4EE4\u724C\uFF08--text2/--surface2/--green/--red \u4E3A\u517C\u5BB9\u522B\u540D\uFF09 */
3642
- ${j}
3642
+ ${_}
3643
3643
 
3644
3644
  * { margin:0; padding:0; box-sizing:border-box; }
3645
3645
  body {
@@ -3910,7 +3910,7 @@ async function doSkip() {
3910
3910
 
3911
3911
  document.getElementById("setupForm").addEventListener("submit", doSave);
3912
3912
  </script>
3913
- ${Z}
3913
+ ${re}
3914
3914
  </body>
3915
- </html>`;export{p as dashboardRouter,Re as noteDashboardActivity};
3915
+ </html>`;export{u as dashboardRouter,Oe as noteDashboardActivity};
3916
3916