aws-runtime-bridge 1.9.102 → 1.9.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/AcodeSdkAdapter.js +3 -3
- package/dist/index.js +1 -1
- package/dist/remote-desktop/computer-use-backend.d.ts +111 -0
- package/dist/remote-desktop/computer-use-backend.js +1 -0
- package/dist/remote-desktop/types.d.ts +79 -0
- package/dist/routes/computer.d.ts +1 -0
- package/dist/routes/computer.js +2 -0
- package/dist/routes/file-change-diff.d.ts +27 -0
- package/dist/routes/file-change-diff.js +5 -0
- package/dist/routes/instance.js +2 -2
- package/dist/routes/pty.d.ts +2 -2
- package/dist/routes/pty.js +3 -3
- package/dist/routes/task-context.js +1 -1
- package/dist/routes/terminal.js +28 -28
- package/dist/services/auto-register.d.ts +1 -1
- package/dist/services/auto-register.js +1 -1
- package/dist/services/instance-features.d.ts +10 -0
- package/dist/services/instance-features.js +2 -0
- package/dist/services/sdk-tool-file-change-recorder.d.ts +12 -0
- package/dist/services/sdk-tool-file-change-recorder.js +2 -0
- package/dist/services/workspace-files.js +1 -1
- package/dist/services/workspaceTaskChangeWatcher.d.ts +9 -1
- package/dist/services/workspaceTaskChangeWatcher.js +3 -1
- package/package/acode/dist/built-in-file-tools.d.ts +4 -0
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/runtime.d.ts +13 -0
- package/package/acode/dist/runtime.js +18 -18
- package/package/aws-client-agent-mcp/README.md +2 -2
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +14 -4
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.test.js +36 -36
- package/package/aws-client-agent-mcp/dist/config.js +1 -1
- package/package/aws-client-agent-mcp/dist/config.test.js +2 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/mcp-server.js +21 -21
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +35 -36
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +6 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +25 -5
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.js +17 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +14 -12
- package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
- package/package.json +3 -2
- package/scripts/ensure-playwright-browser.mjs +118 -0
package/dist/routes/instance.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{Router as
|
|
2
|
-
[output truncated]`:r}function se(r,t){return new Promise((e,s)=>{const n=N(r,t,{shell:!1,windowsHide:!0});let a="",i="";n.stdout.on("data",o=>{a+=o.toString("utf8")}),n.stderr.on("data",o=>{i+=o.toString("utf8")}),n.on("error",s),n.on("close",o=>{e({command:r,args:t,exitCode:o,stdout:q(a),stderr:q(i)})})})}function O(r){return String(r||"").trim()||void 0}function K(r){const t=r.get("host");if(t)return`${r.protocol}://${t}`}async function ne(r){const t={...r.operation,status:"running",message:"Bridge \u66F4\u65B0\u6B63\u5728\u540E\u53F0\u6267\u884C\u3002"};await b(t);try{l.info("[update-bridge] \u6B63\u5728\u540E\u53F0\u66F4\u65B0 aws-runtime-bridge \u5230\u6700\u65B0\u7248\u672C");const e=await se(r.command,r.args),s=e.exitCode===0;await b({...t,status:s?"succeeded":"failed",message:s?"Bridge \u66F4\u65B0\u5B8C\u6210\uFF0C\u8BF7\u91CD\u542F\u5B9E\u4F8B Bridge \u4EE5\u52A0\u8F7D\u65B0\u7248\u672C\u3002":`Bridge \u66F4\u65B0\u5931\u8D25\uFF0Cnpm \u9000\u51FA\u7801: ${e.exitCode??"unknown"}`,error:s?void 0:e.stderr||e.stdout}),await C()}catch(e){const s=e;l.error("[update-bridge] background update failed:",s),await b({...t,status:"failed",message:"Bridge \u66F4\u65B0\u5931\u8D25\u3002",error:s.message||"update bridge failed"}),await C()}}async function P(r){const t=await import("node:fs/promises"),e=await import("node:path"),s=await import("node:os"),n=e.join(s.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");if(r){await t.mkdir(e.dirname(n),{recursive:!0}),await t.writeFile(n,JSON.stringify({preserveSessions:!0,timestamp:new Date().toISOString()}),"utf-8"),l.info(`[prepare-restart] \u5DF2\u521B\u5EFA\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\u6587\u4EF6: ${n}`);return}try{await t.unlink(n),l.info("[prepare-restart] \u5DF2\u5220\u9664\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\u6587\u4EF6")}catch{}}function oe(r){return $("md5").update(r,"utf8").digest("hex")}function ae(r){const t=r.trim().toLowerCase();if(!/^[a-f0-9]{32}$/.test(t))return!1;const e=Buffer.from(t,"hex");return _().map(s=>s.trim()).filter(Boolean).some(s=>{const n=Buffer.from(oe(s),"hex");return n.length===e.length&&F(n,e)})}function ie(r){const e=_().length>0,s=y();return e?ae(r)?{status:200,body:{ok:!0,runtimeBridge:"healthy",version:s,connectionKeyMatched:!0,connectionKeyRequired:!0}}:{status:401,body:{ok:!1,error:"connection_key_mismatch",version:s,connectionKeyMatched:!1,connectionKeyRequired:!0}}:{status:200,body:{ok:!0,runtimeBridge:"healthy",version:s,connectionKeyMatched:!0,connectionKeyRequired:!1}}}function le(r,t){const s=t.trim()||"http://localhost:8080",n=/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?(?:\/|$)/i.test(s);return{ok:!1,error:r.message||"scheduler ping failed",failureStage:"scheduler_ping",runtimeBridge:"healthy",schedulerBaseUrl:s,hint:n?"aws-runtime-bridge \u5DF2\u8FDE\u901A\uFF0C\u4F46\u5B83\u56DE\u8FDE\u8C03\u5EA6\u4E2D\u5FC3\u5931\u8D25\u3002\u8BF7\u5728 bridge \u542F\u52A8\u73AF\u5883\u4E2D\u5C06 AWS_RUNTIME_SCHEDULER_BASE_URL \u914D\u7F6E\u4E3A\u8BE5\u5B9E\u4F8B\u53EF\u8BBF\u95EE\u7684\u8C03\u5EA6\u4E2D\u5FC3\u5730\u5740\uFF0C\u4F8B\u5982 http://<server-host>:7380\u3002":"aws-runtime-bridge \u5DF2\u8FDE\u901A\uFF0C\u4F46\u5B83\u56DE\u8FDE\u8C03\u5EA6\u4E2D\u5FC3\u5931\u8D25\u3002\u8BF7\u786E\u8BA4 AWS_RUNTIME_SCHEDULER_BASE_URL \u6307\u5411\u7684\u8C03\u5EA6\u4E2D\u5FC3\u5730\u5740\u53EF\u4ECE bridge \u673A\u5668\u8BBF\u95EE\uFF0C\u5E76\u4E14\u8FD0\u884C\u65F6\u8BBF\u95EE\u4EE4\u724C\u4ECD\u6709\u6548\u3002"}}function ce(r){if(typeof r!="object"||r===null)return;const t=Reflect.get(r,"response");if(typeof t!="object"||t===null)return;const e=Reflect.get(t,"status");return typeof e=="number"?e:void 0}async function ue(r,t){try{const e=await I.get(`${r}/api/runtime/ping`,{headers:{"X-Runtime-Token":t}});return{schedulerReachable:e.status>=200&&e.status<300,tokenRefreshed:!1}}catch(e){if(ce(e)!==401)throw e;const s=await H(r);if(!s.success||!s.runtimeAccessToken)throw e;const n=await I.get(`${r}/api/runtime/ping`,{headers:{"X-Runtime-Token":s.runtimeAccessToken}});return{schedulerReachable:n.status>=200&&n.status<300,tokenRefreshed:!0}}}function de(r){return{ok:!1,error:"ambiguous_scheduler_base_url",failureStage:"scheduler_ping",runtimeBridge:"healthy",schedulerBaseUrl:"",autoRegisterTargetUrls:r,hint:"Multiple autoRegisterTargets.serverUrl values were found, so bridge cannot safely infer which scheduler /runtime/ping should call back. Set AWS_RUNTIME_SCHEDULER_BASE_URL explicitly, or use future schedulerId/token-bound multi-scheduler routing."}}function ge(r){return Array.from(new Set([...r,...te].map(t=>String(t||"").trim().toLowerCase()).filter(Boolean)))}function fe(r,t){const e=r.filter(s=>t[s]?.installed);return e.length===0?"":e.map(s=>{const n=t[s],a=n?.error||n?.executable||"command is still available";return`${s}: ${a}`}).join("; ")}function T(r){return Object.fromEntries(Object.entries(r||{}).map(([t,e])=>[t,{installed:!!e?.installed,version:e?.version||null,executable:e?.executable||null,error:e?.error||null}]))}let k=null;const me=3e5;async function he(){return(await I.get("https://registry.npmjs.org/aws-runtime-bridge/latest",{timeout:1e4,responseType:"json"})).data?.version||"unknown"}d.get("/check-update",async(r,t)=>{try{let e;k&&Date.now()-k.ts<me?e=k.latestVersion:(e=await he(),k={latestVersion:e,ts:Date.now()});const s=y(),n=e!=="unknown"&&s!=="unknown"&&e!==s;t.json({ok:!0,hasUpdate:n,currentVersion:s,latestVersion:e})}catch(e){const s=e;l.warn("[check-update] Failed to query npm registry:",s.message),t.json({ok:!1,hasUpdate:!1,currentVersion:y(),latestVersion:null,error:s.message||"failed to check for updates"})}}),d.get("/healthz",(r,t)=>{t.json({ok:!0,runtimeBridge:"healthy"})}),d.get("/connection-check",(r,t)=>{const e=String(r.header("X-Bridge-Connection-Key-MD5")||""),s=ie(e);t.status(s.status).json(s.body)}),d.get("/ping",S,async(r,t)=>{let e=M(r.header("X-Scheduler-Base-Url"),r.header("X-Bridge-Instance-Id"),r.header("X-Bridge-Instance-Name"));if(e.source==="ambiguous-auto-register-targets"){const n=X(r.header("X-Runtime-Token"));if(n)e={url:n,source:"token-match",ambiguousTargetUrls:[]};else{const a=r.header("X-Bridge-Instance-Id");if(a){const i=z(),o=Object.entries(i.registrations).find(([,c])=>c===a)?.[0];o&&(e={url:o,source:"instance-id-match",ambiguousTargetUrls:[]})}if(!e.url||e.source==="ambiguous-auto-register-targets"){t.status(400).json(de(e.ambiguousTargetUrls));return}}}const s=e.url;try{const n=Y(s);if(!n){t.status(401).json({ok:!1,error:"runtime_access_token_required"});return}const a=await ue(s,n);t.json({ok:!0,runtimeBridge:"healthy",version:y(),schedulerReachable:a.schedulerReachable,tokenRefreshed:a.tokenRefreshed,schedulerBaseUrl:s,instanceId:e.instanceId,instanceName:e.instanceName})}catch(n){const a=n;t.status(502).json(le(a,s))}}),d.post("/init-instance",S,async(r,t)=>{const{agentId:e,workspacePath:s,skillEnabled:n,mcpEnabled:a,ccSwitchEnabledTools:i,skillPackage:o,skillPackages:c,mcpServers:m}=r.body||{};if(!e||!s){t.status(400).json({error:"agentId and workspacePath are required"});return}try{l.info("[init-instance] Request received",{agentId:String(e),workspacePath:String(s),skillEnabled:n,mcpEnabled:a,ccSwitchEnabledTools:i});const u=await G(e,s,{skillEnabled:n,mcpEnabled:a,ccSwitchEnabledTools:i,skillPackage:o,skillPackages:c,mcpServers:m});l.info("[init-instance] Initialization completed",{agentId:String(e),ok:u.ok,logCount:u.logs?.length||0,enabledTools:u.enabledTools}),t.json(u)}catch(u){const g=u;l.error("[init-instance] Initialization failed",{agentId:String(e),workspacePath:String(s),error:g?.message||String(u),stack:g?.stack||null}),t.status(400).json({error:g?.message||"initialize instance failed"})}}),d.post("/cc-switch/state",S,async(r,t)=>{const{agentId:e}=r.body||{};if(!e){t.status(400).json({error:"agentId is required"});return}try{l.info("[cc-switch/state] Request received",{agentId:String(e)});const s=await W(e),n=await V(s),i=(await J(e,s)).state,o=ge(i.enabledTools||[]);l.info("[cc-switch/state] Detecting SDK statuses",{agentId:String(e),detectionTargets:o});const c=await R(o);l.info("[cc-switch/state] SDK status detection completed",{agentId:String(e),toolStatus:T(c),importedMcpCount:n.mcpServers,importedSkillCount:n.skills}),t.json({ok:!0,agentId:String(e),imported:{mcpServers:n.mcpServers,skills:n.skills},state:{...i,toolStatus:c}})}catch(s){const n=s;l.error("[cc-switch/state] Failed to load state",{agentId:String(e),error:n?.message||String(s),stack:n?.stack||null}),t.status(400).json({error:n?.message||"load state failed"})}}),d.post("/cc-switch/install-tools",S,async(r,t)=>{const{agentId:e,tools:s}=r.body||{};if(!e){t.status(400).json({error:"agentId is required"});return}const n=Array.isArray(s)?s.map(o=>String(o||"").trim().toLowerCase()).filter(Boolean):[];l.info("[cc-switch/install-tools] Request received",{agentId:String(e),requestedTools:n});const a=new Set(U),i=n.filter(o=>a.has(o));if(l.info("[cc-switch/install-tools] Request normalized",{agentId:String(e),requestedTools:n,installableTools:i,supportedInstallableTools:U}),i.length===0){l.warn("[cc-switch/install-tools] No supported installable tools requested",{agentId:String(e),requestedTools:n}),t.status(400).json({error:`tools must include ${U.join(", ")}`});return}try{const o=await x(e),c=Array.from(new Set([...o.enabledTools||[],...i]));l.info("[cc-switch/install-tools] Starting installer",{agentId:String(e),installableTools:i,previousEnabledTools:o.enabledTools||[],nextEnabledTools:c});const m=await Q(i);l.info("[cc-switch/install-tools] Installer completed",{agentId:String(e),toolStatus:T(m)});const u=await R(c);l.info("[cc-switch/install-tools] Refreshed enabled SDK statuses",{agentId:String(e),refreshedToolStatus:T(u)});const g={...u,...m},h=await L(e,{...o,enabledTools:c,toolStatus:g}),w=new Set(i),p=Object.entries(g).filter(([f])=>w.has(f)).filter(([,f])=>!f.installed).map(([f,B])=>({tool:f,error:B.error||null}));p.length>0&&l.warn("[cc-switch/install-tools] Some SDKs remain unavailable",{agentId:String(e),failedTools:p}),l.info("[cc-switch/install-tools] State saved",{agentId:String(e),enabledTools:h.enabledTools,toolStatus:T(g)}),t.json({ok:p.length===0,agentId:String(e),toolStatus:g,failedTools:p,state:h})}catch(o){const c=o;l.error("[cc-switch/install-tools] Install route failed",{agentId:String(e),requestedTools:n,installableTools:i,error:c?.message||String(o),stack:c?.stack||null}),t.status(400).json({error:c?.message||"install tools failed"})}}),d.post("/cc-switch/uninstall-tools",S,async(r,t)=>{const{agentId:e,tools:s}=r.body||{};if(!e){t.status(400).json({error:"agentId is required"});return}const n=Array.isArray(s)?s.map(o=>String(o||"").trim().toLowerCase()).filter(Boolean):[],a=new Set(A),i=n.filter(o=>a.has(o));if(i.length===0){t.status(400).json({error:`tools must include ${A.join(", ")}`});return}try{const o=await x(e),c=new Set(i),m=(o.enabledTools||[]).filter(B=>!c.has(String(B||"").trim().toLowerCase())),u=await Z(i),h={...await R([...m,...i]),...u},w=fe(i,h),p=w?o.enabledTools||[]:m,f=await L(e,{...o,enabledTools:p,toolStatus:h});if(w){t.status(400).json({ok:!1,agentId:String(e),error:`uninstall incomplete: ${w}`,toolStatus:h,state:f});return}t.json({ok:!0,agentId:String(e),toolStatus:h,state:f})}catch(o){const c=o;t.status(400).json({error:c?.message||"uninstall tools failed"})}}),d.post("/prepare-restart",S,async(r,t)=>{const{preserveSessions:e=!0}=r.body||{};try{l.info(`[prepare-restart] \u6536\u5230\u51C6\u5907\u91CD\u542F\u901A\u77E5\uFF0CpreserveSessions=${e}`),await P(!!e),t.json({ok:!0,preserveSessions:e,message:e?"Bridge will preserve sessions for aws-mcp-server restart":"Bridge will clean up sessions on shutdown"})}catch(s){const n=s;l.error("[prepare-restart] Error:",n),t.status(500).json({error:n.message})}}),d.post("/update-bridge",j,async(r,t)=>{const e=re(),s=["install","-g","aws-runtime-bridge@latest","--omit=optional"],n=O(r.body?.requestedByUserId);try{if(!n){t.status(400).json({error:"requestedByUserId is required"});return}const a=E({operationType:"update",requestedByUserId:n,schedulerBaseUrl:r.body?.schedulerBaseUrl,runtimeBridgeBaseUrl:K(r),status:"accepted",message:"Bridge \u66F4\u65B0\u8BF7\u6C42\u5DF2\u6536\u5230\uFF0C\u5C06\u5728\u540E\u53F0\u6267\u884C\u3002"});await b(a),ne({command:e,args:s,operation:a}),t.json({ok:!0,operationId:a.operationId,message:"Bridge \u66F4\u65B0\u5DF2\u5728\u540E\u53F0\u5F00\u59CB\uFF0C\u5B8C\u6210\u540E\u4F1A\u901A\u8FC7\u6D88\u606F\u4E2D\u5FC3\u901A\u77E5\u7ED3\u679C\u3002"})}catch(a){const i=a;l.error("[update-bridge] Error:",i),t.status(500).json({error:i.message||"update bridge failed"})}}),d.post("/restart-bridge",j,async(r,t)=>{const{preserveSessions:e=!0}=r.body||{},s=O(r.body?.requestedByUserId);try{if(!s){t.status(400).json({error:"requestedByUserId is required"});return}l.info(`[restart-bridge] \u6536\u5230\u5B9E\u4F8B Bridge \u91CD\u542F\u8BF7\u6C42\uFF0CpreserveSessions=${e}`);const n=E({operationType:"restart",requestedByUserId:s,schedulerBaseUrl:r.body?.schedulerBaseUrl,runtimeBridgeBaseUrl:K(r),status:"accepted",message:"Bridge \u5DF2\u6536\u5230\u91CD\u542F\u8BF7\u6C42\uFF1B\u4E0B\u6B21\u542F\u52A8\u540E\u4F1A\u53D1\u9001\u786E\u8BA4\u901A\u77E5\u3002"});await b(n),await P(!!e),t.json({ok:!0,operationId:n.operationId,preserveSessions:!!e,message:"Bridge \u6B63\u5728\u4F18\u96C5\u9000\u51FA\uFF1B\u4E0B\u6B21\u542F\u52A8\u540E\u4F1A\u901A\u8FC7\u6D88\u606F\u4E2D\u5FC3\u901A\u77E5\u7ED3\u679C\u3002\u82E5\u672A\u7531\u5B88\u62A4\u8FDB\u7A0B\u7BA1\u7406\uFF0C\u8BF7\u624B\u52A8\u91CD\u65B0\u542F\u52A8\u3002"}),setTimeout(()=>{if(process.exitCode=42,v){v("PANEL_RESTART",!!e).catch(a=>{const i=a;l.error("[restart-bridge] graceful shutdown failed:",i),process.exit(1)});return}process.exit(42)},250)}catch(n){const a=n;l.error("[restart-bridge] Error:",a),t.status(500).json({error:a.message||"restart bridge failed"})}});export{de as buildAmbiguousSchedulerBaseUrlResponse,ie as buildConnectionCheckResponse,le as buildSchedulerPingFailureResponse,ge as buildToolStatusDetectionTargets,fe as buildUninstallFailureMessage,d as instanceRouter,Ee as setGracefulShutdownFn,T as summarizeToolStatus};
|
|
1
|
+
import{Router as F}from"express";import I from"axios";import{spawn as N}from"node:child_process";import{createHash as $,timingSafeEqual as M}from"node:crypto";import{getBridgeVersion as y,resolveSchedulerBaseUrlFrom as z}from"../config.js";import{validateToken as h,validateTokenOrPanelSession as v}from"../middleware/auth.js";import{getConfiguredConnectionKeys as _,getRegistrationState as H,requestRuntimeAccessTokenRefreshForServer as X,resolveSchedulerBaseUrlFromToken as V}from"../services/auto-register.js";import{discoverCcSwitchConfiguredItems as W,loadCcSwitchSdk as G}from"../services/cc-switch-sdk.js";import{initInstance as J,syncLegacyStateFromSdk as Y}from"../services/instance-init-service.js";import{setAgentFeatures as Q,getAgentFeatures as E}from"../services/instance-features.js";import{createBridgeLifecycleOperation as C,deliverPendingBridgeLifecycleNotifications as x,upsertBridgeLifecycleOperation as b}from"../services/lifecycle-state.js";import{loadInstanceState as L,saveInstanceState as A}from"../services/instance-state.js";import{getRuntimeAccessToken as Z}from"../services/runtime-binding.js";import{detectToolStatuses as R,ensureToolsInstalled as ee,SUPPORTED_INSTALLABLE_TOOLS as U,SUPPORTED_UNINSTALLABLE_TOOLS as q,uninstallTools as te}from"../services/tool-installer.js";import{createLogger as re}from"../utils/logger.js";const l=re("instance"),se=["acode","claude","opencode","codex"];let j=null;function Le(r){j=r}const d=F();function ne(){return process.platform==="win32"?"npm.cmd":"npm"}function O(r){return r.length>16e3?`${r.slice(r.length-16e3)}
|
|
2
|
+
[output truncated]`:r}function oe(r,t){return new Promise((e,s)=>{const n=N(r,t,{shell:!1,windowsHide:!0});let a="",i="";n.stdout.on("data",o=>{a+=o.toString("utf8")}),n.stderr.on("data",o=>{i+=o.toString("utf8")}),n.on("error",s),n.on("close",o=>{e({command:r,args:t,exitCode:o,stdout:O(a),stderr:O(i)})})})}function K(r){return String(r||"").trim()||void 0}function P(r){const t=r.get("host");if(t)return`${r.protocol}://${t}`}async function ae(r){const t={...r.operation,status:"running",message:"Bridge \u66F4\u65B0\u6B63\u5728\u540E\u53F0\u6267\u884C\u3002"};await b(t);try{l.info("[update-bridge] \u6B63\u5728\u540E\u53F0\u66F4\u65B0 aws-runtime-bridge \u5230\u6700\u65B0\u7248\u672C");const e=await oe(r.command,r.args),s=e.exitCode===0;await b({...t,status:s?"succeeded":"failed",message:s?"Bridge \u66F4\u65B0\u5B8C\u6210\uFF0C\u8BF7\u91CD\u542F\u5B9E\u4F8B Bridge \u4EE5\u52A0\u8F7D\u65B0\u7248\u672C\u3002":`Bridge \u66F4\u65B0\u5931\u8D25\uFF0Cnpm \u9000\u51FA\u7801: ${e.exitCode??"unknown"}`,error:s?void 0:e.stderr||e.stdout}),await x()}catch(e){const s=e;l.error("[update-bridge] background update failed:",s),await b({...t,status:"failed",message:"Bridge \u66F4\u65B0\u5931\u8D25\u3002",error:s.message||"update bridge failed"}),await x()}}async function D(r){const t=await import("node:fs/promises"),e=await import("node:path"),s=await import("node:os"),n=e.join(s.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");if(r){await t.mkdir(e.dirname(n),{recursive:!0}),await t.writeFile(n,JSON.stringify({preserveSessions:!0,timestamp:new Date().toISOString()}),"utf-8"),l.info(`[prepare-restart] \u5DF2\u521B\u5EFA\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\u6587\u4EF6: ${n}`);return}try{await t.unlink(n),l.info("[prepare-restart] \u5DF2\u5220\u9664\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\u6587\u4EF6")}catch{}}function ie(r){return $("md5").update(r,"utf8").digest("hex")}function le(r){const t=r.trim().toLowerCase();if(!/^[a-f0-9]{32}$/.test(t))return!1;const e=Buffer.from(t,"hex");return _().map(s=>s.trim()).filter(Boolean).some(s=>{const n=Buffer.from(ie(s),"hex");return n.length===e.length&&M(n,e)})}function ce(r){const e=_().length>0,s=y();return e?le(r)?{status:200,body:{ok:!0,runtimeBridge:"healthy",version:s,connectionKeyMatched:!0,connectionKeyRequired:!0}}:{status:401,body:{ok:!1,error:"connection_key_mismatch",version:s,connectionKeyMatched:!1,connectionKeyRequired:!0}}:{status:200,body:{ok:!0,runtimeBridge:"healthy",version:s,connectionKeyMatched:!0,connectionKeyRequired:!1}}}function ue(r,t){const s=t.trim()||"http://localhost:8080",n=/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?(?:\/|$)/i.test(s);return{ok:!1,error:r.message||"scheduler ping failed",failureStage:"scheduler_ping",runtimeBridge:"healthy",schedulerBaseUrl:s,hint:n?"aws-runtime-bridge \u5DF2\u8FDE\u901A\uFF0C\u4F46\u5B83\u56DE\u8FDE\u8C03\u5EA6\u4E2D\u5FC3\u5931\u8D25\u3002\u8BF7\u5728 bridge \u542F\u52A8\u73AF\u5883\u4E2D\u5C06 AWS_RUNTIME_SCHEDULER_BASE_URL \u914D\u7F6E\u4E3A\u8BE5\u5B9E\u4F8B\u53EF\u8BBF\u95EE\u7684\u8C03\u5EA6\u4E2D\u5FC3\u5730\u5740\uFF0C\u4F8B\u5982 http://<server-host>:7380\u3002":"aws-runtime-bridge \u5DF2\u8FDE\u901A\uFF0C\u4F46\u5B83\u56DE\u8FDE\u8C03\u5EA6\u4E2D\u5FC3\u5931\u8D25\u3002\u8BF7\u786E\u8BA4 AWS_RUNTIME_SCHEDULER_BASE_URL \u6307\u5411\u7684\u8C03\u5EA6\u4E2D\u5FC3\u5730\u5740\u53EF\u4ECE bridge \u673A\u5668\u8BBF\u95EE\uFF0C\u5E76\u4E14\u8FD0\u884C\u65F6\u8BBF\u95EE\u4EE4\u724C\u4ECD\u6709\u6548\u3002"}}function de(r){if(typeof r!="object"||r===null)return;const t=Reflect.get(r,"response");if(typeof t!="object"||t===null)return;const e=Reflect.get(t,"status");return typeof e=="number"?e:void 0}async function ge(r,t){try{const e=await I.get(`${r}/api/runtime/ping`,{headers:{"X-Runtime-Token":t}});return{schedulerReachable:e.status>=200&&e.status<300,tokenRefreshed:!1}}catch(e){if(de(e)!==401)throw e;const s=await X(r);if(!s.success||!s.runtimeAccessToken)throw e;const n=await I.get(`${r}/api/runtime/ping`,{headers:{"X-Runtime-Token":s.runtimeAccessToken}});return{schedulerReachable:n.status>=200&&n.status<300,tokenRefreshed:!0}}}function fe(r){return{ok:!1,error:"ambiguous_scheduler_base_url",failureStage:"scheduler_ping",runtimeBridge:"healthy",schedulerBaseUrl:"",autoRegisterTargetUrls:r,hint:"Multiple autoRegisterTargets.serverUrl values were found, so bridge cannot safely infer which scheduler /runtime/ping should call back. Set AWS_RUNTIME_SCHEDULER_BASE_URL explicitly, or use future schedulerId/token-bound multi-scheduler routing."}}function me(r){return Array.from(new Set([...r,...se].map(t=>String(t||"").trim().toLowerCase()).filter(Boolean)))}function pe(r,t){const e=r.filter(s=>t[s]?.installed);return e.length===0?"":e.map(s=>{const n=t[s],a=n?.error||n?.executable||"command is still available";return`${s}: ${a}`}).join("; ")}function T(r){return Object.fromEntries(Object.entries(r||{}).map(([t,e])=>[t,{installed:!!e?.installed,version:e?.version||null,executable:e?.executable||null,error:e?.error||null}]))}let k=null;const he=3e5;async function Se(){return(await I.get("https://registry.npmjs.org/aws-runtime-bridge/latest",{timeout:1e4,responseType:"json"})).data?.version||"unknown"}d.get("/check-update",async(r,t)=>{try{let e;k&&Date.now()-k.ts<he?e=k.latestVersion:(e=await Se(),k={latestVersion:e,ts:Date.now()});const s=y(),n=e!=="unknown"&&s!=="unknown"&&e!==s;t.json({ok:!0,hasUpdate:n,currentVersion:s,latestVersion:e})}catch(e){const s=e;l.warn("[check-update] Failed to query npm registry:",s.message),t.json({ok:!1,hasUpdate:!1,currentVersion:y(),latestVersion:null,error:s.message||"failed to check for updates"})}}),d.get("/healthz",(r,t)=>{t.json({ok:!0,runtimeBridge:"healthy"})}),d.get("/connection-check",(r,t)=>{const e=String(r.header("X-Bridge-Connection-Key-MD5")||""),s=ce(e);t.status(s.status).json(s.body)}),d.get("/ping",h,async(r,t)=>{let e=z(r.header("X-Scheduler-Base-Url"),r.header("X-Bridge-Instance-Id"),r.header("X-Bridge-Instance-Name"));if(e.source==="ambiguous-auto-register-targets"){const n=V(r.header("X-Runtime-Token"));if(n)e={url:n,source:"token-match",ambiguousTargetUrls:[]};else{const a=r.header("X-Bridge-Instance-Id");if(a){const i=H(),o=Object.entries(i.registrations).find(([,c])=>c===a)?.[0];o&&(e={url:o,source:"instance-id-match",ambiguousTargetUrls:[]})}if(!e.url||e.source==="ambiguous-auto-register-targets"){t.status(400).json(fe(e.ambiguousTargetUrls));return}}}const s=e.url;try{const n=Z(s);if(!n){t.status(401).json({ok:!1,error:"runtime_access_token_required"});return}const a=await ge(s,n);t.json({ok:!0,runtimeBridge:"healthy",version:y(),schedulerReachable:a.schedulerReachable,tokenRefreshed:a.tokenRefreshed,schedulerBaseUrl:s,instanceId:e.instanceId,instanceName:e.instanceName})}catch(n){const a=n;t.status(502).json(ue(a,s))}}),d.post("/init-instance",h,async(r,t)=>{const{agentId:e,workspacePath:s,skillEnabled:n,mcpEnabled:a,ccSwitchEnabledTools:i,skillPackage:o,skillPackages:c,mcpServers:m}=r.body||{};if(!e||!s){t.status(400).json({error:"agentId and workspacePath are required"});return}try{l.info("[init-instance] Request received",{agentId:String(e),workspacePath:String(s),skillEnabled:n,mcpEnabled:a,ccSwitchEnabledTools:i});const u=await J(e,s,{skillEnabled:n,mcpEnabled:a,ccSwitchEnabledTools:i,skillPackage:o,skillPackages:c,mcpServers:m});l.info("[init-instance] Initialization completed",{agentId:String(e),ok:u.ok,logCount:u.logs?.length||0,enabledTools:u.enabledTools}),t.json(u)}catch(u){const g=u;l.error("[init-instance] Initialization failed",{agentId:String(e),workspacePath:String(s),error:g?.message||String(u),stack:g?.stack||null}),t.status(400).json({error:g?.message||"initialize instance failed"})}}),d.post("/features",h,async(r,t)=>{const{agentId:e,features:s}=r.body||{};if(!e){t.status(400).json({error:"agentId is required"});return}Q(String(e),s),l.info("[instance/features] \u80FD\u529B\u5F00\u5173\u5DF2\u66F4\u65B0",{agentId:String(e),features:E(String(e))}),t.json({ok:!0,agentId:String(e),features:E(String(e))})}),d.post("/cc-switch/state",h,async(r,t)=>{const{agentId:e}=r.body||{};if(!e){t.status(400).json({error:"agentId is required"});return}try{l.info("[cc-switch/state] Request received",{agentId:String(e)});const s=await G(e),n=await W(s),i=(await Y(e,s)).state,o=me(i.enabledTools||[]);l.info("[cc-switch/state] Detecting SDK statuses",{agentId:String(e),detectionTargets:o});const c=await R(o);l.info("[cc-switch/state] SDK status detection completed",{agentId:String(e),toolStatus:T(c),importedMcpCount:n.mcpServers,importedSkillCount:n.skills}),t.json({ok:!0,agentId:String(e),imported:{mcpServers:n.mcpServers,skills:n.skills},state:{...i,toolStatus:c}})}catch(s){const n=s;l.error("[cc-switch/state] Failed to load state",{agentId:String(e),error:n?.message||String(s),stack:n?.stack||null}),t.status(400).json({error:n?.message||"load state failed"})}}),d.post("/cc-switch/install-tools",h,async(r,t)=>{const{agentId:e,tools:s}=r.body||{};if(!e){t.status(400).json({error:"agentId is required"});return}const n=Array.isArray(s)?s.map(o=>String(o||"").trim().toLowerCase()).filter(Boolean):[];l.info("[cc-switch/install-tools] Request received",{agentId:String(e),requestedTools:n});const a=new Set(U),i=n.filter(o=>a.has(o));if(l.info("[cc-switch/install-tools] Request normalized",{agentId:String(e),requestedTools:n,installableTools:i,supportedInstallableTools:U}),i.length===0){l.warn("[cc-switch/install-tools] No supported installable tools requested",{agentId:String(e),requestedTools:n}),t.status(400).json({error:`tools must include ${U.join(", ")}`});return}try{const o=await L(e),c=Array.from(new Set([...o.enabledTools||[],...i]));l.info("[cc-switch/install-tools] Starting installer",{agentId:String(e),installableTools:i,previousEnabledTools:o.enabledTools||[],nextEnabledTools:c});const m=await ee(i);l.info("[cc-switch/install-tools] Installer completed",{agentId:String(e),toolStatus:T(m)});const u=await R(c);l.info("[cc-switch/install-tools] Refreshed enabled SDK statuses",{agentId:String(e),refreshedToolStatus:T(u)});const g={...u,...m},p=await A(e,{...o,enabledTools:c,toolStatus:g}),w=new Set(i),S=Object.entries(g).filter(([f])=>w.has(f)).filter(([,f])=>!f.installed).map(([f,B])=>({tool:f,error:B.error||null}));S.length>0&&l.warn("[cc-switch/install-tools] Some SDKs remain unavailable",{agentId:String(e),failedTools:S}),l.info("[cc-switch/install-tools] State saved",{agentId:String(e),enabledTools:p.enabledTools,toolStatus:T(g)}),t.json({ok:S.length===0,agentId:String(e),toolStatus:g,failedTools:S,state:p})}catch(o){const c=o;l.error("[cc-switch/install-tools] Install route failed",{agentId:String(e),requestedTools:n,installableTools:i,error:c?.message||String(o),stack:c?.stack||null}),t.status(400).json({error:c?.message||"install tools failed"})}}),d.post("/cc-switch/uninstall-tools",h,async(r,t)=>{const{agentId:e,tools:s}=r.body||{};if(!e){t.status(400).json({error:"agentId is required"});return}const n=Array.isArray(s)?s.map(o=>String(o||"").trim().toLowerCase()).filter(Boolean):[],a=new Set(q),i=n.filter(o=>a.has(o));if(i.length===0){t.status(400).json({error:`tools must include ${q.join(", ")}`});return}try{const o=await L(e),c=new Set(i),m=(o.enabledTools||[]).filter(B=>!c.has(String(B||"").trim().toLowerCase())),u=await te(i),p={...await R([...m,...i]),...u},w=pe(i,p),S=w?o.enabledTools||[]:m,f=await A(e,{...o,enabledTools:S,toolStatus:p});if(w){t.status(400).json({ok:!1,agentId:String(e),error:`uninstall incomplete: ${w}`,toolStatus:p,state:f});return}t.json({ok:!0,agentId:String(e),toolStatus:p,state:f})}catch(o){const c=o;t.status(400).json({error:c?.message||"uninstall tools failed"})}}),d.post("/prepare-restart",h,async(r,t)=>{const{preserveSessions:e=!0}=r.body||{};try{l.info(`[prepare-restart] \u6536\u5230\u51C6\u5907\u91CD\u542F\u901A\u77E5\uFF0CpreserveSessions=${e}`),await D(!!e),t.json({ok:!0,preserveSessions:e,message:e?"Bridge will preserve sessions for aws-mcp-server restart":"Bridge will clean up sessions on shutdown"})}catch(s){const n=s;l.error("[prepare-restart] Error:",n),t.status(500).json({error:n.message})}}),d.post("/update-bridge",v,async(r,t)=>{const e=ne(),s=["install","-g","aws-runtime-bridge@latest","--omit=optional"],n=K(r.body?.requestedByUserId);try{if(!n){t.status(400).json({error:"requestedByUserId is required"});return}const a=C({operationType:"update",requestedByUserId:n,schedulerBaseUrl:r.body?.schedulerBaseUrl,runtimeBridgeBaseUrl:P(r),status:"accepted",message:"Bridge \u66F4\u65B0\u8BF7\u6C42\u5DF2\u6536\u5230\uFF0C\u5C06\u5728\u540E\u53F0\u6267\u884C\u3002"});await b(a),ae({command:e,args:s,operation:a}),t.json({ok:!0,operationId:a.operationId,message:"Bridge \u66F4\u65B0\u5DF2\u5728\u540E\u53F0\u5F00\u59CB\uFF0C\u5B8C\u6210\u540E\u4F1A\u901A\u8FC7\u6D88\u606F\u4E2D\u5FC3\u901A\u77E5\u7ED3\u679C\u3002"})}catch(a){const i=a;l.error("[update-bridge] Error:",i),t.status(500).json({error:i.message||"update bridge failed"})}}),d.post("/restart-bridge",v,async(r,t)=>{const{preserveSessions:e=!0}=r.body||{},s=K(r.body?.requestedByUserId);try{if(!s){t.status(400).json({error:"requestedByUserId is required"});return}l.info(`[restart-bridge] \u6536\u5230\u5B9E\u4F8B Bridge \u91CD\u542F\u8BF7\u6C42\uFF0CpreserveSessions=${e}`);const n=C({operationType:"restart",requestedByUserId:s,schedulerBaseUrl:r.body?.schedulerBaseUrl,runtimeBridgeBaseUrl:P(r),status:"accepted",message:"Bridge \u5DF2\u6536\u5230\u91CD\u542F\u8BF7\u6C42\uFF1B\u4E0B\u6B21\u542F\u52A8\u540E\u4F1A\u53D1\u9001\u786E\u8BA4\u901A\u77E5\u3002"});await b(n),await D(!!e),t.json({ok:!0,operationId:n.operationId,preserveSessions:!!e,message:"Bridge \u6B63\u5728\u4F18\u96C5\u9000\u51FA\uFF1B\u4E0B\u6B21\u542F\u52A8\u540E\u4F1A\u901A\u8FC7\u6D88\u606F\u4E2D\u5FC3\u901A\u77E5\u7ED3\u679C\u3002\u82E5\u672A\u7531\u5B88\u62A4\u8FDB\u7A0B\u7BA1\u7406\uFF0C\u8BF7\u624B\u52A8\u91CD\u65B0\u542F\u52A8\u3002"}),setTimeout(()=>{if(process.exitCode=42,j){j("PANEL_RESTART",!!e).catch(a=>{const i=a;l.error("[restart-bridge] graceful shutdown failed:",i),process.exit(1)});return}process.exit(42)},250)}catch(n){const a=n;l.error("[restart-bridge] Error:",a),t.status(500).json({error:a.message||"restart bridge failed"})}});export{fe as buildAmbiguousSchedulerBaseUrlResponse,ce as buildConnectionCheckResponse,ue as buildSchedulerPingFailureResponse,me as buildToolStatusDetectionTargets,pe as buildUninstallFailureMessage,d as instanceRouter,Le as setGracefulShutdownFn,T as summarizeToolStatus};
|
|
3
3
|
|
package/dist/routes/pty.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export interface PtySessionSummary {
|
|
|
20
20
|
attachedClients: number;
|
|
21
21
|
ownerUserId?: string;
|
|
22
22
|
tenantId?: string;
|
|
23
|
-
|
|
23
|
+
projectId?: string;
|
|
24
24
|
}
|
|
25
25
|
interface PtySessionEntry extends PtySessionSummary {
|
|
26
26
|
ptyProcess: pty.IPty;
|
|
@@ -57,7 +57,7 @@ export declare function createPtySession(input: {
|
|
|
57
57
|
preCommand?: unknown;
|
|
58
58
|
ownerUserId?: unknown;
|
|
59
59
|
tenantId?: unknown;
|
|
60
|
-
|
|
60
|
+
projectId?: unknown;
|
|
61
61
|
}): PtySessionSummary;
|
|
62
62
|
export declare function resolvePtyExitedTtlMs(env?: NodeJS.ProcessEnv): number;
|
|
63
63
|
export declare function resolveMaxPtySessions(env?: NodeJS.ProcessEnv): number;
|
package/dist/routes/pty.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import L from"node:crypto";import A from"node:fs";import l from"node:path";import{Router as N}from"express";import*as D from"node-pty";import{v4 as M}from"uuid";import U,{WebSocketServer as z}from"ws";import{isRuntimeTokenValid as x,validateToken as h}from"../middleware/auth.js";import{createLogger as R}from"../utils/logger.js";const p=R("pty"),j=80,W=24,_=2e5,E=30*60*1e3,$=5*60*1e3,v=60*1e3,b=8,F=new Set(["false","halt","nologin","reboot","shutdown","sync","true"]),c=new Map,w=new Map;function B(e=process.env){const t=String(e.AWS_PTY_IDLE_TTL_MS||"").trim();if(!t)return E;const r=Number(t);return!Number.isFinite(r)||r<1e3?E:r}function Y(e=process.platform,t=process.env,r=A.existsSync){return e==="win32"?{shell:String(t.ComSpec||t.COMSPEC||"").trim()||"powershell.exe",args:[]}:{shell:[String(t.SHELL||"").trim(),"/bin/bash","/bin/sh"].find(o=>X(o,r))||"/bin/sh",args:[]}}function X(e,t){const r=e.trim();if(!r)return!1;const n=l.basename(r).toLowerCase();return F.has(n)?!1:!l.isAbsolute(r)||t(r)}function H(e,t=process.platform,r=process.env){const n=String(e||"auto").trim();if(!n||n==="auto")return Y(t,r);const i=new Set(["bash","sh","zsh","fish","pwsh","pwsh.exe","powershell","powershell.exe","cmd","cmd.exe"]),o=(t==="win32"?l.win32.basename(n):l.basename(n)).toLowerCase();if(!i.has(o))throw new Error(`shell is not allowed: ${n}`);return{shell:/^[A-Za-z]:[\\/]/.test(n)||n.startsWith("\\")||n.startsWith("/")?n:t==="win32"?{cmd:"cmd.exe",powershell:"powershell.exe",pwsh:"pwsh.exe"}[o]??n:n,args:[]}}function J(e,t){const r=l.relative(l.resolve(t),l.resolve(e));return r===""||!r.startsWith("..")&&!l.isAbsolute(r)}function V(e=process.env){return String(e.AWS_PTY_ALLOWED_ROOTS||"").split(l.delimiter).map(t=>t.trim()).filter(Boolean).map(t=>l.resolve(t))}function K(e,t=process.env){const r=String(e||"").trim();if(!r)throw new Error("workspacePath is required");if(!l.isAbsolute(r))throw new Error("workspacePath must be absolute");const n=l.resolve(r);if(!A.statSync(n).isDirectory())throw new Error("workspacePath must be an existing directory");const o=V(t);if(o.length>0&&!o.some(a=>J(n,a)))throw new Error("workspacePath is outside allowed roots");return n}function T(e,t){const r=Number(e);return!Number.isInteger(r)||r<=0?t:Math.min(r,500)}function q(e){return{...e,TERM:e.TERM||"xterm-256color",COLORTERM:e.COLORTERM||"truecolor"}}function Z(e,t){e.outputBuffer=`${e.outputBuffer}${t}`,e.outputBuffer.length>_&&(e.outputBuffer=e.outputBuffer.slice(-_))}function g(e){return{id:e.id,title:e.title,workspacePath:e.workspacePath,shell:e.shell,cols:e.cols,rows:e.rows,status:e.status,createdAt:e.createdAt,lastActiveAt:e.lastActiveAt,exitCode:e.exitCode,signal:e.signal,attachedClients:e.sockets.size,ownerUserId:e.ownerUserId,tenantId:e.tenantId,projectId:e.projectId}}function k(e,t){e.readyState===U.OPEN&&e.send(JSON.stringify(t))}function I(e,t){for(const r of e.sockets)k(r,t)}function P(e){e.idleTimer&&clearTimeout(e.idleTimer),e.idleTimer=setTimeout(()=>{e.sockets.size===0&&S(e.id,"idle-timeout")},B())}function C(e){e.idleTimer&&(clearTimeout(e.idleTimer),e.idleTimer=null)}function G(e){if(c.size>=re())throw new Error("maximum PTY sessions reached");const t=K(e.workspacePath),r=H(e.shell),n=T(e.cols,j),i=T(e.rows,W),o=`pty_${M()}`,a=new Date().toISOString(),d=String(e.title||"").trim()||`Terminal ${c.size+1}`,u=D.spawn(r.shell,r.args,{name:"xterm-256color",cols:n,rows:i,cwd:t,env:q(process.env)}),s={id:o,title:d,workspacePath:t,shell:r.shell,cols:n,rows:i,status:"running",createdAt:a,lastActiveAt:a,attachedClients:0,ptyProcess:u,sockets:new Set,outputBuffer:"",idleTimer:null,persistent:e.persistent===!0,ownerUserId:String(e.ownerUserId||"").trim()||void 0,tenantId:String(e.tenantId||"").trim()||void 0,projectId:String(e.projectId||"").trim()||void 0};return u.onData(f=>{s.lastActiveAt=new Date().toISOString(),Z(s,f),I(s,{type:"output",data:f})}),u.onExit(({exitCode:f,signal:m})=>{s.status="exited",s.exitCode=f,s.signal=m,s.lastActiveAt=new Date().toISOString(),I(s,{type:"exit",exitCode:f,signal:m}),s.sockets.size===0&&!s.persistent?P(s):s.persistent&&(s.idleTimer&&clearTimeout(s.idleTimer),s.idleTimer=setTimeout(()=>{S(s.id,"exited-timeout")},te()))}),c.set(o,s),s.persistent||P(s),Q(s,e.preCommand),p.info(`created pty session id=${o}, cwd=${t}, shell=${r.shell}`),g(s)}function Q(e,t){const r=typeof t=="string"?t:"";if(!r.trim())return;const n=`${r.replace(/\n/g,"\r").replace(/\r+$/g,"")}\r`;try{e.ptyProcess.write(n)}catch(i){const o=i;p.warn(`failed to inject pty pre-command sessionId=${e.id}: ${o.message}`)}}function ee(e=process.env){const t=String(e.AWS_PTY_CONNECT_TOKEN_TTL_MS||"").trim();if(!t)return v;const r=Number(t);return!Number.isFinite(r)||r<5e3||r>10*60*1e3?v:r}function te(e=process.env){const t=String(e.AWS_PTY_EXITED_TTL_MS||"").trim();if(!t)return $;const r=Number(t);return!Number.isFinite(r)||r<1e3?$:r}function re(e=process.env){const t=String(e.AWS_PTY_MAX_SESSIONS||"").trim();if(!t)return b;const r=Number(t);return!Number.isInteger(r)||r<1||r>100?b:r}function ne(e){if(!e||typeof e!="object")return{workspacePath:void 0};const t=e;return{workspacePath:t.workspacePath,title:t.title,shell:t.shell,cols:t.cols,rows:t.rows,persistent:t.persistent,preCommand:t.preCommand,ownerUserId:t.ownerUserId,tenantId:t.tenantId,projectId:t.projectId}}function se(){return Array.from(c.values()).map(g)}function oe(e){const t=c.get(e);return t?g(t):void 0}function ie(e){if(!c.has(e))return;const t=`ptyws_${L.randomBytes(32).toString("base64url")}`,r=Date.now()+ee();return w.set(t,{sessionId:e,expiresAt:r}),{token:t,expiresAt:new Date(r).toISOString()}}function ce(e,t){const r=w.get(t);return r?r.expiresAt<Date.now()?(w.delete(t),p.warn(`[pty-ws] consumePtyConnectToken: token \u5DF2\u8FC7\u671F, sessionId=${e}, expiredAt=${new Date(r.expiresAt).toISOString()}`),!1):r.sessionId!==e?(p.warn(`[pty-ws] consumePtyConnectToken: sessionId \u4E0D\u5339\u914D, expected=${r.sessionId}, actual=${e}`),!1):(w.delete(t),p.info(`[pty-ws] consumePtyConnectToken: \u6210\u529F, sessionId=${e}`),!0):(p.warn(`[pty-ws] consumePtyConnectToken: token \u4E0D\u5B58\u5728, sessionId=${e}, ptyConnectTokens.size=${w.size}`),!1)}function ae(e){for(const[t,r]of w.entries())r.sessionId===e&&w.delete(t)}function S(e,t="closed"){const r=c.get(e);if(!r)return!1;C(r),ae(e),I(r,{type:"status",status:"closing",reason:t});for(const n of r.sockets)n.close(1e3,t);return r.sockets.clear(),r.status==="running"&&r.ptyProcess.kill(),c.delete(e),p.info(`closed pty session id=${e}, reason=${t}`),!0}function ge(e="shutdown"){for(const t of Array.from(c.keys()))S(t,e)}const y=N();y.get("/sessions",h,(e,t)=>{t.json({ok:!0,sessions:se()})}),y.post("/sessions",h,(e,t)=>{try{const r=G(ne(e.body));t.status(201).json({ok:!0,session:r})}catch(r){const n=r;t.status(400).json({error:n.message})}}),y.get("/sessions/:sessionId",h,(e,t)=>{const r=oe(e.params.sessionId);if(!r){t.status(404).json({error:"pty session not found"});return}t.json({ok:!0,session:r})}),y.delete("/sessions/:sessionId",h,(e,t)=>{if(!S(e.params.sessionId,"explicit-close")){t.status(404).json({error:"pty session not found"});return}t.json({ok:!0})}),y.post("/sessions/:sessionId/connect-token",h,(e,t)=>{const r=ie(e.params.sessionId);if(!r){t.status(404).json({error:"pty session not found"});return}t.json({ok:!0,...r})});function ue(e){const t=e.toString();try{return JSON.parse(t)}catch{return{type:"input",data:t}}}function le(e,t){C(e),e.sockets.add(t),e.lastActiveAt=new Date().toISOString(),k(t,{type:"status",status:e.status,session:g(e)}),e.outputBuffer&&k(t,{type:"output",data:e.outputBuffer,replay:!0}),t.on("message",r=>{const n=ue(r);if(!n||typeof n!="object")return;const i=n,o=String(i.type||"");if(e.lastActiveAt=new Date().toISOString(),o==="input"){e.ptyProcess.write(String(i.data||""));return}if(o==="resize"){const a=T(i.cols,e.cols),d=T(i.rows,e.rows);e.cols=a,e.rows=d,e.ptyProcess.resize(a,d);return}if(o==="close"){S(e.id,"client-close");return}o==="ping"&&k(t,{type:"pong"})}),t.on("close",()=>{e.sockets.delete(t),e.lastActiveAt=new Date().toISOString(),e.sockets.size===0&&e.status==="running"&&!e.persistent&&P(e)})}function pe(e,t){const r=t.searchParams.get("token")||"";if(r.trim())return r.trim();const n=e.headers["x-runtime-token"];return Array.isArray(n)?n[0]?.trim()||"":typeof n=="string"?n.trim():String(e.headers.authorization||"").match(/^Bearer\s+(.+)$/i)?.[1]?.trim()||""}function ke(e){const t=new z({noServer:!0});e.on("upgrade",(r,n,i)=>{const o=r.headers.host||"localhost",a=new URL(r.url||"/",`http://${o}`),d=a.pathname.match(/^\/pty\/sessions\/([^/]+)\/stream$/);if(!d)return;const u=pe(r,a),s=decodeURIComponent(d[1]||""),f=u?u.length>12?u.substring(0,12)+"...":u:"empty";if(p.info(`[pty-ws] upgrade \u8BF7\u6C42: sessionId=${s}, token=${f}, pathname=${a.pathname}`),!x(u)&&!ce(s,u)){p.warn(`[pty-ws] token \u6821\u9A8C\u5931\u8D25: sessionId=${s}, token=${f}, runtimeTokenValid=${x(u)}, ptySessions.size=${c.size}`),n.write(`HTTP/1.1 401 Unauthorized\r
|
|
2
2
|
\r
|
|
3
|
-
`),n.destroy();return}const m=
|
|
3
|
+
`),n.destroy();return}const m=c.get(s);if(!m){p.warn(`[pty-ws] session \u4E0D\u5B58\u5728: sessionId=${s}, ptySessions.size=${c.size}, keys=${Array.from(c.keys()).join(",")}`),n.write(`HTTP/1.1 404 Not Found\r
|
|
4
4
|
\r
|
|
5
|
-
`),n.destroy();return}p.info(`[pty-ws] handleUpgrade: sessionId=${s}, status=${m.status}, persistent=${m.persistent}, sockets=${m.sockets.size}`),t.handleUpgrade(r,n,i,
|
|
5
|
+
`),n.destroy();return}p.info(`[pty-ws] handleUpgrade: sessionId=${s}, status=${m.status}, persistent=${m.persistent}, sockets=${m.sockets.size}`),t.handleUpgrade(r,n,i,O=>{le(m,O)})})}export{ke as attachPtyWebSocketServer,ge as closeAllPtySessions,S as closePtySession,ie as createPtyConnectToken,G as createPtySession,oe as getPtySessionSummary,J as isPathInsideRoot,se as listPtySessions,y as ptyRouter,c as ptySessions,Y as resolveDefaultShell,re as resolveMaxPtySessions,te as resolvePtyExitedTtlMs,B as resolvePtyIdleTtlMs,K as resolvePtyWorkspacePath,H as resolveRequestedShell};
|
|
6
6
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Router as g}from"express";import{createLogger as
|
|
1
|
+
import{Router as g}from"express";import{createLogger as I}from"../utils/logger.js";import{validateToken as s}from"../middleware/auth.js";import{setTaskContext as m,clearTaskContext as x,getTaskContext as p,startWatching as u,stopWatching as j}from"../services/workspaceTaskChangeWatcher.js";const a=I("task-context"),c=g();c.post("/task-context",s,async(o,r)=>{try{const{agentId:t,taskInstanceId:e,taskNodeId:i,tenantId:k,workspacePath:n,projectId:d}=o.body||{};if(!t||!e||!i||!k||!n){r.status(400).json({error:"agentId, taskInstanceId, taskNodeId, tenantId, workspacePath are required"});return}await u(String(n).trim()),m({agentId:String(t).trim(),taskInstanceId:String(e).trim(),taskNodeId:String(i).trim(),tenantId:String(k).trim(),workspacePath:String(n).trim(),projectId:String(d||"").trim()}),a.info(`Task context set via API: agent=${t}, taskInstance=${e}`),r.json({ok:!0})}catch(t){const e=t;a.error(`Failed to set task context: ${e.message}`),r.status(500).json({error:e.message})}}),c.delete("/task-context",s,async(o,r)=>{try{await j(),x(),a.info("Task context cleared via API"),r.json({ok:!0})}catch(t){const e=t;a.error(`Failed to clear task context: ${e.message}`),r.status(500).json({error:e.message})}}),c.get("/task-context",s,async(o,r)=>{const t=p();r.json({ok:!0,context:t})});export{c as taskContextRouter};
|
|
2
2
|
|
package/dist/routes/terminal.js
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
import{spawn as
|
|
1
|
+
import{spawn as We}from"node:child_process";import{promises as N}from"node:fs";import we from"node:os";import j from"node:path";import{TextDecoder as ee}from"node:util";import{Router as He}from"express";import{v4 as Qe}from"uuid";import Ce from"axios";import{adapterRegistry as w,getToolActionInfo as ye,isTransientClipboardPasteFilePath as be,redactTransientClipboardPastePaths as q,registerSdkProviders as Xe,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 Ve}from"../services/instance-features.js";import{getAiConfigService as Ye}from"../services/cc-switch-sdk.js";import{prepareAcodeInstanceConfig as Ze,redactForLog as te}from"../services/instance-ai-config-service.js";import{enqueueMcpLaunchBinding as et}from"../services/mcp-launch-binding-queue.js";import{resolveSchedulerBaseUrlFromToken as $e}from"../services/auto-register.js";import{findClaudeCodeProcesses as tt,isProcessRunning as nt}from"../services/process-detector.js";import{bridgeEventBuffer as _e,sendOutput as Q,sendQuestionRequest as rt,sendStatus as _}from"../services/session-output.js";import{getAllPushStats as ot,startHeartbeatScheduler as st}from"../services/event-delta-pusher.js";import{forgetSession as v,onSdkToolUseEnd as it,onSdkToolUseStart as at}from"../services/sdk-tool-file-change-recorder.js";import{findPersistedSessionByAgentId as ct,removePersistedSession as F,savePersistedSessions as ut,updatePersistedSessionAutoCommands as dt,updatePersistedSessionRuntimeState as lt,upsertPersistedSession as mt}from"../services/terminal-persistence.js";import{getInstanceAiConfigDebugLogger as ft}from"../utils/instance-ai-config-debug-logger.js";import{logger as h}from"../utils/logger.js";const A=He();function De(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 f=new Map,pt=45e3,ne=new Map;function gt(e){if(ne.has(e))return;const n=setInterval(()=>{const t=f.get(e);if(!t){M(e);return}const r=t.currentRuntimeStatus;if(r!=="thinking"&&r!=="tool_using"&&r!=="compacting"){M(e);return}_(t.agentId,e,r,void 0,void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl}).catch(()=>{})},pt);ne.set(e,n)}function M(e){const n=ne.get(e);n&&(clearInterval(n),ne.delete(e))}const Pe=4e3,yt=`
|
|
2
2
|
|
|
3
3
|
\u8BF7\u6C42\u4F53:
|
|
4
|
-
`;function
|
|
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 ht=`
|
|
5
5
|
|
|
6
6
|
\u8BF7\u6C42\u5934:
|
|
7
|
-
`,K=new Set;async function
|
|
7
|
+
`,K=new Set;async function It(e,n){const t=[],r=[],s=j.join(e,".agentswork","memory");try{const c=(await N.readdir(s)).filter(u=>u.endsWith(".json")),d=await Promise.all(c.map(async u=>{try{const l=await N.readFile(j.join(s,u),"utf-8");return JSON.parse(l)}catch{return h.warn("[loadAgentStartupMemories] Failed to parse memory file: %s",j.join(s,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"?t.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",s)}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 p=m.value;if(!Array.isArray(p))continue;const T=d[l]==="recently_memory"?t:r;for(const y of p){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 o=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,o).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
|
-
`)}`),
|
|
11
|
+
`)}`),t.length>o&&i.push(`... \u53CA\u53E6\u5916 ${t.length-o} \u6761\u77ED\u671F\u8BB0\u5FC6`)}if(r.length>0){const c=r.slice(0,o).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>o&&i.push(`... \u53CA\u53E6\u5916 ${r.length-o} \u6761 agent \u8BA4\u77E5`)}if(i.length!==0)return i.join(`
|
|
16
16
|
|
|
17
|
-
`)}function
|
|
17
|
+
`)}function St(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 At(e){return e!=="acode"}function Tt(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;return t<=0&&r<=0&&!n.contextLimit&&!n.maxOutput&&!n.inputLimit&&!n.compactionThreshold?void 0:{inputTokens:t,outputTokens:r,...n.contextLimit?{contextLimit:n.contextLimit}:{},...n.maxOutput?{maxOutput:n.maxOutput}:{},...n.inputLimit?{inputLimit:n.inputLimit}:{},...n.compactionThreshold?{compactionThreshold:n.compactionThreshold}:{}}}function kt(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 X=new Map,wt="utf-8",Re="utf-8",xe=300,Ee=6e4;function G(e){return String(e).padStart(2,"0")}function Ct(e,n=new Date){const t=n.getFullYear(),r=G(n.getMonth()+1),s=G(n.getDate()),o=G(n.getHours()),i=G(n.getMinutes()),a=`${t}${r}${s}-${o}${i}${G(n.getSeconds())}-${String(n.getMilliseconds()).padStart(3,"0")}`;return j.join(we.homedir(),".acode","cmd-dist",e,`${t}-${r}-${s}`,o,i,`${a}-cmd.out`)}function bt(e){if(!e)return 0;const n=e.replace(/\r\n/g,`
|
|
18
18
|
`).replace(/\r/g,`
|
|
19
|
-
`),n
|
|
20
|
-
`)?
|
|
21
|
-
`).length:1}function
|
|
22
|
-
[ACode] \u547D\u4EE4\u8F93\u51FA\u8D85\u8FC7 ${
|
|
19
|
+
`),t=n.endsWith(`
|
|
20
|
+
`)?n.slice(0,-1):n;return t?t.split(`
|
|
21
|
+
`).length:1}function $t(e,n=xe){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
|
|
24
|
+
`}function _t(e=Ee){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
|
|
27
|
-
`).trim()}function
|
|
28
|
-
`),!0;const s=
|
|
26
|
+
`}async function Me(e){const n=e.outputPath||Ct(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 Dt(e){return String(e??"").replace(/\r/g,`
|
|
27
|
+
`).trim()}function Pt(e=process.platform,n=process.env){const t=n.AWS_TERMINAL_OUTPUT_ENCODING?.trim();return t||(e==="win32"?wt:Re)}function Le(e=Pt()){if(e!=="utf-8")try{return new ee(e,{fatal:!1})}catch{return new ee(Re,{fatal:!1})}return Rt()}function Rt(){let e=null,n=null,t=null;const r=[];function s(o){try{return new ee(o,{fatal:!1})}catch{return new ee("utf-8",{fatal:!1})}}return{decode(o,i){if(o!=null&&r.push(o instanceof ArrayBuffer?Buffer.from(o):Buffer.isBuffer(o)?o:Buffer.from(o.buffer,o.byteOffset,o.byteLength)),t==="gb18030")return n||(n=s("gb18030")),n.decode(o,i);e||(e=s("utf-8"));const a=e.decode(o,i);if(t===null&&a.includes("\uFFFD")){t="gb18030",n=s("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 xt(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 Et(e){const n=X.get(e.sessionId);if(n)return n;const t={currentDirectory:e.workspacePath,runningProcess:null};return X.set(e.sessionId,t),t}function Ue(e){for(const n of f.values())if(n.agentId===e)return n}async function Mt(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 o=String(n||"").trim(),i=String(t||"").trim().toLowerCase();return r.toLowerCase()==="tool_using"&&o.toLowerCase()==="waiting_input"&&i==="idle"?o:r}return String(n||"").trim()||"running"}function Lt(e,n=nt){return e.pid?n(e.pid)?ve(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=Ue(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}`),M(t),f.delete(t),v(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=X.get(e);if(!n?.runningProcess){X.delete(e);return}try{n.runningProcess.kill()}catch{}finally{n.runningProcess=null,X.delete(e)}}function C(e,n){n&&(e.seq+=1,Q(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 Ut(e,n){return n==="~"?we.homedir():j.resolve(e,n)}async function jt(e,n,t){const r=xt(t);if(r===void 0)return!1;if(r===null)return C(e,`${n.currentDirectory}\r
|
|
28
|
+
`),!0;const s=Ut(n.currentDirectory,r);try{return(await N.stat(s)).isDirectory()?(n.currentDirectory=s,C(e,`${n.currentDirectory}\r
|
|
29
29
|
`),!0):(C(e,`cd: not a directory: ${s}\r
|
|
30
30
|
`),!0)}catch(o){const i=o instanceof Error?o.message:String(o);return C(e,`cd: ${i}\r
|
|
31
|
-
`),!0}}async function
|
|
32
|
-
`),
|
|
33
|
-
`),C(
|
|
31
|
+
`),!0}}async function Bt(e,n){const t=f.get(e);if(!t)throw new Error("SDK session not found");const r=Dt(n),s=Et(t);if(!r)return{started:!1,cwd:s.currentDirectory};if(s.runningProcess)throw new Error("A terminal command is already running for this session");const o=q(r);if(C(t,`${Se(s.currentDirectory)}${o}\r
|
|
32
|
+
`),be(r))return C(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
|
+
`),C(t,Se(s.currentDirectory)),{started:!1,cwd:s.currentDirectory};if(await jt(t,s,r))return{started:!1,cwd:s.currentDirectory};await _(t.agentId,e,"tool_using",{actionType:"bash",actionLabel:"\u7EC8\u7AEF\u547D\u4EE4",actionDetail:o},void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl});const a=We(r,{cwd:s.currentDirectory,shell:!0,env:je(t.agentId,t.workspacePath,process.env,t.config.envOverrides)});s.runningProcess=a;const c=Le(),d=Le(),u=t.providerId==="acode",l={agentId:t.agentId,startedAt:new Date,chunks:[],spilled:!1};let m;const p=()=>{m&&(clearTimeout(m),m=void 0)},T=()=>{p(),m=setTimeout(()=>{s.runningProcess===a&&(C(t,_t()),a.kill())},Ee)},y=(g,b=!0)=>{if(g&&(u&&l.chunks.push(g),u&&b&&T(),!(u&&l.spilled))){if(u&&bt(l.chunks.join(""))>xe){l.spilled=!0,Me(l).then($=>{C(t,$t($))}).catch($=>{const E=$ instanceof Error?$.message:String($);C(t,`\r
|
|
34
34
|
[ACode] \u547D\u4EE4\u8F93\u51FA\u843D\u76D8\u5931\u8D25: ${E}\r
|
|
35
|
-
`)});return}C(
|
|
35
|
+
`)});return}C(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=>{C(t,`\r
|
|
36
36
|
[Terminal Error] ${g.message}\r
|
|
37
|
-
`)}),a.on("close",(g,b)=>{p(),s.runningProcess=null,y(
|
|
37
|
+
`)}),a.on("close",(g,b)=>{p(),s.runningProcess=null,y(oe(c,void 0,!0),!1),y(oe(d,void 0,!0),!1),l.spilled&&Me(l).catch($=>{const E=$ instanceof Error?$.message:String($);C(t,`\r
|
|
38
38
|
[ACode] \u547D\u4EE4\u8F93\u51FA\u6700\u7EC8\u843D\u76D8\u5931\u8D25: ${E}\r
|
|
39
|
-
`)}),g&&g!==0?C(
|
|
39
|
+
`)}),g&&g!==0?C(t,`\r
|
|
40
40
|
[exit ${g}]\r
|
|
41
|
-
`):b&&C(
|
|
41
|
+
`):b&&C(t,`\r
|
|
42
42
|
[signal ${b}]\r
|
|
43
|
-
`),C(
|
|
44
|
-
...\uFF08\u7ED3\u679C\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`}function
|
|
45
|
-
[ACode] \u6B63\u5728\u8BF7\u6C42\u6A21\u578B${
|
|
43
|
+
`),C(t,Se(s.currentDirectory)),_(t.agentId,e,"waiting_input",void 0,void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl})}),{started:!0,cwd:s.currentDirectory}}function je(e,n,t,r){const s={};for(const[o,i]of Object.entries(t))i!==void 0&&(s[o]=i);if(n&&(s.AWS_WORKSPACE_PATH=String(n)),r)for(const[o,i]of Object.entries(r)){const a=o.trim();if(!a||i===void 0||i===null)continue;const c=String(i).trim();c&&(s[a]=c)}return s.AWS_AGENT_ID=String(e),s.AWS_MCP_CLAIM_LAUNCH_BINDING="true",s}function Ot(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 Nt(e){const n=String(e);if(!be(n))return n;const t=Ot(n);return j.isAbsolute(t)?N.readFile(t,"utf-8"):n}function Be(e,n){const t={};for(const s of[e?.env,n])if(s)for(const[o,i]of Object.entries(s)){const a=o.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 qt(){try{return await Ye().readClaudeCodeConfig()}catch(e){return console.warn(`[Runtime] Failed to read saved ClaudeCode AI config: ${e.message}`),{}}}function vt(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 Ft(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 Kt(e){if(e.type!=="tool_use_end")return;const n=vt(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")return r==="mcp"&&Ft(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 zt(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
|
|
49
|
-
...\uFF08\u8F93\u5165\u53C2\u6570\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`:
|
|
50
|
-
`)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",s=
|
|
51
|
-
`)}`:"",o=e.requestBody?`${lt}${e.requestBody}`:"";return`${r}${s}${o}`}function Jt(e){return e?Object.entries(e).map(([t,n])=>`${t}: ${n}`).filter(t=>t.trim().length>0):[]}function Yt(e,t){return String(t||"").trim().toLowerCase()!=="waiting_input"?!1:e.type==="thinking"||e.type==="text_delta"}function Zt(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 en(e,t){if(!Yt(e,t)){if(e.type==="ai_request"){const n=Zt(e.data);return{status:"thinking",actionInfo:{actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:Vt(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=ge(e.data.toolName,e.data.toolInput),r=Oe(e,n),s=Gt(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:s,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:s,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,ie=new Map,ae=new Map,G=new Map,tn=20,nn=500,rn=3e4;async function ce(e,t=rn,n=2){for(let r=0;r<=n;r++){const s=new AbortController;let o;try{const i=e(s.signal);i.catch(()=>{}),await Promise.race([i,new Promise((a,c)=>{o=setTimeout(()=>{s.abort(),c(new Error(`sendOutput timeout after ${t}ms`))},t)})]),o&&clearTimeout(o);return}catch(i){o&&clearTimeout(o);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 ue(e,t){const n=t?`${e}:${t}`:void 0;let r,s;if(n)r=G.get(n),s=n;else{const p=[];for(const[T,y]of G)T.startsWith(e+":")&&y.buffer&&p.push(y.sourceEventType);for(const T of p)ue(e,T);return}if(!r||!r.buffer)return;r.timer=null;const o=r.buffer,i=r.seq,a=r.entry,c=r.sourceEventType;r.buffer="",s&&G.delete(s);const d={sourceEventType:c,logCategory:"acode"},u={runtimeAccessToken:a.runtimeAccessToken,schedulerBaseUrl:a.schedulerBaseUrl},m=(L.get(e)??Promise.resolve()).then(()=>ce(p=>H(a.agentId,o,e,i,d,u,p)),()=>ce(p=>H(a.agentId,o,e,i,d,u,p)));L.set(e,m),m.finally(()=>{L.get(e)===m&&L.delete(e)})}function on(e,t){const n=Nt(e);if(!n)return;t.seq+=1;const r=t.seq,s=qt(e),o={runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl};if((e.type==="command_output"||e.type==="text_delta"||e.type==="thinking")&&n.length<tn){const c=`${e.sessionId}:${e.type}`;let d=G.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(()=>ue(u,l),nn)}G.set(c,d);return}ue(e.sessionId);const a=(L.get(e.sessionId)??Promise.resolve()).then(()=>ce(c=>H(t.agentId,n,e.sessionId,r,s,o,c)),()=>ce(c=>H(t.agentId,n,e.sessionId,r,s,o,c)));L.set(e.sessionId,a),a.finally(()=>{L.get(e.sessionId)===a&&L.delete(e.sessionId)})}function qe(e){return Xe(e)}let ve=!1;function sn(){ve||(Qe(w,an),nt(),ve=!0)}function an(e,t){e.on("event",n=>{const r=f.get(n.sessionId);if(r){if(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=en(n,r.currentRuntimeStatus);i&&_(r.agentId,n.sessionId,i.status,i.actionInfo,ne(i.actionInfo),{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},n.timestamp?new Date(n.timestamp).getTime():void 0,n.type)}on(n,r);const o=Ot(n);if(o){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",o,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",o,void 0,i,a,n.type)}}}),e.on("status-change",(n,r,s)=>{const o=f.get(n);if(o){ue(n),r==="thinking"||r==="tool_using"||r==="compacting"?dt(n):M(n);const i=ht(r,s);o.currentRuntimeStatus=i.status;const a=o.currentRuntimeActionDetail??"",c=a.includes("poll_message")||a.includes("get_message"),u=!(i.actionInfo?.actionType==="ai_request")&&(i.status==="thinking"||i.status==="waiting_input")&&(o.currentRuntimeActionType==="idle"||o.currentRuntimeActionType==="mcp")&&c;(i.actionInfo?.actionType||!u)&&(o.currentRuntimeActionType=i.actionInfo?.actionType,o.currentRuntimeActionLabel=i.actionInfo?.actionLabel,o.currentRuntimeActionDetail=i.actionInfo?.actionDetail,o.currentRuntimeActionInput=i.actionInfo?.actionInput),console.log(`[${t.displayName} Adapter] Status changed: ${i.status} for agent ${o.agentId}`,i.actionInfo||""),it(n,{runtimeStatus:i.status,runtimeActionType:o.currentRuntimeActionType,runtimeActionLabel:o.currentRuntimeActionLabel,runtimeActionDetail:o.currentRuntimeActionDetail});const l=i.actionInfo?.actionType?i.actionInfo:o.currentRuntimeActionType?{actionType:o.currentRuntimeActionType,actionLabel:o.currentRuntimeActionLabel??"",actionDetail:o.currentRuntimeActionDetail,actionInput:o.currentRuntimeActionInput}:void 0;if(i.status==="compacting"){const p=(ie.get(n)??Promise.resolve()).then(async()=>{for(let y=0;y<=2;y++){if(await _(o.agentId,n,i.status,l,ne(i.actionInfo),{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.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(b=>setTimeout(b,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)});ie.set(n,p),p.finally(()=>{ie.get(n)===p&&ie.delete(n)})}else{const m=u&&!i.actionInfo?.actionType;if(l?.actionType==="idle"||o.currentRuntimeActionType==="idle"&&u){const y=(ae.get(n)??Promise.resolve()).then(async()=>{for(let b=0;b<=2;b++){if(await _(o.agentId,n,i.status,m?void 0:l,ne(i.actionInfo),{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})!==void 0)return;b<2&&await new Promise(E=>setTimeout(E,1e3*(b+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)});ae.set(n,y),y.finally(()=>{ae.get(n)===y&&ae.delete(n)})}else _(o.agentId,n,i.status,m?void 0:l,ne(i.actionInfo),{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})}if(i.status==="waiting_input"&&o.cachedCapabilitiesActionDetail){const m=o.cachedCapabilitiesActionDetail;o.cachedCapabilitiesActionDetail=void 0,console.log(`[${t.displayName} Adapter] Re-sending cached runtime_capabilities for agent ${o.agentId} (session stabilized to waiting_input)`),_(o.agentId,n,"waiting_input",{actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:m},void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})}}}),e.on("ask-user-question",n=>{const r=f.get(n.sessionId);r&&(console.log(`[${t.displayName} Adapter] AskUserQuestion for agent ${r.agentId}`),et(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 s=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:s||n.toolName},void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl})}})}A.post("/start",S,async(e,t)=>{const{agentId:n,workspacePath:r,mode:s="sdk"}=e.body||{};if(!n||!r){t.status(400).json({error:"agentId and workspacePath are required"});return}const o=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||be(_e(e))||void 0;Je({agentId:String(n),workspacePath:String(r),serverUrl:e.body?.serverUrl||o,runtimeAccessToken:e.body?.runtimeAccessToken,userId:e.body?.userId,schedulerBaseUrl:o}),s&&s!=="sdk"&&console.warn(`[Runtime] Unsupported runtime mode "${s}" requested for agent ${n}; starting SDK session instead.`),await cn(e,t)});async function cn(e,t){const{agentId:n,workspacePath:r,command:s,autoAccept:o=!0,initialPrompt:i,systemPrompt:a,globalPrompt:c,rolePrompt:d,memory:u,mcpConfigPath:l,extraMcpServers:m,envOverrides:p,idleInputAutoCommand:T,nonInputAutoCommand:y,model:g,instanceAiConfig:b,subAgentModel:$,subAgentEffort:E,scopeKey:Ae}=e.body||{},F=ct();F.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:b?ee(b):null,perAgentModel:g??null}});let D=null;const I=String(n||"").trim(),de=String(e.body?.runtimeAccessToken||"").trim()||void 0,B=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||be(_e(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(sn(),!I){t.status(400).json({error:"agentId is required"});return}const O=Le(I);if(O){t.json(await Dt(O));return}const k=await rt(I);if(k){const P=Pt(k);if(!P.reusable)console.warn(`[Runtime] Ignoring stale persisted SDK session for agentId=${I}, sessionId=${k.sessionId}, reason=${P.reason}`),await v(k.sessionId);else{const R=oe(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 mn=(s||"acode").toLowerCase(),x=qe(s),Ke=w.get(x);D=He();const Fe=x==="claude-code"?await jt():null,V=Ue(x==="claude-code"?Fe:null,p),z=x==="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})();F.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:z??null,providerId:x,note:x==="acode"?"adapter handles full priority":"request > global"}});const le={...V.envOverrides};z&&(le.ANTHROPIC_MODEL=z,le.CODEX_MODEL=z);let W,me=l;if(x==="acode"){const P=b||{},R=await Ve({apiOverrides:he(P)??void 0,agentId:I,sessionId:D??void 0,runtimeBridgeBaseUrl:B});W=R.instanceConfig.config,me=R.perInstanceConfigPath,F.log({level:"info",category:"apply",message:"prepareAcodeInstanceConfig \u5B8C\u6210",source:"bridge",agentId:I,sessionId:D??void 0,details:{sanitizedApiOverrides:he(P)?ee(he(P)):null,resolvedInstanceAiConfig:W?ee(W):null,perInstanceConfigPath:me,instanceConfigSources:R.instanceConfig.source??null}})}let Te=a||void 0,fe,pe,J;if(x==="acode")if(fe=typeof c=="string"&&c.trim()||void 0,pe=typeof d=="string"&&d.trim()||void 0,typeof u=="string"&&u.trim())J=u.trim();else{const P=await ft(r,{schedulerBaseUrl:B,runtimeAccessToken:de,agentId:I});P&&(J=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(Y=>typeof Y=="string"&&Y.trim().length>0).map(Y=>Y.trim());Te=R.length>0?R.join(`
|
|
48
|
+
`:void 0}function Wt(e){const n=Xt(e);return{sourceEventType:e.type,logCategory:"acode",...Qt(e),...n?{logLevel:Ht(e),logMessage:n}:{}}}function Ht(e){return e.type==="error"?"error":e.type==="command_output"&&e.data.stream==="stderr"?"warn":"info"}function Qt(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 Xt(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 Oe(e,"\u5F00\u59CB");if(e.type==="tool_use_end")return Oe(e,"\u5B8C\u6210");if(e.type==="command_output")return Vt(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 Gt=/\x1b\[[0-9;?]*[a-zA-Z]/g;function Jt(e){return e.replace(Gt,"")}function Vt(e){const n=typeof e.data.stream=="string"?e.data.stream:"mixed",t=typeof e.data.sequence=="number"?` #${e.data.sequence}`:"",r=Jt(String(e.data.text||"")).replace(/\s+/g," ").trim(),s=r.length>240?`${r.slice(0,240)}...`:r;return`\u547D\u4EE4\u8F93\u51FA(${n}${t}): ${s||"(empty)"}`}function Oe(e,n){const t=ye(e.data.toolName,e.data.toolInput),r=e.data.actionLabel||t.actionLabel||"\u8C03\u7528\u5DE5\u5177",s=Ne(e,t);return s?`${n}${r}: ${s}`:`${n}${r}: ${e.data.actionDetail||e.data.toolName||"tool"}`}function Ne(e,n){const t=e.data.toolInput;return n.actionType==="bash"?Yt(t)||e.data.actionDetail||n.actionDetail:n.actionType==="read_file"||n.actionType==="edit_file"||n.actionType==="write_file"?Zt(t)||e.data.actionDetail||n.actionDetail:e.data.actionDetail||n.actionDetail}function Yt(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?q(t):void 0}return Ae(e?.args)}function Zt(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 q(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=>q(n)):[]}function en(e){if(!(!e||Object.keys(e).length===0))try{const n=q(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 tn(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=nn(e.requestHeaders),r=n.join(`
|
|
50
|
+
`)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",s=t.length>0?`${ht}${t.join(`
|
|
51
|
+
`)}`:"",o=e.requestBody?`${yt}${e.requestBody}`:"";return`${r}${s}${o}`}function nn(e){return e?Object.entries(e).map(([n,t])=>`${n}: ${t}`).filter(n=>n.trim().length>0):[]}function rn(e,n){return String(n||"").trim().toLowerCase()!=="waiting_input"?!1:e.type==="thinking"||e.type==="text_delta"}function on(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 sn(e,n){if(!rn(e,n)){if(e.type==="ai_request"){const t=on(e.data);return{status:"thinking",actionInfo:{actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:tn(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=Ne(e,t),s=en(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:s,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:s,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,J=new Map,an=20,cn=500,un=3e4;async function ue(e,n=un,t=2){for(let r=0;r<=t;r++){const s=new AbortController;let o;try{const i=e(s.signal);i.catch(()=>{}),await Promise.race([i,new Promise((a,c)=>{o=setTimeout(()=>{s.abort(),c(new Error(`sendOutput timeout after ${n}ms`))},n)})]),o&&clearTimeout(o);return}catch(i){o&&clearTimeout(o);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,s;if(t)r=J.get(t),s=t;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 o=r.buffer,i=r.seq,a=r.entry,c=r.sourceEventType;r.buffer="",s&&J.delete(s);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,o,e,i,d,u,p)),()=>ue(p=>Q(a.agentId,o,e,i,d,u,p)));L.set(e,m),m.finally(()=>{L.get(e)===m&&L.delete(e)})}function dn(e,n){const t=zt(e);if(!t)return;n.seq+=1;const r=n.seq,s=Wt(e),o={runtimeAccessToken:n.runtimeAccessToken,schedulerBaseUrl:n.schedulerBaseUrl};if((e.type==="command_output"||e.type==="text_delta"||e.type==="thinking")&&t.length<an){const c=`${e.sessionId}:${e.type}`;let d=J.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),cn)}J.set(c,d);return}de(e.sessionId);const a=(L.get(e.sessionId)??Promise.resolve()).then(()=>ue(c=>Q(n.agentId,t,e.sessionId,r,s,o,c)),()=>ue(c=>Q(n.agentId,t,e.sessionId,r,s,o,c)));L.set(e.sessionId,a),a.finally(()=>{L.get(e.sessionId)===a&&L.delete(e.sessionId)})}function ve(e){return Ge(e)}let Fe=!1;function ln(){Fe||(Xe(w,mn),st(),Fe=!0)}function mn(e,n){e.on("event",t=>{const r=f.get(t.sessionId);if(r){if(t.type==="tool_use_start"?at(r.sessionId,t.data.toolUseId||t.data.actionId,t.data.toolInput,t.data.toolName,r.workspacePath):t.type==="tool_use_end"&&it(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=sn(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)}dn(t,r);const o=Kt(t);if(o){const i={runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},a=t.timestamp?new Date(t.timestamp).getTime():void 0;String(t.data?.toolName||"").toLowerCase()==="browser_launch"?(async()=>{for(let u=0;u<3;u++){if(await _(r.agentId,t.sessionId,"tool_result",o,void 0,i,a,t.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,t.sessionId,"tool_result",o,void 0,i,a,t.type)}}}),e.on("status-change",(t,r,s)=>{const o=f.get(t);if(o){de(t),r==="thinking"||r==="tool_using"||r==="compacting"?gt(t):M(t);const i=kt(r,s);o.currentRuntimeStatus=i.status;const a=o.currentRuntimeActionDetail??"",c=a.includes("poll_message")||a.includes("get_message"),u=!(i.actionInfo?.actionType==="ai_request")&&(i.status==="thinking"||i.status==="waiting_input")&&(o.currentRuntimeActionType==="idle"||o.currentRuntimeActionType==="mcp")&&c;(i.actionInfo?.actionType||!u)&&(o.currentRuntimeActionType=i.actionInfo?.actionType,o.currentRuntimeActionLabel=i.actionInfo?.actionLabel,o.currentRuntimeActionDetail=i.actionInfo?.actionDetail,o.currentRuntimeActionInput=i.actionInfo?.actionInput),console.log(`[${n.displayName} Adapter] Status changed: ${i.status} for agent ${o.agentId}`,i.actionInfo||""),lt(t,{runtimeStatus:i.status,runtimeActionType:o.currentRuntimeActionType,runtimeActionLabel:o.currentRuntimeActionLabel,runtimeActionDetail:o.currentRuntimeActionDetail});const l=i.actionInfo?.actionType?i.actionInfo:o.currentRuntimeActionType?{actionType:o.currentRuntimeActionType,actionLabel:o.currentRuntimeActionLabel??"",actionDetail:o.currentRuntimeActionDetail,actionInput:o.currentRuntimeActionInput}:void 0;if(i.status==="compacting"){const p=(ae.get(t)??Promise.resolve()).then(async()=>{for(let y=0;y<=2;y++){if(await _(o.agentId,t,i.status,l,re(i.actionInfo),{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.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(b=>setTimeout(b,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,p),p.finally(()=>{ae.get(t)===p&&ae.delete(t)})}else{const m=u&&!i.actionInfo?.actionType;if(l?.actionType==="idle"||o.currentRuntimeActionType==="idle"&&u){const y=(ce.get(t)??Promise.resolve()).then(async()=>{for(let b=0;b<=2;b++){if(await _(o.agentId,t,i.status,m?void 0:l,re(i.actionInfo),{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})!==void 0)return;b<2&&await new Promise(E=>setTimeout(E,1e3*(b+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 _(o.agentId,t,i.status,m?void 0:l,re(i.actionInfo),{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})}if(i.status==="waiting_input"&&o.cachedCapabilitiesActionDetail){const m=o.cachedCapabilitiesActionDetail;o.cachedCapabilitiesActionDetail=void 0,console.log(`[${n.displayName} Adapter] Re-sending cached runtime_capabilities for agent ${o.agentId} (session stabilized to waiting_input)`),_(o.agentId,t,"waiting_input",{actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:m},void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})}}}),e.on("ask-user-question",t=>{const r=f.get(t.sessionId);r&&(console.log(`[${n.displayName} Adapter] AskUserQuestion for agent ${r.agentId}`),rt(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=f.get(t.sessionId);if(r){console.log(`[${n.displayName} Adapter] Permission request: ${t.toolName} for agent ${r.agentId}`);const s=t.toolInput?q(JSON.stringify(t.toolInput).slice(0,400)):void 0;_(r.agentId,t.sessionId,"waiting_input",{actionType:"other",actionLabel:"\u6743\u9650\u786E\u8BA4",actionDetail:s||t.toolName},void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl})}})}A.post("/start",S,async(e,n)=>{const{agentId:t,workspacePath:r,mode:s="sdk"}=e.body||{};if(!t||!r){n.status(400).json({error:"agentId and workspacePath are required"});return}const o=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||$e(De(e))||void 0;et({agentId:String(t),workspacePath:String(r),serverUrl:e.body?.serverUrl||o,runtimeAccessToken:e.body?.runtimeAccessToken,userId:e.body?.userId,schedulerBaseUrl:o}),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(Ve(String(t)))}`)),s&&s!=="sdk"&&console.warn(`[Runtime] Unsupported runtime mode "${s}" requested for agent ${t}; starting SDK session instead.`),await fn(e,n)});async function fn(e,n){const{agentId:t,workspacePath:r,command:s,autoAccept:o=!0,initialPrompt:i,systemPrompt:a,globalPrompt:c,rolePrompt:d,memory:u,mcpConfigPath:l,extraMcpServers:m,envOverrides:p,idleInputAutoCommand:T,nonInputAutoCommand:y,model:g,instanceAiConfig:b,subAgentModel:$,subAgentEffort:E,scopeKey:Te}=e.body||{},z=ft();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:b?te(b):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(De(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(ln(),!I){n.status(400).json({error:"agentId is required"});return}const O=Ue(I);if(O){n.json(await Mt(O));return}const k=await ct(I);if(k){const P=Lt(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);n.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)){n.status(409).json({error:"SDK session is already starting for this agent"});return}K.add(I);const hn=(s||"acode").toLowerCase(),x=ve(s),Ke=w.get(x);D=Qe();const ze=x==="claude-code"?await qt():null,V=Be(x==="claude-code"?ze:null,p),W=x==="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:W??null,providerId:x,note:x==="acode"?"adapter handles full priority":"request > global"}});const me={...V.envOverrides};W&&(me.ANTHROPIC_MODEL=W,me.CODEX_MODEL=W);let H,fe=l;if(x==="acode"){const P=b||{},R=await Ze({apiOverrides:Ie(P)??void 0,agentId:I,sessionId:D??void 0,runtimeBridgeBaseUrl:B});H=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:H?te(H):null,perInstanceConfigPath:fe,instanceConfigSources:R.instanceConfig.source??null}})}let ke=a||void 0,pe,ge,Y;if(x==="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 It(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());ke=R.length>0?R.join(`
|
|
52
52
|
|
|
53
|
-
`):void 0}const j={command:s||"acode",workingDirectory:r,agentId:I,...Ae?{scopeKey:Ae}:{},autoAccept:!!o,initialPrompt:i,systemPrompt:Te,...fe!==void 0?{globalPrompt:fe}:{},...pe!==void 0?{rolePrompt:pe}:{},...J!==void 0?{memory:J}:{},model:z,mcpConfigPath:me,...W?{instanceAiConfig:W}:{},...typeof $=="string"&&$.trim()?{subAgentModel:$.trim()}:{},...typeof E=="string"&&E.trim()?{subAgentEffort:E.trim()}:{},extraMcpServers:m||{},envOverrides:je(String(n),String(r),process.env,le)};F.log({level:"info",category:"launch",message:"\u4F20\u9012\u7ED9 Adapter \u7684\u5B8C\u6574 AdapterSessionConfig",source:"bridge",agentId:I,sessionId:D,details:{adapterModel:j.model??null,adapterInstanceAiConfig:j.instanceAiConfig?ee(j.instanceAiConfig):null,adapterMcpConfigPath:j.mcpConfigPath??null}}),await F.flush(),f.set(D,{agentId:I,workspacePath:r,sessionId:D,config:j,providerId:x,seq:0,runtimeAccessToken:de,schedulerBaseUrl:B}),t.json({sessionId:D,status:"starting",runtimeStatus:"starting",agentId:I,workspacePath:r,command:j.command,mode:"sdk"}),un({sessionId:D,agentId:I,config:j,adapter:Ke,providerId:x,idleInputAutoCommand:T,nonInputAutoCommand:y,runtimeAccessToken:de,requestedSchedulerBaseUrl:B})}catch(O){if(D&&(M(D),f.delete(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 un(e){const{sessionId:t,agentId:n,config:r,adapter:s,providerId:o,idleInputAutoCommand:i,nonInputAutoCommand:a,runtimeAccessToken:c,requestedSchedulerBaseUrl:d}=e;try{await s.startSession(t,r),(i||a)&&s.setIdleCommands?.(t,{idleInputCommand:i||"",nonInputCommand:a||""});let u;if(gt(o))try{if(await new Promise(m=>setTimeout(m,500)),u=s.getSessionPid?.(t),!u){const p=(await Ye()).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=oe(s.getSessionStatus(t),f.get(t)?.currentRuntimeStatus,f.get(t)?.currentRuntimeActionType);await at({sessionId:t,agentId:n,workspacePath:r.workingDirectory,command:r.command,startedAt:new Date().toISOString(),status:"running",runtimeStatus:l,mode:"sdk",pid:u,providerSessionId:s.getProviderSessionId(t)}),u&&await ye().startProcess({agentId:n,sessionId:t,pid:u,mode:"sdk",workspacePath:r.workingDirectory,command:r.command}),await dn({agentId:n,sessionId:t,sdkPid:u,status:l,schedulerBaseUrl:d,runtimeAccessToken:c})}catch(u){M(t),f.delete(t),await v(t);const l=u instanceof Error?u.message:String(u);console.error(`[Runtime] Background SDK session startup failed for agentId=${n}: ${l}`),await ln({agentId:n,sessionId:t,schedulerBaseUrl:d,runtimeAccessToken:c,errorMessage:l})}finally{K.delete(n)}}async function dn(e){const{agentId:t,sessionId:n,sdkPid:r,status:s,schedulerBaseUrl:o,runtimeAccessToken:i}=e;if(!o||!i){h.debug(`[Runtime] notifyServerSessionReady skipped: missing schedulerBaseUrl or runtimeAccessToken for agentId=${t}`);return}const a=`${o.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await we.post(a,{agentId:t,sessionId:n,status:s,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=${s}`)}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 ln(e){const{agentId:t,sessionId:n,schedulerBaseUrl:r,runtimeAccessToken:s}=e;if(!r||!s)return;const o=`${r.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await we.post(o,{agentId:t,sessionId:n,status:"stopped"},{headers:{"X-Runtime-Token":s,"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 s=f.get(n);if(!s){t.status(404).json({error:"SDK session not found"});return}try{const o=s.providerId||"claude-code";await w.get(o).sendMessage(n,r),t.json({ok:!0})}catch(o){const i=o instanceof Error?o.message:String(o);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 s=f.get(n);if(!s){t.status(404).json({error:"SDK session not found"});return}try{const o=s.providerId||"claude-code",i=w.get(o);i.sendQuestionAnswer&&await i.sendQuestionAnswer(n,r),t.json({ok:!0})}catch(o){const i=o instanceof Error?o.message:String(o);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 s=f.get(n);if(!s){t.status(404).json({error:"SDK session not found"});return}try{const o=s.providerId||"claude-code";await w.get(o).sendConfirmation(n,!!r),t.json({ok:!0})}catch(o){const i=o instanceof Error?o.message:String(o);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 s=r.providerId||"claude-code";await w.get(s).abortCurrentTurn(n),t.json({ok:!0})}catch(s){const o=s instanceof Error?s.message:String(s);t.status(500).json({error:o})}}),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 s=r.providerId||"claude-code",o=w.get(s);o.abortCurrentTurn(n).catch(()=>{}),await o.terminateSession(n),M(n),f.delete(n),se(n),await v(n),await ye().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(s){const o=s instanceof Error?s.message:String(s);t.status(500).json({error:o})}}),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 s=r.providerId||"claude-code",o=w.get(s),i=o.getSessionStatus(n),a=o.getConversation(n);t.json({sessionId:n,status:i,agentId:r.agentId,workspacePath:r.workspacePath,messageCount:a.length})}catch(s){const o=s instanceof Error?s.message:String(s);t.status(500).json({error:o})}}),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 s=r.providerId||"claude-code",i=w.get(s).getCapabilities?.(n)??null;t.json({ok:!0,sessionId:n,agentId:r.agentId,capabilities:i,fetchedAt:Date.now()})}catch(s){const o=s instanceof Error?s.message:String(s);t.status(500).json({error:o})}}),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 s=r.providerId||"claude-code",i=w.get(s).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(s){const o=s instanceof Error?s.message:String(s);t.status(500).json({error:o})}}),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 s=await Et(String(n),r);t.json({ok:!0,mode:"terminal",...s})}catch(s){const o=s instanceof Error?s.message:String(s);t.status(500).json({error:o})}}),A.post("/input",S,async(e,t)=>{const{sessionId:n,input:r,mode:s}=e.body||{};if(!n||r===void 0||r===null){t.status(400).json({error:"sessionId and input are required"});return}const o=f.get(n);if(!o){t.status(404).json({error:"SDK session not found"});return}try{const i=o.providerId||"claude-code",a=w.get(i);if(s==="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 Lt(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:s=""}=e.body||{},o=String(n||"").trim();if(!o){t.status(400).json({error:"agentId is required"});return}const i=[...f.values()].find(c=>c.agentId===o),a={idleInputCommand:String(r||""),nonInputCommand:String(s||"")};try{let c=!1;i&&(w.get(i.providerId||"claude-code").setIdleCommands?.(i.sessionId,a),c=!0);const d=await st(o,{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:s}=e.body||{};if(!n||!r||!s){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(s)})}),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 s=f.get(n);if(!s){t.status(404).json({error:"SDK session not found"});return}const o=s.providerId||"claude-code",i=w.get(o),a=i.resetContext?.bind(i),c=pt(o,!!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=oe(i.getSessionStatus(String(n)),s.currentRuntimeStatus,s.currentRuntimeActionType);t.json({ok:!0,contextReset:!0,sessionId:n,status:d,runtimeStatus:d,agentId:s.agentId,mode:"sdk",providerId:o,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=yt(e.body);if(!n){t.status(400).json({error:"sessionId is required"});return}const s=f.get(n);if(!s){await v(n),t.json({ok:!0,status:"stopped",mode:"none",statusNotified:!1,reason:r.reason});return}const o=s.agentId;try{console.log(`[Runtime] Stopping SDK session ${n}; suppressStatus=${!r.statusNotified}, reason=${r.reason||"unspecified"}`);const i=s.providerId||"claude-code",a=w.get(i);a.abortCurrentTurn(n).catch(()=>{}),await a.terminateSession(n),M(n),f.delete(n),se(n),await v(n),await ye().removeProcess(o),r.statusNotified?await _(o,null,"stopped",void 0,void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.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[s,o]of f.entries())try{const i=o.providerId||"claude-code",a=w.get(i);a.abortCurrentTurn(s).catch(()=>{}),await a.terminateSession(s),M(s),f.delete(s),se(s),n.push(s),await _(o.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})}catch(i){const a=i instanceof Error?i.message:String(i);r.push(`SDK ${s}: ${a}`)}try{await ot([]),console.log("[Runtime] \u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD")}catch(s){const o=s instanceof Error?s.message:String(s);r.push(`Persistence: ${o}`)}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=$e.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=$e.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=tt();t.json({ok:!0,count:n.length,agents:n})});export{St as buildAcodeCommandOutputPath,Ue as buildClaudeCodeLaunchConfig,je as buildRuntimeEnv,qt as buildSdkOutputMetadata,Ot as buildToolResultTimelineActionInfo,Ln as cleanupSdkSessionByAgentId,At as countTerminalOutputLines,Me as createTerminalOutputDecoder,re as decodeTerminalOutputChunk,Pt as evaluatePersistedSessionReuse,kt as formatCommandInactivityTimeoutNotice,Tt as formatCommandOutputSpilloverNotice,Nt as formatSdkOutputEvent,Ie as formatTerminalPrompt,wt as normalizeTerminalCommandInput,yt as parseRuntimeStopOptions,$t as parseTerminalDirectoryChangeTarget,ce as raceSendOutputWithRetry,pt as resolveRuntimeContextResetSupport,en as resolveRuntimeStatusFromProviderEvent,Lt as resolveSdkInputMessage,qe as resolveSdkProviderId,oe as resolveSdkSessionDisplayStatus,ht as resolveStatusChangeRuntimeState,ne as resolveStatusChangeUsage,Ct as resolveTerminalOutputEncoding,f as sdkSessions,gt as shouldProbeSdkProcessPid,A as terminalRouter};
|
|
53
|
+
`):void 0}const U={command:s||"acode",workingDirectory:r,agentId:I,...Te?{scopeKey:Te}:{},autoAccept:!!o,initialPrompt:i,systemPrompt:ke,...pe!==void 0?{globalPrompt:pe}:{},...ge!==void 0?{rolePrompt:ge}:{},...Y!==void 0?{memory:Y}:{},model:W,mcpConfigPath:fe,...H?{instanceAiConfig:H}:{},...typeof $=="string"&&$.trim()?{subAgentModel:$.trim()}:{},...typeof E=="string"&&E.trim()?{subAgentEffort:E.trim()}:{},extraMcpServers:m||{},envOverrides:je(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(),f.set(D,{agentId:I,workspacePath:r,sessionId:D,config:U,providerId:x,seq:0,runtimeAccessToken:le,schedulerBaseUrl:B}),n.json({sessionId:D,status:"starting",runtimeStatus:"starting",agentId:I,workspacePath:r,command:U.command,mode:"sdk"}),pn({sessionId:D,agentId:I,config:U,adapter:Ke,providerId:x,idleInputAutoCommand:T,nonInputAutoCommand:y,runtimeAccessToken:le,requestedSchedulerBaseUrl:B})}catch(O){if(D&&(M(D),f.delete(D),v(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 pn(e){const{sessionId:n,agentId:t,config:r,adapter:s,providerId:o,idleInputAutoCommand:i,nonInputAutoCommand:a,runtimeAccessToken:c,requestedSchedulerBaseUrl:d}=e;try{await s.startSession(n,r),(i||a)&&s.setIdleCommands?.(n,{idleInputCommand:i||"",nonInputCommand:a||""});let u;if(At(o))try{if(await new Promise(m=>setTimeout(m,500)),u=s.getSessionPid?.(n),!u){const p=(await tt()).find(T=>T.agentId===t||T.cwd===r.workingDirectory||T.command.includes(r.workingDirectory));p&&(u=p.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(s.getSessionStatus(n),f.get(n)?.currentRuntimeStatus,f.get(n)?.currentRuntimeActionType);await mt({sessionId:n,agentId:t,workspacePath:r.workingDirectory,command:r.command,startedAt:new Date().toISOString(),status:"running",runtimeStatus:l,mode:"sdk",pid:u,providerSessionId:s.getProviderSessionId(n)}),u&&await he().startProcess({agentId:t,sessionId:n,pid:u,mode:"sdk",workspacePath:r.workingDirectory,command:r.command}),await gn({agentId:t,sessionId:n,sdkPid:u,status:l,schedulerBaseUrl:d,runtimeAccessToken:c})}catch(u){M(n),f.delete(n),v(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 yn({agentId:t,sessionId:n,schedulerBaseUrl:d,runtimeAccessToken:c,errorMessage:l})}finally{K.delete(t)}}async function gn(e){const{agentId:n,sessionId:t,sdkPid:r,status:s,schedulerBaseUrl:o,runtimeAccessToken:i}=e;if(!o||!i){h.debug(`[Runtime] notifyServerSessionReady skipped: missing schedulerBaseUrl or runtimeAccessToken for agentId=${n}`);return}const a=`${o.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await Ce.post(a,{agentId:n,sessionId:t,status:s,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=${s}`)}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 yn(e){const{agentId:n,sessionId:t,schedulerBaseUrl:r,runtimeAccessToken:s}=e;if(!r||!s)return;const o=`${r.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await Ce.post(o,{agentId:n,sessionId:t,status:"stopped"},{headers:{"X-Runtime-Token":s,"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 s=f.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const o=s.providerId||"claude-code";await w.get(o).sendMessage(t,r),n.json({ok:!0})}catch(o){const i=o instanceof Error?o.message:String(o);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 s=f.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const o=s.providerId||"claude-code",i=w.get(o);i.sendQuestionAnswer&&await i.sendQuestionAnswer(t,r),n.json({ok:!0})}catch(o){const i=o instanceof Error?o.message:String(o);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 s=f.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const o=s.providerId||"claude-code";await w.get(o).sendConfirmation(t,!!r),n.json({ok:!0})}catch(o){const i=o instanceof Error?o.message:String(o);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=f.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const s=r.providerId||"claude-code";await w.get(s).abortCurrentTurn(t),n.json({ok:!0})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),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=f.get(t);if(!r){n.json({ok:!0,status:"stopped"});return}try{const s=r.providerId||"claude-code",o=w.get(s);o.abortCurrentTurn(t).catch(()=>{}),await o.terminateSession(t),M(t),f.delete(t),v(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(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),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=f.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const s=r.providerId||"claude-code",o=w.get(s),i=o.getSessionStatus(t),a=o.getConversation(t);n.json({sessionId:t,status:i,agentId:r.agentId,workspacePath:r.workspacePath,messageCount:a.length})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),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=f.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const s=r.providerId||"claude-code",i=w.get(s).getCapabilities?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,capabilities:i,fetchedAt:Date.now()})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),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=f.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const s=r.providerId||"claude-code",i=w.get(s).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(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),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 s=await Bt(String(t),r);n.json({ok:!0,mode:"terminal",...s})}catch(s){const o=s instanceof Error?s.message:String(s);n.status(500).json({error:o})}}),A.post("/input",S,async(e,n)=>{const{sessionId:t,input:r,mode:s}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and input are required"});return}const o=f.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const i=o.providerId||"claude-code",a=w.get(i);if(s==="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 Nt(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:s=""}=e.body||{},o=String(t||"").trim();if(!o){n.status(400).json({error:"agentId is required"});return}const i=[...f.values()].find(c=>c.agentId===o),a={idleInputCommand:String(r||""),nonInputCommand:String(s||"")};try{let c=!1;i&&(w.get(i.providerId||"claude-code").setIdleCommands?.(i.sessionId,a),c=!0);const d=await dt(o,{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:s}=e.body||{};if(!t||!r||!s){n.status(400).json({error:"sessionId, cols, rows are required"});return}if(!f.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(s)})}),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 s=f.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}const o=s.providerId||"claude-code",i=w.get(o),a=i.resetContext?.bind(i),c=St(o,!!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)),s.currentRuntimeStatus,s.currentRuntimeActionType);n.json({ok:!0,contextReset:!0,sessionId:t,status:d,runtimeStatus:d,agentId:s.agentId,mode:"sdk",providerId:o,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=Tt(e.body);if(!t){n.status(400).json({error:"sessionId is required"});return}const s=f.get(t);if(!s){await F(t),n.json({ok:!0,status:"stopped",mode:"none",statusNotified:!1,reason:r.reason});return}const o=s.agentId;try{console.log(`[Runtime] Stopping SDK session ${t}; suppressStatus=${!r.statusNotified}, reason=${r.reason||"unspecified"}`);const i=s.providerId||"claude-code",a=w.get(i);a.abortCurrentTurn(t).catch(()=>{}),await a.terminateSession(t),M(t),f.delete(t),v(t),ie(t),await F(t),await he().removeProcess(o),r.statusNotified?await _(o,null,"stopped",void 0,void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.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[s,o]of f.entries())try{const i=o.providerId||"claude-code",a=w.get(i);a.abortCurrentTurn(s).catch(()=>{}),await a.terminateSession(s),M(s),f.delete(s),v(s),ie(s),t.push(s),await _(o.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl})}catch(i){const a=i instanceof Error?i.message:String(i);r.push(`SDK ${s}: ${a}`)}try{await ut([]),console.log("[Runtime] \u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD")}catch(s){const o=s instanceof Error?s.message:String(s);r.push(`Persistence: ${o}`)}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=_e.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=_e.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=ot();n.json({ok:!0,count:t.length,agents:t})});export{Ct as buildAcodeCommandOutputPath,Be as buildClaudeCodeLaunchConfig,je as buildRuntimeEnv,Wt as buildSdkOutputMetadata,Kt as buildToolResultTimelineActionInfo,vn as cleanupSdkSessionByAgentId,bt as countTerminalOutputLines,Le as createTerminalOutputDecoder,oe as decodeTerminalOutputChunk,Lt as evaluatePersistedSessionReuse,_t as formatCommandInactivityTimeoutNotice,$t as formatCommandOutputSpilloverNotice,zt as formatSdkOutputEvent,Se as formatTerminalPrompt,Dt as normalizeTerminalCommandInput,Tt as parseRuntimeStopOptions,xt as parseTerminalDirectoryChangeTarget,ue as raceSendOutputWithRetry,St as resolveRuntimeContextResetSupport,sn as resolveRuntimeStatusFromProviderEvent,Nt as resolveSdkInputMessage,ve as resolveSdkProviderId,se as resolveSdkSessionDisplayStatus,kt as resolveStatusChangeRuntimeState,re as resolveStatusChangeUsage,Pt as resolveTerminalOutputEncoding,f as sdkSessions,At as shouldProbeSdkProcessPid,A as terminalRouter};
|
|
54
54
|
|