aws-runtime-bridge 1.9.120 → 1.9.124

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 (105) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +18 -0
  2. package/dist/adapter/AcodeSdkAdapter.js +5 -5
  3. package/dist/adapter/types.d.ts +4 -0
  4. package/dist/adapter/types.js +1 -1
  5. package/dist/browser/browser-ws-bridge.js +3 -3
  6. package/dist/browser/built-in-browser-tools.js +1 -1
  7. package/dist/desktop/built-in-desktop-tools.d.ts +49 -0
  8. package/dist/desktop/built-in-desktop-tools.js +2 -0
  9. package/dist/desktop/desktop-mcp-client.d.ts +47 -0
  10. package/dist/desktop/desktop-mcp-client.js +3 -0
  11. package/dist/index.js +1 -1
  12. package/dist/remote-desktop/index.js +2 -2
  13. package/dist/routes/dashboard.js +521 -17
  14. package/dist/routes/git.d.ts +39 -0
  15. package/dist/routes/git.js +33 -25
  16. package/dist/routes/instance.js +1 -1
  17. package/dist/routes/jdks.d.ts +2 -0
  18. package/dist/routes/jdks.js +2 -0
  19. package/dist/routes/launch.d.ts +6 -0
  20. package/dist/routes/launch.js +30 -0
  21. package/dist/routes/pty.js +3 -3
  22. package/dist/routes/runtime-binding.js +1 -1
  23. package/dist/routes/terminal.js +30 -30
  24. package/dist/services/access-control.d.ts +18 -0
  25. package/dist/services/access-control.js +5 -0
  26. package/dist/services/agent-process-manager.js +1 -1
  27. package/dist/services/auto-register.js +1 -1
  28. package/dist/services/change-cache-retention.d.ts +5 -0
  29. package/dist/services/change-cache-retention.js +2 -0
  30. package/dist/services/desktop-mcp-manager.d.ts +47 -0
  31. package/dist/services/desktop-mcp-manager.js +2 -0
  32. package/dist/services/instance-features.d.ts +6 -0
  33. package/dist/services/instance-features.js +1 -1
  34. package/dist/services/jdk-scanner.d.ts +20 -0
  35. package/dist/services/jdk-scanner.js +2 -0
  36. package/dist/services/launch-manager.d.ts +181 -0
  37. package/dist/services/launch-manager.js +12 -0
  38. package/dist/services/launch-metrics.d.ts +89 -0
  39. package/dist/services/launch-metrics.js +4 -0
  40. package/dist/services/launch-streams.d.ts +24 -0
  41. package/dist/services/launch-streams.js +11 -0
  42. package/dist/services/mcp-launch-binding-queue.js +1 -1
  43. package/dist/services/panel-auth.d.ts +11 -1
  44. package/dist/services/panel-auth.js +1 -1
  45. package/dist/services/panel-env.d.ts +5 -0
  46. package/dist/services/panel-env.js +2 -0
  47. package/dist/services/port-detector.d.ts +3 -0
  48. package/dist/services/port-detector.js +6 -0
  49. package/dist/services/runtime-lifecycle-policy.d.ts +1 -0
  50. package/dist/services/runtime-lifecycle-policy.js +1 -1
  51. package/dist/services/system-metrics.js +1 -1
  52. package/dist/services/tunnel-client.d.ts +4 -0
  53. package/dist/services/tunnel-client.js +1 -1
  54. package/dist/services/workspace-files.d.ts +3 -0
  55. package/dist/services/workspace-files.js +1 -1
  56. package/dist/services/workspaceTaskChangeWatcher.d.ts +2 -0
  57. package/dist/services/workspaceTaskChangeWatcher.js +3 -3
  58. package/dist/utils/config-write-queue.d.ts +3 -0
  59. package/dist/utils/config-write-queue.js +2 -0
  60. package/package/acode/dist/built-in-file-tools.d.ts +2 -0
  61. package/package/acode/dist/runtime.d.ts +20 -0
  62. package/package/acode/dist/runtime.js +27 -27
  63. package/package/acode/dist/sub-agent-manager.d.ts +4 -0
  64. package/package/acode/dist/sub-agent-manager.js +1 -1
  65. package/package/acode/dist/sub-agent-tools.d.ts +6 -0
  66. package/package/acode/dist/sub-agent-tools.js +39 -10
  67. package/package/acode/dist/sub-agent-types.d.ts +2 -0
  68. package/package/acode/dist/tool-allocation.d.ts +55 -0
  69. package/package/acode/dist/tool-allocation.js +2 -0
  70. package/package/acode/dist/types.d.ts +6 -0
  71. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +24 -0
  72. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  73. package/package/aws-client-agent-mcp/dist/agent-client.test.js +19 -5
  74. package/package/aws-client-agent-mcp/dist/context-manager.test.js +6 -6
  75. package/package/aws-client-agent-mcp/dist/http-client.d.ts +2 -0
  76. package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
  77. package/package/aws-client-agent-mcp/dist/index.js +1 -1
  78. package/package/aws-client-agent-mcp/dist/launch-config-tools.test.d.ts +1 -0
  79. package/package/aws-client-agent-mcp/dist/launch-config-tools.test.js +106 -0
  80. package/package/aws-client-agent-mcp/dist/logger.d.ts +4 -0
  81. package/package/aws-client-agent-mcp/dist/logger.js +2 -2
  82. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +21 -0
  83. package/package/aws-client-agent-mcp/dist/mcp-server.js +25 -25
  84. package/package/aws-client-agent-mcp/dist/mcp-server.test.js +24 -16
  85. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +20 -0
  86. package/package/aws-client-agent-mcp/dist/mcp-tools.js +8 -8
  87. package/package/aws-client-agent-mcp/dist/mcp-tools.test.js +55 -1
  88. package/package/aws-client-agent-mcp/dist/memory-store.test.js +5 -1
  89. package/package/aws-client-agent-mcp/dist/parent-lifecycle.d.ts +10 -0
  90. package/package/aws-client-agent-mcp/dist/parent-lifecycle.js +2 -0
  91. package/package/aws-client-agent-mcp/dist/parent-lifecycle.test.d.ts +1 -0
  92. package/package/aws-client-agent-mcp/dist/parent-lifecycle.test.js +81 -0
  93. package/package/aws-client-agent-mcp/dist/status-reporter.js +1 -1
  94. package/package/aws-client-agent-mcp/dist/types.d.ts +4 -0
  95. package/package/aws-client-agent-mcp/dist/watchdog-worker.d.ts +1 -0
  96. package/package/aws-client-agent-mcp/dist/watchdog-worker.js +3 -0
  97. package/package/aws-client-agent-mcp/dist/watchdog.d.ts +17 -0
  98. package/package/aws-client-agent-mcp/dist/watchdog.js +2 -0
  99. package/package/aws-client-agent-mcp/dist/watchdog.test.d.ts +1 -0
  100. package/package/aws-client-agent-mcp/dist/watchdog.test.js +124 -0
  101. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts +4 -0
  102. package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
  103. package/package/aws-client-agent-mcp/dist/websocket-client.test.js +83 -6
  104. package/package/aws-client-agent-mcp/package.json +1 -1
  105. package/package.json +2 -1
@@ -1,2 +1,2 @@
1
- import b from"axios";import{Router as T}from"express";import{getConfiguredConnectionKeys as I}from"../services/auto-register.js";import{validateToken as f}from"../middleware/auth.js";import{claimMcpLaunchBinding as j,getLatestAgentToken as R,getMcpLaunchQueueSize as k}from"../services/mcp-launch-binding-queue.js";import{clearRuntimeBinding as y,getRuntimeAccessToken as B,getRuntimeBindingPublicState as g,getRuntimePairingCode as S,hasRuntimeBinding as v,saveRuntimeBinding as p,validateRuntimeBindingToken as w,validateRuntimePairingCode as A}from"../services/runtime-binding.js";import{createLogger as U}from"../utils/logger.js";const a=U("runtime-binding-route"),d=T();function $(n){return{success:!1,error:"MCP runtime token must be claimed from launch binding; bridge-scoped token refresh is disabled"}}function q(n){const e=n.header("X-Runtime-Token");return e?e.trim():(n.header("Authorization")||"").match(/^Bearer\s+(.+)$/i)?.[1]?.trim()||""}d.get("/binding/status",(n,e)=>{const i=g();e.json({ok:!0,...i,pairingRequired:!i.paired})}),d.post("/binding/pair",(n,e)=>{const{accessToken:i,instanceId:t,userId:o,schedulerBaseUrl:r,pairingCode:s}=n.body||{},u=v(),c=q(n);if(u){if(!w(c)){e.status(401).json({error:"unauthorized",message:"Bridge is already paired. Provide the current runtime token to rotate binding."});return}}else if(!A(s)){e.status(401).json({error:"invalid_pairing_code",message:"Invalid pairing code. Read the current pairing code from the bridge console and try again."});return}try{p({accessToken:String(i||""),instanceId:t?String(t):void 0,userId:o?String(o):void 0,schedulerBaseUrl:r?String(r):void 0}),a.info(`[runtime-bridge] paired with instanceId=${t||"unknown"}`),e.json({ok:!0,...g()})}catch(l){const h=l;e.status(400).json({error:h.message||"pair runtime bridge failed"})}});function m(n){const e=n.ip||n.socket.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}d.post("/binding/request-token",async(n,e)=>{if(!m(n)){e.status(403).json({ok:!1,error:"loopback request required"});return}const i=$(n.body||{});if(!i.success||!i.runtimeAccessToken){e.status(400).json({ok:!1,error:i.error||"request runtime token failed"});return}e.json({ok:!0,runtimeAccessToken:i.runtimeAccessToken,updated:i.updated})}),d.post("/binding/claim-agent",(n,e)=>{if(!m(n)){e.status(403).json({ok:!1,error:"loopback request required"});return}const{agentId:i,workspacePath:t,serverUrl:o}=n.body||{};if(!t||!String(t).trim()){e.status(400).json({ok:!1,error:"workspacePath is required"});return}if(!o||!String(o).trim()){e.status(400).json({ok:!1,error:"serverUrl is required"});return}const r=j({agentId:i,workspacePath:t,serverUrl:o});if(!r){e.status(404).json({ok:!1,error:"launch binding not found for workspacePath and serverUrl",queueSize:k(t)});return}C(r.agentId,r.schedulerBaseUrl).catch(()=>{}),e.json({ok:!0,agentId:r.agentId,workspacePath:r.workspacePath,runtimeAccessToken:r.runtimeAccessToken,userId:r.userId,schedulerBaseUrl:r.schedulerBaseUrl,serverUrl:r.serverUrl,mcpHttpUrl:r.mcpHttpUrl,bindingId:r.id,remainingQueueSize:k(t)})}),d.post("/binding/refresh-token",(n,e)=>{if(!m(n)){e.status(403).json({ok:!1,error:"loopback request required"});return}const{agentId:i,currentToken:t,forceRefresh:o}=n.body||{},r=String(i||"").trim();if(!r){e.status(400).json({ok:!1,error:"agentId is required"});return}const s=R(r);if(!s){e.status(404).json({ok:!1,error:"no cached token for agent"});return}const u=String(t||"").trim();if(!o&&u&&s.runtimeAccessToken===u){e.status(409).json({ok:!1,error:"token_unchanged",message:"Bridge cached token is the same as current; token may be revoked server-side"});return}e.json({ok:!0,runtimeAccessToken:s.runtimeAccessToken})}),d.post("/binding/issue",f,(n,e)=>{const{accessToken:i,instanceId:t,userId:o,schedulerBaseUrl:r}=n.body||{},s=String(i||"").trim();if(!s){e.status(400).json({error:"accessToken is required"});return}try{const c=B()!==s;c?(p({accessToken:s,instanceId:t?String(t):void 0,userId:o?String(o):void 0,schedulerBaseUrl:r?String(r):void 0}),a.info(`[runtime-bridge] runtime token redispatched and updated: instanceId=${t||"unknown"}`)):a.info(`[runtime-bridge] runtime token redispatched but unchanged: instanceId=${t||"unknown"}`),e.json({ok:!0,updated:c,...g()})}catch(u){const c=u;e.status(400).json({error:c.message||"issue runtime token failed"})}}),d.post("/binding/unpair",f,(n,e)=>{y(),e.json({ok:!0,...g()})});function H(){const n=g();if(n.paired){a.info(`[runtime-bridge] runtime binding loaded: instanceId=${n.instanceId||"unknown"}`);return}a.info("[runtime-bridge] bridge is unpaired; sensitive APIs will reject requests until paired"),a.info(`[runtime-bridge] pairing code: ${S()}`)}async function C(n,e){if(!e){a.debug(`[runtime-binding] notifySchedulerBindingClaimed skipped: no schedulerBaseUrl for agentId=${n}`);return}const t=I()[0];if(!t){a.warn(`[runtime-binding] notifySchedulerBindingClaimed skipped: no connection key for agentId=${n}`);return}const o=`${e.replace(/\/+$/,"")}/api/runtime/bridge/binding-claimed`;try{await b.post(o,{agentId:n},{headers:{"X-Runtime-Token":t,"Content-Type":"application/json"},timeout:5e3}),a.debug(`[runtime-binding] Notified scheduler: agentId=${n}, url=${o}`)}catch(r){const s=r instanceof Error?r.message:String(r);a.warn(`[runtime-binding] Failed to notify scheduler binding claimed: agentId=${n}, error=${s}`)}}export{H as logRuntimeBindingStartupState,$ as resolveRuntimeTokenRequest,d as runtimeBindingRouter};
1
+ import T from"axios";import{Router as I}from"express";import{getConfiguredConnectionKeys as j}from"../services/auto-register.js";import{validateToken as f}from"../middleware/auth.js";import{claimMcpLaunchBinding as R,getLatestAgentToken as S,getMcpLaunchQueueSize as k}from"../services/mcp-launch-binding-queue.js";import{clearRuntimeBinding as B,getRuntimeAccessToken as p,getRuntimeBindingPublicState as g,getRuntimePairingCode as y,hasRuntimeBinding as v,saveRuntimeBinding as h,validateRuntimeBindingToken as w,validateRuntimePairingCode as A}from"../services/runtime-binding.js";import{createLogger as $}from"../utils/logger.js";const s=$("runtime-binding-route"),d=I();function q(n){return{success:!1,error:"MCP runtime token must be claimed from launch binding; bridge-scoped token refresh is disabled"}}function U(n){const e=n.header("X-Runtime-Token");return e?e.trim():(n.header("Authorization")||"").match(/^Bearer\s+(.+)$/i)?.[1]?.trim()||""}d.get("/binding/status",(n,e)=>{const t=g();e.json({ok:!0,...t,pairingRequired:!t.paired})}),d.post("/binding/pair",(n,e)=>{const{accessToken:t,instanceId:i,userId:o,schedulerBaseUrl:r,pairingCode:a}=n.body||{},u=v(),c=U(n);if(u){if(!w(c)){e.status(401).json({error:"unauthorized",message:"Bridge is already paired. Provide the current runtime token to rotate binding."});return}}else if(!A(a)){e.status(401).json({error:"invalid_pairing_code",message:"Invalid pairing code. Read the current pairing code from the bridge console and try again."});return}try{h({accessToken:String(t||""),instanceId:i?String(i):void 0,userId:o?String(o):void 0,schedulerBaseUrl:r?String(r):void 0}),s.info(`[runtime-bridge] paired with instanceId=${i||"unknown"}`),e.json({ok:!0,...g()})}catch(l){const b=l;e.status(400).json({error:b.message||"pair runtime bridge failed"})}});function m(n){const e=n.ip||n.socket.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}d.post("/binding/request-token",async(n,e)=>{if(!m(n)){e.status(403).json({ok:!1,error:"loopback request required"});return}const t=q(n.body||{});if(!t.success||!t.runtimeAccessToken){e.status(400).json({ok:!1,error:t.error||"request runtime token failed"});return}e.json({ok:!0,runtimeAccessToken:t.runtimeAccessToken,updated:t.updated})}),d.post("/binding/claim-agent",(n,e)=>{if(!m(n)){e.status(403).json({ok:!1,error:"loopback request required"});return}const{agentId:t,workspacePath:i,serverUrl:o}=n.body||{};if(!i||!String(i).trim()){e.status(400).json({ok:!1,error:"workspacePath is required"});return}if(!o||!String(o).trim()){e.status(400).json({ok:!1,error:"serverUrl is required"});return}const r=R({agentId:t,workspacePath:i,serverUrl:o});if(!r){e.status(404).json({ok:!1,error:"launch binding not found for workspacePath and serverUrl",queueSize:k(i)});return}C(r.agentId,r.schedulerBaseUrl).catch(()=>{}),e.json({ok:!0,agentId:r.agentId,workspacePath:r.workspacePath,runtimeAccessToken:r.runtimeAccessToken,userId:r.userId,schedulerBaseUrl:r.schedulerBaseUrl,serverUrl:r.serverUrl,mcpHttpUrl:r.mcpHttpUrl,bindingId:r.id,remainingQueueSize:k(i)})}),d.post("/binding/refresh-token",(n,e)=>{if(!m(n)){e.status(403).json({ok:!1,error:"loopback request required"});return}const{agentId:t,currentToken:i,forceRefresh:o}=n.body||{},r=String(t||"").trim();if(!r){e.status(400).json({ok:!1,error:"agentId is required"});return}const a=S(r);if(!a){e.status(404).json({ok:!1,error:"no cached token for agent"});return}const u=String(i||"").trim();if(!o&&u&&a.runtimeAccessToken===u){e.status(409).json({ok:!1,error:"token_unchanged",message:"Bridge cached token is the same as current; token may be revoked server-side"});return}e.json({ok:!0,runtimeAccessToken:a.runtimeAccessToken})}),d.post("/binding/issue",f,(n,e)=>{const{accessToken:t,instanceId:i,userId:o,schedulerBaseUrl:r}=n.body||{},a=String(t||"").trim();if(!a){e.status(400).json({error:"accessToken is required"});return}try{const c=p()!==a;c?(h({accessToken:a,instanceId:i?String(i):void 0,userId:o?String(o):void 0,schedulerBaseUrl:r?String(r):void 0}),s.info(`[runtime-bridge] runtime token redispatched and updated: instanceId=${i||"unknown"}`)):s.info(`[runtime-bridge] runtime token redispatched but unchanged: instanceId=${i||"unknown"}`),e.json({ok:!0,updated:c,...g()})}catch(u){const c=u;e.status(400).json({error:c.message||"issue runtime token failed"})}}),d.post("/binding/unpair",f,(n,e)=>{B(),e.json({ok:!0,...g()})});function Q(){const n=g();if(n.paired){s.info(`[runtime-bridge] runtime binding loaded: instanceId=${n.instanceId||"unknown"}`);return}s.info("[runtime-bridge] bridge is unpaired; sensitive APIs will reject requests until paired"),s.info(`[runtime-bridge] pairing code: ${y()}`)}async function C(n,e){if(!e){s.debug(`[runtime-binding] notifySchedulerBindingClaimed skipped: no schedulerBaseUrl for agentId=${n}`);return}const t=p(e)||j()[0];if(!t){s.warn(`[runtime-binding] notifySchedulerBindingClaimed skipped: no connection key for agentId=${n}`);return}const i=`${e.replace(/\/+$/,"")}/api/runtime/bridge/binding-claimed`;try{await T.post(i,{agentId:n},{headers:{"X-Runtime-Token":t,"Content-Type":"application/json"},timeout:5e3}),s.debug(`[runtime-binding] Notified scheduler: agentId=${n}, url=${i}`)}catch(o){const r=o instanceof Error?o.message:String(o);s.warn(`[runtime-binding] Failed to notify scheduler binding claimed: agentId=${n}, error=${r}`)}}export{Q as logRuntimeBindingStartupState,q as resolveRuntimeTokenRequest,d as runtimeBindingRouter};
2
2
 
@@ -1,54 +1,54 @@
1
- import{spawn as We}from"node:child_process";import{promises as N}from"node:fs";import be from"node:os";import j from"node:path";import{TextDecoder as ee}from"node:util";import{Router as Qe}from"express";import{v4 as Xe}from"uuid";import Ce from"axios";import{adapterRegistry as w,getToolActionInfo as ye,isTransientClipboardPasteFilePath as $e,redactTransientClipboardPastePaths as q,registerSdkProviders as Ge,resolveSdkProviderIdByCommand as Je}from"../adapter/index.js";import{validateToken as S}from"../middleware/auth.js";import{getAgentProcessManager as he}from"../services/agent-process-manager.js";import{setAgentFeatures as Ve,getAgentFeatures as Ye}from"../services/instance-features.js";import{getAiConfigService as Ze}from"../services/cc-switch-sdk.js";import{prepareAcodeInstanceConfig as et,redactForLog as te}from"../services/instance-ai-config-service.js";import{enqueueMcpLaunchBinding as tt}from"../services/mcp-launch-binding-queue.js";import{resolveSchedulerBaseUrlFromToken as _e}from"../services/auto-register.js";import{findClaudeCodeProcesses as nt,isProcessRunning as rt}from"../services/process-detector.js";import{bridgeEventBuffer as De,sendOutput as Q,sendQuestionRequest as ot,sendStatus as _}from"../services/session-output.js";import{getAllPushStats as st,startHeartbeatScheduler as it}from"../services/event-delta-pusher.js";import{forgetSession as v,onSdkToolUseEnd as at,onSdkToolUseStart as ct}from"../services/sdk-tool-file-change-recorder.js";import{findPersistedSessionByAgentId as ut,removePersistedSession as F,savePersistedSessions as dt,updatePersistedSessionAutoCommands as lt,updatePersistedSessionRuntimeState as mt,upsertPersistedSession as ft}from"../services/terminal-persistence.js";import{getInstanceAiConfigDebugLogger as pt}from"../utils/instance-ai-config-debug-logger.js";import{logger as h}from"../utils/logger.js";const A=Qe();function Pe(e){const t=e.header("X-Runtime-Token");return t&&t.trim()?t.trim():(e.header("Authorization")||"").match(/^Bearer\s+(.+)$/i)?.[1]?.trim()||void 0}const f=new Map,gt=45e3,ne=new Map;function yt(e){if(ne.has(e))return;const t=setInterval(()=>{const n=f.get(e);if(!n){x(e);return}const r=n.currentRuntimeStatus;if(r!=="thinking"&&r!=="tool_using"&&r!=="compacting"){x(e);return}_(n.agentId,e,r,void 0,void 0,{runtimeAccessToken:n.runtimeAccessToken,schedulerBaseUrl:n.schedulerBaseUrl}).catch(()=>{})},gt);ne.set(e,t)}function x(e){const t=ne.get(e);t&&(clearInterval(t),ne.delete(e))}const Re=4e3,ht=`
1
+ import{spawn as We}from"node:child_process";import{promises as N}from"node:fs";import be from"node:os";import j from"node:path";import{TextDecoder as ee}from"node:util";import{Router as Xe}from"express";import{v4 as Qe}from"uuid";import Ce from"axios";import{adapterRegistry as w,getToolActionInfo as ye,isTransientClipboardPasteFilePath as _e,redactTransientClipboardPastePaths as v,registerSdkProviders as Ve,resolveSdkProviderIdByCommand as Ge}from"../adapter/index.js";import{validateToken as S}from"../middleware/auth.js";import{getAgentProcessManager as he}from"../services/agent-process-manager.js";import{setAgentFeatures as Je,getAgentFeatures as Ye,isFeatureEnabled as Ze,LAUNCH_ITEM_FEATURE_KEY as et}from"../services/instance-features.js";import{setPanelEnvVars as tt}from"../services/panel-env.js";import{setChangeCacheRetentionDays as nt}from"../services/change-cache-retention.js";import{getAiConfigService as rt}from"../services/cc-switch-sdk.js";import{prepareAcodeInstanceConfig as ot,redactForLog as te}from"../services/instance-ai-config-service.js";import{enqueueMcpLaunchBinding as st}from"../services/mcp-launch-binding-queue.js";import{resolveSchedulerBaseUrlFromToken as $e}from"../services/auto-register.js";import{findClaudeCodeProcesses as it,isProcessRunning as at}from"../services/process-detector.js";import{bridgeEventBuffer as De,sendOutput as X,sendQuestionRequest as ct,sendStatus as _}from"../services/session-output.js";import{getAllPushStats as ut,startHeartbeatScheduler as dt}from"../services/event-delta-pusher.js";import{forgetSession as q,onSdkToolUseEnd as lt,onSdkToolUseStart as mt}from"../services/sdk-tool-file-change-recorder.js";import{findPersistedSessionByAgentId as ft,removePersistedSession as F,savePersistedSessions as pt,updatePersistedSessionAutoCommands as gt,updatePersistedSessionRuntimeState as yt,upsertPersistedSession as ht}from"../services/terminal-persistence.js";import{getInstanceAiConfigDebugLogger as It}from"../utils/instance-ai-config-debug-logger.js";import{logger as h}from"../utils/logger.js";const A=Xe();function Re(e){const n=e.header("X-Runtime-Token");return n&&n.trim()?n.trim():(e.header("Authorization")||"").match(/^Bearer\s+(.+)$/i)?.[1]?.trim()||void 0}const p=new Map,St=45e3,ne=new Map;function At(e){if(ne.has(e))return;const n=setInterval(()=>{const t=p.get(e);if(!t){x(e);return}const r=t.currentRuntimeStatus;if(r!=="thinking"&&r!=="tool_using"&&r!=="compacting"){x(e);return}_(t.agentId,e,r,void 0,void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl}).catch(()=>{})},St);ne.set(e,n)}function x(e){const n=ne.get(e);n&&(clearInterval(n),ne.delete(e))}const Pe=4e3,Tt=`
2
2
 
3
3
  \u8BF7\u6C42\u4F53:
4
- `;function Ie(e){if(e==null||typeof e!="object"||Array.isArray(e))return;const t=e,n={};return typeof t.model=="string"&&t.model.trim()&&(n.model=t.model.trim()),typeof t.baseURL=="string"&&t.baseURL.trim()&&(n.baseURL=t.baseURL.trim()),typeof t.apiKey=="string"&&t.apiKey.trim()&&(n.apiKey=t.apiKey.trim()),typeof t.effort=="string"&&t.effort.trim()&&(n.effort=t.effort.trim()),n}const It=`
4
+ `;function Ie(e){if(e==null||typeof e!="object"||Array.isArray(e))return;const n=e,t={};return typeof n.model=="string"&&n.model.trim()&&(t.model=n.model.trim()),typeof n.baseURL=="string"&&n.baseURL.trim()&&(t.baseURL=n.baseURL.trim()),typeof n.apiKey=="string"&&n.apiKey.trim()&&(t.apiKey=n.apiKey.trim()),typeof n.effort=="string"&&n.effort.trim()&&(t.effort=n.effort.trim()),t}const kt=`
5
5
 
6
6
  \u8BF7\u6C42\u5934:
7
- `,K=new Set;async function St(e,t){const n=[],r=[],o=j.join(e,".agentswork","memory");try{const c=(await N.readdir(o)).filter(u=>u.endsWith(".json")),d=await Promise.all(c.map(async u=>{try{const l=await N.readFile(j.join(o,u),"utf-8");return JSON.parse(l)}catch{return h.warn("[loadAgentStartupMemories] Failed to parse memory file: %s",j.join(o,u)),null}}));for(const u of d)if(u?.by_uri)for(const l of Object.values(u.by_uri)){const m=l.memory_type||"memory",p=(l.content||"").trim();p&&(m==="recently_memory"?n.push({title:l.title,content:p,uri:l.uri||""}):m==="agent_memory"&&r.push({title:l.title,content:p,uri:l.uri||""}))}}catch{h.debug("[loadAgentStartupMemories] \u65E0\u6CD5\u8BFB\u53D6\u8BB0\u5FC6\u76EE\u5F55: %s",o)}if(n.length===0&&r.length===0&&t?.schedulerBaseUrl&&t?.runtimeAccessToken&&t?.agentId){const a=`${t.schedulerBaseUrl.replace(/\/+$/,"")}/mcp/call`,c={"Content-Type":"application/json","X-Runtime-Token":t.runtimeAccessToken,Authorization:`Bearer ${t.runtimeAccessToken}`},d=["recently_memory","agent_memory"],u=await Promise.allSettled(d.map(l=>fetch(a,{method:"POST",headers:c,body:JSON.stringify({tool:"list_memories",arguments:{agentId:t.agentId,memory_type:l}})}).then(m=>{if(!m.ok)throw new Error(`Server returned ${m.status}`);return m.json()})));for(let l=0;l<u.length;l++){const m=u[l];if(m.status!=="fulfilled")continue;const p=m.value;if(!Array.isArray(p))continue;const T=d[l]==="recently_memory"?n:r;for(const y of p){const g=(y.content||"").trim();g&&T.push({title:y.title,content:g,uri:y.uri||""})}}(n.length>0||r.length>0)&&h.info(`[loadAgentStartupMemories] Loaded ${n.length} task(s) and ${r.length} memory(s) from server for ${t.agentId}`)}const s=10;n.sort((a,c)=>c.uri.localeCompare(a.uri)),r.sort((a,c)=>c.uri.localeCompare(a.uri));const i=[];if(n.length>0){const c=n.slice(0,s).map((d,u)=>`${d.title?`\u3010${d.title}\u3011`:`\u6761\u76EE ${u+1}`}
7
+ `,K=new Set;async function wt(e,n){const t=[],r=[],o=j.join(e,".agentswork","memory");try{const c=(await N.readdir(o)).filter(u=>u.endsWith(".json")),d=await Promise.all(c.map(async u=>{try{const l=await N.readFile(j.join(o,u),"utf-8");return JSON.parse(l)}catch{return h.warn("[loadAgentStartupMemories] Failed to parse memory file: %s",j.join(o,u)),null}}));for(const u of d)if(u?.by_uri)for(const l of Object.values(u.by_uri)){const m=l.memory_type||"memory",f=(l.content||"").trim();f&&(m==="recently_memory"?t.push({title:l.title,content:f,uri:l.uri||""}):m==="agent_memory"&&r.push({title:l.title,content:f,uri:l.uri||""}))}}catch{h.debug("[loadAgentStartupMemories] \u65E0\u6CD5\u8BFB\u53D6\u8BB0\u5FC6\u76EE\u5F55: %s",o)}if(t.length===0&&r.length===0&&n?.schedulerBaseUrl&&n?.runtimeAccessToken&&n?.agentId){const a=`${n.schedulerBaseUrl.replace(/\/+$/,"")}/mcp/call`,c={"Content-Type":"application/json","X-Runtime-Token":n.runtimeAccessToken,Authorization:`Bearer ${n.runtimeAccessToken}`},d=["recently_memory","agent_memory"],u=await Promise.allSettled(d.map(l=>fetch(a,{method:"POST",headers:c,body:JSON.stringify({tool:"list_memories",arguments:{agentId:n.agentId,memory_type:l}})}).then(m=>{if(!m.ok)throw new Error(`Server returned ${m.status}`);return m.json()})));for(let l=0;l<u.length;l++){const m=u[l];if(m.status!=="fulfilled")continue;const f=m.value;if(!Array.isArray(f))continue;const T=d[l]==="recently_memory"?t:r;for(const y of f){const g=(y.content||"").trim();g&&T.push({title:y.title,content:g,uri:y.uri||""})}}(t.length>0||r.length>0)&&h.info(`[loadAgentStartupMemories] Loaded ${t.length} task(s) and ${r.length} memory(s) from server for ${n.agentId}`)}const s=10;t.sort((a,c)=>c.uri.localeCompare(a.uri)),r.sort((a,c)=>c.uri.localeCompare(a.uri));const i=[];if(t.length>0){const c=t.slice(0,s).map((d,u)=>`${d.title?`\u3010${d.title}\u3011`:`\u6761\u76EE ${u+1}`}
8
8
  ${d.content}`);i.push(`\u3010\u77ED\u671F\u8BB0\u5FC6\u3011
9
9
  ${c.join(`
10
10
 
11
- `)}`),n.length>s&&i.push(`... \u53CA\u53E6\u5916 ${n.length-s} \u6761\u77ED\u671F\u8BB0\u5FC6`)}if(r.length>0){const c=r.slice(0,s).map(d=>{const u=d.title?`\u3010${d.title}\u3011`:"";return u?`${u}
11
+ `)}`),t.length>s&&i.push(`... \u53CA\u53E6\u5916 ${t.length-s} \u6761\u77ED\u671F\u8BB0\u5FC6`)}if(r.length>0){const c=r.slice(0,s).map(d=>{const u=d.title?`\u3010${d.title}\u3011`:"";return u?`${u}
12
12
  ${d.content}`:d.content});i.push(`\u3010agent\u8BA4\u77E5\u3011
13
13
  ${c.join(`
14
14
 
15
15
  `)}`),r.length>s&&i.push(`... \u53CA\u53E6\u5916 ${r.length-s} \u6761 agent \u8BA4\u77E5`)}if(i.length!==0)return i.join(`
16
16
 
17
- `)}function At(e,t){return e!=="acode"?{supported:!1,statusCode:400,error:"context reset without restart is only supported by ACode"}:t?{supported:!0}:{supported:!1,statusCode:500,error:"ACode adapter does not expose resetContext"}}function Tt(e){return e!=="acode"}function kt(e){const t=typeof e=="object"&&e!==null&&"suppressStatus"in e&&e.suppressStatus===!0,n=typeof e=="object"&&e!==null&&"reason"in e&&typeof e.reason=="string"&&e.reason.trim()?e.reason.trim():void 0;return{statusNotified:!t,reason:n}}function re(e){const t=e?.usage;if(!t)return;const n=Number.isFinite(t.inputTokens)?t.inputTokens:0,r=Number.isFinite(t.outputTokens)?t.outputTokens:0;if(n<=0&&r<=0&&!t.contextLimit&&!t.maxOutput&&!t.inputLimit&&!t.compactionThreshold)return;const o={inputTokens:n,outputTokens:r,...t.contextLimit?{contextLimit:t.contextLimit}:{},...t.maxOutput?{maxOutput:t.maxOutput}:{},...t.inputLimit?{inputLimit:t.inputLimit}:{},...t.compactionThreshold?{compactionThreshold:t.compactionThreshold}:{},...t.cacheHitTokens?{cacheHitTokens:t.cacheHitTokens}:{},...t.cacheMissTokens?{cacheMissTokens:t.cacheMissTokens}:{}};return process.env.ACODE_TOKEN_DEBUG==="1"&&(o.inputTokens>0||o.outputTokens>0||o.cacheHitTokens!==void 0||o.cacheMissTokens!==void 0)&&console.log(`[TokenDebug][Terminal] resolveStatusChangeUsage: input=${o.inputTokens} output=${o.outputTokens} cacheHit=${o.cacheHitTokens??"(none)"} cacheMiss=${o.cacheMissTokens??"(none)"} actionType=${e?.actionType??"(none)"}`),o}function wt(e,t){const n=String(e||"").trim().toLowerCase(),r=String(t?.actionType||"").trim().toLowerCase();return n==="tool_using"&&r==="idle"?t?{status:"waiting_input",actionInfo:t}:{status:"waiting_input"}:t?{status:e,actionInfo:t}:{status:e}}const X=new Map,bt="utf-8",Me="utf-8",Ee=300,xe=6e4;function G(e){return String(e).padStart(2,"0")}function Ct(e,t=new Date){const n=t.getFullYear(),r=G(t.getMonth()+1),o=G(t.getDate()),s=G(t.getHours()),i=G(t.getMinutes()),a=`${n}${r}${o}-${s}${i}${G(t.getSeconds())}-${String(t.getMilliseconds()).padStart(3,"0")}`;return j.join(be.homedir(),".acode","cmd-dist",e,`${n}-${r}-${o}`,s,i,`${a}-cmd.out`)}function $t(e){if(!e)return 0;const t=e.replace(/\r\n/g,`
17
+ `)}function bt(e,n){return e!=="acode"?{supported:!1,statusCode:400,error:"context reset without restart is only supported by ACode"}:n?{supported:!0}:{supported:!1,statusCode:500,error:"ACode adapter does not expose resetContext"}}function Ct(e){return e!=="acode"}function _t(e){const n=typeof e=="object"&&e!==null&&"suppressStatus"in e&&e.suppressStatus===!0,t=typeof e=="object"&&e!==null&&"reason"in e&&typeof e.reason=="string"&&e.reason.trim()?e.reason.trim():void 0;return{statusNotified:!n,reason:t}}function re(e){const n=e?.usage;if(!n)return;const t=Number.isFinite(n.inputTokens)?n.inputTokens:0,r=Number.isFinite(n.outputTokens)?n.outputTokens:0;if(t<=0&&r<=0&&!n.contextLimit&&!n.maxOutput&&!n.inputLimit&&!n.compactionThreshold)return;const o={inputTokens:t,outputTokens:r,...n.contextLimit?{contextLimit:n.contextLimit}:{},...n.maxOutput?{maxOutput:n.maxOutput}:{},...n.inputLimit?{inputLimit:n.inputLimit}:{},...n.compactionThreshold?{compactionThreshold:n.compactionThreshold}:{},...n.cacheHitTokens?{cacheHitTokens:n.cacheHitTokens}:{},...n.cacheMissTokens?{cacheMissTokens:n.cacheMissTokens}:{}};return process.env.ACODE_TOKEN_DEBUG==="1"&&(o.inputTokens>0||o.outputTokens>0||o.cacheHitTokens!==void 0||o.cacheMissTokens!==void 0)&&console.log(`[TokenDebug][Terminal] resolveStatusChangeUsage: input=${o.inputTokens} output=${o.outputTokens} cacheHit=${o.cacheHitTokens??"(none)"} cacheMiss=${o.cacheMissTokens??"(none)"} actionType=${e?.actionType??"(none)"}`),o}function $t(e,n){const t=String(e||"").trim().toLowerCase(),r=String(n?.actionType||"").trim().toLowerCase();return t==="tool_using"&&r==="idle"?n?{status:"waiting_input",actionInfo:n}:{status:"waiting_input"}:n?{status:e,actionInfo:n}:{status:e}}const Q=new Map,Dt="utf-8",Ee="utf-8",Me=300,xe=6e4;function V(e){return String(e).padStart(2,"0")}function Rt(e,n=new Date){const t=n.getFullYear(),r=V(n.getMonth()+1),o=V(n.getDate()),s=V(n.getHours()),i=V(n.getMinutes()),a=`${t}${r}${o}-${s}${i}${V(n.getSeconds())}-${String(n.getMilliseconds()).padStart(3,"0")}`;return j.join(be.homedir(),".acode","cmd-dist",e,`${t}-${r}-${o}`,s,i,`${a}-cmd.out`)}function Pt(e){if(!e)return 0;const n=e.replace(/\r\n/g,`
18
18
  `).replace(/\r/g,`
19
- `),n=t.endsWith(`
20
- `)?t.slice(0,-1):t;return n?n.split(`
21
- `).length:1}function _t(e,t=Ee){return`\r
22
- [ACode] \u547D\u4EE4\u8F93\u51FA\u8D85\u8FC7 ${t} \u884C\uFF0C\u5B8C\u6574\u8F93\u51FA\u5DF2\u5199\u5165: ${e}\r
19
+ `),t=n.endsWith(`
20
+ `)?n.slice(0,-1):n;return t?t.split(`
21
+ `).length:1}function Et(e,n=Me){return`\r
22
+ [ACode] \u547D\u4EE4\u8F93\u51FA\u8D85\u8FC7 ${n} \u884C\uFF0C\u5B8C\u6574\u8F93\u51FA\u5DF2\u5199\u5165: ${e}\r
23
23
  [ACode] Agent \u53EF\u81EA\u884C\u8BFB\u53D6\u8BE5\u6587\u4EF6\uFF0C\u6216\u5728\u8BE5\u6587\u4EF6\u4E2D\u641C\u7D22\u9700\u8981\u7684\u5185\u5BB9\u3002\r
24
- `}function Dt(e=xe){return`\r
24
+ `}function Mt(e=xe){return`\r
25
25
  [ACode] \u547D\u4EE4\u8D85\u8FC7 ${Math.round(e/1e3)} \u79D2\u6CA1\u6709\u65B0\u7684\u8F93\u51FA\uFF0C\u5DF2\u505C\u6B62\u6267\u884C\u5E76\u4FDD\u7559\u6B64\u524D\u8F93\u51FA\u3002\r
26
- `}async function Le(e){const t=e.outputPath||Ct(e.agentId,e.startedAt);return e.outputPath=t,await N.mkdir(j.dirname(t),{recursive:!0}),await N.writeFile(t,e.chunks.join(""),"utf-8"),t}function Pt(e){return String(e??"").replace(/\r/g,`
27
- `).trim()}function Rt(e=process.platform,t=process.env){const n=t.AWS_TERMINAL_OUTPUT_ENCODING?.trim();return n||(e==="win32"?bt:Me)}function Ue(e=Rt()){if(e!=="utf-8")try{return new ee(e,{fatal:!1})}catch{return new ee(Me,{fatal:!1})}return Mt()}function Mt(){let e=null,t=null,n=null;const r=[];function o(s){try{return new ee(s,{fatal:!1})}catch{return new ee("utf-8",{fatal:!1})}}return{decode(s,i){if(s!=null&&r.push(s instanceof ArrayBuffer?Buffer.from(s):Buffer.isBuffer(s)?s:Buffer.from(s.buffer,s.byteOffset,s.byteLength)),n==="gb18030")return t||(t=o("gb18030")),t.decode(s,i);e||(e=o("utf-8"));const a=e.decode(s,i);if(n===null&&a.includes("\uFFFD")){n="gb18030",t=o("gb18030");const c=Buffer.concat(r);return t.decode(c)}return n===null&&!i?.stream&&(n="utf-8"),a}}}function oe(e,t,n=!1){return n?e.decode():!t||t.length===0?"":e.decode(t,{stream:!0})}function Et(e){const t=e.trim().match(/^cd(?:\s+(.*))?$/i);if(!t)return;const n=t[1]?.trim();if(!n)return null;const r=n.replace(/^\/d\s+/i,"").trim();return r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1):r}function xt(e){const t=X.get(e.sessionId);if(t)return t;const n={currentDirectory:e.workspacePath,runningProcess:null};return X.set(e.sessionId,n),n}function je(e){for(const t of f.values())if(t.agentId===e)return t}async function Lt(e){const t=w.get(e.providerId||"claude-code"),n=se(t.getSessionStatus(e.sessionId),e.currentRuntimeStatus,e.currentRuntimeActionType);return{sessionId:e.sessionId,status:n,runtimeStatus:n,runtimeActionType:e.currentRuntimeActionType,runtimeActionLabel:e.currentRuntimeActionLabel,runtimeActionDetail:e.currentRuntimeActionDetail,agentId:e.agentId,workspacePath:e.workspacePath,command:e.config.command,mode:"sdk",providerSessionId:t.getProviderSessionId(e.sessionId),reused:!0}}function se(e,t,n){const r=String(e||"").trim();if(r){const s=String(t||"").trim(),i=String(n||"").trim().toLowerCase();return r.toLowerCase()==="tool_using"&&s.toLowerCase()==="waiting_input"&&i==="idle"?s:r}return String(t||"").trim()||"running"}function Ut(e,t=rt){return e.pid?t(e.pid)?Fe(e.command)==="acode"?{reusable:!1,reason:"in-process-provider"}:{reusable:!0,reason:"active-pid"}:{reusable:!1,reason:"dead-pid"}:{reusable:!1,reason:"missing-pid"}}function Kn(e){const t=je(e);if(!t)h.info(`[cleanupSdkSessionByAgentId] No active SDK session found for agentId=${e}, cleaning residual state anyway`);else{const n=t.sessionId;return h.info(`[cleanupSdkSessionByAgentId] Cleaning up SDK session for agentId=${e}, sessionId=${n}`),x(n),f.delete(n),v(n),ie(n),F(n).catch(r=>{h.warn(`[cleanupSdkSessionByAgentId] Failed to remove persisted session for agentId=${e}: ${r}`)}),n}K.has(e)&&(K.delete(e),h.info(`[cleanupSdkSessionByAgentId] Released startingAgents lock for agentId=${e}`))}function ie(e){const t=X.get(e);if(!t?.runningProcess){X.delete(e);return}try{t.runningProcess.kill()}catch{}finally{t.runningProcess=null,X.delete(e)}}function b(e,t){t&&(e.seq+=1,Q(e.agentId,t,e.sessionId,e.seq,void 0,{runtimeAccessToken:e.runtimeAccessToken,schedulerBaseUrl:e.schedulerBaseUrl}).catch(()=>{}))}function Se(e){return`\x1B[36m${e}>\x1B[0m `}function jt(e,t){return t==="~"?be.homedir():j.resolve(e,t)}async function Bt(e,t,n){const r=Et(n);if(r===void 0)return!1;if(r===null)return b(e,`${t.currentDirectory}\r
28
- `),!0;const o=jt(t.currentDirectory,r);try{return(await N.stat(o)).isDirectory()?(t.currentDirectory=o,b(e,`${t.currentDirectory}\r
26
+ `}async function Le(e){const n=e.outputPath||Rt(e.agentId,e.startedAt);return e.outputPath=n,await N.mkdir(j.dirname(n),{recursive:!0}),await N.writeFile(n,e.chunks.join(""),"utf-8"),n}function xt(e){return String(e??"").replace(/\r/g,`
27
+ `).trim()}function Lt(e=process.platform,n=process.env){const t=n.AWS_TERMINAL_OUTPUT_ENCODING?.trim();return t||(e==="win32"?Dt:Ee)}function Ue(e=Lt()){if(e!=="utf-8")try{return new ee(e,{fatal:!1})}catch{return new ee(Ee,{fatal:!1})}return Ut()}function Ut(){let e=null,n=null,t=null;const r=[];function o(s){try{return new ee(s,{fatal:!1})}catch{return new ee("utf-8",{fatal:!1})}}return{decode(s,i){if(s!=null&&r.push(s instanceof ArrayBuffer?Buffer.from(s):Buffer.isBuffer(s)?s:Buffer.from(s.buffer,s.byteOffset,s.byteLength)),t==="gb18030")return n||(n=o("gb18030")),n.decode(s,i);e||(e=o("utf-8"));const a=e.decode(s,i);if(t===null&&a.includes("\uFFFD")){t="gb18030",n=o("gb18030");const c=Buffer.concat(r);return n.decode(c)}return t===null&&!i?.stream&&(t="utf-8"),a}}}function oe(e,n,t=!1){return t?e.decode():!n||n.length===0?"":e.decode(n,{stream:!0})}function jt(e){const n=e.trim().match(/^cd(?:\s+(.*))?$/i);if(!n)return;const t=n[1]?.trim();if(!t)return null;const r=t.replace(/^\/d\s+/i,"").trim();return r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1):r}function Bt(e){const n=Q.get(e.sessionId);if(n)return n;const t={currentDirectory:e.workspacePath,runningProcess:null};return Q.set(e.sessionId,t),t}function je(e){for(const n of p.values())if(n.agentId===e)return n}async function Ot(e){const n=w.get(e.providerId||"claude-code"),t=se(n.getSessionStatus(e.sessionId),e.currentRuntimeStatus,e.currentRuntimeActionType);return{sessionId:e.sessionId,status:t,runtimeStatus:t,runtimeActionType:e.currentRuntimeActionType,runtimeActionLabel:e.currentRuntimeActionLabel,runtimeActionDetail:e.currentRuntimeActionDetail,agentId:e.agentId,workspacePath:e.workspacePath,command:e.config.command,mode:"sdk",providerSessionId:n.getProviderSessionId(e.sessionId),reused:!0}}function se(e,n,t){const r=String(e||"").trim();if(r){const s=String(n||"").trim(),i=String(t||"").trim().toLowerCase();return r.toLowerCase()==="tool_using"&&s.toLowerCase()==="waiting_input"&&i==="idle"?s:r}return String(n||"").trim()||"running"}function Nt(e,n=at){return e.pid?n(e.pid)?Fe(e.command)==="acode"?{reusable:!1,reason:"in-process-provider"}:{reusable:!0,reason:"active-pid"}:{reusable:!1,reason:"dead-pid"}:{reusable:!1,reason:"missing-pid"}}function Vn(e){const n=je(e);if(!n)h.info(`[cleanupSdkSessionByAgentId] No active SDK session found for agentId=${e}, cleaning residual state anyway`);else{const t=n.sessionId;return h.info(`[cleanupSdkSessionByAgentId] Cleaning up SDK session for agentId=${e}, sessionId=${t}`),x(t),p.delete(t),q(t),ie(t),F(t).catch(r=>{h.warn(`[cleanupSdkSessionByAgentId] Failed to remove persisted session for agentId=${e}: ${r}`)}),t}K.has(e)&&(K.delete(e),h.info(`[cleanupSdkSessionByAgentId] Released startingAgents lock for agentId=${e}`))}function ie(e){const n=Q.get(e);if(!n?.runningProcess){Q.delete(e);return}try{n.runningProcess.kill()}catch{}finally{n.runningProcess=null,Q.delete(e)}}function b(e,n){n&&(e.seq+=1,X(e.agentId,n,e.sessionId,e.seq,void 0,{runtimeAccessToken:e.runtimeAccessToken,schedulerBaseUrl:e.schedulerBaseUrl}).catch(()=>{}))}function Se(e){return`\x1B[36m${e}>\x1B[0m `}function vt(e,n){return n==="~"?be.homedir():j.resolve(e,n)}async function qt(e,n,t){const r=jt(t);if(r===void 0)return!1;if(r===null)return b(e,`${n.currentDirectory}\r
28
+ `),!0;const o=vt(n.currentDirectory,r);try{return(await N.stat(o)).isDirectory()?(n.currentDirectory=o,b(e,`${n.currentDirectory}\r
29
29
  `),!0):(b(e,`cd: not a directory: ${o}\r
30
30
  `),!0)}catch(s){const i=s instanceof Error?s.message:String(s);return b(e,`cd: ${i}\r
31
- `),!0}}async function Ot(e,t){const n=f.get(e);if(!n)throw new Error("SDK session not found");const r=Pt(t),o=xt(n);if(!r)return{started:!1,cwd:o.currentDirectory};if(o.runningProcess)throw new Error("A terminal command is already running for this session");const s=q(r);if(b(n,`${Se(o.currentDirectory)}${s}\r
32
- `),$e(r))return b(n,`[Terminal Warning] \u68C0\u6D4B\u5230\u526A\u8D34\u677F\u4E34\u65F6 paste \u6587\u4EF6\u8DEF\u5F84\uFF0C\u5DF2\u8DF3\u8FC7\u6267\u884C\u3002\u8BF7\u7C98\u8D34\u6587\u4EF6\u5185\u5BB9\u6216\u4F7F\u7528\u663E\u5F0F\u8BFB\u53D6\u547D\u4EE4\u3002\r
33
- `),b(n,Se(o.currentDirectory)),{started:!1,cwd:o.currentDirectory};if(await Bt(n,o,r))return{started:!1,cwd:o.currentDirectory};await _(n.agentId,e,"tool_using",{actionType:"bash",actionLabel:"\u7EC8\u7AEF\u547D\u4EE4",actionDetail:s},void 0,{runtimeAccessToken:n.runtimeAccessToken,schedulerBaseUrl:n.schedulerBaseUrl});const a=We(r,{cwd:o.currentDirectory,shell:!0,env:Be(n.agentId,n.workspacePath,process.env,n.config.envOverrides)});o.runningProcess=a;const c=Ue(),d=Ue(),u=n.providerId==="acode",l={agentId:n.agentId,startedAt:new Date,chunks:[],spilled:!1};let m;const p=()=>{m&&(clearTimeout(m),m=void 0)},T=()=>{p(),m=setTimeout(()=>{o.runningProcess===a&&(b(n,Dt()),a.kill())},xe)},y=(g,C=!0)=>{if(g&&(u&&l.chunks.push(g),u&&C&&T(),!(u&&l.spilled))){if(u&&$t(l.chunks.join(""))>Ee){l.spilled=!0,Le(l).then($=>{b(n,_t($))}).catch($=>{const E=$ instanceof Error?$.message:String($);b(n,`\r
34
- [ACode] \u547D\u4EE4\u8F93\u51FA\u843D\u76D8\u5931\u8D25: ${E}\r
35
- `)});return}b(n,g)}};return u&&T(),a.stdout.on("data",g=>{y(oe(c,g))}),a.stderr.on("data",g=>{y(oe(d,g))}),a.on("error",g=>{b(n,`\r
31
+ `),!0}}async function Ft(e,n){const t=p.get(e);if(!t)throw new Error("SDK session not found");const r=xt(n),o=Bt(t);if(!r)return{started:!1,cwd:o.currentDirectory};if(o.runningProcess)throw new Error("A terminal command is already running for this session");const s=v(r);if(b(t,`${Se(o.currentDirectory)}${s}\r
32
+ `),_e(r))return b(t,`[Terminal Warning] \u68C0\u6D4B\u5230\u526A\u8D34\u677F\u4E34\u65F6 paste \u6587\u4EF6\u8DEF\u5F84\uFF0C\u5DF2\u8DF3\u8FC7\u6267\u884C\u3002\u8BF7\u7C98\u8D34\u6587\u4EF6\u5185\u5BB9\u6216\u4F7F\u7528\u663E\u5F0F\u8BFB\u53D6\u547D\u4EE4\u3002\r
33
+ `),b(t,Se(o.currentDirectory)),{started:!1,cwd:o.currentDirectory};if(await qt(t,o,r))return{started:!1,cwd:o.currentDirectory};await _(t.agentId,e,"tool_using",{actionType:"bash",actionLabel:"\u7EC8\u7AEF\u547D\u4EE4",actionDetail:s},void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl});const a=We(r,{cwd:o.currentDirectory,shell:!0,env:Be(t.agentId,t.workspacePath,process.env,t.config.envOverrides)});o.runningProcess=a;const c=Ue(),d=Ue(),u=t.providerId==="acode",l={agentId:t.agentId,startedAt:new Date,chunks:[],spilled:!1};let m;const f=()=>{m&&(clearTimeout(m),m=void 0)},T=()=>{f(),m=setTimeout(()=>{o.runningProcess===a&&(b(t,Mt()),a.kill())},xe)},y=(g,C=!0)=>{if(g&&(u&&l.chunks.push(g),u&&C&&T(),!(u&&l.spilled))){if(u&&Pt(l.chunks.join(""))>Me){l.spilled=!0,Le(l).then($=>{b(t,Et($))}).catch($=>{const M=$ instanceof Error?$.message:String($);b(t,`\r
34
+ [ACode] \u547D\u4EE4\u8F93\u51FA\u843D\u76D8\u5931\u8D25: ${M}\r
35
+ `)});return}b(t,g)}};return u&&T(),a.stdout.on("data",g=>{y(oe(c,g))}),a.stderr.on("data",g=>{y(oe(d,g))}),a.on("error",g=>{b(t,`\r
36
36
  [Terminal Error] ${g.message}\r
37
- `)}),a.on("close",(g,C)=>{p(),o.runningProcess=null,y(oe(c,void 0,!0),!1),y(oe(d,void 0,!0),!1),l.spilled&&Le(l).catch($=>{const E=$ instanceof Error?$.message:String($);b(n,`\r
38
- [ACode] \u547D\u4EE4\u8F93\u51FA\u6700\u7EC8\u843D\u76D8\u5931\u8D25: ${E}\r
39
- `)}),g&&g!==0?b(n,`\r
37
+ `)}),a.on("close",(g,C)=>{f(),o.runningProcess=null,y(oe(c,void 0,!0),!1),y(oe(d,void 0,!0),!1),l.spilled&&Le(l).catch($=>{const M=$ instanceof Error?$.message:String($);b(t,`\r
38
+ [ACode] \u547D\u4EE4\u8F93\u51FA\u6700\u7EC8\u843D\u76D8\u5931\u8D25: ${M}\r
39
+ `)}),g&&g!==0?b(t,`\r
40
40
  [exit ${g}]\r
41
- `):C&&b(n,`\r
41
+ `):C&&b(t,`\r
42
42
  [signal ${C}]\r
43
- `),b(n,Se(o.currentDirectory)),_(n.agentId,e,"waiting_input",void 0,void 0,{runtimeAccessToken:n.runtimeAccessToken,schedulerBaseUrl:n.schedulerBaseUrl})}),{started:!0,cwd:o.currentDirectory}}function Be(e,t,n,r){const o={};for(const[s,i]of Object.entries(n))i!==void 0&&(o[s]=i);if(t&&(o.AWS_WORKSPACE_PATH=String(t)),r)for(const[s,i]of Object.entries(r)){const a=s.trim();if(!a||i===void 0||i===null)continue;const c=String(i).trim();c&&(o[a]=c)}return o.AWS_AGENT_ID=String(e),o.AWS_MCP_CLAIM_LAUNCH_BINDING="true",o}function Nt(e){const t=e.trim(),n=t[0],r=t[t.length-1];return(n==='"'||n==="'")&&n===r?t.slice(1,-1):t}async function qt(e){const t=String(e);if(!$e(t))return t;const n=Nt(t);return j.isAbsolute(n)?N.readFile(n,"utf-8"):t}function Oe(e,t){const n={};for(const o of[e?.env,t])if(o)for(const[s,i]of Object.entries(o)){const a=s.trim();if(!a||i===void 0||i===null)continue;const c=String(i).trim();c&&(n[a]=c)}const r=n.ANTHROPIC_MODEL?.trim()||n.CODEX_MODEL?.trim()||void 0;return{envOverrides:n,model:r}}async function vt(){try{return await Ze().readClaudeCodeConfig()}catch(e){return console.warn(`[Runtime] Failed to read saved ClaudeCode AI config: ${e.message}`),{}}}function Ft(e){if(e==null)return;const n=(typeof e=="string"?e:JSON.stringify(e,null,2)).trim();if(n)return n.length<=Re?n:`${n.slice(0,Re)}
44
- ...\uFF08\u7ED3\u679C\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`}function Kt(e){try{const t=JSON.parse(e);if(t&&typeof t=="object"&&!Array.isArray(t))return["directMessages","groupMessages","messages"].some(n=>Array.isArray(t[n])&&t[n].length>0)}catch{}return e.trim().length>0}function zt(e){if(e.data.actionType==="mcp")return!0;const n=String(e.data.toolName||"").toLowerCase();return n.startsWith("mcp__")||n.includes("-mcp__")||n.includes("mcp_")}function Ht(e){if(e.type!=="tool_use_end")return;const t=Ft(e.data.toolResult??e.data.actionResult);if(!t)return;const n=ye(e.data.toolName,e.data.toolInput),r=e.data.actionType||n.actionType;if(!(r==="idle"&&!Kt(t)))return r==="mcp"&&zt(e)?{actionType:"mcp",actionLabel:"MCP\u8FD4\u56DE",actionDetail:e.data.actionDetail||e.data.toolName,actionId:e.data.actionId||e.data.toolUseId,actionResult:t}:{actionType:r,actionLabel:e.data.actionLabel||n.actionLabel,actionDetail:e.data.actionDetail||n.actionDetail||e.data.toolName,actionId:e.data.actionId||e.data.toolUseId,actionResult:t}}function Wt(e){if(e.type==="ai_request"){const t=e.data.model?` ${e.data.model}`:"",n=e.data.lastUserMessagePreview?`\uFF1A${e.data.lastUserMessagePreview}`:"";return`\r
45
- [ACode] \u6B63\u5728\u8BF7\u6C42\u6A21\u578B${t}${n}\r
43
+ `),b(t,Se(o.currentDirectory)),_(t.agentId,e,"waiting_input",void 0,void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl})}),{started:!0,cwd:o.currentDirectory}}function Be(e,n,t,r){const o={};for(const[s,i]of Object.entries(t))i!==void 0&&(o[s]=i);if(n&&(o.AWS_WORKSPACE_PATH=String(n)),r)for(const[s,i]of Object.entries(r)){const a=s.trim();if(!a||i===void 0||i===null)continue;const c=String(i).trim();c&&(o[a]=c)}return o.AWS_AGENT_ID=String(e),o.AWS_MCP_CLAIM_LAUNCH_BINDING="true",Ze(e,et)&&(o.AWS_LAUNCH_CONFIG_TOOLS="1"),o}function Kt(e){const n=e.trim(),t=n[0],r=n[n.length-1];return(t==='"'||t==="'")&&t===r?n.slice(1,-1):n}async function zt(e){const n=String(e);if(!_e(n))return n;const t=Kt(n);return j.isAbsolute(t)?N.readFile(t,"utf-8"):n}function Oe(e,n){const t={};for(const o of[e?.env,n])if(o)for(const[s,i]of Object.entries(o)){const a=s.trim();if(!a||i===void 0||i===null)continue;const c=String(i).trim();c&&(t[a]=c)}const r=t.ANTHROPIC_MODEL?.trim()||t.CODEX_MODEL?.trim()||void 0;return{envOverrides:t,model:r}}async function Ht(){try{return await rt().readClaudeCodeConfig()}catch(e){return console.warn(`[Runtime] Failed to read saved ClaudeCode AI config: ${e.message}`),{}}}function Wt(e){if(e==null)return;const t=(typeof e=="string"?e:JSON.stringify(e,null,2)).trim();if(t)return t.length<=Pe?t:`${t.slice(0,Pe)}
44
+ ...\uFF08\u7ED3\u679C\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`}function Xt(e){try{const n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return["directMessages","groupMessages","messages"].some(t=>Array.isArray(n[t])&&n[t].length>0)}catch{}return e.trim().length>0}function Qt(e){if(e.data.actionType==="mcp")return!0;const t=String(e.data.toolName||"").toLowerCase();return t.startsWith("mcp__")||t.includes("-mcp__")||t.includes("mcp_")}function Vt(e){if(e.type!=="tool_use_end")return;const n=Wt(e.data.toolResult??e.data.actionResult);if(!n)return;const t=ye(e.data.toolName,e.data.toolInput),r=e.data.actionType||t.actionType;if(!(r==="idle"&&!Xt(n)))return r==="mcp"&&Qt(e)?{actionType:"mcp",actionLabel:"MCP\u8FD4\u56DE",actionDetail:e.data.actionDetail||e.data.toolName,actionId:e.data.actionId||e.data.toolUseId,actionResult:n}:{actionType:r,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:e.data.actionDetail||t.actionDetail||e.data.toolName,actionId:e.data.actionId||e.data.toolUseId,actionResult:n}}function Gt(e){if(e.type==="ai_request"){const n=e.data.model?` ${e.data.model}`:"",t=e.data.lastUserMessagePreview?`\uFF1A${e.data.lastUserMessagePreview}`:"";return`\r
45
+ [ACode] \u6B63\u5728\u8BF7\u6C42\u6A21\u578B${n}${t}\r
46
46
  `}if(e.type==="text_delta"||e.type==="thinking"||e.type==="command_output")return e.data.text||void 0;if(e.type==="error")return e.data.text?`\r
47
47
  [SDK Error] ${e.data.text}\r
48
- `:void 0}function Qt(e){const t=Jt(e);return{sourceEventType:e.type,logCategory:"acode",...Gt(e),...t?{logLevel:Xt(e),logMessage:t}:{}}}function Xt(e){return e.type==="error"?"error":e.type==="command_output"&&e.data.stream==="stderr"?"warn":"info"}function Gt(e){return e.type!=="command_output"?{}:{...typeof e.data.stream=="string"?{stream:e.data.stream}:{},...typeof e.data.sequence=="number"?{sequence:e.data.sequence}:{},...typeof e.data.cwd=="string"?{cwd:e.data.cwd}:{},...typeof e.data.commandFilePath=="string"?{commandFilePath:e.data.commandFilePath}:{},...typeof e.data.commandLineCount=="number"?{commandLineCount:e.data.commandLineCount}:{}}}function Jt(e){if(e.type==="ai_request"){const t=e.data.model||"unknown-model",n=e.data.endpoint?` @ ${e.data.endpoint}`:"",r=typeof e.data.toolCount=="number"?`, tools=${e.data.toolCount}`:"";return`AI request started: ${t}${n}${r}`}if(e.type==="tool_use_start")return Ne(e,"\u5F00\u59CB");if(e.type==="tool_use_end")return Ne(e,"\u5B8C\u6210");if(e.type==="command_output")return Zt(e);if(e.type==="turn_complete")return`Turn completed${e.data.finishReason?`, finish=${e.data.finishReason}`:""}`;if(e.type==="session_complete")return`Session completed: exitCode=${e.data.exitCode??0}`;if(e.type==="error")return e.data.text||"ACode runtime error"}const Vt=/\x1b\[[0-9;?]*[a-zA-Z]/g;function Yt(e){return e.replace(Vt,"")}function Zt(e){const t=typeof e.data.stream=="string"?e.data.stream:"mixed",n=typeof e.data.sequence=="number"?` #${e.data.sequence}`:"",r=Yt(String(e.data.text||"")).replace(/\s+/g," ").trim(),o=r.length>240?`${r.slice(0,240)}...`:r;return`\u547D\u4EE4\u8F93\u51FA(${t}${n}): ${o||"(empty)"}`}function Ne(e,t){const n=ye(e.data.toolName,e.data.toolInput),r=e.data.actionLabel||n.actionLabel||"\u8C03\u7528\u5DE5\u5177",o=qe(e,n);return o?`${t}${r}: ${o}`:`${t}${r}: ${e.data.actionDetail||e.data.toolName||"tool"}`}function qe(e,t){const n=e.data.toolInput;return t.actionType==="bash"?en(n)||e.data.actionDetail||t.actionDetail:t.actionType==="read_file"||t.actionType==="edit_file"||t.actionType==="write_file"?tn(n)||e.data.actionDetail||t.actionDetail:e.data.actionDetail||t.actionDetail}function en(e){const t=Ae(e?.command,e?.cmd);if(t)return t;if(Array.isArray(e?.argv)){const n=e.argv.map(r=>String(r??"").trim()).filter(Boolean).join(" ");return n?q(n):void 0}return Ae(e?.args)}function tn(e){const t=ve(e?.paths);return t.length>0?t.length===1?t[0]:`${t.length}\u4E2A\u6587\u4EF6: ${t.join(", ")}`:Ae(e?.file_path,e?.filePath,e?.path,e?.target_file,e?.targetFile)}function Ae(...e){for(const t of e){if(typeof t=="string"&&t.trim())return q(t.trim());if(Array.isArray(t)){const n=ve(t)[0];if(n)return n}}}function ve(e){return Array.isArray(e)?e.map(t=>typeof t=="string"?t.trim():"").filter(Boolean).map(t=>q(t)):[]}function nn(e){if(!(!e||Object.keys(e).length===0))try{const t=q(JSON.stringify(e,null,2));return t.length>8e3?`${t.slice(0,8e3)}
49
- ...\uFF08\u8F93\u5165\u53C2\u6570\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`:t}catch{return}}function rn(e){const t=[e.model?`\u6A21\u578B: ${e.model}`:void 0,e.endpoint||e.requestUrl?`\u63A5\u53E3: ${e.endpoint||e.requestUrl}`:void 0,e.requestMethod?`\u65B9\u6CD5: ${e.requestMethod}`:void 0,typeof e.stream=="boolean"?`\u6D41\u5F0F: ${e.stream?"\u662F":"\u5426"}`:void 0,typeof e.messageCount=="number"?`\u4E0A\u4E0B\u6587\u6D88\u606F: ${e.messageCount}`:void 0,typeof e.toolCount=="number"?`\u53EF\u7528\u5DE5\u5177: ${e.toolCount}`:void 0,e.lastUserMessagePreview?`\u6700\u540E\u8BF7\u6C42: ${e.lastUserMessagePreview}`:void 0].filter(i=>!!i),n=on(e.requestHeaders),r=t.join(`
50
- `)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",o=n.length>0?`${It}${n.join(`
51
- `)}`:"",s=e.requestBody?`${ht}${e.requestBody}`:"";return`${r}${o}${s}`}function on(e){return e?Object.entries(e).map(([t,n])=>`${t}: ${n}`).filter(t=>t.trim().length>0):[]}function sn(e,t){return String(t||"").trim().toLowerCase()!=="waiting_input"?!1:e.type==="thinking"||e.type==="text_delta"}function an(e){for(const t of["estimatedContextTokens","contextTokens","context_tokens","contextUsedTokens","context_used_tokens"]){const n=e[t],r=Number(n);if(Number.isFinite(r)&&r>0)return r}}function cn(e,t){if(!sn(e,t)){if(e.type==="ai_request"){const n=an(e.data);return{status:"thinking",actionInfo:{actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:rn(e.data),...n!==void 0?{usage:{inputTokens:n,outputTokens:0}}:{}}}}if(e.type==="background_command_completed")return{status:"tool_result",actionInfo:{actionType:"background_command",actionLabel:"\u540E\u53F0\u547D\u4EE4",actionDetail:"background_command_completed"}};if(e.type==="thinking"||e.type==="text_delta")return{status:"thinking"};if(e.type==="tool_use_start"){const n=ye(e.data.toolName,e.data.toolInput),r=qe(e,n),o=nn(e.data.toolInput);return e.data.actionType==="idle"||n.actionType==="idle"?{status:"waiting_input",actionInfo:{actionType:e.data.actionType||n.actionType,actionLabel:e.data.actionLabel||n.actionLabel,actionDetail:r||e.data.actionDetail||n.actionDetail||e.data.toolName,actionInput:o,actionId:e.data.actionId||e.data.toolUseId}}:{status:"tool_using",actionInfo:{actionType:e.data.actionType||n.actionType,actionLabel:e.data.actionLabel||n.actionLabel,actionDetail:r||e.data.actionDetail||n.actionDetail||e.data.toolName,actionInput:o,actionId:e.data.actionId||e.data.toolUseId}}}if(e.type==="turn_complete")return{status:"waiting_input",actionInfo:e.data.usage?{usage:e.data.usage}:void 0};if(e.type==="error")return{status:"error"};if(e.type==="context_compaction")return{status:"compacting",actionInfo:{actionType:"context_compaction",actionLabel:e.data.actionLabel,actionDetail:e.data.actionDetail,...e.data.actionId?{actionId:e.data.actionId}:{},...e.data.parentId?{parentId:e.data.parentId}:{}}};if(e.type==="runtime_capabilities")return{status:t||"waiting_input",actionInfo:{actionType:"runtime_capabilities",actionLabel:e.data.actionLabel||"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:e.data.actionDetail}}}}const L=new Map,ae=new Map,ce=new Map,J=new Map,un=20,dn=500,ln=3e4;async function ue(e,t=ln,n=2){for(let r=0;r<=n;r++){const o=new AbortController;let s;try{const i=e(o.signal);i.catch(()=>{}),await Promise.race([i,new Promise((a,c)=>{s=setTimeout(()=>{o.abort(),c(new Error(`sendOutput timeout after ${t}ms`))},t)})]),s&&clearTimeout(s);return}catch(i){s&&clearTimeout(s);const a=i instanceof Error?i.message:String(i);if(r<n){const c=1e3*(r+1);h.warn(`sendOutput attempt ${r+1}/${n+1} failed (${a}), retrying in ${c}ms...`),await new Promise(d=>setTimeout(d,c));continue}h.warn(`sendOutput failed after ${n+1} attempts (${a}), giving up to unblock serial queue`)}}}function de(e,t){const n=t?`${e}:${t}`:void 0;let r,o;if(n)r=J.get(n),o=n;else{const p=[];for(const[T,y]of J)T.startsWith(e+":")&&y.buffer&&p.push(y.sourceEventType);for(const T of p)de(e,T);return}if(!r||!r.buffer)return;r.timer=null;const s=r.buffer,i=r.seq,a=r.entry,c=r.sourceEventType;r.buffer="",o&&J.delete(o);const d={sourceEventType:c,logCategory:"acode"},u={runtimeAccessToken:a.runtimeAccessToken,schedulerBaseUrl:a.schedulerBaseUrl},m=(L.get(e)??Promise.resolve()).then(()=>ue(p=>Q(a.agentId,s,e,i,d,u,p)),()=>ue(p=>Q(a.agentId,s,e,i,d,u,p)));L.set(e,m),m.finally(()=>{L.get(e)===m&&L.delete(e)})}function mn(e,t){const n=Wt(e);if(!n)return;t.seq+=1;const r=t.seq,o=Qt(e),s={runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl};if((e.type==="command_output"||e.type==="text_delta"||e.type==="thinking")&&n.length<un){const c=`${e.sessionId}:${e.type}`;let d=J.get(c);if(d||(d={buffer:"",seq:0,timer:null,entry:t,sourceEventType:e.type}),d.buffer+=n,d.seq=r,d.entry=t,!d.timer){const u=e.sessionId,l=e.type;d.timer=setTimeout(()=>de(u,l),dn)}J.set(c,d);return}de(e.sessionId);const a=(L.get(e.sessionId)??Promise.resolve()).then(()=>ue(c=>Q(t.agentId,n,e.sessionId,r,o,s,c)),()=>ue(c=>Q(t.agentId,n,e.sessionId,r,o,s,c)));L.set(e.sessionId,a),a.finally(()=>{L.get(e.sessionId)===a&&L.delete(e.sessionId)})}function Fe(e){return Je(e)}let Ke=!1;function fn(){Ke||(Ge(w,pn),it(),Ke=!0)}function pn(e,t){e.on("event",n=>{const r=f.get(n.sessionId);if(r){if(n.type==="tool_use_start"?ct(r.sessionId,n.data.toolUseId||n.data.actionId,n.data.toolInput,n.data.toolName,r.workspacePath):n.type==="tool_use_end"&&at(n,{sessionId:r.sessionId,agentId:r.agentId,workspacePath:r.workspacePath,providerId:r.providerId}),console.log(`[${t.displayName} Adapter] Event: ${n.type} for session ${n.sessionId}`),!(n.type==="thinking"||n.type==="text_delta"||n.type==="tool_use_start"||n.type==="context_compaction"||n.type==="ai_request")){n.type==="runtime_capabilities"&&n.data.actionDetail&&(r.cachedCapabilitiesActionDetail=n.data.actionDetail);const i=cn(n,r.currentRuntimeStatus);i&&_(r.agentId,n.sessionId,i.status,i.actionInfo,re(i.actionInfo),{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},n.timestamp?new Date(n.timestamp).getTime():void 0,n.type)}mn(n,r);const s=Ht(n);if(s){const i={runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},a=n.timestamp?new Date(n.timestamp).getTime():void 0;String(n.data?.toolName||"").toLowerCase()==="browser_launch"?(async()=>{for(let u=0;u<3;u++){if(await _(r.agentId,n.sessionId,"tool_result",s,void 0,i,a,n.type)!==void 0)return;u<2&&await new Promise(m=>setTimeout(m,3e3*(u+1)))}})().catch(d=>console.warn("[Runtime] browser_launch sendStatus retry exhausted:",d)):_(r.agentId,n.sessionId,"tool_result",s,void 0,i,a,n.type)}}}),e.on("status-change",(n,r,o)=>{const s=f.get(n);if(s){de(n),r==="thinking"||r==="tool_using"||r==="compacting"?yt(n):x(n);const i=wt(r,o);s.currentRuntimeStatus=i.status;const a=s.currentRuntimeActionDetail??"",c=a.includes("poll_message")||a.includes("get_message"),u=!(i.actionInfo?.actionType==="ai_request")&&(i.status==="thinking"||i.status==="waiting_input")&&(s.currentRuntimeActionType==="idle"||s.currentRuntimeActionType==="mcp")&&c;(i.actionInfo?.actionType||!u)&&(s.currentRuntimeActionType=i.actionInfo?.actionType,s.currentRuntimeActionLabel=i.actionInfo?.actionLabel,s.currentRuntimeActionDetail=i.actionInfo?.actionDetail,s.currentRuntimeActionInput=i.actionInfo?.actionInput),console.log(`[${t.displayName} Adapter] Status changed: ${i.status} for agent ${s.agentId}`,i.actionInfo||""),mt(n,{runtimeStatus:i.status,runtimeActionType:s.currentRuntimeActionType,runtimeActionLabel:s.currentRuntimeActionLabel,runtimeActionDetail:s.currentRuntimeActionDetail});const l=i.actionInfo?.actionType?i.actionInfo:s.currentRuntimeActionType?{actionType:s.currentRuntimeActionType,actionLabel:s.currentRuntimeActionLabel??"",actionDetail:s.currentRuntimeActionDetail,actionInput:s.currentRuntimeActionInput}:void 0;if(i.status==="compacting"){const p=(ae.get(n)??Promise.resolve()).then(async()=>{for(let y=0;y<=2;y++){if(await _(s.agentId,n,i.status,l,re(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})!==void 0)return;y<2&&(h.warn(`[${t.displayName}] compaction sendStatus attempt ${y+1} failed (HTTP), retrying in ${1e3*(y+1)}ms...`),await new Promise(C=>setTimeout(C,1e3*(y+1))))}h.warn(`[${t.displayName}] compaction sendStatus failed after 3 attempts, event may be lost`)}).catch(T=>{h.warn(`[${t.displayName}] compaction status chain error:`,T)});ae.set(n,p),p.finally(()=>{ae.get(n)===p&&ae.delete(n)})}else{const m=u&&!i.actionInfo?.actionType;if(l?.actionType==="idle"||s.currentRuntimeActionType==="idle"&&u){const y=(ce.get(n)??Promise.resolve()).then(async()=>{for(let C=0;C<=2;C++){if(await _(s.agentId,n,i.status,m?void 0:l,re(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})!==void 0)return;C<2&&await new Promise(E=>setTimeout(E,1e3*(C+1)))}h.warn(`[${t.displayName}] idle tool sendStatus failed after 3 attempts, status may be stale (frontend will fall back to timeline tool_use event)`)}).catch(g=>{h.warn(`[${t.displayName}] idle status chain error:`,g)});ce.set(n,y),y.finally(()=>{ce.get(n)===y&&ce.delete(n)})}else _(s.agentId,n,i.status,m?void 0:l,re(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}if(i.status==="waiting_input"&&s.cachedCapabilitiesActionDetail){const m=s.cachedCapabilitiesActionDetail;s.cachedCapabilitiesActionDetail=void 0,console.log(`[${t.displayName} Adapter] Re-sending cached runtime_capabilities for agent ${s.agentId} (session stabilized to waiting_input)`),_(s.agentId,n,"waiting_input",{actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:m},void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}}}),e.on("ask-user-question",n=>{const r=f.get(n.sessionId);r&&(console.log(`[${t.displayName} Adapter] AskUserQuestion for agent ${r.agentId}`),ot(r.agentId,n.sessionId,Array.isArray(n.questions)?n.questions:[],{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},n.toolCallId))}),e.on("permission-request",n=>{const r=f.get(n.sessionId);if(r){console.log(`[${t.displayName} Adapter] Permission request: ${n.toolName} for agent ${r.agentId}`);const o=n.toolInput?q(JSON.stringify(n.toolInput).slice(0,400)):void 0;_(r.agentId,n.sessionId,"waiting_input",{actionType:"other",actionLabel:"\u6743\u9650\u786E\u8BA4",actionDetail:o||n.toolName},void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl})}})}A.post("/start",S,async(e,t)=>{const{agentId:n,workspacePath:r,mode:o="sdk"}=e.body||{};if(!n||!r){t.status(400).json({error:"agentId and workspacePath are required"});return}const s=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||_e(Pe(e))||void 0;tt({agentId:String(n),workspacePath:String(r),serverUrl:e.body?.serverUrl||s,runtimeAccessToken:e.body?.runtimeAccessToken,userId:e.body?.userId,schedulerBaseUrl:s}),e.body?.runtimeFeatures!=null&&(Ve(String(n),e.body.runtimeFeatures),console.log(`[Runtime] agent ${n} \u542F\u52A8\u4E0B\u53D1\u80FD\u529B\u5F00\u5173: ${JSON.stringify(Ye(String(n)))}`)),o&&o!=="sdk"&&console.warn(`[Runtime] Unsupported runtime mode "${o}" requested for agent ${n}; starting SDK session instead.`),await gn(e,t)});async function gn(e,t){const{agentId:n,workspacePath:r,command:o,autoAccept:s=!0,initialPrompt:i,systemPrompt:a,globalPrompt:c,rolePrompt:d,memory:u,mcpConfigPath:l,extraMcpServers:m,envOverrides:p,idleInputAutoCommand:T,nonInputAutoCommand:y,model:g,instanceAiConfig:C,subAgentModel:$,subAgentEffort:E,scopeKey:Te,browserAllowPrivate:ke}=e.body||{},z=pt();z.log({level:"info",category:"launch",message:"startSdkSession: \u6536\u5230\u542F\u52A8\u8BF7\u6C42",source:"bridge",agentId:String(n||"").trim()||void 0,details:{reqBodyKeys:Object.keys(e.body||{}),perInstanceAiConfig:C?te(C):null,perAgentModel:g??null}});let D=null;const I=String(n||"").trim(),le=String(e.body?.runtimeAccessToken||"").trim()||void 0,B=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||_e(Pe(e))||void 0;B?h.info(`[startSdkSession] \u56DE\u8C03\u76EE\u6807 server: ${B} (agentId=${I})`):h.warn(`[startSdkSession] \u672A\u89E3\u6790\u5230 schedulerBaseUrl\uFF0C\u5C06\u56DE\u9000\u5230\u9ED8\u8BA4\u5730\u5740 (agentId=${I})`);try{if(fn(),!I){t.status(400).json({error:"agentId is required"});return}const O=je(I);if(O){t.json(await Lt(O));return}const k=await ut(I);if(k){const P=Ut(k);if(!P.reusable)console.warn(`[Runtime] Ignoring stale persisted SDK session for agentId=${I}, sessionId=${k.sessionId}, reason=${P.reason}`),await F(k.sessionId);else{const R=se(k.runtimeStatus,k.runtimeStatus,k.runtimeActionType);t.json({sessionId:k.sessionId,status:R,runtimeStatus:R,runtimeActionType:k.runtimeActionType,runtimeActionLabel:k.runtimeActionLabel,runtimeActionDetail:k.runtimeActionDetail,agentId:k.agentId,workspacePath:k.workspacePath,command:k.command,mode:k.mode||"sdk",pid:k.pid,reused:!0,persistedOnly:!0});return}}if(K.has(I)){t.status(409).json({error:"SDK session is already starting for this agent"});return}K.add(I);const Sn=(o||"acode").toLowerCase(),M=Fe(o),ze=w.get(M);D=Xe();const He=M==="claude-code"?await vt():null,V=Oe(M==="claude-code"?He:null,p),H=M==="acode"?g?String(g).trim():void 0:(()=>{const P=g?String(g).trim():void 0,R=V.model?String(V.model).trim():void 0;return P||R})();z.log({level:"info",category:"resolve",message:"\u6A21\u578B\u89E3\u6790\u7ED3\u679C",source:"bridge",agentId:I,sessionId:D??void 0,details:{perAgentModel:g??null,globalModel:V.model??null,resolvedModel:H??null,providerId:M,note:M==="acode"?"adapter handles full priority":"request > global"}});const me={...V.envOverrides};H&&(me.ANTHROPIC_MODEL=H,me.CODEX_MODEL=H);let W,fe=l;if(M==="acode"){const P=C||{},R=await et({apiOverrides:Ie(P)??void 0,agentId:I,sessionId:D??void 0,runtimeBridgeBaseUrl:B});W=R.instanceConfig.config,fe=R.perInstanceConfigPath,z.log({level:"info",category:"apply",message:"prepareAcodeInstanceConfig \u5B8C\u6210",source:"bridge",agentId:I,sessionId:D??void 0,details:{sanitizedApiOverrides:Ie(P)?te(Ie(P)):null,resolvedInstanceAiConfig:W?te(W):null,perInstanceConfigPath:fe,instanceConfigSources:R.instanceConfig.source??null}})}let we=a||void 0,pe,ge,Y;if(M==="acode")if(pe=typeof c=="string"&&c.trim()||void 0,ge=typeof d=="string"&&d.trim()||void 0,typeof u=="string"&&u.trim())Y=u.trim();else{const P=await St(r,{schedulerBaseUrl:B,runtimeAccessToken:le,agentId:I});P&&(Y=P,h.info(`[startSdkSession] Auto-loaded memories for ACode agent ${I}`))}else if(typeof c=="string"&&c.trim()||typeof d=="string"&&d.trim()||typeof u=="string"&&u.trim()){const R=[c,d,u,a].filter(Z=>typeof Z=="string"&&Z.trim().length>0).map(Z=>Z.trim());we=R.length>0?R.join(`
48
+ `:void 0}function Jt(e){const n=en(e);return{sourceEventType:e.type,logCategory:"acode",...Zt(e),...n?{logLevel:Yt(e),logMessage:n}:{}}}function Yt(e){return e.type==="error"?"error":e.type==="command_output"&&e.data.stream==="stderr"?"warn":"info"}function Zt(e){return e.type!=="command_output"?{}:{...typeof e.data.stream=="string"?{stream:e.data.stream}:{},...typeof e.data.sequence=="number"?{sequence:e.data.sequence}:{},...typeof e.data.cwd=="string"?{cwd:e.data.cwd}:{},...typeof e.data.commandFilePath=="string"?{commandFilePath:e.data.commandFilePath}:{},...typeof e.data.commandLineCount=="number"?{commandLineCount:e.data.commandLineCount}:{}}}function en(e){if(e.type==="ai_request"){const n=e.data.model||"unknown-model",t=e.data.endpoint?` @ ${e.data.endpoint}`:"",r=typeof e.data.toolCount=="number"?`, tools=${e.data.toolCount}`:"";return`AI request started: ${n}${t}${r}`}if(e.type==="tool_use_start")return Ne(e,"\u5F00\u59CB");if(e.type==="tool_use_end")return Ne(e,"\u5B8C\u6210");if(e.type==="command_output")return rn(e);if(e.type==="turn_complete")return`Turn completed${e.data.finishReason?`, finish=${e.data.finishReason}`:""}`;if(e.type==="session_complete")return`Session completed: exitCode=${e.data.exitCode??0}`;if(e.type==="error")return e.data.text||"ACode runtime error"}const tn=/\x1b\[[0-9;?]*[a-zA-Z]/g;function nn(e){return e.replace(tn,"")}function rn(e){const n=typeof e.data.stream=="string"?e.data.stream:"mixed",t=typeof e.data.sequence=="number"?` #${e.data.sequence}`:"",r=nn(String(e.data.text||"")).replace(/\s+/g," ").trim(),o=r.length>240?`${r.slice(0,240)}...`:r;return`\u547D\u4EE4\u8F93\u51FA(${n}${t}): ${o||"(empty)"}`}function Ne(e,n){const t=ye(e.data.toolName,e.data.toolInput),r=e.data.actionLabel||t.actionLabel||"\u8C03\u7528\u5DE5\u5177",o=ve(e,t);return o?`${n}${r}: ${o}`:`${n}${r}: ${e.data.actionDetail||e.data.toolName||"tool"}`}function ve(e,n){const t=e.data.toolInput;return n.actionType==="bash"?on(t)||e.data.actionDetail||n.actionDetail:n.actionType==="read_file"||n.actionType==="edit_file"||n.actionType==="write_file"?sn(t)||e.data.actionDetail||n.actionDetail:e.data.actionDetail||n.actionDetail}function on(e){const n=Ae(e?.command,e?.cmd);if(n)return n;if(Array.isArray(e?.argv)){const t=e.argv.map(r=>String(r??"").trim()).filter(Boolean).join(" ");return t?v(t):void 0}return Ae(e?.args)}function sn(e){const n=qe(e?.paths);return n.length>0?n.length===1?n[0]:`${n.length}\u4E2A\u6587\u4EF6: ${n.join(", ")}`:Ae(e?.file_path,e?.filePath,e?.path,e?.target_file,e?.targetFile)}function Ae(...e){for(const n of e){if(typeof n=="string"&&n.trim())return v(n.trim());if(Array.isArray(n)){const t=qe(n)[0];if(t)return t}}}function qe(e){return Array.isArray(e)?e.map(n=>typeof n=="string"?n.trim():"").filter(Boolean).map(n=>v(n)):[]}function an(e){if(!(!e||Object.keys(e).length===0))try{const n=v(JSON.stringify(e,null,2));return n.length>8e3?`${n.slice(0,8e3)}
49
+ ...\uFF08\u8F93\u5165\u53C2\u6570\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`:n}catch{return}}function cn(e){const n=[e.model?`\u6A21\u578B: ${e.model}`:void 0,e.endpoint||e.requestUrl?`\u63A5\u53E3: ${e.endpoint||e.requestUrl}`:void 0,e.requestMethod?`\u65B9\u6CD5: ${e.requestMethod}`:void 0,typeof e.stream=="boolean"?`\u6D41\u5F0F: ${e.stream?"\u662F":"\u5426"}`:void 0,typeof e.messageCount=="number"?`\u4E0A\u4E0B\u6587\u6D88\u606F: ${e.messageCount}`:void 0,typeof e.toolCount=="number"?`\u53EF\u7528\u5DE5\u5177: ${e.toolCount}`:void 0,e.lastUserMessagePreview?`\u6700\u540E\u8BF7\u6C42: ${e.lastUserMessagePreview}`:void 0].filter(i=>!!i),t=un(e.requestHeaders),r=n.join(`
50
+ `)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",o=t.length>0?`${kt}${t.join(`
51
+ `)}`:"",s=e.requestBody?`${Tt}${e.requestBody}`:"";return`${r}${o}${s}`}function un(e){return e?Object.entries(e).map(([n,t])=>`${n}: ${t}`).filter(n=>n.trim().length>0):[]}function dn(e,n){return String(n||"").trim().toLowerCase()!=="waiting_input"?!1:e.type==="thinking"||e.type==="text_delta"}function ln(e){for(const n of["estimatedContextTokens","contextTokens","context_tokens","contextUsedTokens","context_used_tokens"]){const t=e[n],r=Number(t);if(Number.isFinite(r)&&r>0)return r}}function mn(e,n){if(!dn(e,n)){if(e.type==="ai_request"){const t=ln(e.data);return{status:"thinking",actionInfo:{actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:cn(e.data),...t!==void 0?{usage:{inputTokens:t,outputTokens:0}}:{}}}}if(e.type==="background_command_completed")return{status:"tool_result",actionInfo:{actionType:"background_command",actionLabel:"\u540E\u53F0\u547D\u4EE4",actionDetail:"background_command_completed"}};if(e.type==="thinking"||e.type==="text_delta")return{status:"thinking"};if(e.type==="tool_use_start"){const t=ye(e.data.toolName,e.data.toolInput),r=ve(e,t),o=an(e.data.toolInput);return e.data.actionType==="idle"||t.actionType==="idle"?{status:"waiting_input",actionInfo:{actionType:e.data.actionType||t.actionType,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:r||e.data.actionDetail||t.actionDetail||e.data.toolName,actionInput:o,actionId:e.data.actionId||e.data.toolUseId}}:{status:"tool_using",actionInfo:{actionType:e.data.actionType||t.actionType,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:r||e.data.actionDetail||t.actionDetail||e.data.toolName,actionInput:o,actionId:e.data.actionId||e.data.toolUseId}}}if(e.type==="turn_complete")return{status:"waiting_input",actionInfo:e.data.usage?{usage:e.data.usage}:void 0};if(e.type==="error")return{status:"error"};if(e.type==="context_compaction")return{status:"compacting",actionInfo:{actionType:"context_compaction",actionLabel:e.data.actionLabel,actionDetail:e.data.actionDetail,...e.data.actionId?{actionId:e.data.actionId}:{},...e.data.parentId?{parentId:e.data.parentId}:{}}};if(e.type==="runtime_capabilities")return{status:n||"waiting_input",actionInfo:{actionType:"runtime_capabilities",actionLabel:e.data.actionLabel||"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:e.data.actionDetail}}}}const L=new Map,ae=new Map,ce=new Map,G=new Map,fn=20,pn=500,gn=3e4;async function ue(e,n=gn,t=2){for(let r=0;r<=t;r++){const o=new AbortController;let s;try{const i=e(o.signal);i.catch(()=>{}),await Promise.race([i,new Promise((a,c)=>{s=setTimeout(()=>{o.abort(),c(new Error(`sendOutput timeout after ${n}ms`))},n)})]),s&&clearTimeout(s);return}catch(i){s&&clearTimeout(s);const a=i instanceof Error?i.message:String(i);if(r<t){const c=1e3*(r+1);h.warn(`sendOutput attempt ${r+1}/${t+1} failed (${a}), retrying in ${c}ms...`),await new Promise(d=>setTimeout(d,c));continue}h.warn(`sendOutput failed after ${t+1} attempts (${a}), giving up to unblock serial queue`)}}}function de(e,n){const t=n?`${e}:${n}`:void 0;let r,o;if(t)r=G.get(t),o=t;else{const f=[];for(const[T,y]of G)T.startsWith(e+":")&&y.buffer&&f.push(y.sourceEventType);for(const T of f)de(e,T);return}if(!r||!r.buffer)return;r.timer=null;const s=r.buffer,i=r.seq,a=r.entry,c=r.sourceEventType;r.buffer="",o&&G.delete(o);const d={sourceEventType:c,logCategory:"acode"},u={runtimeAccessToken:a.runtimeAccessToken,schedulerBaseUrl:a.schedulerBaseUrl},m=(L.get(e)??Promise.resolve()).then(()=>ue(f=>X(a.agentId,s,e,i,d,u,f)),()=>ue(f=>X(a.agentId,s,e,i,d,u,f)));L.set(e,m),m.finally(()=>{L.get(e)===m&&L.delete(e)})}function yn(e,n){const t=Gt(e);if(!t)return;n.seq+=1;const r=n.seq,o=Jt(e),s={runtimeAccessToken:n.runtimeAccessToken,schedulerBaseUrl:n.schedulerBaseUrl};if((e.type==="command_output"||e.type==="text_delta"||e.type==="thinking")&&t.length<fn){const c=`${e.sessionId}:${e.type}`;let d=G.get(c);if(d||(d={buffer:"",seq:0,timer:null,entry:n,sourceEventType:e.type}),d.buffer+=t,d.seq=r,d.entry=n,!d.timer){const u=e.sessionId,l=e.type;d.timer=setTimeout(()=>de(u,l),pn)}G.set(c,d);return}de(e.sessionId);const a=(L.get(e.sessionId)??Promise.resolve()).then(()=>ue(c=>X(n.agentId,t,e.sessionId,r,o,s,c)),()=>ue(c=>X(n.agentId,t,e.sessionId,r,o,s,c)));L.set(e.sessionId,a),a.finally(()=>{L.get(e.sessionId)===a&&L.delete(e.sessionId)})}function Fe(e){return Ge(e)}let Ke=!1;function hn(){Ke||(Ve(w,In),dt(),Ke=!0)}function In(e,n){e.on("event",t=>{const r=p.get(t.sessionId);if(r){if(t.type==="tool_use_start"?mt(r.sessionId,t.data.toolUseId||t.data.actionId,t.data.toolInput,t.data.toolName,r.workspacePath):t.type==="tool_use_end"&&lt(t,{sessionId:r.sessionId,agentId:r.agentId,workspacePath:r.workspacePath,providerId:r.providerId}),console.log(`[${n.displayName} Adapter] Event: ${t.type} for session ${t.sessionId}`),!(t.type==="thinking"||t.type==="text_delta"||t.type==="tool_use_start"||t.type==="context_compaction"||t.type==="ai_request")){t.type==="runtime_capabilities"&&t.data.actionDetail&&(r.cachedCapabilitiesActionDetail=t.data.actionDetail);const i=mn(t,r.currentRuntimeStatus);i&&_(r.agentId,t.sessionId,i.status,i.actionInfo,re(i.actionInfo),{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},t.timestamp?new Date(t.timestamp).getTime():void 0,t.type)}yn(t,r);const s=Vt(t);if(s){const i={runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},a=t.timestamp?new Date(t.timestamp).getTime():void 0,c=String(t.data?.toolName||"").toLowerCase()==="browser_launch",d=t.type==="tool_use_end"&&String(t.data?.rawToolName||t.data?.toolName||"").toLowerCase().replace(/[_-]/g,"").includes("todowrite");c?(async()=>{for(let l=0;l<3;l++){if(await _(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)!==void 0)return;l<2&&await new Promise(f=>setTimeout(f,3e3*(l+1)))}})().catch(u=>console.warn("[Runtime] browser_launch sendStatus retry exhausted:",u)):d?(async()=>{for(let l=0;l<3;l++){if(await _(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)!==void 0)return;l<2&&await new Promise(f=>setTimeout(f,1e3*(l+1)))}})().catch(u=>console.warn("[Runtime] todo_write sendStatus retry exhausted:",u)):_(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)}}}),e.on("status-change",(t,r,o)=>{const s=p.get(t);if(s){de(t),r==="thinking"||r==="tool_using"||r==="compacting"?At(t):x(t);const i=$t(r,o);s.currentRuntimeStatus=i.status;const a=s.currentRuntimeActionDetail??"",c=a.includes("poll_message")||a.includes("get_message"),u=!(i.actionInfo?.actionType==="ai_request")&&(i.status==="thinking"||i.status==="waiting_input")&&(s.currentRuntimeActionType==="idle"||s.currentRuntimeActionType==="mcp")&&c;(i.actionInfo?.actionType||!u)&&(s.currentRuntimeActionType=i.actionInfo?.actionType,s.currentRuntimeActionLabel=i.actionInfo?.actionLabel,s.currentRuntimeActionDetail=i.actionInfo?.actionDetail,s.currentRuntimeActionInput=i.actionInfo?.actionInput),console.log(`[${n.displayName} Adapter] Status changed: ${i.status} for agent ${s.agentId}`,i.actionInfo||""),yt(t,{runtimeStatus:i.status,runtimeActionType:s.currentRuntimeActionType,runtimeActionLabel:s.currentRuntimeActionLabel,runtimeActionDetail:s.currentRuntimeActionDetail});const l=i.actionInfo?.actionType?i.actionInfo:s.currentRuntimeActionType?{actionType:s.currentRuntimeActionType,actionLabel:s.currentRuntimeActionLabel??"",actionDetail:s.currentRuntimeActionDetail,actionInput:s.currentRuntimeActionInput}:void 0;if(i.status==="compacting"){const f=(ae.get(t)??Promise.resolve()).then(async()=>{for(let y=0;y<=2;y++){if(await _(s.agentId,t,i.status,l,re(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})!==void 0)return;y<2&&(h.warn(`[${n.displayName}] compaction sendStatus attempt ${y+1} failed (HTTP), retrying in ${1e3*(y+1)}ms...`),await new Promise(C=>setTimeout(C,1e3*(y+1))))}h.warn(`[${n.displayName}] compaction sendStatus failed after 3 attempts, event may be lost`)}).catch(T=>{h.warn(`[${n.displayName}] compaction status chain error:`,T)});ae.set(t,f),f.finally(()=>{ae.get(t)===f&&ae.delete(t)})}else{const m=u&&!i.actionInfo?.actionType;if(l?.actionType==="idle"||s.currentRuntimeActionType==="idle"&&u){const y=(ce.get(t)??Promise.resolve()).then(async()=>{for(let C=0;C<=2;C++){if(await _(s.agentId,t,i.status,m?void 0:l,re(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})!==void 0)return;C<2&&await new Promise(M=>setTimeout(M,1e3*(C+1)))}h.warn(`[${n.displayName}] idle tool sendStatus failed after 3 attempts, status may be stale (frontend will fall back to timeline tool_use event)`)}).catch(g=>{h.warn(`[${n.displayName}] idle status chain error:`,g)});ce.set(t,y),y.finally(()=>{ce.get(t)===y&&ce.delete(t)})}else _(s.agentId,t,i.status,m?void 0:l,re(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}if(i.status==="waiting_input"&&s.cachedCapabilitiesActionDetail){const m=s.cachedCapabilitiesActionDetail;s.cachedCapabilitiesActionDetail=void 0,console.log(`[${n.displayName} Adapter] Re-sending cached runtime_capabilities for agent ${s.agentId} (session stabilized to waiting_input)`),_(s.agentId,t,"waiting_input",{actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:m},void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}}}),e.on("ask-user-question",t=>{const r=p.get(t.sessionId);r&&(console.log(`[${n.displayName} Adapter] AskUserQuestion for agent ${r.agentId}`),ct(r.agentId,t.sessionId,Array.isArray(t.questions)?t.questions:[],{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},t.toolCallId))}),e.on("permission-request",t=>{const r=p.get(t.sessionId);if(r){console.log(`[${n.displayName} Adapter] Permission request: ${t.toolName} for agent ${r.agentId}`);const o=t.toolInput?v(JSON.stringify(t.toolInput).slice(0,400)):void 0;_(r.agentId,t.sessionId,"waiting_input",{actionType:"other",actionLabel:"\u6743\u9650\u786E\u8BA4",actionDetail:o||t.toolName},void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl})}})}A.post("/start",S,async(e,n)=>{const{agentId:t,workspacePath:r,mode:o="sdk"}=e.body||{};if(!t||!r){n.status(400).json({error:"agentId and workspacePath are required"});return}const s=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||$e(Re(e))||void 0;st({agentId:String(t),workspacePath:String(r),serverUrl:e.body?.serverUrl||s,runtimeAccessToken:e.body?.runtimeAccessToken,userId:e.body?.userId,schedulerBaseUrl:s}),e.body?.runtimeFeatures!=null&&(Je(String(t),e.body.runtimeFeatures),console.log(`[Runtime] agent ${t} \u542F\u52A8\u4E0B\u53D1\u80FD\u529B\u5F00\u5173: ${JSON.stringify(Ye(String(t)))}`)),e.body?.envVars!=null&&typeof e.body.envVars=="object"&&(tt(e.body.envVars),console.log(`[Runtime] agent ${t} \u4E0B\u53D1\u9762\u677F\u73AF\u5883\u53D8\u91CF: ${Object.keys(e.body.envVars).length} \u9879 \u2192 \u684C\u9762\u5DE5\u5177\u5B50\u8FDB\u7A0B`)),e.body?.changeCacheRetentionDays!==void 0&&(nt(e.body.changeCacheRetentionDays),console.log(`[Runtime] agent ${t} \u4E0B\u53D1\u53D8\u66F4\u7F13\u5B58\u4FDD\u7559\u5929\u6570: ${e.body.changeCacheRetentionDays??"\u4E0D\u6E05\u7406"}`)),o&&o!=="sdk"&&console.warn(`[Runtime] Unsupported runtime mode "${o}" requested for agent ${t}; starting SDK session instead.`),await Sn(e,n)});async function Sn(e,n){const{agentId:t,workspacePath:r,command:o,autoAccept:s=!0,initialPrompt:i,systemPrompt:a,globalPrompt:c,rolePrompt:d,memory:u,mcpConfigPath:l,extraMcpServers:m,envOverrides:f,idleInputAutoCommand:T,nonInputAutoCommand:y,model:g,instanceAiConfig:C,subAgentModel:$,subAgentEffort:M,scopeKey:Te,browserAllowPrivate:ke}=e.body||{},z=It();z.log({level:"info",category:"launch",message:"startSdkSession: \u6536\u5230\u542F\u52A8\u8BF7\u6C42",source:"bridge",agentId:String(t||"").trim()||void 0,details:{reqBodyKeys:Object.keys(e.body||{}),perInstanceAiConfig:C?te(C):null,perAgentModel:g??null}});let D=null;const I=String(t||"").trim(),le=String(e.body?.runtimeAccessToken||"").trim()||void 0,B=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||$e(Re(e))||void 0;B?h.info(`[startSdkSession] \u56DE\u8C03\u76EE\u6807 server: ${B} (agentId=${I})`):h.warn(`[startSdkSession] \u672A\u89E3\u6790\u5230 schedulerBaseUrl\uFF0C\u5C06\u56DE\u9000\u5230\u9ED8\u8BA4\u5730\u5740 (agentId=${I})`);try{if(hn(),!I){n.status(400).json({error:"agentId is required"});return}const O=je(I);if(O){n.json(await Ot(O));return}const k=await ft(I);if(k){const R=Nt(k);if(!R.reusable)console.warn(`[Runtime] Ignoring stale persisted SDK session for agentId=${I}, sessionId=${k.sessionId}, reason=${R.reason}`),await F(k.sessionId);else{const P=se(k.runtimeStatus,k.runtimeStatus,k.runtimeActionType);n.json({sessionId:k.sessionId,status:P,runtimeStatus:P,runtimeActionType:k.runtimeActionType,runtimeActionLabel:k.runtimeActionLabel,runtimeActionDetail:k.runtimeActionDetail,agentId:k.agentId,workspacePath:k.workspacePath,command:k.command,mode:k.mode||"sdk",pid:k.pid,reused:!0,persistedOnly:!0});return}}if(K.has(I)){n.status(409).json({error:"SDK session is already starting for this agent"});return}K.add(I);const wn=(o||"acode").toLowerCase(),E=Fe(o),ze=w.get(E);D=Qe();const He=E==="claude-code"?await Ht():null,J=Oe(E==="claude-code"?He:null,f),H=E==="acode"?g?String(g).trim():void 0:(()=>{const R=g?String(g).trim():void 0,P=J.model?String(J.model).trim():void 0;return R||P})();z.log({level:"info",category:"resolve",message:"\u6A21\u578B\u89E3\u6790\u7ED3\u679C",source:"bridge",agentId:I,sessionId:D??void 0,details:{perAgentModel:g??null,globalModel:J.model??null,resolvedModel:H??null,providerId:E,note:E==="acode"?"adapter handles full priority":"request > global"}});const me={...J.envOverrides};H&&(me.ANTHROPIC_MODEL=H,me.CODEX_MODEL=H);let W,fe=l;if(E==="acode"){const R=C||{},P=await ot({apiOverrides:Ie(R)??void 0,agentId:I,sessionId:D??void 0,runtimeBridgeBaseUrl:B});W=P.instanceConfig.config,fe=P.perInstanceConfigPath,z.log({level:"info",category:"apply",message:"prepareAcodeInstanceConfig \u5B8C\u6210",source:"bridge",agentId:I,sessionId:D??void 0,details:{sanitizedApiOverrides:Ie(R)?te(Ie(R)):null,resolvedInstanceAiConfig:W?te(W):null,perInstanceConfigPath:fe,instanceConfigSources:P.instanceConfig.source??null}})}let we=a||void 0,pe,ge,Y;if(E==="acode")if(pe=typeof c=="string"&&c.trim()||void 0,ge=typeof d=="string"&&d.trim()||void 0,typeof u=="string"&&u.trim())Y=u.trim();else{const R=await wt(r,{schedulerBaseUrl:B,runtimeAccessToken:le,agentId:I});R&&(Y=R,h.info(`[startSdkSession] Auto-loaded memories for ACode agent ${I}`))}else if(typeof c=="string"&&c.trim()||typeof d=="string"&&d.trim()||typeof u=="string"&&u.trim()){const P=[c,d,u,a].filter(Z=>typeof Z=="string"&&Z.trim().length>0).map(Z=>Z.trim());we=P.length>0?P.join(`
52
52
 
53
- `):void 0}const U={command:o||"acode",workingDirectory:r,agentId:I,...Te?{scopeKey:Te}:{},...typeof ke=="boolean"?{browserAllowPrivate:ke}:{},autoAccept:!!s,initialPrompt:i,systemPrompt:we,...pe!==void 0?{globalPrompt:pe}:{},...ge!==void 0?{rolePrompt:ge}:{},...Y!==void 0?{memory:Y}:{},model:H,mcpConfigPath:fe,...W?{instanceAiConfig:W}:{},...typeof $=="string"&&$.trim()?{subAgentModel:$.trim()}:{},...typeof E=="string"&&E.trim()?{subAgentEffort:E.trim()}:{},extraMcpServers:m||{},envOverrides:Be(String(n),String(r),process.env,me)};z.log({level:"info",category:"launch",message:"\u4F20\u9012\u7ED9 Adapter \u7684\u5B8C\u6574 AdapterSessionConfig",source:"bridge",agentId:I,sessionId:D,details:{adapterModel:U.model??null,adapterInstanceAiConfig:U.instanceAiConfig?te(U.instanceAiConfig):null,adapterMcpConfigPath:U.mcpConfigPath??null}}),await z.flush(),f.set(D,{agentId:I,workspacePath:r,sessionId:D,config:U,providerId:M,seq:0,runtimeAccessToken:le,schedulerBaseUrl:B}),t.json({sessionId:D,status:"starting",runtimeStatus:"starting",agentId:I,workspacePath:r,command:U.command,mode:"sdk"}),yn({sessionId:D,agentId:I,config:U,adapter:ze,providerId:M,idleInputAutoCommand:T,nonInputAutoCommand:y,runtimeAccessToken:le,requestedSchedulerBaseUrl:B})}catch(O){if(D&&(x(D),f.delete(D),v(D)),I&&K.delete(I),!t.headersSent){const k=O instanceof Error?O.message:String(O);t.status(500).json({error:`Failed to start SDK session: ${k}`})}}}async function yn(e){const{sessionId:t,agentId:n,config:r,adapter:o,providerId:s,idleInputAutoCommand:i,nonInputAutoCommand:a,runtimeAccessToken:c,requestedSchedulerBaseUrl:d}=e;try{await o.startSession(t,r),(i||a)&&o.setIdleCommands?.(t,{idleInputCommand:i||"",nonInputCommand:a||""});let u;if(Tt(s))try{if(await new Promise(m=>setTimeout(m,500)),u=o.getSessionPid?.(t),!u){const p=(await nt()).find(T=>T.agentId===n||T.cwd===r.workingDirectory||T.command.includes(r.workingDirectory));p&&(u=p.pid,console.log(`[Runtime] Found SDK process PID: ${u} for agentId=${n}`))}}catch(m){console.warn(`[Runtime] Failed to get SDK PID for agentId=${n}:`,m)}const l=se(o.getSessionStatus(t),f.get(t)?.currentRuntimeStatus,f.get(t)?.currentRuntimeActionType);await ft({sessionId:t,agentId:n,workspacePath:r.workingDirectory,command:r.command,startedAt:new Date().toISOString(),status:"running",runtimeStatus:l,mode:"sdk",pid:u,providerSessionId:o.getProviderSessionId(t)}),u&&await he().startProcess({agentId:n,sessionId:t,pid:u,mode:"sdk",workspacePath:r.workingDirectory,command:r.command}),await hn({agentId:n,sessionId:t,sdkPid:u,status:l,schedulerBaseUrl:d,runtimeAccessToken:c})}catch(u){x(t),f.delete(t),v(t),await F(t);const l=u instanceof Error?u.message:String(u);console.error(`[Runtime] Background SDK session startup failed for agentId=${n}: ${l}`),await In({agentId:n,sessionId:t,schedulerBaseUrl:d,runtimeAccessToken:c,errorMessage:l})}finally{K.delete(n)}}async function hn(e){const{agentId:t,sessionId:n,sdkPid:r,status:o,schedulerBaseUrl:s,runtimeAccessToken:i}=e;if(!s||!i){h.debug(`[Runtime] notifyServerSessionReady skipped: missing schedulerBaseUrl or runtimeAccessToken for agentId=${t}`);return}const a=`${s.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await Ce.post(a,{agentId:t,sessionId:n,status:o,pid:r},{headers:{"X-Runtime-Token":i,"Content-Type":"application/json"},timeout:5e3}),h.debug(`[Runtime] Notified server session ready: agentId=${t}, sessionId=${n}, status=${o}`)}catch(c){const d=c instanceof Error?c.message:String(c);h.warn(`[Runtime] Failed to notify server session ready: agentId=${t}, error=${d}`)}}async function In(e){const{agentId:t,sessionId:n,schedulerBaseUrl:r,runtimeAccessToken:o}=e;if(!r||!o)return;const s=`${r.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await Ce.post(s,{agentId:t,sessionId:n,status:"stopped"},{headers:{"X-Runtime-Token":o,"Content-Type":"application/json"},timeout:5e3}),h.debug(`[Runtime] Notified server session failed: agentId=${t}, sessionId=${n}`)}catch(i){const a=i instanceof Error?i.message:String(i);h.warn(`[Runtime] Failed to notify server session failed: agentId=${t}, error=${a}`)}}A.post("/sdk/message",S,async(e,t)=>{const{sessionId:n,message:r}=e.body||{};if(!n||!r){t.status(400).json({error:"sessionId and message are required"});return}const o=f.get(n);if(!o){t.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code";await w.get(s).sendMessage(n,r),t.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);t.status(500).json({error:i})}}),A.post("/sdk/answer",S,async(e,t)=>{const{sessionId:n,answers:r}=e.body||{};if(!n||!r){t.status(400).json({error:"sessionId and answers are required"});return}const o=f.get(n);if(!o){t.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code",i=w.get(s);i.sendQuestionAnswer&&await i.sendQuestionAnswer(n,r),t.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);t.status(500).json({error:i})}}),A.post("/sdk/confirm",S,async(e,t)=>{const{sessionId:n,accept:r}=e.body||{};if(!n){t.status(400).json({error:"sessionId is required"});return}const o=f.get(n);if(!o){t.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code";await w.get(s).sendConfirmation(n,!!r),t.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);t.status(500).json({error:i})}}),A.post("/sdk/abort",S,async(e,t)=>{const{sessionId:n}=e.body||{};if(!n){t.status(400).json({error:"sessionId is required"});return}const r=f.get(n);if(!r){t.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code";await w.get(o).abortCurrentTurn(n),t.json({ok:!0})}catch(o){const s=o instanceof Error?o.message:String(o);t.status(500).json({error:s})}}),A.post("/sdk/stop",S,async(e,t)=>{const{sessionId:n}=e.body||{};if(!n){t.status(400).json({error:"sessionId is required"});return}const r=f.get(n);if(!r){t.json({ok:!0,status:"stopped"});return}try{const o=r.providerId||"claude-code",s=w.get(o);s.abortCurrentTurn(n).catch(()=>{}),await s.terminateSession(n),x(n),f.delete(n),v(n),ie(n),await F(n),await he().removeProcess(r.agentId),await _(r.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl}),t.json({ok:!0,status:"stopped"})}catch(o){const s=o instanceof Error?o.message:String(o);t.status(500).json({error:s})}}),A.get("/sdk/status/:sessionId",S,(e,t)=>{const n=e.params.sessionId;if(!n){t.status(400).json({error:"sessionId is required"});return}const r=f.get(n);if(!r){t.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",s=w.get(o),i=s.getSessionStatus(n),a=s.getConversation(n);t.json({sessionId:n,status:i,agentId:r.agentId,workspacePath:r.workspacePath,messageCount:a.length})}catch(o){const s=o instanceof Error?o.message:String(o);t.status(500).json({error:s})}}),A.get("/sdk/capabilities/:sessionId",S,(e,t)=>{const n=e.params.sessionId;if(!n){t.status(400).json({error:"sessionId is required"});return}const r=f.get(n);if(!r){t.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=w.get(o).getCapabilities?.(n)??null;t.json({ok:!0,sessionId:n,agentId:r.agentId,capabilities:i,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);t.status(500).json({error:s})}}),A.get("/sdk/pending-questions/:sessionId",S,(e,t)=>{const n=e.params.sessionId;if(!n){t.status(400).json({error:"sessionId is required"});return}const r=f.get(n);if(!r){t.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=w.get(o).getPendingQuestion?.(n)??null;t.json({ok:!0,sessionId:n,agentId:r.agentId,pendingQuestion:i?{toolCallId:i.toolCallId,questions:i.questions}:null,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);t.status(500).json({error:s})}}),A.post("/command",S,async(e,t)=>{const{sessionId:n,command:r}=e.body||{};if(!n||r===void 0||r===null){t.status(400).json({error:"sessionId and command are required"});return}try{const o=await Ot(String(n),r);t.json({ok:!0,mode:"terminal",...o})}catch(o){const s=o instanceof Error?o.message:String(o);t.status(500).json({error:s})}}),A.post("/input",S,async(e,t)=>{const{sessionId:n,input:r,mode:o}=e.body||{};if(!n||r===void 0||r===null){t.status(400).json({error:"sessionId and input are required"});return}const s=f.get(n);if(!s){t.status(404).json({error:"SDK session not found"});return}try{const i=s.providerId||"claude-code",a=w.get(i);if(o==="shortcut"){if(!a.sendShortcutInput){t.status(400).json({error:"shortcut input is not supported by this SDK provider"});return}await a.sendShortcutInput(n,String(r)),t.json({ok:!0,mode:"shortcut"});return}await a.sendMessage(n,await qt(r)),t.json({ok:!0,mode:"sdk"})}catch(i){const a=i instanceof Error?i.message:String(i);t.status(500).json({error:a})}}),A.post("/update-auto-commands",S,async(e,t)=>{const{agentId:n,idleInputAutoCommand:r="",nonInputAutoCommand:o=""}=e.body||{},s=String(n||"").trim();if(!s){t.status(400).json({error:"agentId is required"});return}const i=[...f.values()].find(c=>c.agentId===s),a={idleInputCommand:String(r||""),nonInputCommand:String(o||"")};try{let c=!1;i&&(w.get(i.providerId||"claude-code").setIdleCommands?.(i.sessionId,a),c=!0);const d=await lt(s,{idleInputAutoCommand:a.idleInputCommand,nonInputAutoCommand:a.nonInputCommand});t.json({ok:!0,mode:"sdk",sessionUpdated:c,persistedUpdated:d})}catch(c){const d=c instanceof Error?c.message:String(c);t.status(500).json({ok:!1,mode:"sdk",error:d})}}),A.post("/resize",S,(e,t)=>{const{sessionId:n,cols:r,rows:o}=e.body||{};if(!n||!r||!o){t.status(400).json({error:"sessionId, cols, rows are required"});return}if(!f.has(n)){t.status(404).json({error:"SDK session not found"});return}t.json({ok:!0,mode:"sdk",noop:!0,cols:Number(r),rows:Number(o)})}),A.post("/reset-context",S,async(e,t)=>{const{sessionId:n,reason:r}=e.body||{};if(!n){t.status(400).json({error:"sessionId is required"});return}const o=f.get(n);if(!o){t.status(404).json({error:"SDK session not found"});return}const s=o.providerId||"claude-code",i=w.get(s),a=i.resetContext?.bind(i),c=At(s,!!a);if(!c.supported){t.status(c.statusCode).json({error:c.error});return}if(!a){t.status(500).json({error:"ACode adapter does not expose resetContext"});return}try{await a(String(n));const d=se(i.getSessionStatus(String(n)),o.currentRuntimeStatus,o.currentRuntimeActionType);t.json({ok:!0,contextReset:!0,sessionId:n,status:d,runtimeStatus:d,agentId:o.agentId,mode:"sdk",providerId:s,reason:typeof r=="string"&&r.trim()?r.trim():void 0})}catch(d){const u=d instanceof Error?d.message:String(d);t.status(500).json({ok:!1,contextReset:!1,mode:"sdk",error:u})}}),A.post("/stop",S,async(e,t)=>{const{sessionId:n}=e.body||{},r=kt(e.body);if(!n){t.status(400).json({error:"sessionId is required"});return}const o=f.get(n);if(!o){await F(n),t.json({ok:!0,status:"stopped",mode:"none",statusNotified:!1,reason:r.reason});return}const s=o.agentId;try{console.log(`[Runtime] Stopping SDK session ${n}; suppressStatus=${!r.statusNotified}, reason=${r.reason||"unspecified"}`);const i=o.providerId||"claude-code",a=w.get(i);a.abortCurrentTurn(n).catch(()=>{}),await a.terminateSession(n),x(n),f.delete(n),v(n),ie(n),await F(n),await he().removeProcess(s),r.statusNotified?await _(s,null,"stopped",void 0,void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl}):console.log(`[Runtime] Stopped status notification suppressed for SDK session ${n}; reason=${r.reason||"unspecified"}`),t.json({ok:!0,status:"stopped",mode:"sdk",statusNotified:r.statusNotified,reason:r.reason})}catch(i){const a=i instanceof Error?i.message:String(i);console.error(`[Runtime] Failed to terminate SDK session ${n}:`,a),t.status(500).json({ok:!1,status:"stop_failed",mode:"sdk",error:a})}}),A.post("/stop-all",S,async(e,t)=>{const n=[],r=[];for(const[o,s]of f.entries())try{const i=s.providerId||"claude-code",a=w.get(i);a.abortCurrentTurn(o).catch(()=>{}),await a.terminateSession(o),x(o),f.delete(o),v(o),ie(o),n.push(o),await _(s.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}catch(i){const a=i instanceof Error?i.message:String(i);r.push(`SDK ${o}: ${a}`)}try{await dt([]),console.log("[Runtime] \u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD")}catch(o){const s=o instanceof Error?o.message:String(o);r.push(`Persistence: ${s}`)}t.json({ok:!0,stopped:{sdk:n.length},errors:r.length>0?r:void 0})}),A.get("/events/last/:n",S,(e,t)=>{const n=parseInt(e.params.n,10);if(!Number.isFinite(n)||n<1){t.status(400).json({error:":n must be a positive integer"});return}const r=De.getLastN(n);t.json({ok:!0,count:r.length,entries:r})}),A.get("/events/since/:index",S,(e,t)=>{const n=parseInt(e.params.index,10);if(!Number.isFinite(n)||n<0){t.status(400).json({error:":index must be a non-negative integer"});return}const r=De.getSinceIndex(n);t.json({ok:!0,entries:r.entries,nextIndex:r.nextIndex,oldestIndex:r.oldestIndex,dataLoss:r.oldestIndex>n+1})}),A.get("/events/push-stats",S,(e,t)=>{const n=st();t.json({ok:!0,count:n.length,agents:n})});export{Ct as buildAcodeCommandOutputPath,Oe as buildClaudeCodeLaunchConfig,Be as buildRuntimeEnv,Qt as buildSdkOutputMetadata,Ht as buildToolResultTimelineActionInfo,Kn as cleanupSdkSessionByAgentId,$t as countTerminalOutputLines,Ue as createTerminalOutputDecoder,oe as decodeTerminalOutputChunk,Ut as evaluatePersistedSessionReuse,Dt as formatCommandInactivityTimeoutNotice,_t as formatCommandOutputSpilloverNotice,Wt as formatSdkOutputEvent,Se as formatTerminalPrompt,Pt as normalizeTerminalCommandInput,kt as parseRuntimeStopOptions,Et as parseTerminalDirectoryChangeTarget,ue as raceSendOutputWithRetry,At as resolveRuntimeContextResetSupport,cn as resolveRuntimeStatusFromProviderEvent,qt as resolveSdkInputMessage,Fe as resolveSdkProviderId,se as resolveSdkSessionDisplayStatus,wt as resolveStatusChangeRuntimeState,re as resolveStatusChangeUsage,Rt as resolveTerminalOutputEncoding,f as sdkSessions,Tt as shouldProbeSdkProcessPid,A as terminalRouter};
53
+ `):void 0}const U={command:o||"acode",workingDirectory:r,agentId:I,...Te?{scopeKey:Te}:{},...typeof ke=="boolean"?{browserAllowPrivate:ke}:{},autoAccept:!!s,initialPrompt:i,systemPrompt:we,...pe!==void 0?{globalPrompt:pe}:{},...ge!==void 0?{rolePrompt:ge}:{},...Y!==void 0?{memory:Y}:{},model:H,mcpConfigPath:fe,...W?{instanceAiConfig:W}:{},...typeof $=="string"&&$.trim()?{subAgentModel:$.trim()}:{},...typeof M=="string"&&M.trim()?{subAgentEffort:M.trim()}:{},extraMcpServers:m||{},envOverrides:Be(String(t),String(r),process.env,me)};z.log({level:"info",category:"launch",message:"\u4F20\u9012\u7ED9 Adapter \u7684\u5B8C\u6574 AdapterSessionConfig",source:"bridge",agentId:I,sessionId:D,details:{adapterModel:U.model??null,adapterInstanceAiConfig:U.instanceAiConfig?te(U.instanceAiConfig):null,adapterMcpConfigPath:U.mcpConfigPath??null}}),await z.flush(),p.set(D,{agentId:I,workspacePath:r,sessionId:D,config:U,providerId:E,seq:0,runtimeAccessToken:le,schedulerBaseUrl:B}),n.json({sessionId:D,status:"starting",runtimeStatus:"starting",agentId:I,workspacePath:r,command:U.command,mode:"sdk"}),An({sessionId:D,agentId:I,config:U,adapter:ze,providerId:E,idleInputAutoCommand:T,nonInputAutoCommand:y,runtimeAccessToken:le,requestedSchedulerBaseUrl:B})}catch(O){if(D&&(x(D),p.delete(D),q(D)),I&&K.delete(I),!n.headersSent){const k=O instanceof Error?O.message:String(O);n.status(500).json({error:`Failed to start SDK session: ${k}`})}}}async function An(e){const{sessionId:n,agentId:t,config:r,adapter:o,providerId:s,idleInputAutoCommand:i,nonInputAutoCommand:a,runtimeAccessToken:c,requestedSchedulerBaseUrl:d}=e;try{await o.startSession(n,r),(i||a)&&o.setIdleCommands?.(n,{idleInputCommand:i||"",nonInputCommand:a||""});let u;if(Ct(s))try{if(await new Promise(m=>setTimeout(m,500)),u=o.getSessionPid?.(n),!u){const f=(await it()).find(T=>T.agentId===t||T.cwd===r.workingDirectory||T.command.includes(r.workingDirectory));f&&(u=f.pid,console.log(`[Runtime] Found SDK process PID: ${u} for agentId=${t}`))}}catch(m){console.warn(`[Runtime] Failed to get SDK PID for agentId=${t}:`,m)}const l=se(o.getSessionStatus(n),p.get(n)?.currentRuntimeStatus,p.get(n)?.currentRuntimeActionType);await ht({sessionId:n,agentId:t,workspacePath:r.workingDirectory,command:r.command,startedAt:new Date().toISOString(),status:"running",runtimeStatus:l,mode:"sdk",pid:u,providerSessionId:o.getProviderSessionId(n)}),u&&await he().startProcess({agentId:t,sessionId:n,pid:u,mode:"sdk",workspacePath:r.workingDirectory,command:r.command}),await Tn({agentId:t,sessionId:n,sdkPid:u,status:l,schedulerBaseUrl:d,runtimeAccessToken:c})}catch(u){x(n),p.delete(n),q(n),await F(n);const l=u instanceof Error?u.message:String(u);console.error(`[Runtime] Background SDK session startup failed for agentId=${t}: ${l}`),await kn({agentId:t,sessionId:n,schedulerBaseUrl:d,runtimeAccessToken:c,errorMessage:l})}finally{K.delete(t)}}async function Tn(e){const{agentId:n,sessionId:t,sdkPid:r,status:o,schedulerBaseUrl:s,runtimeAccessToken:i}=e;if(!s||!i){h.debug(`[Runtime] notifyServerSessionReady skipped: missing schedulerBaseUrl or runtimeAccessToken for agentId=${n}`);return}const a=`${s.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await Ce.post(a,{agentId:n,sessionId:t,status:o,pid:r},{headers:{"X-Runtime-Token":i,"Content-Type":"application/json"},timeout:5e3}),h.debug(`[Runtime] Notified server session ready: agentId=${n}, sessionId=${t}, status=${o}`)}catch(c){const d=c instanceof Error?c.message:String(c);h.warn(`[Runtime] Failed to notify server session ready: agentId=${n}, error=${d}`)}}async function kn(e){const{agentId:n,sessionId:t,schedulerBaseUrl:r,runtimeAccessToken:o}=e;if(!r||!o)return;const s=`${r.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await Ce.post(s,{agentId:n,sessionId:t,status:"stopped"},{headers:{"X-Runtime-Token":o,"Content-Type":"application/json"},timeout:5e3}),h.debug(`[Runtime] Notified server session failed: agentId=${n}, sessionId=${t}`)}catch(i){const a=i instanceof Error?i.message:String(i);h.warn(`[Runtime] Failed to notify server session failed: agentId=${n}, error=${a}`)}}A.post("/sdk/message",S,async(e,n)=>{const{sessionId:t,message:r}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and message are required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code";await w.get(s).sendMessage(t,r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),A.post("/sdk/answer",S,async(e,n)=>{const{sessionId:t,answers:r}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and answers are required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code",i=w.get(s);i.sendQuestionAnswer&&await i.sendQuestionAnswer(t,r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),A.post("/sdk/confirm",S,async(e,n)=>{const{sessionId:t,accept:r}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code";await w.get(s).sendConfirmation(t,!!r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),A.post("/sdk/abort",S,async(e,n)=>{const{sessionId:t}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code";await w.get(o).abortCurrentTurn(t),n.json({ok:!0})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),A.post("/sdk/stop",S,async(e,n)=>{const{sessionId:t}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.json({ok:!0,status:"stopped"});return}try{const o=r.providerId||"claude-code",s=w.get(o);s.abortCurrentTurn(t).catch(()=>{}),await s.terminateSession(t),x(t),p.delete(t),q(t),ie(t),await F(t),await he().removeProcess(r.agentId),await _(r.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl}),n.json({ok:!0,status:"stopped"})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),A.get("/sdk/status/:sessionId",S,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",s=w.get(o),i=s.getSessionStatus(t),a=s.getConversation(t);n.json({sessionId:t,status:i,agentId:r.agentId,workspacePath:r.workspacePath,messageCount:a.length})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),A.get("/sdk/capabilities/:sessionId",S,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=w.get(o).getCapabilities?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,capabilities:i,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),A.get("/sdk/pending-questions/:sessionId",S,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=w.get(o).getPendingQuestion?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,pendingQuestion:i?{toolCallId:i.toolCallId,questions:i.questions}:null,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),A.post("/command",S,async(e,n)=>{const{sessionId:t,command:r}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and command are required"});return}try{const o=await Ft(String(t),r);n.json({ok:!0,mode:"terminal",...o})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),A.post("/input",S,async(e,n)=>{const{sessionId:t,input:r,mode:o}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and input are required"});return}const s=p.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const i=s.providerId||"claude-code",a=w.get(i);if(o==="shortcut"){if(!a.sendShortcutInput){n.status(400).json({error:"shortcut input is not supported by this SDK provider"});return}await a.sendShortcutInput(t,String(r)),n.json({ok:!0,mode:"shortcut"});return}await a.sendMessage(t,await zt(r)),n.json({ok:!0,mode:"sdk"})}catch(i){const a=i instanceof Error?i.message:String(i);n.status(500).json({error:a})}}),A.post("/update-auto-commands",S,async(e,n)=>{const{agentId:t,idleInputAutoCommand:r="",nonInputAutoCommand:o=""}=e.body||{},s=String(t||"").trim();if(!s){n.status(400).json({error:"agentId is required"});return}const i=[...p.values()].find(c=>c.agentId===s),a={idleInputCommand:String(r||""),nonInputCommand:String(o||"")};try{let c=!1;i&&(w.get(i.providerId||"claude-code").setIdleCommands?.(i.sessionId,a),c=!0);const d=await gt(s,{idleInputAutoCommand:a.idleInputCommand,nonInputAutoCommand:a.nonInputCommand});n.json({ok:!0,mode:"sdk",sessionUpdated:c,persistedUpdated:d})}catch(c){const d=c instanceof Error?c.message:String(c);n.status(500).json({ok:!1,mode:"sdk",error:d})}}),A.post("/resize",S,(e,n)=>{const{sessionId:t,cols:r,rows:o}=e.body||{};if(!t||!r||!o){n.status(400).json({error:"sessionId, cols, rows are required"});return}if(!p.has(t)){n.status(404).json({error:"SDK session not found"});return}n.json({ok:!0,mode:"sdk",noop:!0,cols:Number(r),rows:Number(o)})}),A.post("/reset-context",S,async(e,n)=>{const{sessionId:t,reason:r}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}const s=o.providerId||"claude-code",i=w.get(s),a=i.resetContext?.bind(i),c=bt(s,!!a);if(!c.supported){n.status(c.statusCode).json({error:c.error});return}if(!a){n.status(500).json({error:"ACode adapter does not expose resetContext"});return}try{await a(String(t));const d=se(i.getSessionStatus(String(t)),o.currentRuntimeStatus,o.currentRuntimeActionType);n.json({ok:!0,contextReset:!0,sessionId:t,status:d,runtimeStatus:d,agentId:o.agentId,mode:"sdk",providerId:s,reason:typeof r=="string"&&r.trim()?r.trim():void 0})}catch(d){const u=d instanceof Error?d.message:String(d);n.status(500).json({ok:!1,contextReset:!1,mode:"sdk",error:u})}}),A.post("/stop",S,async(e,n)=>{const{sessionId:t}=e.body||{},r=_t(e.body);if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){await F(t),n.json({ok:!0,status:"stopped",mode:"none",statusNotified:!1,reason:r.reason});return}const s=o.agentId;try{console.log(`[Runtime] Stopping SDK session ${t}; suppressStatus=${!r.statusNotified}, reason=${r.reason||"unspecified"}`);const i=o.providerId||"claude-code",a=w.get(i);a.abortCurrentTurn(t).catch(()=>{}),await a.terminateSession(t),x(t),p.delete(t),q(t),ie(t),await F(t),await he().removeProcess(s),r.statusNotified?await _(s,null,"stopped",void 0,void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl}):console.log(`[Runtime] Stopped status notification suppressed for SDK session ${t}; reason=${r.reason||"unspecified"}`),n.json({ok:!0,status:"stopped",mode:"sdk",statusNotified:r.statusNotified,reason:r.reason})}catch(i){const a=i instanceof Error?i.message:String(i);console.error(`[Runtime] Failed to terminate SDK session ${t}:`,a),n.status(500).json({ok:!1,status:"stop_failed",mode:"sdk",error:a})}}),A.post("/stop-all",S,async(e,n)=>{const t=[],r=[];for(const[o,s]of p.entries())try{const i=s.providerId||"claude-code",a=w.get(i);a.abortCurrentTurn(o).catch(()=>{}),await a.terminateSession(o),x(o),p.delete(o),q(o),ie(o),t.push(o),await _(s.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}catch(i){const a=i instanceof Error?i.message:String(i);r.push(`SDK ${o}: ${a}`)}try{await pt([]),console.log("[Runtime] \u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD")}catch(o){const s=o instanceof Error?o.message:String(o);r.push(`Persistence: ${s}`)}n.json({ok:!0,stopped:{sdk:t.length},errors:r.length>0?r:void 0})}),A.get("/events/last/:n",S,(e,n)=>{const t=parseInt(e.params.n,10);if(!Number.isFinite(t)||t<1){n.status(400).json({error:":n must be a positive integer"});return}const r=De.getLastN(t);n.json({ok:!0,count:r.length,entries:r})}),A.get("/events/since/:index",S,(e,n)=>{const t=parseInt(e.params.index,10);if(!Number.isFinite(t)||t<0){n.status(400).json({error:":index must be a non-negative integer"});return}const r=De.getSinceIndex(t);n.json({ok:!0,entries:r.entries,nextIndex:r.nextIndex,oldestIndex:r.oldestIndex,dataLoss:r.oldestIndex>t+1})}),A.get("/events/push-stats",S,(e,n)=>{const t=ut();n.json({ok:!0,count:t.length,agents:t})});export{Rt as buildAcodeCommandOutputPath,Oe as buildClaudeCodeLaunchConfig,Be as buildRuntimeEnv,Jt as buildSdkOutputMetadata,Vt as buildToolResultTimelineActionInfo,Vn as cleanupSdkSessionByAgentId,Pt as countTerminalOutputLines,Ue as createTerminalOutputDecoder,oe as decodeTerminalOutputChunk,Nt as evaluatePersistedSessionReuse,Mt as formatCommandInactivityTimeoutNotice,Et as formatCommandOutputSpilloverNotice,Gt as formatSdkOutputEvent,Se as formatTerminalPrompt,xt as normalizeTerminalCommandInput,_t as parseRuntimeStopOptions,jt as parseTerminalDirectoryChangeTarget,ue as raceSendOutputWithRetry,bt as resolveRuntimeContextResetSupport,mn as resolveRuntimeStatusFromProviderEvent,zt as resolveSdkInputMessage,Fe as resolveSdkProviderId,se as resolveSdkSessionDisplayStatus,$t as resolveStatusChangeRuntimeState,re as resolveStatusChangeUsage,Lt as resolveTerminalOutputEncoding,p as sdkSessions,Ct as shouldProbeSdkProcessPid,A as terminalRouter};
54
54
 
@@ -0,0 +1,18 @@
1
+
2
+ import type { IncomingMessage } from "node:http";
3
+ import type { Socket } from "node:net";
4
+ import type { NextFunction, Request, Response } from "express";
5
+
6
+ export declare function parseAllowIps(raw: unknown): string[];
7
+
8
+ export declare function isValidIpEntry(entry: string): boolean;
9
+
10
+ export declare function isIpAllowed(clientIp: string, entries: string[]): boolean;
11
+
12
+ export declare function getAccessControlEntries(): string[];
13
+
14
+ export declare function refreshAccessControlCache(): void;
15
+
16
+ export declare function accessControlMiddleware(req: Request, res: Response, next: NextFunction): void;
17
+
18
+ export declare function isUpgradeAllowed(request: IncomingMessage, socket: Socket): boolean;
@@ -0,0 +1,5 @@
1
+ import{existsSync as S,readFileSync as w,statSync as C}from"node:fs";import f from"node:net";import{getAutoRegisterConfigFilePath as $}from"./auto-register.js";import{createLogger as y}from"../utils/logger.js";const p=y("access-control"),I=new Set(["0.0.0.0","*"]);function P(n){const[t,r,e,s]=n.split(".").map(Number);return BigInt(t)<<24n|BigInt(r)<<16n|BigInt(e)<<8n|BigInt(s)}function b(n){let t=n;const r=t.lastIndexOf(":"),e=t.slice(r+1);if(e.includes(".")){if(!f.isIPv4(e))return null;t=`${t.slice(0,r+1)}0:0`}const s=(t.match(/::/g)||[]).length;if(s>1)return null;if(s===1){const l=t.indexOf("::"),d=t.slice(0,l)?t.slice(0,l).split(":").filter(Boolean):[],a=t.slice(l+2)?t.slice(l+2).split(":").filter(Boolean):[],g=8-d.length-a.length;if(g<1)return null;t=[...d,...Array(g).fill("0"),...a].join(":")}const i=t.split(":");if(i.length!==8)return null;let o=0n;for(const l of i){if(!/^[0-9a-fA-F]{1,4}$/.test(l))return null;o=o<<16n|BigInt(parseInt(l,16))}return o}function m(n){return f.isIPv4(n)?P(n):f.isIPv6(n)?b(n):null}function u(n){let t=String(n||"").trim();const r=t.indexOf("%");r!==-1&&(t=t.slice(0,r));const e=t.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i);return e&&f.isIPv4(e[1])?e[1]:t}function h(n){const t=String(n.socket?.remoteAddress||""),r=u(t);if(r==="127.0.0.1"||r==="::1"){const e=n.headers?.["x-forwarded-for"];if(typeof e=="string"&&e.trim()){const s=e.split(",").map(i=>u(i.trim())).filter(Boolean);for(let i=s.length-1;i>=0;i--){const o=s[i];if(o&&!x(o)&&m(o)!==null)return o}}}return t}function x(n){return n==="::1"||/^127\./.test(n)}function v(n,t,r){const e=n.lastIndexOf("/");let s=n.slice(0,e),i=Number(n.slice(e+1));const o=s.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i);if(o){if(r!==32||i<96)return!1;s=o[1],i=i-96}const l=m(s);if(l===null||!Number.isInteger(i)||i<0||i>r||(s.includes(":")?128:32)!==r)return!1;const a=BigInt(r-i);return t>>a===l>>a}function N(n){let t;if(typeof n=="string")t=n.split(/[\n,;]+/);else if(Array.isArray(n))t=n.map(s=>String(s));else return[];const r=new Set,e=[];for(const s of t){const i=s.trim();!i||r.has(i)||(r.add(i),e.push(i))}return e}function E(n){const t=String(n||"").trim();if(!t)return!1;if(I.has(t))return!0;const r=t.lastIndexOf("/");if(r===-1)return f.isIP(t)!==0;const e=t.slice(0,r),s=Number(t.slice(r+1));if(f.isIP(e)===0||!/^\d+$/.test(t.slice(r+1)))return!1;const i=e.includes(":")?128:32;return Number.isInteger(s)&&s>=0&&s<=i}function B(n,t){const r=(t||[]).map(o=>u(String(o||"").trim())).filter(Boolean);if(r.length===0||r.some(o=>I.has(o)))return!0;const e=u(n);if(x(e))return!0;const s=m(e);if(s===null)return!1;const i=e.includes(":")?128:32;return r.some(o=>o===e||o.includes("/")&&v(o,s,i))}let c=null;function A(){try{const n=$();if(!S(n))return[];const t=C(n).mtimeMs;if(c&&c.mtimeMs===t)return c.entries;const r=JSON.parse(w(n,"utf-8")),e=N(r?.accessControl?.allowIps);return c={mtimeMs:t,entries:e},e}catch(n){return p.warn(`[access-control] \u8BFB\u53D6 config.json \u5931\u8D25\uFF0C\u6CBF\u7528\u7F13\u5B58${c?"":"\uFF08\u65E0\u7F13\u5B58\uFF0C\u9ED8\u8BA4\u5168\u653E\u884C\uFF09"}: ${n.message}`),c?.entries??[]}}function F(){c=null}function M(n,t,r){const e=A(),s=h(n);if(!B(s,e)){p.warn(`[access-control] \u62D2\u7EDD\u6765\u81EA ${u(s)||"unknown"} \u7684\u8BF7\u6C42: ${n.method} ${n.originalUrl||n.url}`),t.status(403).json({ok:!1,error:"access denied: client IP is not allowed"});return}r()}function j(n,t){const r=A(),e=h(n);if(B(e,r))return!0;p.warn(`[access-control] \u62D2\u7EDD\u6765\u81EA ${u(e)||"unknown"} \u7684 WebSocket \u8FDE\u63A5: ${n.url}`);try{t.write(`HTTP/1.1 403 Forbidden\r
2
+ Connection: close\r
3
+ \r
4
+ `)}catch{}return t.destroy(),!1}export{M as accessControlMiddleware,A as getAccessControlEntries,B as isIpAllowed,j as isUpgradeAllowed,E as isValidIpEntry,N as parseAllowIps,F as refreshAccessControlCache};
5
+
@@ -1,2 +1,2 @@
1
- import{execSync as I}from"node:child_process";import k from"node:os";import{createLogger as S}from"../utils/logger.js";import{getProcessRegistry as R}from"./process-registry.js";import{isProcessRunning as l,findClaudeCodeProcesses as y,findOrphanProcessByAgentId as $,terminateProcessTree as g,waitForProcessExit as m,checkProcessHealth as v}from"./process-detector.js";import{loadPersistedSessions as w}from"./terminal-persistence.js";const r=S("agent-process-manager");class p{constructor(){this.registry=R()}static getInstance(){return p.instance===null&&(p.instance=new p),p.instance}async startProcess(e){const{agentId:s,sessionId:t,pid:a,mode:o,workspacePath:n,command:i}=e;if(r.info(`[startProcess] Starting process: agentId=${s}, pid=${a}, mode=${o}`),await this.registry.register({agentId:s,sessionId:t,pid:a,mode:o,state:"creating",workspacePath:n,command:i}),r.debug(`[startProcess] Verifying process is running: pid=${a}`),!l(a))throw r.error(`[startProcess] Process not running after registration: agentId=${s}, pid=${a}`),await this.registry.markTerminated(s),new Error(`Process ${a} is not running`);await this.registry.update(s,{state:"running"}),await this.registry.updateHeartbeat(s),r.info(`[startProcess] Process started successfully: agentId=${s}, pid=${a}`)}async discoverAllProcesses(){r.debug("[discoverAllProcesses] Scanning for all agent processes");const e=await y(),s=this.registry.getAll(),t=[],a=new Set(s.map(i=>i.pid)),o=new Set(s.map(i=>i.agentId)),n=new Map(s.map(i=>[i.pid,i]));for(const i of e){const d=a.has(i.pid),c=i.agentId&&o.has(i.agentId),h=n.get(i.pid),u=i.agentId||h?.agentId;if(d||c){const P=s.find(f=>f.pid===i.pid||f.agentId===i.agentId||f.agentId===u);t.push({...i,agentId:u,managementStatus:"managed",sessionId:P?.sessionId})}else u?t.push({...i,agentId:u,managementStatus:"orphan"}):t.push({...i,agentId:u,managementStatus:"unknown"})}for(const i of s)if(!t.find(c=>c.pid===i.pid)){const c=l(i.pid);t.push({pid:i.pid,command:i.command,agentId:i.agentId,managementStatus:c?"managed":"orphan",sessionId:i.sessionId})}return r.debug(`[discoverAllProcesses] Discovered ${t.length} processes: ${t.filter(i=>i.managementStatus==="managed").length} managed, ${t.filter(i=>i.managementStatus==="orphan").length} orphans, ${t.filter(i=>i.managementStatus==="unknown").length} unknown`),t}async healthCheckAll(){r.debug("[healthCheckAll] Starting health check for all processes");const e=new Map,s=this.registry.getAll(),t=s.map(async a=>{const o=await this.healthCheck(a.agentId);return e.set(a.agentId,o),o});return await Promise.all(t),r.debug(`[healthCheckAll] Completed health check for ${s.length} processes`),e}async healthCheck(e){const s=this.registry.get(e);if(!s)return r.warn(`[healthCheck] Process not found in registry: agentId=${e}`),{pid:-1,agentId:e,alive:!1,cpu:0,memoryMB:0,status:"dead",lastUpdate:new Date};const t=await v(s.pid,e),a={cpu:t.cpu,memoryMB:t.memoryMB,status:t.status};return await this.registry.updateHealth(e,a),t.alive?await this.registry.updateHeartbeat(e):s.state!=="terminated"&&s.state!=="orphaned"&&(r.warn(`[healthCheck] Process died unexpectedly: agentId=${e}, pid=${s.pid}`),await this.registry.markOrphaned(e)),t}async stopProcess(e){const s=this.registry.get(e);if(!s)return{success:!1,agentId:e,pid:-1,level:0,terminated:0,failed:0,message:`Process not found in registry: ${e}`};const{pid:t}=s;if(r.info(`[stopProcess] Stopping process: agentId=${e}, pid=${t}`),!l(t))return r.info(`[stopProcess] Process already stopped: agentId=${e}, pid=${t}`),await this.registry.markTerminated(e),{success:!0,agentId:e,pid:t,level:0,terminated:1,failed:0,message:"Process was already stopped"};if(await this.registry.update(e,{state:"stopping"}),r.debug(`[stopProcess] Level 1: Sending SIGTERM to pid=${t}`),this.sendSigterm(t)&&await m(t,3e3))return await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 1: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:1,terminated:1,failed:0,message:"Process terminated with SIGTERM"};if(r.debug(`[stopProcess] Level 2: Force killing pid=${t}`),this.sendForceKill(t)&&await m(t,3e3))return await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 2: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:2,terminated:1,failed:0,message:"Process terminated with force kill"};r.debug(`[stopProcess] Level 3: Terminating process tree for pid=${t}`);const n=await g(t);return await m(t,5e3)?(await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 3: agentId=${e}, pid=${t}, terminated=${n.terminated}, failed=${n.failed}`),{success:!0,agentId:e,pid:t,level:3,terminated:n.terminated,failed:n.failed,message:`Process tree terminated (${n.terminated} processes)`}):(r.error(`[stopProcess] Level 4: Process is unstoppable: agentId=${e}, pid=${t}`),(l(t)?"still running":"terminated")==="terminated"?(await this.registry.markTerminated(e),{success:!0,agentId:e,pid:t,level:4,terminated:1,failed:0,message:"Process eventually terminated after all escalation levels"}):{success:!1,agentId:e,pid:t,level:4,terminated:n.terminated,failed:n.failed+1,message:"Process could not be terminated - marked as unstoppable"})}sendSigterm(e){try{return process.kill(e,"SIGTERM"),!0}catch(s){return r.debug(`[sendSigterm] Failed to send SIGTERM to ${e}:`,s),!1}}sendForceKill(e){try{return k.platform()==="win32"?I(`taskkill /PID ${e} /F`,{encoding:"utf8",timeout:5e3,windowsHide:!0}):process.kill(e,"SIGKILL"),!0}catch(s){return r.debug(`[sendForceKill] Failed to force kill ${e}:`,s),!1}}async forceKill(e){const s=this.registry.get(e);if(!s)return{success:!1,agentId:e,pid:-1,level:0,terminated:0,failed:0,message:`Process not found in registry: ${e}`};const{pid:t}=s;r.info(`[forceKill] Force killing process: agentId=${e}, pid=${t}`),await this.registry.update(e,{state:"stopping"});const a=await g(t);return await m(t,2e3)?(await this.registry.markTerminated(e),r.info(`[forceKill] Process terminated: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:3,terminated:a.terminated,failed:a.failed,message:`Process force killed (${a.terminated} processes terminated)`}):(r.error(`[forceKill] Process could not be force killed: agentId=${e}, pid=${t}`),{success:!1,agentId:e,pid:t,level:3,terminated:a.terminated,failed:a.failed+1,message:"Force kill failed - process may require manual intervention"})}async reclaimOrphan(e){if(r.info(`[reclaimOrphan] Attempting to reclaim orphan: agentId=${e}`),this.registry.isManaged(e)){const o=this.registry.get(e);return o?(r.info(`[reclaimOrphan] Process already managed: agentId=${e}, pid=${o.pid}`),{success:!0,pid:o.pid,action:"adopted"}):{success:!1,pid:-1,action:"failed"}}const s=await $(e);if(!s)return r.warn(`[reclaimOrphan] No orphan process found: agentId=${e}`),{success:!1,pid:-1,action:"failed"};if(!l(s.pid))return r.warn(`[reclaimOrphan] Orphan process not running: agentId=${e}, pid=${s.pid}`),{success:!1,pid:s.pid,action:"failed"};if(this.registry.isManagedByPid(s.pid)){const o=this.registry.getByPid(s.pid);if(!o)try{const i=(await w()).find(d=>d.agentId===e);return await this.registry.register({agentId:e,sessionId:i?.sessionId||`reclaimed-${Date.now()}`,pid:s.pid,mode:"sdk",state:"running",workspacePath:i?.workspacePath||s.cwd||"",command:s.command||i?.command||"",metadata:{reclaimedAt:new Date().toISOString(),wasOrphan:!0}}),{success:!0,pid:s.pid,action:"adopted"}}catch{return await g(s.pid),{success:!1,pid:s.pid,action:"terminated"}}return r.warn(`[reclaimOrphan] PID already managed by different agent: pid=${s.pid}, existingAgentId=${o.agentId}`),o.agentId===e?{success:!0,pid:s.pid,action:"adopted"}:(r.warn(`[reclaimOrphan] Terminating conflicting orphan: agentId=${e}, pid=${s.pid}`),await g(s.pid),{success:!0,pid:s.pid,action:"terminated"})}const a=(await w()).find(o=>o.agentId===e);try{return await this.registry.register({agentId:e,sessionId:a?.sessionId||`reclaimed-${Date.now()}`,pid:s.pid,mode:"sdk",state:"running",workspacePath:a?.workspacePath||s.cwd||"",command:s.command||a?.command||"",metadata:{reclaimedAt:new Date().toISOString(),wasOrphan:!0}}),r.info(`[reclaimOrphan] Successfully adopted orphan: agentId=${e}, pid=${s.pid}`),{success:!0,pid:s.pid,action:"adopted"}}catch(o){return r.error(`[reclaimOrphan] Failed to adopt orphan: agentId=${e}, pid=${s.pid}`,o),await g(s.pid),{success:!1,pid:s.pid,action:"terminated"}}}async scanAndReclaimAll(){r.info("[scanAndReclaimAll] Scanning for all orphan processes");const e=[],s=await w(),t=await y(),a=new Set(this.registry.getAll().map(n=>n.pid)),o=t.filter(n=>a.has(n.pid)?!1:!!(n.agentId&&!this.registry.isManaged(n.agentId)));r.info(`[scanAndReclaimAll] Found ${o.length} orphan processes`);for(const n of o){if(!n.agentId){r.warn(`[scanAndReclaimAll] Orphan without agentId, terminating: pid=${n.pid}`),await g(n.pid),e.push({agentId:"unknown",pid:n.pid,action:"terminated"});continue}const i=await this.reclaimOrphan(n.agentId);e.push({agentId:n.agentId,pid:i.pid,action:i.action})}for(const n of s)if(n.agentId&&!this.registry.isManaged(n.agentId)&&await $(n.agentId)){const d=await this.reclaimOrphan(n.agentId);e.find(h=>h.agentId===n.agentId)||e.push({agentId:n.agentId,pid:d.pid,action:d.action})}return r.info(`[scanAndReclaimAll] Reclamation complete: ${e.length} processes processed`),e}async markOrphaned(e){return r.info(`[markOrphaned] Marking process as orphaned: agentId=${e}`),await this.registry.markOrphaned(e)}isManaged(e){return this.registry.isManaged(e)}getAllManagedProcesses(){return this.registry.getAll()}getManagedProcessesByState(e){return this.registry.getByState(e)}async getUnmanagedProcesses(){const e=await y(),s=new Set(this.registry.getAll().map(a=>a.pid)),t=new Set(this.registry.getAll().map(a=>a.agentId));return e.filter(a=>!(s.has(a.pid)||a.agentId&&t.has(a.agentId)))}async rebuildRegistry(e){r.info(`[rebuildRegistry] Rebuilding registry from ${e.length} persisted sessions`),await this.registry.clear();for(const t of e){if(!t.pid){r.debug(`[rebuildRegistry] Skipping session without PID: agentId=${t.agentId}`);continue}const a=l(t.pid),o=a?"running":"unknown";try{await this.registry.register({agentId:t.agentId,sessionId:t.sessionId,pid:t.pid,mode:"sdk",state:o,workspacePath:t.workspacePath||"",command:t.command||"",metadata:{rebuiltAt:new Date().toISOString(),wasRunningOnStartup:a}}),r.debug(`[rebuildRegistry] Registered: agentId=${t.agentId}, pid=${t.pid}, state=${o}`)}catch(n){r.warn(`[rebuildRegistry] Failed to register: agentId=${t.agentId}`,n)}}const s=this.registry.getStats();r.info(`[rebuildRegistry] Registry rebuilt: total=${s.total}, running=${s.running}, unknown=${s.unknown}`)}getStats(){return this.registry.getStats()}async cleanupStaleRegistry(){const e=this.registry.getAll();let s=0;for(const t of e)(t.state==="terminated"||t.state==="unknown")&&!l(t.pid)&&(await this.registry.remove(t.agentId),s++,r.debug(`[cleanupStaleRegistry] Removed stale entry: agentId=${t.agentId}, pid=${t.pid}, state=${t.state}`));return s>0&&r.info(`[cleanupStaleRegistry] Cleaned up ${s} stale registry entries`),s}async removeProcess(e){return r.info(`[removeProcess] Removing process from registry: agentId=${e}`),await this.registry.remove(e)}getProcess(e){return this.registry.get(e)}getProcessByPid(e){return this.registry.getByPid(e)}}p.instance=null;function T(){return p.getInstance()}export{p as AgentProcessManager,T as getAgentProcessManager};
1
+ import{execSync as R}from"node:child_process";import v from"node:os";import{createLogger as A}from"../utils/logger.js";import{getProcessRegistry as b}from"./process-registry.js";import{isProcessRunning as p,isProcessRunningAsync as O,findClaudeCodeProcesses as w,findOrphanProcessByAgentId as I,terminateProcessTree as u,waitForProcessExit as f,checkProcessHealth as M}from"./process-detector.js";import{loadPersistedSessions as $}from"./terminal-persistence.js";const r=A("agent-process-manager");async function x(h,e,s){const t=new Array(h.length);let i=0;const o=Math.min(Math.max(e,1),h.length),a=Array.from({length:o},async()=>{for(;i<h.length;){const d=i++;t[d]=await s(h[d])}});return await Promise.all(a),t}class g{constructor(){this.registry=b()}static getInstance(){return g.instance===null&&(g.instance=new g),g.instance}async startProcess(e){const{agentId:s,sessionId:t,pid:i,mode:o,workspacePath:a,command:d}=e;if(r.info(`[startProcess] Starting process: agentId=${s}, pid=${i}, mode=${o}`),await this.registry.register({agentId:s,sessionId:t,pid:i,mode:o,state:"creating",workspacePath:a,command:d}),r.debug(`[startProcess] Verifying process is running: pid=${i}`),!p(i))throw r.error(`[startProcess] Process not running after registration: agentId=${s}, pid=${i}`),await this.registry.markTerminated(s),new Error(`Process ${i} is not running`);await this.registry.update(s,{state:"running"}),await this.registry.updateHeartbeat(s),r.info(`[startProcess] Process started successfully: agentId=${s}, pid=${i}`)}async discoverAllProcesses(){r.debug("[discoverAllProcesses] Scanning for all agent processes");const e=await w(),s=this.registry.getAll(),t=[],i=new Set(s.map(n=>n.pid)),o=new Set(s.map(n=>n.agentId)),a=new Map(s.map(n=>[n.pid,n]));for(const n of e){const l=i.has(n.pid),P=n.agentId&&o.has(n.agentId),k=a.get(n.pid),m=n.agentId||k?.agentId;if(l||P){const S=s.find(y=>y.pid===n.pid||y.agentId===n.agentId||y.agentId===m);t.push({...n,agentId:m,managementStatus:"managed",sessionId:S?.sessionId})}else m?t.push({...n,agentId:m,managementStatus:"orphan"}):t.push({...n,agentId:m,managementStatus:"unknown"})}const d=s.filter(n=>!t.some(l=>l.pid===n.pid)),c=await x(d,4,async n=>{const l=await O(n.pid);return{pid:n.pid,command:n.command,agentId:n.agentId,managementStatus:l?"managed":"orphan",sessionId:n.sessionId}});return t.push(...c),r.debug(`[discoverAllProcesses] Discovered ${t.length} processes: ${t.filter(n=>n.managementStatus==="managed").length} managed, ${t.filter(n=>n.managementStatus==="orphan").length} orphans, ${t.filter(n=>n.managementStatus==="unknown").length} unknown`),t}async healthCheckAll(){r.debug("[healthCheckAll] Starting health check for all processes");const e=new Map,s=this.registry.getAll(),t=s.map(async i=>{const o=await this.healthCheck(i.agentId);return e.set(i.agentId,o),o});return await Promise.all(t),r.debug(`[healthCheckAll] Completed health check for ${s.length} processes`),e}async healthCheck(e){const s=this.registry.get(e);if(!s)return r.warn(`[healthCheck] Process not found in registry: agentId=${e}`),{pid:-1,agentId:e,alive:!1,cpu:0,memoryMB:0,status:"dead",lastUpdate:new Date};const t=await M(s.pid,e),i={cpu:t.cpu,memoryMB:t.memoryMB,status:t.status};return await this.registry.updateHealth(e,i),t.alive?await this.registry.updateHeartbeat(e):s.state!=="terminated"&&s.state!=="orphaned"&&(r.warn(`[healthCheck] Process died unexpectedly: agentId=${e}, pid=${s.pid}`),await this.registry.markOrphaned(e)),t}async stopProcess(e){const s=this.registry.get(e);if(!s)return{success:!1,agentId:e,pid:-1,level:0,terminated:0,failed:0,message:`Process not found in registry: ${e}`};const{pid:t}=s;if(r.info(`[stopProcess] Stopping process: agentId=${e}, pid=${t}`),!p(t))return r.info(`[stopProcess] Process already stopped: agentId=${e}, pid=${t}`),await this.registry.markTerminated(e),{success:!0,agentId:e,pid:t,level:0,terminated:1,failed:0,message:"Process was already stopped"};if(await this.registry.update(e,{state:"stopping"}),r.debug(`[stopProcess] Level 1: Sending SIGTERM to pid=${t}`),this.sendSigterm(t)&&await f(t,3e3))return await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 1: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:1,terminated:1,failed:0,message:"Process terminated with SIGTERM"};if(r.debug(`[stopProcess] Level 2: Force killing pid=${t}`),this.sendForceKill(t)&&await f(t,3e3))return await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 2: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:2,terminated:1,failed:0,message:"Process terminated with force kill"};r.debug(`[stopProcess] Level 3: Terminating process tree for pid=${t}`);const a=await u(t);return await f(t,5e3)?(await this.registry.markTerminated(e),r.info(`[stopProcess] Process stopped at Level 3: agentId=${e}, pid=${t}, terminated=${a.terminated}, failed=${a.failed}`),{success:!0,agentId:e,pid:t,level:3,terminated:a.terminated,failed:a.failed,message:`Process tree terminated (${a.terminated} processes)`}):(r.error(`[stopProcess] Level 4: Process is unstoppable: agentId=${e}, pid=${t}`),(p(t)?"still running":"terminated")==="terminated"?(await this.registry.markTerminated(e),{success:!0,agentId:e,pid:t,level:4,terminated:1,failed:0,message:"Process eventually terminated after all escalation levels"}):{success:!1,agentId:e,pid:t,level:4,terminated:a.terminated,failed:a.failed+1,message:"Process could not be terminated - marked as unstoppable"})}sendSigterm(e){try{return process.kill(e,"SIGTERM"),!0}catch(s){return r.debug(`[sendSigterm] Failed to send SIGTERM to ${e}:`,s),!1}}sendForceKill(e){try{return v.platform()==="win32"?R(`taskkill /PID ${e} /F`,{encoding:"utf8",timeout:5e3,windowsHide:!0}):process.kill(e,"SIGKILL"),!0}catch(s){return r.debug(`[sendForceKill] Failed to force kill ${e}:`,s),!1}}async forceKill(e){const s=this.registry.get(e);if(!s)return{success:!1,agentId:e,pid:-1,level:0,terminated:0,failed:0,message:`Process not found in registry: ${e}`};const{pid:t}=s;r.info(`[forceKill] Force killing process: agentId=${e}, pid=${t}`),await this.registry.update(e,{state:"stopping"});const i=await u(t);return await f(t,2e3)?(await this.registry.markTerminated(e),r.info(`[forceKill] Process terminated: agentId=${e}, pid=${t}`),{success:!0,agentId:e,pid:t,level:3,terminated:i.terminated,failed:i.failed,message:`Process force killed (${i.terminated} processes terminated)`}):(r.error(`[forceKill] Process could not be force killed: agentId=${e}, pid=${t}`),{success:!1,agentId:e,pid:t,level:3,terminated:i.terminated,failed:i.failed+1,message:"Force kill failed - process may require manual intervention"})}async reclaimOrphan(e){if(r.info(`[reclaimOrphan] Attempting to reclaim orphan: agentId=${e}`),this.registry.isManaged(e)){const o=this.registry.get(e);return o?(r.info(`[reclaimOrphan] Process already managed: agentId=${e}, pid=${o.pid}`),{success:!0,pid:o.pid,action:"adopted"}):{success:!1,pid:-1,action:"failed"}}const s=await I(e);if(!s)return r.warn(`[reclaimOrphan] No orphan process found: agentId=${e}`),{success:!1,pid:-1,action:"failed"};if(!p(s.pid))return r.warn(`[reclaimOrphan] Orphan process not running: agentId=${e}, pid=${s.pid}`),{success:!1,pid:s.pid,action:"failed"};if(this.registry.isManagedByPid(s.pid)){const o=this.registry.getByPid(s.pid);if(!o)try{const d=(await $()).find(c=>c.agentId===e);return await this.registry.register({agentId:e,sessionId:d?.sessionId||`reclaimed-${Date.now()}`,pid:s.pid,mode:"sdk",state:"running",workspacePath:d?.workspacePath||s.cwd||"",command:s.command||d?.command||"",metadata:{reclaimedAt:new Date().toISOString(),wasOrphan:!0}}),{success:!0,pid:s.pid,action:"adopted"}}catch{return await u(s.pid),{success:!1,pid:s.pid,action:"terminated"}}return r.warn(`[reclaimOrphan] PID already managed by different agent: pid=${s.pid}, existingAgentId=${o.agentId}`),o.agentId===e?{success:!0,pid:s.pid,action:"adopted"}:(r.warn(`[reclaimOrphan] Terminating conflicting orphan: agentId=${e}, pid=${s.pid}`),await u(s.pid),{success:!0,pid:s.pid,action:"terminated"})}const i=(await $()).find(o=>o.agentId===e);try{return await this.registry.register({agentId:e,sessionId:i?.sessionId||`reclaimed-${Date.now()}`,pid:s.pid,mode:"sdk",state:"running",workspacePath:i?.workspacePath||s.cwd||"",command:s.command||i?.command||"",metadata:{reclaimedAt:new Date().toISOString(),wasOrphan:!0}}),r.info(`[reclaimOrphan] Successfully adopted orphan: agentId=${e}, pid=${s.pid}`),{success:!0,pid:s.pid,action:"adopted"}}catch(o){return r.error(`[reclaimOrphan] Failed to adopt orphan: agentId=${e}, pid=${s.pid}`,o),await u(s.pid),{success:!1,pid:s.pid,action:"terminated"}}}async scanAndReclaimAll(){r.info("[scanAndReclaimAll] Scanning for all orphan processes");const e=[],s=await $(),t=await w(),i=new Set(this.registry.getAll().map(a=>a.pid)),o=t.filter(a=>i.has(a.pid)?!1:!!(a.agentId&&!this.registry.isManaged(a.agentId)));r.info(`[scanAndReclaimAll] Found ${o.length} orphan processes`);for(const a of o){if(!a.agentId){r.warn(`[scanAndReclaimAll] Orphan without agentId, terminating: pid=${a.pid}`),await u(a.pid),e.push({agentId:"unknown",pid:a.pid,action:"terminated"});continue}const d=await this.reclaimOrphan(a.agentId);e.push({agentId:a.agentId,pid:d.pid,action:d.action})}for(const a of s)if(a.agentId&&!this.registry.isManaged(a.agentId)&&await I(a.agentId)){const c=await this.reclaimOrphan(a.agentId);e.find(l=>l.agentId===a.agentId)||e.push({agentId:a.agentId,pid:c.pid,action:c.action})}return r.info(`[scanAndReclaimAll] Reclamation complete: ${e.length} processes processed`),e}async markOrphaned(e){return r.info(`[markOrphaned] Marking process as orphaned: agentId=${e}`),await this.registry.markOrphaned(e)}isManaged(e){return this.registry.isManaged(e)}getAllManagedProcesses(){return this.registry.getAll()}getManagedProcessesByState(e){return this.registry.getByState(e)}async getUnmanagedProcesses(){const e=await w(),s=new Set(this.registry.getAll().map(i=>i.pid)),t=new Set(this.registry.getAll().map(i=>i.agentId));return e.filter(i=>!(s.has(i.pid)||i.agentId&&t.has(i.agentId)))}async rebuildRegistry(e){r.info(`[rebuildRegistry] Rebuilding registry from ${e.length} persisted sessions`),await this.registry.clear();for(const t of e){if(!t.pid){r.debug(`[rebuildRegistry] Skipping session without PID: agentId=${t.agentId}`);continue}const i=p(t.pid),o=i?"running":"unknown";try{await this.registry.register({agentId:t.agentId,sessionId:t.sessionId,pid:t.pid,mode:"sdk",state:o,workspacePath:t.workspacePath||"",command:t.command||"",metadata:{rebuiltAt:new Date().toISOString(),wasRunningOnStartup:i}}),r.debug(`[rebuildRegistry] Registered: agentId=${t.agentId}, pid=${t.pid}, state=${o}`)}catch(a){r.warn(`[rebuildRegistry] Failed to register: agentId=${t.agentId}`,a)}}const s=this.registry.getStats();r.info(`[rebuildRegistry] Registry rebuilt: total=${s.total}, running=${s.running}, unknown=${s.unknown}`)}getStats(){return this.registry.getStats()}async cleanupStaleRegistry(){const e=this.registry.getAll();let s=0;for(const t of e)(t.state==="terminated"||t.state==="unknown")&&!p(t.pid)&&(await this.registry.remove(t.agentId),s++,r.debug(`[cleanupStaleRegistry] Removed stale entry: agentId=${t.agentId}, pid=${t.pid}, state=${t.state}`));return s>0&&r.info(`[cleanupStaleRegistry] Cleaned up ${s} stale registry entries`),s}async removeProcess(e){return r.info(`[removeProcess] Removing process from registry: agentId=${e}`),await this.registry.remove(e)}getProcess(e){return this.registry.get(e)}getProcessByPid(e){return this.registry.getByPid(e)}}g.instance=null;function L(){return g.getInstance()}export{g as AgentProcessManager,L as getAgentProcessManager};
2
2
 
@@ -1,2 +1,2 @@
1
- import{v4 as M}from"uuid";import R from"axios";import m from"node:os";import F from"node:path";import g from"node:fs";import{logger as i}from"../utils/logger.js";import{schedulerBaseUrl as u}from"../config.js";import{clearRuntimeBinding as z,clearScopedRuntimeAccessToken as J,getRuntimeAccessToken as h,getRuntimeBindingPublicState as w,getScopedRuntimeAccessToken as Y,loadRuntimeBinding as v,normalizeSchedulerBaseUrl as I,saveRuntimeBinding as K,saveScopedRuntimeAccessToken as q}from"./runtime-binding.js";const C={enabled:!1,serverUrl:u,preferSameLanIp:!0,maxRetries:3,retryInterval:2e3};let c={registered:!1,registrations:{}},b=[];function Re(){return[...b]}const H=3e4;function P(){const e=Number(process.env.AWS_REGISTER_BACKGROUND_RETRY_INTERVAL);return Number.isFinite(e)&&e>0?e:H}const A=new Map;function W(e){const r=e.serverUrl||u,t=I(r)||r;if(A.has(t))return;const n=setTimeout(()=>{A.delete(t),V(e,t)},P());n.unref?.(),A.set(t,n)}async function V(e,r){try{const t=S().find(n=>(I(n.serverUrl||u)||n.serverUrl||u)===r)||e;await $(t,{backgroundRetry:!0})}catch(t){i.warn(`[AutoRegister] \u540E\u53F0\u91CD\u8BD5\u6CE8\u518C\u5F02\u5E38: ${t.message}`),W(e)}}function Ae(){for(const e of A.values())clearTimeout(e);A.clear()}function d(e){return e==null?void 0:String(e).trim()||void 0}function L(e){return I(e)}function T(e){if(typeof e=="boolean")return e;if(typeof e=="string"){const r=e.trim().toLowerCase();if(["true","1","yes","y"].includes(r))return!0;if(["false","0","no","n"].includes(r))return!1}}function O(e){if(e==null||e==="")return;const r=Number(e);return Number.isFinite(r)?r:void 0}function N(e){const r=d(e.serverUrl)||d(e.schedulerBaseUrl),t=d(e.connectionKey)||d(e.password);return{enabled:T(e.enabled),serverUrl:r,tenantId:d(e.tenantId),userKey:d(e.userKey),connectionKey:t,instanceName:d(e.instanceName),instanceId:d(e.instanceId),projectId:d(e.projectId),roleName:d(e.roleName),workspacePath:d(e.workspacePath),registerAddr:d(e.registerAddr),registerIp:d(e.registerIp),virtualIp:d(e.virtualIp),tunnel:T(e.tunnel),preferSameLanIp:T(e.preferSameLanIp),maxRetries:O(e.maxRetries),retryInterval:O(e.retryInterval)}}function k(){const e=String(process.env.AWS_RUNTIME_HOME_DIR||"").trim()||m.homedir();return F.join(e,".aws-bridge","config.json")}function x(){const e=k();try{if(!g.existsSync(e))return i.debug(`[AutoRegister] \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728: ${e}`),null;const r=g.readFileSync(e,"utf-8"),t=JSON.parse(r);return i.info(`[AutoRegister] \u4ECE\u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u914D\u7F6E: ${e}`),N(t)}catch(r){const t=r;return i.warn(`[AutoRegister] \u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6\u5931\u8D25: ${e}, error: ${t.message}`),null}}function X(){const e=k();try{if(!g.existsSync(e))return[];const r=g.readFileSync(e,"utf-8"),t=JSON.parse(r),n=N(t),o=Array.isArray(t.autoRegisterTargets)?t.autoRegisterTargets:[];return o.length===0?n.userKey?[n]:[]:o.filter(s=>!!(s&&typeof s=="object"&&!Array.isArray(s))).map(s=>{const a=N(s);return{...n,...a,connectionKey:a.connectionKey||n.connectionKey}})}catch(r){const t=r;return i.warn(`[AutoRegister] \u8BFB\u53D6\u81EA\u52A8\u6CE8\u518C\u76EE\u6807\u5931\u8D25: ${e}, error: ${t.message}`),[]}}function j(){const e={};return process.env.AWS_AUTO_REGISTER==="true"&&(e.enabled=!0),process.env.AWS_RUNTIME_SCHEDULER_BASE_URL&&(e.serverUrl=process.env.AWS_RUNTIME_SCHEDULER_BASE_URL),process.env.AWS_TENANT_ID&&(e.tenantId=process.env.AWS_TENANT_ID),process.env.AWS_USER_KEY&&(e.userKey=process.env.AWS_USER_KEY),process.env.AWS_BRIDGE_CONNECTION_KEY&&(e.connectionKey=process.env.AWS_BRIDGE_CONNECTION_KEY),process.env.AWS_INSTANCE_NAME&&(e.instanceName=process.env.AWS_INSTANCE_NAME),process.env.AWS_PROJECT_NAME&&(e.projectId=process.env.AWS_PROJECT_NAME),process.env.AWS_ROLE_NAME&&(e.roleName=process.env.AWS_ROLE_NAME),process.env.AWS_WORKSPACE_PATH&&(e.workspacePath=process.env.AWS_WORKSPACE_PATH),process.env.AWS_REGISTER_ADDR&&(e.registerAddr=process.env.AWS_REGISTER_ADDR),process.env.AWS_REGISTER_IP&&(e.registerIp=process.env.AWS_REGISTER_IP),process.env.AWS_VIRTUAL_IP&&(e.virtualIp=process.env.AWS_VIRTUAL_IP),process.env.AWS_PREFER_SAME_LAN_IP&&(e.preferSameLanIp=T(process.env.AWS_PREFER_SAME_LAN_IP)??!0),process.env.AWS_REGISTER_MAX_RETRIES&&(e.maxRetries=parseInt(process.env.AWS_REGISTER_MAX_RETRIES,10)),process.env.AWS_REGISTER_RETRY_INTERVAL&&(e.retryInterval=parseInt(process.env.AWS_REGISTER_RETRY_INTERVAL,10)),e}function _(){const e=x(),r=j(),t={...C,...e||{},...r},n=t.instanceName||m.hostname();let o=!1;return process.env.AWS_AUTO_REGISTER!==void 0?o=process.env.AWS_AUTO_REGISTER==="true":e&&(o=!0),{enabled:o,serverUrl:t.serverUrl||u,tenantId:t.tenantId||"",userKey:t.userKey||"",connectionKey:t.connectionKey,instanceName:n,instanceId:t.instanceId,projectId:t.projectId,roleName:t.roleName,workspacePath:t.workspacePath,registerAddr:t.registerAddr,registerIp:t.registerIp,virtualIp:t.virtualIp,tunnel:typeof t.tunnel=="boolean"?t.tunnel:void 0,preferSameLanIp:t.preferSameLanIp!==!1,maxRetries:t.maxRetries,retryInterval:t.retryInterval}}function S(){const e=X(),r=j(),n=(e.length>0?e:[x()||{}]).map(o=>{const s={...C,...o,...r};let a=!1;return process.env.AWS_AUTO_REGISTER!==void 0?a=process.env.AWS_AUTO_REGISTER==="true":a=e.length>0||!!s.userKey,{enabled:a,serverUrl:s.serverUrl||u,tenantId:s.tenantId||"",userKey:s.userKey||"",connectionKey:s.connectionKey,instanceName:s.instanceName||m.hostname(),instanceId:s.instanceId,projectId:s.projectId,roleName:s.roleName,workspacePath:s.workspacePath,registerAddr:s.registerAddr,registerIp:s.registerIp,virtualIp:s.virtualIp,tunnel:typeof s.tunnel=="boolean"?s.tunnel:void 0,preferSameLanIp:s.preferSameLanIp!==!1,maxRetries:s.maxRetries,retryInterval:s.retryInterval}});return b=n.map(o=>o.connectionKey).filter(o=>!!(o&&o.trim())),n}function Q(){const e=m.networkInterfaces(),r=[];for(const t of Object.keys(e)){const n=e[t];if(n)for(const o of n)o.family==="IPv4"&&!o.internal&&r.push({address:o.address,netmask:o.netmask,name:t})}return r}function B(e){const r=e.split(".").map(Number);return(r[0]<<24)+(r[1]<<16)+(r[2]<<8)+r[3]}function Z(e,r,t){const n=B(e),o=B(r),s=B(t);return(n&s)===(o&s)}function ee(e){try{const r=new URL(e);return r.hostname==="localhost"||r.hostname==="127.0.0.1"?"127.0.0.1":/^(\d{1,3}\.){3}\d{1,3}$/.test(r.hostname)?r.hostname:null}catch{return null}}function re(e){return e==="127.0.0.1"}function te(e){const r=Q();if(r.length===0)return i.warn("[AutoRegister] \u672A\u627E\u5230\u4EFB\u4F55\u975E\u5185\u90E8 IP \u5730\u5740\uFF0C\u4F7F\u7528 127.0.0.1"),"127.0.0.1";const t=ee(e);if(t){if(re(t))return"127.0.0.1";for(const n of r)if(Z(n.address,t,n.netmask))return i.info(`[AutoRegister] \u627E\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3\u540C\u5B50\u7F51\u7684 IP: ${n.address} (\u7F51\u5361: ${n.name}, \u5B50\u7F51\u63A9\u7801: ${n.netmask})`),n.address;i.warn(`[AutoRegister] \u672A\u627E\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3 (${t}) \u540C\u5B50\u7F51\u7684\u672C\u673A IP\uFF0C\u4F7F\u7528 127.0.0.1`)}else i.warn("[AutoRegister] \u65E0\u6CD5\u89E3\u6790\u8C03\u5EA6\u4E2D\u5FC3 IP\uFF0C\u4F7F\u7528 127.0.0.1");return"127.0.0.1"}function ne(e=u){return te(e)}function D(e){const r=e||_();return!r.enabled||!r.userKey?!1:r.tunnel===!0?!0:r.tunnel===!1?!1:!r.registerAddr&&!r.registerIp&&!r.virtualIp}function E(e){const r=process.env.AWS_RUNTIME_BRIDGE_PORT||18081;if(D(e)){const s=e.serverUrl||u;try{const a=new URL(s);if(!e.instanceId)i.warn("[AutoRegister] \u96A7\u9053\u6A21\u5F0F\u4F46\u7F3A\u5C11 instanceId\uFF0C\u964D\u7EA7\u4E3A\u76F4\u8FDE\u6A21\u5F0F");else return`${a.protocol}//${a.host}/tunnel/${e.instanceId}`}catch{i.warn("[AutoRegister] serverUrl \u89E3\u6790\u5931\u8D25\uFF0C\u964D\u7EA7\u4E3A\u76F4\u8FDE\u6A21\u5F0F")}}const t=e.preferSameLanIp===!1?"127.0.0.1":ne(e.serverUrl||u),n=e.registerAddr||e.registerIp||e.virtualIp||t;return n?/^https?:\/\//i.test(n)?n:/:[0-9]+$/.test(n)?`http://${n}`:`http://${n}:${r}`:`http://127.0.0.1:${r}`}function y(){return S()[0]||_()}function Se(e){const r=String(e||"").trim();if(!r)return;const t=[];for(const o of S())o?.serverUrl&&t.push(o.serverUrl);const n=v();n.schedulerBaseUrl&&t.push(n.schedulerBaseUrl);for(const o of t){const s=Y(o);if(s&&s===r)return I(o)}}function se(e){return e?Object.entries(c.registrations).find(([,t])=>t===e)?.[0]:void 0}function U(e,r){const t=se(r);if(t)return t;const n=d(e.serverUrl);if(n&&(n!==u||process.env.AWS_RUNTIME_SCHEDULER_BASE_URL))return n;const o=v(),s=d(o.schedulerBaseUrl);return o.status==="paired"&&s?s:n||u}async function oe(e){const r=e.instanceName||m.hostname(),t=e.serverUrl||u,n={tenantId:e.tenantId,userKey:e.userKey,instanceId:e.instanceId,instanceName:r,hostname:m.hostname(),virtualIp:e.registerAddr||e.registerIp||e.virtualIp,runtimeBridgeBaseUrl:E(e),connectionKey:e.connectionKey,workspacePath:e.workspacePath,projectId:e.projectId,roleName:e.roleName};return i.info(`[AutoRegister] \u6B63\u5728\u6CE8\u518C\u5B9E\u4F8B: ${r}`),i.info(`[AutoRegister] \u8C03\u5EA6\u4E2D\u5FC3: ${t}`),i.info(`[AutoRegister] \u7528\u6237 Key: ${e.userKey?"****"+e.userKey.slice(-4):"(\u672A\u8BBE\u7F6E)"}`),i.info(`[AutoRegister] \u79DF\u6237 ID: ${e.tenantId||"(\u81EA\u52A8\u63A8\u5BFC)"}`),(await R.post(`${t}/api/instances/register`,n,{headers:{"Content-Type":"application/json"},timeout:1e4})).data}let G=Promise.resolve();function ie(e,r){const t=G.then(()=>{const n=k();if(!g.existsSync(n))return;const o=g.readFileSync(n,"utf-8"),s=JSON.parse(o),a=I(e);if(!a)return;let l=!1;const f=p=>{I(String(p.serverUrl||p.schedulerBaseUrl||""))===a&&r&&p.instanceId!==r&&(p.instanceId=r,l=!0)};if(Array.isArray(s.autoRegisterTargets))for(const p of s.autoRegisterTargets)p&&typeof p=="object"&&!Array.isArray(p)&&f(p);else f(s);l&&(g.writeFileSync(n,JSON.stringify(s,null,2),"utf-8"),i.info(`[AutoRegister] \u5DF2\u56DE\u5199 instanceId \u5230 config.json (serverUrl=${e})`))});return G=t.catch(()=>{}),t}async function ae(e){const r=U(y(),e),t=v(),n=h(r);if(!n)throw new Error("runtimeAccessToken is required to unregister bridge instance");return(await R.post(`${r}/api/instances/unregister`,{instanceId:e},{headers:{"Content-Type":"application/json","X-Runtime-Token":n},timeout:1e4})).data}async function ye(e){const r=e?[{..._(),...e}]:S();return r.length>1?(await Promise.all(r.map(n=>$(n)))).every(Boolean):$(r[0]||_())}async function $(e,r){if(!e.enabled)return i.info("[AutoRegister] \u81EA\u52A8\u6CE8\u518C\u672A\u542F\u7528"),i.info("[AutoRegister] \u8981\u542F\u7528\u81EA\u52A8\u6CE8\u518C\uFF0C\u8BF7\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6 ~/.aws-bridge/config.json \u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF AWS_AUTO_REGISTER=true"),!1;if(!e.userKey)return i.error("[AutoRegister] \u7F3A\u5C11\u7528\u6237 Key\uFF08\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u8BBE\u7F6E userKey \u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF AWS_USER_KEY\uFF09"),!1;const t=D(e);t&&!e.instanceId&&(e={...e,instanceId:`bridge-${M().replace(/-/g,"").slice(0,12)}`},i.info(`[AutoRegister] \u96A7\u9053\u6A21\u5F0F\uFF1A\u5DF2\u9884\u58F0\u660E instanceId=${e.instanceId}`));const n=r?.backgroundRetry?1:e.maxRetries??3,o=e.retryInterval??2e3;for(let s=1;s<=n;s++){try{c.lastAttempt=new Date;const a=await oe(e);if(a.success){if(c.registered=!0,c.instanceId=a.instanceId,a.instanceId&&(c.registrations[e.serverUrl||u]=a.instanceId),c.error=void 0,i.info("[AutoRegister] \u2713 \u6CE8\u518C\u6210\u529F\uFF01"),i.info(`[AutoRegister] \u5B9E\u4F8B ID: ${a.instanceId}`),i.info(`[AutoRegister] \u6D88\u606F: ${a.message}`),i.info(`[AutoRegister] \u66F4\u65B0: ${a.isUpdate?"\u662F":"\u5426"}`),a.runtimeAccessToken)try{K({accessToken:a.runtimeAccessToken,instanceId:a.instanceId,userId:a.userId,schedulerBaseUrl:a.serverUrl||e.serverUrl||u}),i.info("[AutoRegister] \u5DF2\u4FDD\u5B58\u8C03\u5EA6\u4E2D\u5FC3\u4E0B\u53D1\u7684 runtime access token"),a.instanceId&&ie(e.serverUrl||u,a.instanceId).catch(l=>{i.warn(`[AutoRegister] \u56DE\u5199 instanceId \u5230 config.json \u5931\u8D25: ${l.message}`)})}catch(l){const f=l;return i.error(`[AutoRegister] \u4FDD\u5B58 runtime access token \u5931\u8D25: ${f.message}`),c.error=f.message,!1}else i.warn("[AutoRegister] \u6CE8\u518C\u54CD\u5E94\u672A\u5305\u542B runtime access token\uFF0CMCP \u5C06\u65E0\u6CD5\u8BBF\u95EE\u8C03\u5EA6\u4E2D\u5FC3\uFF0C\u8BF7\u68C0\u67E5 server \u7684 bridge \u5B9E\u4F8B token \u9881\u53D1\u903B\u8F91");if(t&&a.instanceId&&a.runtimeAccessToken){const{startTunnelClient:l}=await import("./tunnel-client.js"),f=e.serverUrl||u;l(f,a.instanceId),i.info(`[AutoRegister] \u96A7\u9053\u5BA2\u6237\u7AEF\u5DF2\u542F\u52A8: server=${f}, instanceId=${a.instanceId}`)}return!0}else i.warn(`[AutoRegister] \u6CE8\u518C\u5931\u8D25: ${a.message}`),c.error=a.message}catch(a){const l=a,f=l.response?.data?JSON.stringify(l.response.data):l.message;i.error(`[AutoRegister] \u6CE8\u518C\u8BF7\u6C42\u5931\u8D25 (\u5C1D\u8BD5 ${s}/${n}): ${f}`),c.error=f}s<n&&(i.info(`[AutoRegister] ${o/1e3} \u79D2\u540E\u91CD\u8BD5...`),await new Promise(a=>setTimeout(a,o)))}return r?.backgroundRetry?i.warn(`[AutoRegister] \u540E\u53F0\u91CD\u8BD5\u6CE8\u518C\u4ECD\u672A\u6210\u529F (server=${e.serverUrl||u}): ${c.error||"\u672A\u77E5"}`):(i.error("[AutoRegister] \u2717 \u6CE8\u518C\u5931\u8D25\uFF0C\u5DF2\u8FBE\u6700\u5927\u91CD\u8BD5\u6B21\u6570"),i.error("[AutoRegister] ========================================"),i.error("[AutoRegister] \u81EA\u52A8\u6CE8\u518C\u5DF2\u542F\u7528\u4F46\u6CE8\u518C\u5931\u8D25\uFF0C\u5B9E\u4F8B\u6682\u65F6\u65E0\u6CD5\u6B63\u5E38\u5DE5\u4F5C"),i.error("[AutoRegister] \u8BF7\u68C0\u67E5\u4EE5\u4E0B\u914D\u7F6E\uFF1A"),i.error(`[AutoRegister] - \u7528\u6237 Key (userKey): ${e.userKey?"****"+e.userKey.slice(-4):"(\u672A\u8BBE\u7F6E)"}`),i.error(`[AutoRegister] - \u79DF\u6237 ID (tenantId): ${e.tenantId||"(\u53EF\u9009\uFF0C\u5C06\u81EA\u52A8\u63A8\u5BFC)"}`),i.error(`[AutoRegister] - \u5B9E\u4F8B\u540D (instanceName): ${e.instanceName||"(\u4F7F\u7528\u4E3B\u673A\u540D)"}`),i.error(`[AutoRegister] - \u8C03\u5EA6\u4E2D\u5FC3\u5730\u5740: ${e.serverUrl||u}`),i.error(`[AutoRegister] - \u6700\u540E\u9519\u8BEF: ${c.error||"\u672A\u77E5"}`),i.error("[AutoRegister] ========================================"),i.error("[AutoRegister] \u914D\u7F6E\u6765\u6E90\uFF1A~/.aws-bridge/config.json \u6216\u73AF\u5883\u53D8\u91CF"),i.warn(`[AutoRegister] \u5C06\u5728\u540E\u53F0\u6301\u7EED\u91CD\u8BD5\u6CE8\u518C\uFF08\u6BCF ${Math.round(P()/1e3)} \u79D2\uFF09\uFF0C\u76F4\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3\u5EFA\u7ACB\u8FDE\u63A5`)),W(e),!1}async function ve(){const e=y();if(!e.userKey)return{success:!1,error:"userKey is required for runtime token refresh"};const r=w(),t=U(e),n=E(e);try{const o=await R.post(`${t}/api/instances/runtime-tokens/refresh`,{tenantId:e.tenantId,userKey:e.userKey,instanceId:r.instanceId,instanceName:e.instanceName,runtimeBridgeBaseUrl:n},{headers:{"Content-Type":"application/json"},timeout:1e4});if(!o.data.success||!o.data.runtimeAccessToken)return{success:!1,error:o.data.message||"scheduler did not return runtimeAccessToken"};const a=h()!==o.data.runtimeAccessToken;return K({accessToken:o.data.runtimeAccessToken,instanceId:r.instanceId,userId:o.data.userId||e.userKey,schedulerBaseUrl:t}),{success:!0,runtimeAccessToken:o.data.runtimeAccessToken,updated:a}}catch(o){const s=o;return{success:!1,error:s.response?.data?JSON.stringify(s.response.data):s.message}}}async function Te(e){const r=L(e);if(!r)return{success:!1,error:"serverUrl is required for runtime token refresh"};const t=S().find(s=>L(s.serverUrl)===r)||y();if(!t.userKey)return{success:!1,error:"userKey is required for runtime token refresh"};const n=w(),o=E(t);try{const s=await R.post(`${r}/api/instances/runtime-tokens/refresh`,{tenantId:t.tenantId,userKey:t.userKey,instanceId:n.instanceId,instanceName:t.instanceName,runtimeBridgeBaseUrl:o},{headers:{"Content-Type":"application/json"},timeout:1e4});if(!s.data.success||!s.data.runtimeAccessToken)return{success:!1,error:s.data.message||"scheduler did not return runtimeAccessToken"};const l=h(r)!==s.data.runtimeAccessToken;return q({serverBaseUrl:r,accessToken:s.data.runtimeAccessToken}),{success:!0,runtimeAccessToken:s.data.runtimeAccessToken,updated:l}}catch(s){const a=s;return{success:!1,error:a.response?.data?JSON.stringify(a.response.data):a.message}}}async function _e(){if(!c.registered||!c.instanceId)return i.info("[AutoRegister] \u5B9E\u4F8B\u672A\u6CE8\u518C\uFF0C\u65E0\u9700\u6CE8\u9500"),!0;try{const e=await ae(c.instanceId);if(e.success){i.info(`[AutoRegister] \u2713 \u6CE8\u9500\u6210\u529F: ${c.instanceId}`);const r=U(y(),c.instanceId);return v().schedulerBaseUrl&&J(r),z(),c.registered=!1,c.instanceId=void 0,!0}else return i.warn(`[AutoRegister] \u6CE8\u9500\u5931\u8D25: ${e.message}`),!1}catch(e){const r=e;return i.error(`[AutoRegister] \u6CE8\u9500\u8BF7\u6C42\u5931\u8D25: ${r.message}`),!1}}function Ee(){return{...c}}function Ue(){return c.registered}function he(){return c.instanceId}async function Ne(){const e=y(),r=c.instanceId,t=U(e,r),n={};if(r&&(n.instanceId=r),e.enabled&&(n.runtimeBridgeBaseUrl=E(e)),!n.instanceId&&!n.runtimeBridgeBaseUrl)return i.info("[AutoRegister] Bridge \u91CD\u542F\u6E05\u7406\uFF1A\u6CA1\u6709 instanceId \u6216 runtimeBridgeBaseUrl\uFF0C\u8DF3\u8FC7\u6E05\u7406"),{success:!0,agentCount:0};try{i.info("[AutoRegister] Bridge \u91CD\u542F\u6E05\u7406\uFF1A\u6B63\u5728\u901A\u77E5\u8C03\u5EA6\u4E2D\u5FC3..."),i.info(`[AutoRegister] instanceId: ${n.instanceId||"(\u65E0)"}`),i.info(`[AutoRegister] runtimeBridgeBaseUrl: ${n.runtimeBridgeBaseUrl||"(\u65E0)"}`);const o=await R.post(`${t}/api/instances/bridge-restart-cleanup`,n,{headers:{"Content-Type":"application/json"},timeout:1e4});return o.data.success?(i.info(`[AutoRegister] \u2713 Bridge \u91CD\u542F\u6E05\u7406\u6210\u529F\uFF1A${o.data.message}`),i.info(`[AutoRegister] \u6E05\u7406\u4E86 ${o.data.agentCount||0} \u4E2A Agent`),{success:!0,agentCount:o.data.agentCount||0}):(i.warn(`[AutoRegister] Bridge \u91CD\u542F\u6E05\u7406\u5931\u8D25\uFF1A${o.data.message}`),{success:!1,error:o.data.message})}catch(o){const s=o,a=s.response?.data?JSON.stringify(s.response.data):s.message;return i.warn(`[AutoRegister] Bridge \u91CD\u542F\u6E05\u7406\u8BF7\u6C42\u5931\u8D25\uFF1A${a}`),{success:!1,error:a}}}export{ye as autoRegister,Ne as bridgeRestartCleanup,Ae as cancelBackgroundRegisterRetries,k as getAutoRegisterConfigFilePath,Re as getConfiguredConnectionKeys,he as getInstanceId,Ee as getRegistrationState,Ue as isRegistered,D as isTunnelConfig,_ as loadConfig,S as loadConfigs,y as loadPrimaryLifecycleConfig,ve as requestRuntimeAccessTokenRefresh,Te as requestRuntimeAccessTokenRefreshForServer,Se as resolveSchedulerBaseUrlFromToken,_e as unregister};
1
+ import{v4 as G}from"uuid";import I from"axios";import m from"node:os";import M from"node:path";import g from"node:fs";import{logger as i}from"../utils/logger.js";import{schedulerBaseUrl as d}from"../config.js";import{runExclusiveConfigWrite as z}from"../utils/config-write-queue.js";import{clearRuntimeBinding as J,clearScopedRuntimeAccessToken as Y,getRuntimeAccessToken as E,getRuntimeBindingPublicState as w,getScopedRuntimeAccessToken as q,loadRuntimeBinding as v,normalizeSchedulerBaseUrl as p,saveRuntimeBinding as K,saveScopedRuntimeAccessToken as C}from"./runtime-binding.js";const b={enabled:!1,serverUrl:d,preferSameLanIp:!0,maxRetries:3,retryInterval:2e3};let u={registered:!1,registrations:{}},P=[];function Ae(){return[...P]}const H=3e4;function W(){const e=Number(process.env.AWS_REGISTER_BACKGROUND_RETRY_INTERVAL);return Number.isFinite(e)&&e>0?e:H}const A=new Map;function L(e){const r=e.serverUrl||d,t=p(r)||r;if(A.has(t))return;const n=setTimeout(()=>{A.delete(t),V(e,t)},W());n.unref?.(),A.set(t,n)}async function V(e,r){try{const t=R().find(n=>(p(n.serverUrl||d)||n.serverUrl||d)===r)||e;await B(t,{backgroundRetry:!0})}catch(t){i.warn(`[AutoRegister] \u540E\u53F0\u91CD\u8BD5\u6CE8\u518C\u5F02\u5E38: ${t.message}`),L(e)}}function Re(){for(const e of A.values())clearTimeout(e);A.clear()}function f(e){return e==null?void 0:String(e).trim()||void 0}function O(e){return p(e)}function y(e){if(typeof e=="boolean")return e;if(typeof e=="string"){const r=e.trim().toLowerCase();if(["true","1","yes","y"].includes(r))return!0;if(["false","0","no","n"].includes(r))return!1}}function x(e){if(e==null||e==="")return;const r=Number(e);return Number.isFinite(r)?r:void 0}function h(e){const r=f(e.serverUrl)||f(e.schedulerBaseUrl),t=f(e.connectionKey)||f(e.password);return{enabled:y(e.enabled),serverUrl:r,tenantId:f(e.tenantId),userKey:f(e.userKey),connectionKey:t,instanceName:f(e.instanceName),instanceId:f(e.instanceId),projectId:f(e.projectId),roleName:f(e.roleName),workspacePath:f(e.workspacePath),registerAddr:f(e.registerAddr),registerIp:f(e.registerIp),virtualIp:f(e.virtualIp),tunnel:y(e.tunnel),preferSameLanIp:y(e.preferSameLanIp),maxRetries:x(e.maxRetries),retryInterval:x(e.retryInterval)}}function N(){const e=String(process.env.AWS_RUNTIME_HOME_DIR||"").trim()||m.homedir();return M.join(e,".aws-bridge","config.json")}function j(){const e=N();try{if(!g.existsSync(e))return i.debug(`[AutoRegister] \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728: ${e}`),null;const r=g.readFileSync(e,"utf-8"),t=JSON.parse(r);return i.info(`[AutoRegister] \u4ECE\u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u914D\u7F6E: ${e}`),h(t)}catch(r){const t=r;return i.warn(`[AutoRegister] \u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6\u5931\u8D25: ${e}, error: ${t.message}`),null}}function X(){const e=N();try{if(!g.existsSync(e))return[];const r=g.readFileSync(e,"utf-8"),t=JSON.parse(r),n=h(t),o=Array.isArray(t.autoRegisterTargets)?t.autoRegisterTargets:[];return o.length===0?n.userKey?[n]:[]:o.filter(s=>!!(s&&typeof s=="object"&&!Array.isArray(s))).map(s=>{const a=h(s);return{...n,...a,connectionKey:a.connectionKey||n.connectionKey}})}catch(r){const t=r;return i.warn(`[AutoRegister] \u8BFB\u53D6\u81EA\u52A8\u6CE8\u518C\u76EE\u6807\u5931\u8D25: ${e}, error: ${t.message}`),[]}}function D(){const e={};return process.env.AWS_AUTO_REGISTER==="true"&&(e.enabled=!0),process.env.AWS_RUNTIME_SCHEDULER_BASE_URL&&(e.serverUrl=process.env.AWS_RUNTIME_SCHEDULER_BASE_URL),process.env.AWS_TENANT_ID&&(e.tenantId=process.env.AWS_TENANT_ID),process.env.AWS_USER_KEY&&(e.userKey=process.env.AWS_USER_KEY),process.env.AWS_BRIDGE_CONNECTION_KEY&&(e.connectionKey=process.env.AWS_BRIDGE_CONNECTION_KEY),process.env.AWS_INSTANCE_NAME&&(e.instanceName=process.env.AWS_INSTANCE_NAME),process.env.AWS_PROJECT_NAME&&(e.projectId=process.env.AWS_PROJECT_NAME),process.env.AWS_ROLE_NAME&&(e.roleName=process.env.AWS_ROLE_NAME),process.env.AWS_WORKSPACE_PATH&&(e.workspacePath=process.env.AWS_WORKSPACE_PATH),process.env.AWS_REGISTER_ADDR&&(e.registerAddr=process.env.AWS_REGISTER_ADDR),process.env.AWS_REGISTER_IP&&(e.registerIp=process.env.AWS_REGISTER_IP),process.env.AWS_VIRTUAL_IP&&(e.virtualIp=process.env.AWS_VIRTUAL_IP),process.env.AWS_PREFER_SAME_LAN_IP&&(e.preferSameLanIp=y(process.env.AWS_PREFER_SAME_LAN_IP)??!0),process.env.AWS_REGISTER_MAX_RETRIES&&(e.maxRetries=parseInt(process.env.AWS_REGISTER_MAX_RETRIES,10)),process.env.AWS_REGISTER_RETRY_INTERVAL&&(e.retryInterval=parseInt(process.env.AWS_REGISTER_RETRY_INTERVAL,10)),e}function T(){const e=j(),r=D(),t={...b,...e||{},...r},n=t.instanceName||m.hostname();let o=!1;return process.env.AWS_AUTO_REGISTER!==void 0?o=process.env.AWS_AUTO_REGISTER==="true":e&&(o=!0),{enabled:o,serverUrl:t.serverUrl||d,tenantId:t.tenantId||"",userKey:t.userKey||"",connectionKey:t.connectionKey,instanceName:n,instanceId:t.instanceId,projectId:t.projectId,roleName:t.roleName,workspacePath:t.workspacePath,registerAddr:t.registerAddr,registerIp:t.registerIp,virtualIp:t.virtualIp,tunnel:typeof t.tunnel=="boolean"?t.tunnel:void 0,preferSameLanIp:t.preferSameLanIp!==!1,maxRetries:t.maxRetries,retryInterval:t.retryInterval}}function R(){const e=X(),r=D(),n=(e.length>0?e:[j()||{}]).map(o=>{const s={...b,...o,...r};let a=!1;return process.env.AWS_AUTO_REGISTER!==void 0?a=process.env.AWS_AUTO_REGISTER==="true":a=e.length>0||!!s.userKey,{enabled:a,serverUrl:s.serverUrl||d,tenantId:s.tenantId||"",userKey:s.userKey||"",connectionKey:s.connectionKey,instanceName:s.instanceName||m.hostname(),instanceId:s.instanceId,projectId:s.projectId,roleName:s.roleName,workspacePath:s.workspacePath,registerAddr:s.registerAddr,registerIp:s.registerIp,virtualIp:s.virtualIp,tunnel:typeof s.tunnel=="boolean"?s.tunnel:void 0,preferSameLanIp:s.preferSameLanIp!==!1,maxRetries:s.maxRetries,retryInterval:s.retryInterval}});return P=n.map(o=>o.connectionKey).filter(o=>!!(o&&o.trim())),n}function Q(){const e=m.networkInterfaces(),r=[];for(const t of Object.keys(e)){const n=e[t];if(n)for(const o of n)o.family==="IPv4"&&!o.internal&&r.push({address:o.address,netmask:o.netmask,name:t})}return r}function k(e){const r=e.split(".").map(Number);return(r[0]<<24)+(r[1]<<16)+(r[2]<<8)+r[3]}function Z(e,r,t){const n=k(e),o=k(r),s=k(t);return(n&s)===(o&s)}function ee(e){try{const r=new URL(e);return r.hostname==="localhost"||r.hostname==="127.0.0.1"?"127.0.0.1":/^(\d{1,3}\.){3}\d{1,3}$/.test(r.hostname)?r.hostname:null}catch{return null}}function re(e){return e==="127.0.0.1"}function te(e){const r=Q();if(r.length===0)return i.warn("[AutoRegister] \u672A\u627E\u5230\u4EFB\u4F55\u975E\u5185\u90E8 IP \u5730\u5740\uFF0C\u4F7F\u7528 127.0.0.1"),"127.0.0.1";const t=ee(e);if(t){if(re(t))return"127.0.0.1";for(const n of r)if(Z(n.address,t,n.netmask))return i.info(`[AutoRegister] \u627E\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3\u540C\u5B50\u7F51\u7684 IP: ${n.address} (\u7F51\u5361: ${n.name}, \u5B50\u7F51\u63A9\u7801: ${n.netmask})`),n.address;i.warn(`[AutoRegister] \u672A\u627E\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3 (${t}) \u540C\u5B50\u7F51\u7684\u672C\u673A IP\uFF0C\u4F7F\u7528 127.0.0.1`)}else i.warn("[AutoRegister] \u65E0\u6CD5\u89E3\u6790\u8C03\u5EA6\u4E2D\u5FC3 IP\uFF0C\u4F7F\u7528 127.0.0.1");return"127.0.0.1"}function ne(e=d){return te(e)}function F(e){const r=e||T();return!r.enabled||!r.userKey?!1:r.tunnel===!0?!0:r.tunnel===!1?!1:!r.registerAddr&&!r.registerIp&&!r.virtualIp}function _(e){const r=process.env.AWS_RUNTIME_BRIDGE_PORT||18081;if(F(e)){const s=e.serverUrl||d;try{const a=new URL(s);if(!e.instanceId)i.warn("[AutoRegister] \u96A7\u9053\u6A21\u5F0F\u4F46\u7F3A\u5C11 instanceId\uFF0C\u964D\u7EA7\u4E3A\u76F4\u8FDE\u6A21\u5F0F");else return`${a.protocol}//${a.host}/tunnel/${e.instanceId}`}catch{i.warn("[AutoRegister] serverUrl \u89E3\u6790\u5931\u8D25\uFF0C\u964D\u7EA7\u4E3A\u76F4\u8FDE\u6A21\u5F0F")}}const t=e.preferSameLanIp===!1?"127.0.0.1":ne(e.serverUrl||d),n=e.registerAddr||e.registerIp||e.virtualIp||t;return n?/^https?:\/\//i.test(n)?n:/:[0-9]+$/.test(n)?`http://${n}`:`http://${n}:${r}`:`http://127.0.0.1:${r}`}function S(){return R()[0]||T()}function Se(e){const r=String(e||"").trim();if(!r)return;const t=[];for(const o of R())o?.serverUrl&&t.push(o.serverUrl);const n=v();n.schedulerBaseUrl&&t.push(n.schedulerBaseUrl);for(const o of t){const s=q(o);if(s&&s===r)return p(o)}}function se(e){return e?Object.entries(u.registrations).find(([,t])=>t===e)?.[0]:void 0}function U(e,r){const t=se(r);if(t)return t;const n=f(e.serverUrl);if(n&&(n!==d||process.env.AWS_RUNTIME_SCHEDULER_BASE_URL))return n;const o=v(),s=f(o.schedulerBaseUrl);return o.status==="paired"&&s?s:n||d}async function oe(e){const r=e.instanceName||m.hostname(),t=e.serverUrl||d,n={tenantId:e.tenantId,userKey:e.userKey,instanceId:e.instanceId,instanceName:r,hostname:m.hostname(),virtualIp:e.registerAddr||e.registerIp||e.virtualIp,runtimeBridgeBaseUrl:_(e),connectionKey:e.connectionKey,workspacePath:e.workspacePath,projectId:e.projectId,roleName:e.roleName};return i.info(`[AutoRegister] \u6B63\u5728\u6CE8\u518C\u5B9E\u4F8B: ${r}`),i.info(`[AutoRegister] \u8C03\u5EA6\u4E2D\u5FC3: ${t}`),i.info(`[AutoRegister] \u7528\u6237 Key: ${e.userKey?"****"+e.userKey.slice(-4):"(\u672A\u8BBE\u7F6E)"}`),i.info(`[AutoRegister] \u79DF\u6237 ID: ${e.tenantId||"(\u81EA\u52A8\u63A8\u5BFC)"}`),(await I.post(`${t}/api/instances/register`,n,{headers:{"Content-Type":"application/json"},timeout:1e4})).data}function ie(e,r){const t=N();return z(t,()=>{if(!g.existsSync(t))return;const n=g.readFileSync(t,"utf-8"),o=JSON.parse(n),s=p(e);if(!s)return;let a=!1;const l=c=>{p(String(c.serverUrl||c.schedulerBaseUrl||""))===s&&r&&c.instanceId!==r&&(c.instanceId=r,a=!0)};if(Array.isArray(o.autoRegisterTargets))for(const c of o.autoRegisterTargets)c&&typeof c=="object"&&!Array.isArray(c)&&l(c);else l(o);a&&(g.writeFileSync(t,JSON.stringify(o,null,2),"utf-8"),i.info(`[AutoRegister] \u5DF2\u56DE\u5199 instanceId \u5230 config.json (serverUrl=${e})`))})}async function ae(e){const r=U(S(),e),t=v(),n=E(r);if(!n)throw new Error("runtimeAccessToken is required to unregister bridge instance");return(await I.post(`${r}/api/instances/unregister`,{instanceId:e},{headers:{"Content-Type":"application/json","X-Runtime-Token":n},timeout:1e4})).data}async function ve(e){const r=e?[{...T(),...e}]:R(),n=(r.length>1?await Promise.all(r.map(s=>B(s))):[await B(r[0]||T())]).every(Boolean),o=r.every(s=>!s.enabled||!s.userKey);if(!e&&(n||o)){const{stopTunnelClientsExcept:s}=await import("./tunnel-client.js");s(r.map(a=>a.serverUrl).filter(a=>!!a))}return n}async function B(e,r){if(!e.enabled)return i.info("[AutoRegister] \u81EA\u52A8\u6CE8\u518C\u672A\u542F\u7528"),i.info("[AutoRegister] \u8981\u542F\u7528\u81EA\u52A8\u6CE8\u518C\uFF0C\u8BF7\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6 ~/.aws-bridge/config.json \u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF AWS_AUTO_REGISTER=true"),!1;if(!e.userKey)return i.error("[AutoRegister] \u7F3A\u5C11\u7528\u6237 Key\uFF08\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u8BBE\u7F6E userKey \u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF AWS_USER_KEY\uFF09"),!1;const t=F(e);t&&!e.instanceId&&(e={...e,instanceId:`bridge-${G().replace(/-/g,"").slice(0,12)}`},i.info(`[AutoRegister] \u96A7\u9053\u6A21\u5F0F\uFF1A\u5DF2\u9884\u58F0\u660E instanceId=${e.instanceId}`));const n=r?.backgroundRetry?1:e.maxRetries??3,o=e.retryInterval??2e3;for(let s=1;s<=n;s++){try{u.lastAttempt=new Date;const a=await oe(e);if(a.success){if(u.registered=!0,u.instanceId=a.instanceId,a.instanceId&&(u.registrations[e.serverUrl||d]=a.instanceId),u.error=void 0,i.info("[AutoRegister] \u2713 \u6CE8\u518C\u6210\u529F\uFF01"),i.info(`[AutoRegister] \u5B9E\u4F8B ID: ${a.instanceId}`),i.info(`[AutoRegister] \u6D88\u606F: ${a.message}`),i.info(`[AutoRegister] \u66F4\u65B0: ${a.isUpdate?"\u662F":"\u5426"}`),a.runtimeAccessToken)try{const l=e.serverUrl||d;K({accessToken:a.runtimeAccessToken,instanceId:a.instanceId,userId:a.userId,schedulerBaseUrl:l});const c=p(a.serverUrl);c&&c!==p(l)&&(C({serverBaseUrl:c,accessToken:a.runtimeAccessToken}),i.info(`[AutoRegister] \u68C0\u6D4B\u5230 server \u4E0B\u53D1\u5730\u5740(${c})\u4E0E\u8FDE\u63A5\u5730\u5740(${l})\u4E0D\u540C\uFF0C\u5DF2\u6309\u4E24\u4E2A\u5730\u5740\u5206\u522B\u4FDD\u5B58 scoped token`)),i.info("[AutoRegister] \u5DF2\u4FDD\u5B58\u8C03\u5EA6\u4E2D\u5FC3\u4E0B\u53D1\u7684 runtime access token"),a.instanceId&&ie(e.serverUrl||d,a.instanceId).catch($=>{i.warn(`[AutoRegister] \u56DE\u5199 instanceId \u5230 config.json \u5931\u8D25: ${$.message}`)})}catch(l){const c=l;return i.error(`[AutoRegister] \u4FDD\u5B58 runtime access token \u5931\u8D25: ${c.message}`),u.error=c.message,!1}else i.warn("[AutoRegister] \u6CE8\u518C\u54CD\u5E94\u672A\u5305\u542B runtime access token\uFF0CMCP \u5C06\u65E0\u6CD5\u8BBF\u95EE\u8C03\u5EA6\u4E2D\u5FC3\uFF0C\u8BF7\u68C0\u67E5 server \u7684 bridge \u5B9E\u4F8B token \u9881\u53D1\u903B\u8F91");if(t&&a.instanceId&&a.runtimeAccessToken){const{startTunnelClient:l}=await import("./tunnel-client.js"),c=e.serverUrl||d;l(c,a.instanceId),i.info(`[AutoRegister] \u96A7\u9053\u5BA2\u6237\u7AEF\u5DF2\u542F\u52A8: server=${c}, instanceId=${a.instanceId}`)}return!0}else i.warn(`[AutoRegister] \u6CE8\u518C\u5931\u8D25: ${a.message}`),u.error=a.message}catch(a){const l=a,c=l.response?.data?JSON.stringify(l.response.data):l.message;i.error(`[AutoRegister] \u6CE8\u518C\u8BF7\u6C42\u5931\u8D25 (\u5C1D\u8BD5 ${s}/${n}): ${c}`),u.error=c}s<n&&(i.info(`[AutoRegister] ${o/1e3} \u79D2\u540E\u91CD\u8BD5...`),await new Promise(a=>setTimeout(a,o)))}return r?.backgroundRetry?i.warn(`[AutoRegister] \u540E\u53F0\u91CD\u8BD5\u6CE8\u518C\u4ECD\u672A\u6210\u529F (server=${e.serverUrl||d}): ${u.error||"\u672A\u77E5"}`):(i.error("[AutoRegister] \u2717 \u6CE8\u518C\u5931\u8D25\uFF0C\u5DF2\u8FBE\u6700\u5927\u91CD\u8BD5\u6B21\u6570"),i.error("[AutoRegister] ========================================"),i.error("[AutoRegister] \u81EA\u52A8\u6CE8\u518C\u5DF2\u542F\u7528\u4F46\u6CE8\u518C\u5931\u8D25\uFF0C\u5B9E\u4F8B\u6682\u65F6\u65E0\u6CD5\u6B63\u5E38\u5DE5\u4F5C"),i.error("[AutoRegister] \u8BF7\u68C0\u67E5\u4EE5\u4E0B\u914D\u7F6E\uFF1A"),i.error(`[AutoRegister] - \u7528\u6237 Key (userKey): ${e.userKey?"****"+e.userKey.slice(-4):"(\u672A\u8BBE\u7F6E)"}`),i.error(`[AutoRegister] - \u79DF\u6237 ID (tenantId): ${e.tenantId||"(\u53EF\u9009\uFF0C\u5C06\u81EA\u52A8\u63A8\u5BFC)"}`),i.error(`[AutoRegister] - \u5B9E\u4F8B\u540D (instanceName): ${e.instanceName||"(\u4F7F\u7528\u4E3B\u673A\u540D)"}`),i.error(`[AutoRegister] - \u8C03\u5EA6\u4E2D\u5FC3\u5730\u5740: ${e.serverUrl||d}`),i.error(`[AutoRegister] - \u6700\u540E\u9519\u8BEF: ${u.error||"\u672A\u77E5"}`),i.error("[AutoRegister] ========================================"),i.error("[AutoRegister] \u914D\u7F6E\u6765\u6E90\uFF1A~/.aws-bridge/config.json \u6216\u73AF\u5883\u53D8\u91CF"),i.warn(`[AutoRegister] \u5C06\u5728\u540E\u53F0\u6301\u7EED\u91CD\u8BD5\u6CE8\u518C\uFF08\u6BCF ${Math.round(W()/1e3)} \u79D2\uFF09\uFF0C\u76F4\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3\u5EFA\u7ACB\u8FDE\u63A5`)),L(e),!1}async function ye(){const e=S();if(!e.userKey)return{success:!1,error:"userKey is required for runtime token refresh"};const r=w(),t=U(e),n=_(e);try{const o=await I.post(`${t}/api/instances/runtime-tokens/refresh`,{tenantId:e.tenantId,userKey:e.userKey,instanceId:r.instanceId,instanceName:e.instanceName,runtimeBridgeBaseUrl:n},{headers:{"Content-Type":"application/json"},timeout:1e4});if(!o.data.success||!o.data.runtimeAccessToken)return{success:!1,error:o.data.message||"scheduler did not return runtimeAccessToken"};const a=E()!==o.data.runtimeAccessToken;return K({accessToken:o.data.runtimeAccessToken,instanceId:r.instanceId,userId:o.data.userId||e.userKey,schedulerBaseUrl:t}),{success:!0,runtimeAccessToken:o.data.runtimeAccessToken,updated:a}}catch(o){const s=o;return{success:!1,error:s.response?.data?JSON.stringify(s.response.data):s.message}}}async function Te(e){const r=O(e);if(!r)return{success:!1,error:"serverUrl is required for runtime token refresh"};const t=R().find(s=>O(s.serverUrl)===r)||S();if(!t.userKey)return{success:!1,error:"userKey is required for runtime token refresh"};const n=w(),o=_(t);try{const s=await I.post(`${r}/api/instances/runtime-tokens/refresh`,{tenantId:t.tenantId,userKey:t.userKey,instanceId:n.instanceId,instanceName:t.instanceName,runtimeBridgeBaseUrl:o},{headers:{"Content-Type":"application/json"},timeout:1e4});if(!s.data.success||!s.data.runtimeAccessToken)return{success:!1,error:s.data.message||"scheduler did not return runtimeAccessToken"};const l=E(r)!==s.data.runtimeAccessToken;return C({serverBaseUrl:r,accessToken:s.data.runtimeAccessToken}),{success:!0,runtimeAccessToken:s.data.runtimeAccessToken,updated:l}}catch(s){const a=s;return{success:!1,error:a.response?.data?JSON.stringify(a.response.data):a.message}}}async function _e(){if(!u.registered||!u.instanceId)return i.info("[AutoRegister] \u5B9E\u4F8B\u672A\u6CE8\u518C\uFF0C\u65E0\u9700\u6CE8\u9500"),!0;try{const e=await ae(u.instanceId);if(e.success){i.info(`[AutoRegister] \u2713 \u6CE8\u9500\u6210\u529F: ${u.instanceId}`);const r=U(S(),u.instanceId);v().schedulerBaseUrl&&Y(r),J();try{const{stopTunnelClientForServer:n}=await import("./tunnel-client.js");n(r)}catch(n){i.warn(`[AutoRegister] \u6CE8\u9500\u540E\u505C\u6B62\u96A7\u9053\u5931\u8D25: ${n.message}`)}return u.registered=!1,u.instanceId=void 0,!0}else return i.warn(`[AutoRegister] \u6CE8\u9500\u5931\u8D25: ${e.message}`),!1}catch(e){const r=e;return i.error(`[AutoRegister] \u6CE8\u9500\u8BF7\u6C42\u5931\u8D25: ${r.message}`),!1}}function Ue(){return{...u}}function Ee(){return u.registered}function he(){return u.instanceId}async function Ne(){const e=S(),r=u.instanceId,t=U(e,r),n={};if(r&&(n.instanceId=r),e.enabled&&(n.runtimeBridgeBaseUrl=_(e)),!n.instanceId&&!n.runtimeBridgeBaseUrl)return i.info("[AutoRegister] Bridge \u91CD\u542F\u6E05\u7406\uFF1A\u6CA1\u6709 instanceId \u6216 runtimeBridgeBaseUrl\uFF0C\u8DF3\u8FC7\u6E05\u7406"),{success:!0,agentCount:0};try{i.info("[AutoRegister] Bridge \u91CD\u542F\u6E05\u7406\uFF1A\u6B63\u5728\u901A\u77E5\u8C03\u5EA6\u4E2D\u5FC3..."),i.info(`[AutoRegister] instanceId: ${n.instanceId||"(\u65E0)"}`),i.info(`[AutoRegister] runtimeBridgeBaseUrl: ${n.runtimeBridgeBaseUrl||"(\u65E0)"}`);const o=await I.post(`${t}/api/instances/bridge-restart-cleanup`,n,{headers:{"Content-Type":"application/json"},timeout:1e4});return o.data.success?(i.info(`[AutoRegister] \u2713 Bridge \u91CD\u542F\u6E05\u7406\u6210\u529F\uFF1A${o.data.message}`),i.info(`[AutoRegister] \u6E05\u7406\u4E86 ${o.data.agentCount||0} \u4E2A Agent`),{success:!0,agentCount:o.data.agentCount||0}):(i.warn(`[AutoRegister] Bridge \u91CD\u542F\u6E05\u7406\u5931\u8D25\uFF1A${o.data.message}`),{success:!1,error:o.data.message})}catch(o){const s=o,a=s.response?.data?JSON.stringify(s.response.data):s.message;return i.warn(`[AutoRegister] Bridge \u91CD\u542F\u6E05\u7406\u8BF7\u6C42\u5931\u8D25\uFF1A${a}`),{success:!1,error:a}}}export{ve as autoRegister,Ne as bridgeRestartCleanup,Re as cancelBackgroundRegisterRetries,N as getAutoRegisterConfigFilePath,Ae as getConfiguredConnectionKeys,he as getInstanceId,Ue as getRegistrationState,Ee as isRegistered,F as isTunnelConfig,T as loadConfig,R as loadConfigs,S as loadPrimaryLifecycleConfig,ye as requestRuntimeAccessTokenRefresh,Te as requestRuntimeAccessTokenRefreshForServer,Se as resolveSchedulerBaseUrlFromToken,_e as unregister};
2
2
 
@@ -0,0 +1,5 @@
1
+
2
+
3
+ export declare function setChangeCacheRetentionDays(days: unknown): void;
4
+
5
+ export declare function getChangeCacheRetentionDays(): number | null;
@@ -0,0 +1,2 @@
1
+ const u=3650;let e=null;function o(n){if(n==null||n===""){e=null;return}if(typeof n=="boolean"){e=null;return}const t=Number(n);if(!Number.isFinite(t)||t<=0){e=null;return}e=Math.min(Math.floor(t),3650)}function i(){return e}export{i as getChangeCacheRetentionDays,o as setChangeCacheRetentionDays};
2
+