aws-runtime-bridge 1.9.151 → 1.9.153
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/CHANGELOG.md +98 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts +27 -0
- package/dist/adapter/AcodeSdkAdapter.js +5 -5
- package/dist/adapter/types.d.ts +16 -0
- package/dist/desktop/built-in-desktop-tools.js +1 -1
- package/dist/routes/ltr.js +1 -1
- package/dist/routes/sessions.d.ts +87 -0
- package/dist/routes/sessions.js +1 -1
- package/dist/routes/terminal.js +20 -20
- package/dist/services/instance-features.d.ts +11 -1
- package/dist/services/instance-features.js +1 -1
- package/dist/utils/file-utils.d.ts +2 -0
- package/dist/utils/file-utils.js +2 -2
- package/package/acode/dist/capability-prompt.d.ts +16 -0
- package/package/acode/dist/capability-prompt.js +3 -0
- package/package/acode/dist/runtime.d.ts +6 -0
- package/package/acode/dist/runtime.js +23 -22
- package/package/acode/dist/types.d.ts +3 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +28 -4
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +24 -17
- package/package/aws-client-agent-mcp/dist/mcp-server.js +28 -28
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +20 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +25 -8
- package/package/aws-client-agent-mcp/dist/tool-groups.d.ts +57 -0
- package/package/aws-client-agent-mcp/dist/tool-groups.js +3 -0
- package/package/aws-client-agent-mcp/dist/types.d.ts +23 -0
- package/package.json +1 -1
package/dist/routes/sessions.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{execSync as b}from"node:child_process";import{Router as R}from"express";import{adapterRegistry as I}from"../adapter/index.js";import{validateToken as S,validateTokenOrLoopback as T}from"../middleware/auth.js";import{isProcessRunning as w,findOrphanProcessByAgentId as P,findOrphanProcessByWorkspace as F}from"../services/process-detector.js";import{findPersistedSessionByAgentId as k,loadPersistedSessions as K,removePersistedSession as A}from"../services/terminal-persistence.js";import{createLogger as E}from"../utils/logger.js";import{sdkSessions as g,cleanupSdkSessionByAgentId as C}from"./terminal.js";const c=E("sessions"),h=R();h.post("/sessions/:agentId/notify-force-message",T,(u,n)=>{const e=String(u.params.agentId??"").trim();if(!e){n.status(400).json({ok:!1,error:"agentId is required"});return}const r=Array.from(g.entries()).find(([,i])=>i.agentId===e);if(!r){n.json({ok:!0,notified:!1,message:"No active SDK session for this agentId"});return}const[o,s]=r,t=I.get(s.providerId||"claude-code");if(typeof t.notifyForceMessage=="function"){const i=t.notifyForceMessage(o);n.json({ok:!0,notified:i})}else n.json({ok:!0,notified:!1,message:"Adapter does not support force message notification"})});function j(u,n,e){const r=String(u||"").trim();if(r){const s=String(n||"").trim(),t=String(e||"").trim().toLowerCase();return r.toLowerCase()==="tool_using"&&s.toLowerCase()==="waiting_input"&&t==="idle"?s:r}return String(n||"").trim()||"running"}h.get("/sessions",S,async(u,n)=>{try{const r=Array.from(g.entries()).map(([d,p])=>{const m=I.get(p.providerId||"claude-code"),a=j(m.getSessionStatus(d),p.currentRuntimeStatus,p.currentRuntimeActionType);return{sessionId:d,agentId:p.agentId,workspacePath:p.workspacePath,status:a,runtimeStatus:a,runtimeActionType:p.currentRuntimeActionType,runtimeActionLabel:p.currentRuntimeActionLabel,runtimeActionDetail:p.currentRuntimeActionDetail,mode:"sdk",startedAt:null}}),o=await K(),s=new Set(r.map(d=>d.sessionId)),t=o.filter(d=>!s.has(d.sessionId)),i={ok:!0,active:r,persisted:t};n.json(i)}catch(e){const r=e;n.status(500).json({error:r.message})}}),h.post("/sessions/recover",S,async(u,n)=>{const{agentId:e,workspacePath:r,command:o}=u.body;if(!e){n.status(400).json({error:"agentId is required"});return}try{const s=Array.from(g.entries()).find(([,l])=>l.agentId===e);if(s){const l=I.get(s[1].providerId||"claude-code"),v=j(l.getSessionStatus(s[0]),s[1].currentRuntimeStatus,s[1].currentRuntimeActionType);n.json({ok:!0,sessionId:s[0],agentId:e,workspacePath:s[1].workspacePath,command:s[1].config.command,status:v,runtimeStatus:v,runtimeActionType:s[1].currentRuntimeActionType,runtimeActionLabel:s[1].currentRuntimeActionLabel,runtimeActionDetail:s[1].currentRuntimeActionDetail,mode:"sdk",recovered:!1,message:"SDK session already active"});return}const t=await k(e);let i=!1,d;if(t?.pid&&w(t.pid))i=!0,d=t.pid,c.info(`[Recover] Detected orphan process for agentId=${e}, pid=${t.pid}`);else if(t?.mode==="sdk"||!t?.pid){const l=await P(e);l&&(i=!0,d=l.pid,c.info(`[Recover] Found orphan process by agentId search: agentId=${e}, pid=${l.pid}`))}const p=r||t?.workspacePath,m=o||t?.command||"acode",a=t?.mode||"sdk";if(!p){n.status(400).json({error:"workspacePath is required (not found in persisted session)"});return}if(i&&d){c.info(`[Recover] Returning orphan process info for agentId=${e}`),n.json({ok:!0,sessionId:t?.sessionId||"",agentId:e,workspacePath:p,command:m,status:"orphan_detected",runtimeStatus:t?.runtimeStatus,runtimeActionType:t?.runtimeActionType,runtimeActionLabel:t?.runtimeActionLabel,runtimeActionDetail:t?.runtimeActionDetail,recovered:!1,orphan:{pid:d,message:"Found orphan process still running. Manual intervention may be required."},mode:a});return}await A(t?.sessionId||"");const f={ok:!1,sessionId:t?.sessionId||"",agentId:e,workspacePath:p,command:m,status:"stopped",recovered:!1,message:"No active SDK session found; start a new SDK runtime session instead."};n.json(f)}catch(s){const t=s;c.error("Error:",t),n.status(500).json({error:t.message})}}),h.post("/search-orphan",S,async(u,n)=>{const{agentId:e,workspacePath:r}=u.body;if(!e){n.status(400).json({error:"agentId is required"});return}try{const o=Array.from(g.entries()).find(([,a])=>a.agentId===e);let s=!1,t,i;if(o){const[a,f]=o,l=I.get(f.providerId||"claude-code");t=l.getSessionPid?.(a),i=f.config?.command;const v=t?w(t):!1,y=l.getSessionStatus(a),D=y==="completed"||y==="terminated"||y==="error";if(v)s=!0;else if(t&&!v)c.info(`[search-orphan] Cleaning up stale SDK session (process dead): agentId=${e}, sessionId=${a}, pid=${t}`),g.delete(a),await A(a);else if(D){c.info(`[search-orphan] Cleaning up stale in-process SDK session (status=${y}): agentId=${e}, sessionId=${a}`);try{await l.terminateSession(a)}catch($){c.warn(`[search-orphan] Failed to terminate stale in-process session: ${$}`)}g.delete(a),await A(a)}else{c.info(`[search-orphan] Terminating unreachable in-process SDK session: agentId=${e}, sessionId=${a}, status=${y||"unknown"}`);try{await l.abortCurrentTurn(a).catch(()=>{}),await l.terminateSession(a)}catch($){c.warn(`[search-orphan] Failed to terminate in-process session: ${$}`)}g.delete(a),await A(a)}}const d=await P(e);if(d){c.info(`[search-orphan] Found orphan process for agentId=${e}, pid=${d.pid}`),n.json({ok:!0,agentId:e,hasActiveSession:s,found:!0,orphan:{pid:d.pid,command:d.command,cwd:d.cwd,startedAt:d.startedAt,message:"Found orphan process. Click terminate to stop it."}});return}if(s&&t){c.info(`[search-orphan] Active session process still running, reporting as terminable orphan: agentId=${e}, pid=${t}`),n.json({ok:!0,agentId:e,hasActiveSession:!0,found:!0,orphan:{pid:t,command:i||"(active SDK session)",message:"Found active SDK session process. Click terminate to stop it."}});return}const p=await k(e);if(p?.pid&&w(p.pid)){c.info(`[search-orphan] Found orphan by persisted PID: agentId=${e}, pid=${p.pid}`),n.json({ok:!0,agentId:e,hasActiveSession:s,found:!0,orphan:{pid:p.pid,command:p.command||"(persisted session)",message:"Found orphan process by persisted PID. Click terminate to stop it."}});return}const m=r||p?.workspacePath;if(m){const a=await F(m);if(a){c.info(`[search-orphan] Found orphan by workspace: agentId=${e}, pid=${a.pid}, workspace=${m}`),n.json({ok:!0,agentId:e,hasActiveSession:s,found:!0,orphan:{pid:a.pid,command:a.command,message:"Found orphan process by workspace path. Click terminate to stop it."}});return}}c.info(`[search-orphan] No orphan process found for agentId=${e}, hasActiveSession=${!!s}`),n.json({ok:!0,agentId:e,hasActiveSession:!!s,found:!1,orphan:null,message:s?"Agent has active session in runtime-bridge":"No orphan process and no active session found"})}catch(o){const s=o;c.error("[search-orphan] Error:",s),n.status(500).json({error:s.message})}}),h.post("/terminate-orphan",S,async(u,n)=>{const{agentId:e,pid:r}=u.body;if(!e||!r){n.status(400).json({error:"agentId and pid are required"});return}try{const o=Array.from(g.entries()).find(([,i])=>i.agentId===e);if(o){const[i,d]=o,p=I.get(d.providerId||"claude-code");try{await p.terminateSession(i)}catch(m){c.warn(`[terminate-orphan] Failed to terminate SDK session for agentId=${e}:`,m)}g.delete(i),await A(i),c.info(`[terminate-orphan] Cleaned up SDK session for agentId=${e}, sessionId=${i}`)}if(!w(r)){n.json({ok:!0,agentId:e,pid:r,terminated:!1,message:"Process already terminated"});return}const s=process.platform;let t=!1;if(s==="win32")try{b(`taskkill /PID ${r} /T /F`,{encoding:"utf8",timeout:5e3}),t=!0}catch(i){c.warn(`[terminate-orphan] taskkill failed for pid=${r}:`,i)}else try{process.kill(r,"SIGTERM"),t=!0}catch(i){c.warn(`[terminate-orphan] kill failed for pid=${r}:`,i)}t?(c.info(`[terminate-orphan] Terminated orphan process for agentId=${e}, pid=${r}`),n.json({ok:!0,agentId:e,pid:r,terminated:!0,message:"Orphan process terminated successfully"})):n.json({ok:!0,agentId:e,pid:r,terminated:!1,message:"Failed to terminate process"})}catch(o){const s=o;c.error("[terminate-orphan] Error:",s),n.status(500).json({error:s.message})}}),h.get("/sessions/by-agent/:agentId",S,async(u,n)=>{const e=u.params.agentId,r=Array.isArray(e)?e[0]:e;if(!r){n.status(400).json({error:"agentId is required"});return}try{const o=Array.from(g.entries()).find(([,t])=>t.agentId===r);if(o){const t=I.get(o[1].providerId||"claude-code"),i=t.getSessionPid?.(o[0]),d=j(t.getSessionStatus(o[0]),o[1].currentRuntimeStatus,o[1].currentRuntimeActionType);n.json({ok:!0,sessionId:o[0],agentId:r,workspacePath:o[1].workspacePath,status:d,runtimeStatus:d,isActive:!0,mode:"sdk",pid:i,isManaged:!0,providerId:o[1].providerId});return}const s=await k(r);if(s){const{isProcessRunning:t}=await import("../services/process-detector.js"),i=s.pid?t(s.pid):!1;n.json({ok:!0,sessionId:s.sessionId,agentId:r,workspacePath:s.workspacePath,command:s.command,status:i?"orphan":"stopped",runtimeStatus:s.runtimeStatus,runtimeActionType:s.runtimeActionType,runtimeActionLabel:s.runtimeActionLabel,runtimeActionDetail:s.runtimeActionDetail,startedAt:s.startedAt,isActive:!1,mode:s.mode,pid:s.pid,isManaged:!1,isProcessAlive:i,isOrphan:i});return}n.json({ok:!0,agentId:r,status:"none",isActive:!1,isManaged:!1})}catch(o){const s=o;c.error("[sessions/by-agent] Error:",s),n.status(500).json({error:s.message})}}),h.post("/takeover-session",S,async(u,n)=>{const{agentId:e}=u.body;if(!e){n.status(400).json({error:"agentId is required"});return}try{const r=Array.from(g.entries()).find(([,t])=>t.agentId===e);if(r){n.json({ok:!0,agentId:e,sessionId:r[0],mode:"sdk",status:"running",isActive:!0,recovered:!1,message:"SDK session already active"});return}const o=await k(e);if(!o){n.status(404).json({error:"No persisted session found for this agentId",agentId:e});return}let s=!1;if(o.mode==="sdk"&&(s=!!await P(e),!s&&o.pid&&(s=w(o.pid))),!s){c.info(`[takeover-session] Process not alive for agentId=${e}, mode=${o.mode}`),n.json({ok:!1,agentId:e,status:"process_not_alive",isActive:!1,message:"Agent process is no longer running"});return}if(c.info(`[takeover-session] Taking over session for agentId=${e}, mode=${o.mode}, pid=${o.pid}`),o.mode==="sdk"){const t=await P(e);t?(c.info(`[takeover-session] Found SDK process for agentId=${e}, pid=${t.pid}`),n.json({ok:!0,agentId:e,sessionId:o.sessionId,mode:"sdk",status:"running",isActive:!0,recovered:!0,pid:t.pid||o.pid,message:"SDK session process found, can be taken over by aws-mcp-server"})):n.json({ok:!1,agentId:e,status:"process_not_alive",isActive:!1,message:"SDK process not found"})}else n.status(410).json({error:"Session takeover is no longer supported; start a new SDK runtime session.",agentId:e,mode:"sdk"})}catch(r){const o=r;c.error("[takeover-session] Error:",o),n.status(500).json({error:o.message})}}),h.post("/terminate-tree",S,async(u,n)=>{const{agentId:e,sessionId:r}=u.body;if(!e){n.status(400).json({error:"agentId is required"});return}try{let o=r;if(!o){const f=await k(e);if(!f){n.status(404).json({error:"Session not found for this agentId"});return}o=f.sessionId}const s=g.get(o);let t,i;if(s)t=I.get(s.providerId||"claude-code").getSessionPid?.(o),i="sdk";else{const f=await k(e);if(!f?.pid){n.status(404).json({error:"Session PID not found"});return}t=f.pid,i=f.mode||"sdk"}const{terminateProcessTree:d,waitForProcessExit:p}=await import("../services/process-detector.js");if(!t){n.status(404).json({error:"PID not found"});return}const m=await d(t),a=await p(t,5e3);C(e),await import("../services/terminal-persistence.js").then(f=>f.removePersistedSession(o)),c.info(`[terminate-tree] Terminated process tree for agentId=${e}, pid=${t}, mode=${i}, terminated=${m.terminated}, failed=${m.failed}, exited=${a}`),n.json({ok:!0,agentId:e,pid:t,mode:i,terminated:m.terminated,failed:m.failed,exited:a,message:a?`Successfully terminated ${m.terminated} processes`:`Terminated ${m.terminated} processes, but process ${t} still running`})}catch(o){const s=o;c.error("[terminate-tree] Error:",s),n.status(500).json({error:s.message})}}),h.get("/health/:agentId",S,async(u,n)=>{const e=u.params.agentId,r=Array.isArray(e)?e[0]:e;if(!r){n.status(400).json({error:"agentId is required"});return}try{const o=await k(r);if(!o){n.status(404).json({error:"Session not found"});return}const s=g.get(o.sessionId),t=!!s,{checkProcessHealth:i}=await import("../services/process-detector.js"),d={sessionId:o.sessionId,mode:o.mode,workspacePath:o.workspacePath,isManaged:t,isActive:!!s};if(o.pid){const p=await i(o.pid,r);Object.assign(d,p)}else Object.assign(d,{pid:0,alive:!1,cpu:0,memoryMB:0,status:"dead",lastUpdate:new Date});n.json({agentId:r,...d})}catch(o){const s=o;c.error("[health] Error:",s),n.status(500).json({error:s.message})}});export{j as resolveActiveSdkSessionSnapshotStatus,h as sessionsRouter};
|
|
1
|
+
import{execSync as T}from"node:child_process";import{Router as R}from"express";import{adapterRegistry as y}from"../adapter/index.js";import{validateToken as I,validateTokenOrLoopback as P}from"../middleware/auth.js";import{isProcessRunning as b,findOrphanProcessByAgentId as A,findOrphanProcessByWorkspace as C}from"../services/process-detector.js";import{findPersistedSessionByAgentId as S,loadPersistedSessions as F,removePersistedSession as w}from"../services/terminal-persistence.js";import{createLogger as K}from"../utils/logger.js";import{sdkSessions as m,cleanupSdkSessionByAgentId as E}from"./terminal.js";const u=K("sessions"),h=R();h.post("/sessions/:agentId/notify-force-message",P,(i,t)=>{const e=String(i.params.agentId??"").trim();if(!e){t.status(400).json({ok:!1,error:"agentId is required"});return}const n=Array.from(m.entries()).find(([,c])=>c.agentId===e);if(!n){t.json({ok:!0,notified:!1,message:"No active SDK session for this agentId"});return}const[r,s]=n,o=y.get(s.providerId||"claude-code");if(typeof o.notifyForceMessage=="function"){const c=o.notifyForceMessage(r);t.json({ok:!0,notified:c})}else t.json({ok:!0,notified:!1,message:"Adapter does not support force message notification"})});async function x(i){const t=String(i.agentId??"").trim(),e=String(i.capability??"").trim(),n=i.action==="expand"||i.action==="collapse"?i.action:void 0;if(!t)return{status:400,body:{ok:!1,error:"agentId is required"}};if(e!=="browser"&&e!=="desktop")return{status:400,body:{ok:!1,error:'capability must be "browser" or "desktop"'}};if(n!=="expand"&&n!=="collapse")return{status:400,body:{ok:!1,error:'action must be "expand" or "collapse"'}};const s=(i.resolveSession??(()=>{const a=Array.from(m.entries()).find(([,d])=>d.agentId===t);return a?{agentId:a[1].agentId,providerId:a[1].providerId}:void 0}))();if(!s)return{status:200,body:{ok:!0,changed:{sessions:0,tools:0},message:"No active SDK session for this agentId"}};const o=i.resolveAdapter??(a=>y.get(a));let c;try{c=o(s.providerId||"claude-code")}catch(a){return{status:500,body:{ok:!1,error:a?.message||"adapter resolution failed"}}}if(typeof c.setBuiltInCapabilityTools!="function")return{status:200,body:{ok:!0,changed:{sessions:0,tools:0},message:"Adapter does not support built-in capability tool switching"}};try{const a=await c.setBuiltInCapabilityTools(t,e,n),{manifests:d,...l}=a;return{status:200,body:{ok:!0,changed:l,...d&&d.length>0?{manifests:d}:{}}}}catch(a){return u.error("[sessions] capability-tools \u6267\u884C\u5931\u8D25",{agentId:t,capability:e,action:n,error:a?.message||String(a)}),{status:500,body:{ok:!1,error:a?.message||"failed"}}}}async function L(i){const t=String(i.agentId??"").trim(),e=String(i.capability??"").trim(),n=String(i.tool??"").trim(),r=i.args&&typeof i.args=="object"&&!Array.isArray(i.args)?i.args:{};if(!t)return{status:400,body:{ok:!1,error:"agentId is required"}};if(e!=="browser"&&e!=="desktop")return{status:400,body:{ok:!1,error:'capability must be "browser" or "desktop"'}};if(!n)return{status:400,body:{ok:!1,error:"tool is required"}};const o=(i.resolveSession??(()=>{const d=Array.from(m.entries()).find(([,l])=>l.agentId===t);return d?{agentId:d[1].agentId,providerId:d[1].providerId}:void 0}))();if(!o)return{status:200,body:{ok:!1,error:"No active SDK session for this agentId"}};const c=i.resolveAdapter??(d=>y.get(d));let a;try{a=c(o.providerId||"claude-code")}catch(d){return{status:500,body:{ok:!1,error:d?.message||"adapter resolution failed"}}}if(typeof a.callBuiltInCapabilityTool!="function")return{status:200,body:{ok:!1,error:"Adapter does not support built-in capability tool dispatch"}};try{return{status:200,body:await a.callBuiltInCapabilityTool(t,e,n,r)}}catch(d){return u.error("[sessions] capability-tools/call \u6267\u884C\u5931\u8D25",{agentId:t,capability:e,tool:n,error:d?.message||String(d)}),{status:500,body:{ok:!1,error:d?.message||"failed"}}}}h.post("/sessions/:agentId/capability-tools",P,async(i,t)=>{const e=await x({agentId:String(i.params.agentId??""),capability:String(i.body?.capability??""),action:i.body?.action});t.status(e.status).json(e.body)}),h.post("/sessions/:agentId/capability-tools/call",P,async(i,t)=>{const e=await L({agentId:String(i.params.agentId??""),capability:String(i.body?.capability??""),tool:String(i.body?.tool??""),args:i.body?.arguments});t.status(e.status).json(e.body)});function $(i,t,e){const n=String(i||"").trim();if(n){const s=String(t||"").trim(),o=String(e||"").trim().toLowerCase();return n.toLowerCase()==="tool_using"&&s.toLowerCase()==="waiting_input"&&o==="idle"?s:n}return String(t||"").trim()||"running"}h.get("/sessions",I,async(i,t)=>{try{const n=Array.from(m.entries()).map(([a,d])=>{const l=y.get(d.providerId||"claude-code"),p=$(l.getSessionStatus(a),d.currentRuntimeStatus,d.currentRuntimeActionType);return{sessionId:a,agentId:d.agentId,workspacePath:d.workspacePath,status:p,runtimeStatus:p,runtimeActionType:d.currentRuntimeActionType,runtimeActionLabel:d.currentRuntimeActionLabel,runtimeActionDetail:d.currentRuntimeActionDetail,mode:"sdk",startedAt:null}}),r=await F(),s=new Set(n.map(a=>a.sessionId)),o=r.filter(a=>!s.has(a.sessionId)),c={ok:!0,active:n,persisted:o};t.json(c)}catch(e){const n=e;t.status(500).json({error:n.message})}}),h.post("/sessions/recover",I,async(i,t)=>{const{agentId:e,workspacePath:n,command:r}=i.body;if(!e){t.status(400).json({error:"agentId is required"});return}try{const s=Array.from(m.entries()).find(([,g])=>g.agentId===e);if(s){const g=y.get(s[1].providerId||"claude-code"),k=$(g.getSessionStatus(s[0]),s[1].currentRuntimeStatus,s[1].currentRuntimeActionType);t.json({ok:!0,sessionId:s[0],agentId:e,workspacePath:s[1].workspacePath,command:s[1].config.command,status:k,runtimeStatus:k,runtimeActionType:s[1].currentRuntimeActionType,runtimeActionLabel:s[1].currentRuntimeActionLabel,runtimeActionDetail:s[1].currentRuntimeActionDetail,mode:"sdk",recovered:!1,message:"SDK session already active"});return}const o=await S(e);let c=!1,a;if(o?.pid&&b(o.pid))c=!0,a=o.pid,u.info(`[Recover] Detected orphan process for agentId=${e}, pid=${o.pid}`);else if(o?.mode==="sdk"||!o?.pid){const g=await A(e);g&&(c=!0,a=g.pid,u.info(`[Recover] Found orphan process by agentId search: agentId=${e}, pid=${g.pid}`))}const d=n||o?.workspacePath,l=r||o?.command||"acode",p=o?.mode||"sdk";if(!d){t.status(400).json({error:"workspacePath is required (not found in persisted session)"});return}if(c&&a){u.info(`[Recover] Returning orphan process info for agentId=${e}`),t.json({ok:!0,sessionId:o?.sessionId||"",agentId:e,workspacePath:d,command:l,status:"orphan_detected",runtimeStatus:o?.runtimeStatus,runtimeActionType:o?.runtimeActionType,runtimeActionLabel:o?.runtimeActionLabel,runtimeActionDetail:o?.runtimeActionDetail,recovered:!1,orphan:{pid:a,message:"Found orphan process still running. Manual intervention may be required."},mode:p});return}await w(o?.sessionId||"");const f={ok:!1,sessionId:o?.sessionId||"",agentId:e,workspacePath:d,command:l,status:"stopped",recovered:!1,message:"No active SDK session found; start a new SDK runtime session instead."};t.json(f)}catch(s){const o=s;u.error("Error:",o),t.status(500).json({error:o.message})}}),h.post("/search-orphan",I,async(i,t)=>{const{agentId:e,workspacePath:n}=i.body;if(!e){t.status(400).json({error:"agentId is required"});return}try{const r=Array.from(m.entries()).find(([,p])=>p.agentId===e);let s=!1,o,c;if(r){const[p,f]=r,g=y.get(f.providerId||"claude-code");o=g.getSessionPid?.(p),c=f.config?.command;const k=o?b(o):!1,v=g.getSessionStatus(p),D=v==="completed"||v==="terminated"||v==="error";if(k)s=!0;else if(o&&!k)u.info(`[search-orphan] Cleaning up stale SDK session (process dead): agentId=${e}, sessionId=${p}, pid=${o}`),m.delete(p),await w(p);else if(D){u.info(`[search-orphan] Cleaning up stale in-process SDK session (status=${v}): agentId=${e}, sessionId=${p}`);try{await g.terminateSession(p)}catch(j){u.warn(`[search-orphan] Failed to terminate stale in-process session: ${j}`)}m.delete(p),await w(p)}else{u.info(`[search-orphan] Terminating unreachable in-process SDK session: agentId=${e}, sessionId=${p}, status=${v||"unknown"}`);try{await g.abortCurrentTurn(p).catch(()=>{}),await g.terminateSession(p)}catch(j){u.warn(`[search-orphan] Failed to terminate in-process session: ${j}`)}m.delete(p),await w(p)}}const a=await A(e);if(a){u.info(`[search-orphan] Found orphan process for agentId=${e}, pid=${a.pid}`),t.json({ok:!0,agentId:e,hasActiveSession:s,found:!0,orphan:{pid:a.pid,command:a.command,cwd:a.cwd,startedAt:a.startedAt,message:"Found orphan process. Click terminate to stop it."}});return}if(s&&o){u.info(`[search-orphan] Active session process still running, reporting as terminable orphan: agentId=${e}, pid=${o}`),t.json({ok:!0,agentId:e,hasActiveSession:!0,found:!0,orphan:{pid:o,command:c||"(active SDK session)",message:"Found active SDK session process. Click terminate to stop it."}});return}const d=await S(e);if(d?.pid&&b(d.pid)){u.info(`[search-orphan] Found orphan by persisted PID: agentId=${e}, pid=${d.pid}`),t.json({ok:!0,agentId:e,hasActiveSession:s,found:!0,orphan:{pid:d.pid,command:d.command||"(persisted session)",message:"Found orphan process by persisted PID. Click terminate to stop it."}});return}const l=n||d?.workspacePath;if(l){const p=await C(l);if(p){u.info(`[search-orphan] Found orphan by workspace: agentId=${e}, pid=${p.pid}, workspace=${l}`),t.json({ok:!0,agentId:e,hasActiveSession:s,found:!0,orphan:{pid:p.pid,command:p.command,message:"Found orphan process by workspace path. Click terminate to stop it."}});return}}u.info(`[search-orphan] No orphan process found for agentId=${e}, hasActiveSession=${!!s}`),t.json({ok:!0,agentId:e,hasActiveSession:!!s,found:!1,orphan:null,message:s?"Agent has active session in runtime-bridge":"No orphan process and no active session found"})}catch(r){const s=r;u.error("[search-orphan] Error:",s),t.status(500).json({error:s.message})}}),h.post("/terminate-orphan",I,async(i,t)=>{const{agentId:e,pid:n}=i.body;if(!e||!n){t.status(400).json({error:"agentId and pid are required"});return}try{const r=Array.from(m.entries()).find(([,c])=>c.agentId===e);if(r){const[c,a]=r,d=y.get(a.providerId||"claude-code");try{await d.terminateSession(c)}catch(l){u.warn(`[terminate-orphan] Failed to terminate SDK session for agentId=${e}:`,l)}m.delete(c),await w(c),u.info(`[terminate-orphan] Cleaned up SDK session for agentId=${e}, sessionId=${c}`)}if(!b(n)){t.json({ok:!0,agentId:e,pid:n,terminated:!1,message:"Process already terminated"});return}const s=process.platform;let o=!1;if(s==="win32")try{T(`taskkill /PID ${n} /T /F`,{encoding:"utf8",timeout:5e3}),o=!0}catch(c){u.warn(`[terminate-orphan] taskkill failed for pid=${n}:`,c)}else try{process.kill(n,"SIGTERM"),o=!0}catch(c){u.warn(`[terminate-orphan] kill failed for pid=${n}:`,c)}o?(u.info(`[terminate-orphan] Terminated orphan process for agentId=${e}, pid=${n}`),t.json({ok:!0,agentId:e,pid:n,terminated:!0,message:"Orphan process terminated successfully"})):t.json({ok:!0,agentId:e,pid:n,terminated:!1,message:"Failed to terminate process"})}catch(r){const s=r;u.error("[terminate-orphan] Error:",s),t.status(500).json({error:s.message})}}),h.get("/sessions/by-agent/:agentId",I,async(i,t)=>{const e=i.params.agentId,n=Array.isArray(e)?e[0]:e;if(!n){t.status(400).json({error:"agentId is required"});return}try{const r=Array.from(m.entries()).find(([,o])=>o.agentId===n);if(r){const o=y.get(r[1].providerId||"claude-code"),c=o.getSessionPid?.(r[0]),a=$(o.getSessionStatus(r[0]),r[1].currentRuntimeStatus,r[1].currentRuntimeActionType);t.json({ok:!0,sessionId:r[0],agentId:n,workspacePath:r[1].workspacePath,status:a,runtimeStatus:a,isActive:!0,mode:"sdk",pid:c,isManaged:!0,providerId:r[1].providerId});return}const s=await S(n);if(s){const{isProcessRunning:o}=await import("../services/process-detector.js"),c=s.pid?o(s.pid):!1;t.json({ok:!0,sessionId:s.sessionId,agentId:n,workspacePath:s.workspacePath,command:s.command,status:c?"orphan":"stopped",runtimeStatus:s.runtimeStatus,runtimeActionType:s.runtimeActionType,runtimeActionLabel:s.runtimeActionLabel,runtimeActionDetail:s.runtimeActionDetail,startedAt:s.startedAt,isActive:!1,mode:s.mode,pid:s.pid,isManaged:!1,isProcessAlive:c,isOrphan:c});return}t.json({ok:!0,agentId:n,status:"none",isActive:!1,isManaged:!1})}catch(r){const s=r;u.error("[sessions/by-agent] Error:",s),t.status(500).json({error:s.message})}}),h.post("/takeover-session",I,async(i,t)=>{const{agentId:e}=i.body;if(!e){t.status(400).json({error:"agentId is required"});return}try{const n=Array.from(m.entries()).find(([,o])=>o.agentId===e);if(n){t.json({ok:!0,agentId:e,sessionId:n[0],mode:"sdk",status:"running",isActive:!0,recovered:!1,message:"SDK session already active"});return}const r=await S(e);if(!r){t.status(404).json({error:"No persisted session found for this agentId",agentId:e});return}let s=!1;if(r.mode==="sdk"&&(s=!!await A(e),!s&&r.pid&&(s=b(r.pid))),!s){u.info(`[takeover-session] Process not alive for agentId=${e}, mode=${r.mode}`),t.json({ok:!1,agentId:e,status:"process_not_alive",isActive:!1,message:"Agent process is no longer running"});return}if(u.info(`[takeover-session] Taking over session for agentId=${e}, mode=${r.mode}, pid=${r.pid}`),r.mode==="sdk"){const o=await A(e);o?(u.info(`[takeover-session] Found SDK process for agentId=${e}, pid=${o.pid}`),t.json({ok:!0,agentId:e,sessionId:r.sessionId,mode:"sdk",status:"running",isActive:!0,recovered:!0,pid:o.pid||r.pid,message:"SDK session process found, can be taken over by aws-mcp-server"})):t.json({ok:!1,agentId:e,status:"process_not_alive",isActive:!1,message:"SDK process not found"})}else t.status(410).json({error:"Session takeover is no longer supported; start a new SDK runtime session.",agentId:e,mode:"sdk"})}catch(n){const r=n;u.error("[takeover-session] Error:",r),t.status(500).json({error:r.message})}}),h.post("/terminate-tree",I,async(i,t)=>{const{agentId:e,sessionId:n}=i.body;if(!e){t.status(400).json({error:"agentId is required"});return}try{let r=n;if(!r){const f=await S(e);if(!f){t.status(404).json({error:"Session not found for this agentId"});return}r=f.sessionId}const s=m.get(r);let o,c;if(s)o=y.get(s.providerId||"claude-code").getSessionPid?.(r),c="sdk";else{const f=await S(e);if(!f?.pid){t.status(404).json({error:"Session PID not found"});return}o=f.pid,c=f.mode||"sdk"}const{terminateProcessTree:a,waitForProcessExit:d}=await import("../services/process-detector.js");if(!o){t.status(404).json({error:"PID not found"});return}const l=await a(o),p=await d(o,5e3);E(e),await import("../services/terminal-persistence.js").then(f=>f.removePersistedSession(r)),u.info(`[terminate-tree] Terminated process tree for agentId=${e}, pid=${o}, mode=${c}, terminated=${l.terminated}, failed=${l.failed}, exited=${p}`),t.json({ok:!0,agentId:e,pid:o,mode:c,terminated:l.terminated,failed:l.failed,exited:p,message:p?`Successfully terminated ${l.terminated} processes`:`Terminated ${l.terminated} processes, but process ${o} still running`})}catch(r){const s=r;u.error("[terminate-tree] Error:",s),t.status(500).json({error:s.message})}}),h.get("/health/:agentId",I,async(i,t)=>{const e=i.params.agentId,n=Array.isArray(e)?e[0]:e;if(!n){t.status(400).json({error:"agentId is required"});return}try{const r=await S(n);if(!r){t.status(404).json({error:"Session not found"});return}const s=m.get(r.sessionId),o=!!s,{checkProcessHealth:c}=await import("../services/process-detector.js"),a={sessionId:r.sessionId,mode:r.mode,workspacePath:r.workspacePath,isManaged:o,isActive:!!s};if(r.pid){const d=await c(r.pid,n);Object.assign(a,d)}else Object.assign(a,{pid:0,alive:!1,cpu:0,memoryMB:0,status:"dead",lastUpdate:new Date});t.json({agentId:n,...a})}catch(r){const s=r;u.error("[health] Error:",s),t.status(500).json({error:s.message})}});export{L as handleCapabilityToolCallRequest,x as handleCapabilityToolsRequest,$ as resolveActiveSdkSessionSnapshotStatus,h as sessionsRouter};
|
|
2
2
|
|
package/dist/routes/terminal.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import{spawn as
|
|
1
|
+
import{spawn as Je}from"node:child_process";import{promises as v}from"node:fs";import Ze from"node:os";import B from"node:path";import{TextDecoder as te}from"node:util";import we from"axios";import{Router as et}from"express";import{v4 as tt}from"uuid";import{adapterRegistry as b,getToolActionInfo as he,isTransientClipboardPasteFilePath as _e,redactTransientClipboardPastePaths as F,registerSdkProviders as nt,resolveSdkProviderIdByCommand as rt}from"../adapter/index.js";import{MESSAGE_POLLING_IDLE_PROMPT as Ce}from"../adapter/prompts.js";import{getActiveBridgeHttpPort as ot,getAcodeDataHome as $e}from"../config.js";import{validateToken as I}from"../middleware/auth.js";import{getAgentProcessManager as Ie}from"../services/agent-process-manager.js";import{createAiConfigService as st}from"../services/ai-config-service.js";import{resolveSchedulerBaseUrlFromToken as De}from"../services/auto-register.js";import{setChangeCacheRetentionDays as it}from"../services/change-cache-retention.js";import{getAllPushStats as at,startHeartbeatScheduler as ct}from"../services/event-delta-pusher.js";import{prepareAcodeInstanceConfig as ut,redactForLog as ne}from"../services/instance-ai-config-service.js";import{setAgentFeatures as dt,setAgentCapabilities as lt,getAgentFeatures as mt,getFeatureState as x,LAUNCH_ITEM_FEATURE_KEY as Re,HIRE_FEATURE_KEY as Pe,PENCIL_FEATURE_KEY as Ee,DRAW_FEATURE_KEY as Me}from"../services/instance-features.js";import{enqueueMcpLaunchBinding as ft}from"../services/mcp-launch-binding-queue.js";import{setPanelEnvVars as pt}from"../services/panel-env.js";import{findClaudeCodeProcesses as gt,isProcessRunning as yt}from"../services/process-detector.js";import{forgetSession as K,onSdkToolUseEnd as ht,onSdkToolUseStart as It}from"../services/sdk-tool-file-change-recorder.js";import{bridgeEventBuffer as Le,sendOutput as Q,sendQuestionRequest as St,sendToolAuthRequest as At,sendStatus as C}from"../services/session-output.js";import{findPersistedSessionByAgentId as Tt,removePersistedSession as z,savePersistedSessions as kt,updatePersistedSessionAutoCommands as bt,updatePersistedSessionRuntimeState as wt,upsertPersistedSession as _t}from"../services/terminal-persistence.js";import{getInstanceAiConfigDebugLogger as Ct}from"../utils/instance-ai-config-debug-logger.js";import{logger as m}from"../utils/logger.js";const S=et();function xe(e){const n=e.header("X-Runtime-Token");return n&&n.trim()?n.trim():(e.header("Authorization")||"").match(/^Bearer\s+(.+)$/i)?.[1]?.trim()||void 0}const p=new Map,$t=45e3,re=new Map;function Dt(e){if(re.has(e))return;const n=setInterval(()=>{const t=p.get(e);if(!t){L(e);return}const r=t.currentRuntimeStatus;if(r!=="thinking"&&r!=="tool_using"&&r!=="compacting"){L(e);return}C(t.agentId,e,r,void 0,void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl}).catch(()=>{})},$t);re.set(e,n)}function L(e){const n=re.get(e);n&&(clearInterval(n),re.delete(e))}const Ue=4e3,Rt=`
|
|
2
2
|
|
|
3
3
|
\u8BF7\u6C42\u4F53:
|
|
4
|
-
`;function
|
|
4
|
+
`;function je(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 Pt=`
|
|
5
5
|
|
|
6
6
|
\u8BF7\u6C42\u5934:
|
|
7
|
-
`,
|
|
7
|
+
`,H=new Set;async function Et(e,n){const t=[],r=[],o=B.join(e,".agentswork","memory");try{const c=(await v.readdir(o)).filter(u=>u.endsWith(".json")),d=await Promise.all(c.map(async u=>{try{const l=await v.readFile(B.join(o,u),"utf-8");return JSON.parse(l)}catch{return m.warn("[loadAgentStartupMemories] Failed to parse memory file: %s",B.join(o,u)),null}}));for(const u of d)if(u?.by_uri)for(const l of Object.values(u.by_uri)){const f=l.memory_type||"memory",g=(l.content||"").trim();g&&(f==="recently_memory"?t.push({title:l.title,content:g,uri:l.uri||""}):f==="agent_memory"&&r.push({title:l.title,content:g,uri:l.uri||""}))}}catch{m.debug("[loadAgentStartupMemories] \u65E0\u6CD5\u8BFB\u53D6\u8BB0\u5FC6\u76EE\u5F55: %s",o)}if(t.length===0&&r.length===0&&n?.schedulerBaseUrl&&n?.runtimeAccessToken&&n?.agentId){const a=`${n.schedulerBaseUrl.replace(/\/+$/,"")}/mcp/call`,c={"Content-Type":"application/json","X-Runtime-Token":n.runtimeAccessToken,Authorization:`Bearer ${n.runtimeAccessToken}`},d=["recently_memory","agent_memory"],u=await Promise.allSettled(d.map(l=>fetch(a,{method:"POST",headers:c,body:JSON.stringify({tool:"list_memories",arguments:{agentId:n.agentId,memory_type:l}})}).then(f=>{if(!f.ok)throw new Error(`Server returned ${f.status}`);return f.json()})));for(let l=0;l<u.length;l++){const f=u[l];if(f.status!=="fulfilled")continue;const g=f.value;if(!Array.isArray(g))continue;const T=d[l]==="recently_memory"?t:r;for(const h of g){const y=(h.content||"").trim();y&&T.push({title:h.title,content:y,uri:h.uri||""})}}(t.length>0||r.length>0)&&m.info(`[loadAgentStartupMemories] Loaded ${t.length} task(s) and ${r.length} memory(s) from server for ${n.agentId}`)}const s=10;t.sort((a,c)=>c.uri.localeCompare(a.uri)),r.sort((a,c)=>c.uri.localeCompare(a.uri));const i=[];if(t.length>0){const c=t.slice(0,s).map((d,u)=>`${d.title?`\u3010${d.title}\u3011`:`\u6761\u76EE ${u+1}`}
|
|
8
8
|
${d.content}`);i.push(`\u3010\u77ED\u671F\u8BB0\u5FC6\u3011
|
|
9
9
|
${c.join(`
|
|
10
10
|
|
|
@@ -14,41 +14,41 @@ ${c.join(`
|
|
|
14
14
|
|
|
15
15
|
`)}`),r.length>s&&i.push(`... \u53CA\u53E6\u5916 ${r.length-s} \u6761 agent \u8BA4\u77E5`)}if(i.length!==0)return i.join(`
|
|
16
16
|
|
|
17
|
-
`)}function
|
|
17
|
+
`)}function Mt(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 Lt(e){return e!=="acode"}function xt(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 oe(e){const n=e?.usage;if(!n)return;const t=Number.isFinite(n.inputTokens)?n.inputTokens:0,r=Number.isFinite(n.outputTokens)?n.outputTokens:0;if(t<=0&&r<=0&&!n.contextLimit&&!n.maxOutput&&!n.inputLimit&&!n.compactionThreshold)return;const o={inputTokens:t,outputTokens:r,...n.contextLimit?{contextLimit:n.contextLimit}:{},...n.maxOutput?{maxOutput:n.maxOutput}:{},...n.inputLimit?{inputLimit:n.inputLimit}:{},...n.compactionThreshold?{compactionThreshold:n.compactionThreshold}:{},...n.cacheHitTokens?{cacheHitTokens:n.cacheHitTokens}:{},...n.cacheMissTokens?{cacheMissTokens:n.cacheMissTokens}:{}};return process.env.ACODE_TOKEN_DEBUG==="1"&&(o.inputTokens>0||o.outputTokens>0||o.cacheHitTokens!==void 0||o.cacheMissTokens!==void 0)&&m.info(`[TokenDebug][Terminal] resolveStatusChangeUsage: input=${o.inputTokens} output=${o.outputTokens} cacheHit=${o.cacheHitTokens??"(none)"} cacheMiss=${o.cacheMissTokens??"(none)"} actionType=${e?.actionType??"(none)"}`),o}function Ut(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 V=new Map,jt="utf-8",Oe="utf-8",Be=300,Ne=6e4;function Y(e){return String(e).padStart(2,"0")}function Ot(e,n=new Date){const t=n.getFullYear(),r=Y(n.getMonth()+1),o=Y(n.getDate()),s=Y(n.getHours()),i=Y(n.getMinutes()),a=`${t}${r}${o}-${s}${i}${Y(n.getSeconds())}-${String(n.getMilliseconds()).padStart(3,"0")}`;return B.join($e(),"cmd-dist",e,`${t}-${r}-${o}`,s,i,`${a}-cmd.out`)}function Bt(e){if(!e)return 0;const n=e.replace(/\r\n/g,`
|
|
18
18
|
`).replace(/\r/g,`
|
|
19
19
|
`),t=n.endsWith(`
|
|
20
20
|
`)?n.slice(0,-1):n;return t?t.split(`
|
|
21
|
-
`).length:1}function
|
|
21
|
+
`).length:1}function Nt(e,n=Be){return`\r
|
|
22
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 qt(e=Ne){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 o=
|
|
26
|
+
`}async function qe(e){const n=e.outputPath||Ot(e.agentId,e.startedAt);return e.outputPath=n,await v.mkdir(B.dirname(n),{recursive:!0}),await v.writeFile(n,e.chunks.join(""),"utf-8"),n}function vt(e){return String(e??"").replace(/\r/g,`
|
|
27
|
+
`).trim()}function Ft(e=process.platform,n=process.env){const t=n.AWS_TERMINAL_OUTPUT_ENCODING?.trim();return t||(e==="win32"?jt:Oe)}function ve(e=Ft()){if(e!=="utf-8")try{return new te(e,{fatal:!1})}catch{return new te(Oe,{fatal:!1})}return Kt()}function Kt(){let e=null,n=null,t=null;const r=[];function o(s){try{return new te(s,{fatal:!1})}catch{return new te("utf-8",{fatal:!1})}}return{decode(s,i){if(s!=null&&r.push(s instanceof ArrayBuffer?Buffer.from(s):Buffer.isBuffer(s)?s:Buffer.from(s.buffer,s.byteOffset,s.byteLength)),t==="gb18030")return n||(n=o("gb18030")),n.decode(s,i);e||(e=o("utf-8"));const a=e.decode(s,i);if(t===null&&a.includes("\uFFFD")){t="gb18030",n=o("gb18030");const c=Buffer.concat(r);return n.decode(c)}return t===null&&!i?.stream&&(t="utf-8"),a}}}function se(e,n,t=!1){return t?e.decode():!n||n.length===0?"":e.decode(n,{stream:!0})}function zt(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 Ht(e){const n=V.get(e.sessionId);if(n)return n;const t={currentDirectory:e.workspacePath,runningProcess:null};return V.set(e.sessionId,t),t}function Fe(e){for(const n of p.values())if(n.agentId===e)return n}async function Wt(e){const n=b.get(e.providerId||"claude-code"),t=ie(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 ie(e,n,t){const r=String(e||"").trim();if(r){const s=String(n||"").trim(),i=String(t||"").trim().toLowerCase();return r.toLowerCase()==="tool_using"&&s.toLowerCase()==="waiting_input"&&i==="idle"?s:r}return String(n||"").trim()||"running"}function Xt(e,n=yt){return e.pid?n(e.pid)?Ge(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 or(e){const n=Fe(e);if(!n)m.info(`[cleanupSdkSessionByAgentId] No active SDK session found for agentId=${e}, cleaning residual state anyway`);else{const t=n.sessionId;return m.info(`[cleanupSdkSessionByAgentId] Cleaning up SDK session for agentId=${e}, sessionId=${t}`),L(t),p.delete(t),K(t),ae(t),z(t).catch(r=>{m.warn(`[cleanupSdkSessionByAgentId] Failed to remove persisted session for agentId=${e}: ${r}`)}),t}H.has(e)&&(H.delete(e),m.info(`[cleanupSdkSessionByAgentId] Released startingAgents lock for agentId=${e}`))}function ae(e){const n=V.get(e);if(!n?.runningProcess){V.delete(e);return}try{n.runningProcess.kill()}catch{}finally{n.runningProcess=null,V.delete(e)}}function w(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 Gt(e,n){return n==="~"?Ze.homedir():B.resolve(e,n)}async function Qt(e,n,t){const r=zt(t);if(r===void 0)return!1;if(r===null)return w(e,`${n.currentDirectory}\r
|
|
28
|
+
`),!0;const o=Gt(n.currentDirectory,r);try{return(await v.stat(o)).isDirectory()?(n.currentDirectory=o,w(e,`${n.currentDirectory}\r
|
|
29
29
|
`),!0):(w(e,`cd: not a directory: ${o}\r
|
|
30
30
|
`),!0)}catch(s){const i=s instanceof Error?s.message:String(s);return w(e,`cd: ${i}\r
|
|
31
|
-
`),!0}}async function
|
|
31
|
+
`),!0}}async function Vt(e,n){const t=p.get(e);if(!t)throw new Error("SDK session not found");const r=vt(n),o=Ht(t);if(!r)return{started:!1,cwd:o.currentDirectory};if(o.runningProcess)throw new Error("A terminal command is already running for this session");const s=F(r);if(w(t,`${Se(o.currentDirectory)}${s}\r
|
|
32
32
|
`),_e(r))return w(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
|
-
`),w(t,Se(o.currentDirectory)),{started:!1,cwd:o.currentDirectory};if(await
|
|
33
|
+
`),w(t,Se(o.currentDirectory)),{started:!1,cwd:o.currentDirectory};if(await Qt(t,o,r))return{started:!1,cwd:o.currentDirectory};await C(t.agentId,e,"tool_using",{actionType:"bash",actionLabel:"\u7EC8\u7AEF\u547D\u4EE4",actionDetail:s},void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl});const a=Je(r,{cwd:o.currentDirectory,shell:!0,env:Ke(t.agentId,t.workspacePath,process.env,t.config.envOverrides)});o.runningProcess=a;const c=ve(),d=ve(),u=t.providerId==="acode",l={agentId:t.agentId,startedAt:new Date,chunks:[],spilled:!1};let f;const g=()=>{f&&(clearTimeout(f),f=void 0)},T=()=>{g(),f=setTimeout(()=>{o.runningProcess===a&&(w(t,qt()),a.kill())},Ne)},h=(y,_=!0)=>{if(y&&(u&&l.chunks.push(y),u&&_&&T(),!(u&&l.spilled))){if(u&&Bt(l.chunks.join(""))>Be){l.spilled=!0,qe(l).then($=>{w(t,Nt($))}).catch($=>{const M=$ instanceof Error?$.message:String($);w(t,`\r
|
|
34
34
|
[ACode] \u547D\u4EE4\u8F93\u51FA\u843D\u76D8\u5931\u8D25: ${M}\r
|
|
35
|
-
`)});return}w(t,y)}};return u&&T(),a.stdout.on("data",y=>{h(
|
|
35
|
+
`)});return}w(t,y)}};return u&&T(),a.stdout.on("data",y=>{h(se(c,y))}),a.stderr.on("data",y=>{h(se(d,y))}),a.on("error",y=>{w(t,`\r
|
|
36
36
|
[Terminal Error] ${y.message}\r
|
|
37
|
-
`)}),a.on("close",(y,_)=>{g(),o.runningProcess=null,h(
|
|
37
|
+
`)}),a.on("close",(y,_)=>{g(),o.runningProcess=null,h(se(c,void 0,!0),!1),h(se(d,void 0,!0),!1),l.spilled&&qe(l).catch($=>{const M=$ instanceof Error?$.message:String($);w(t,`\r
|
|
38
38
|
[ACode] \u547D\u4EE4\u8F93\u51FA\u6700\u7EC8\u843D\u76D8\u5931\u8D25: ${M}\r
|
|
39
39
|
`)}),y&&y!==0?w(t,`\r
|
|
40
40
|
[exit ${y}]\r
|
|
41
41
|
`):_&&w(t,`\r
|
|
42
42
|
[signal ${_}]\r
|
|
43
|
-
`),w(t,Se(o.currentDirectory)),C(t.agentId,e,"waiting_input",void 0,void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl})}),{started:!0,cwd:o.currentDirectory}}function
|
|
44
|
-
...\uFF08\u7ED3\u679C\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`}function
|
|
43
|
+
`),w(t,Se(o.currentDirectory)),C(t.agentId,e,"waiting_input",void 0,void 0,{runtimeAccessToken:t.runtimeAccessToken,schedulerBaseUrl:t.schedulerBaseUrl})}),{started:!0,cwd:o.currentDirectory}}function Ke(e,n,t,r){const o={};for(const[s,i]of Object.entries(t))i!==void 0&&(o[s]=i);if(n&&(o.AWS_WORKSPACE_PATH=String(n)),r)for(const[s,i]of Object.entries(r)){const a=s.trim();if(!a||i===void 0||i===null)continue;const c=String(i).trim();c&&(o[a]=c)}return o.AWS_AGENT_ID=String(e),o.AWS_MCP_CLAIM_LAUNCH_BINDING="true",o.AWS_RUNTIME_BRIDGE_BASE_URL=`http://127.0.0.1:${ot()}`,String(o.ACODE_HOME||"").trim()||(o.ACODE_HOME=$e()),x(e,Re)!=="disabled"&&(o.AWS_LAUNCH_CONFIG_TOOLS=x(e,Re)),x(e,Pe)!=="disabled"&&(o.AWS_HIRE_TOOLS=x(e,Pe)),x(e,Ee)!=="disabled"&&(o.AWS_PENCIL_TOOLS=x(e,Ee)),x(e,Me)!=="disabled"&&(o.AWS_DRAW_TOOLS=x(e,Me)),o}function Yt(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 Jt(e){const n=String(e);if(!_e(n))return n;const t=Yt(n);return B.isAbsolute(t)?v.readFile(t,"utf-8"):n}function ze(e,n){const t={};for(const o of[e?.env,n])if(o)for(const[s,i]of Object.entries(o)){const a=s.trim();if(!a||i===void 0||i===null)continue;const c=String(i).trim();c&&(t[a]=c)}const r=t.ANTHROPIC_MODEL?.trim()||t.CODEX_MODEL?.trim()||void 0;return{envOverrides:t,model:r}}async function Zt(){try{return await st().readClaudeCodeConfig()}catch(e){return console.warn(`[Runtime] Failed to read saved ClaudeCode AI config: ${e.message}`),{}}}function en(e){if(e==null)return;const t=(typeof e=="string"?e:JSON.stringify(e,null,2)).trim();if(t)return t.length<=Ue?t:`${t.slice(0,Ue)}
|
|
44
|
+
...\uFF08\u7ED3\u679C\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`}function tn(e){try{const n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return["directMessages","groupMessages","messages"].some(t=>Array.isArray(n[t])&&n[t].length>0)}catch{}return e.trim().length>0}function nn(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 rn(e){if(e.type!=="tool_use_end")return;const n=en(e.data.toolResult??e.data.actionResult);if(!n)return;const t=he(e.data.toolName,e.data.toolInput),r=e.data.actionType||t.actionType;if(r==="idle"){const o=String(e.data.rawToolName||e.data.toolName||"").toLowerCase();if((o.includes("poll_message")||o.includes("get_message"))&&!tn(n))return}return r==="mcp"&&nn(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 on(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
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`:n}catch{return}}function
|
|
50
|
-
`)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",o=t.length>0?`${
|
|
51
|
-
`)}`:"",s=e.requestBody?`${Dt}${e.requestBody}`:"";return`${r}${o}${s}`}function yn(e){return e?Object.entries(e).map(([n,t])=>`${n}: ${t}`).filter(n=>n.trim().length>0):[]}function hn(e,n){return String(n||"").trim().toLowerCase()!=="waiting_input"?!1:e.type==="thinking"||e.type==="text_delta"}function In(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(!hn(e,n)){if(e.type==="ai_request"){const t=In(e.data);return{status:"thinking",actionInfo:{actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:gn(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=Fe(e,t),o=pn(e.data.toolInput);return e.data.actionType==="idle"||t.actionType==="idle"?{status:"waiting_input",actionInfo:{actionType:e.data.actionType||t.actionType,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:r||e.data.actionDetail||t.actionDetail||e.data.toolName,actionInput:o,actionId:e.data.actionId||e.data.toolUseId}}:{status:"tool_using",actionInfo:{actionType:e.data.actionType||t.actionType,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:r||e.data.actionDetail||t.actionDetail||e.data.toolName,actionInput:o,actionId:e.data.actionId||e.data.toolUseId}}}if(e.type==="turn_complete")return{status:"waiting_input",actionInfo:e.data.usage?{usage:e.data.usage}:void 0};if(e.type==="error")return{status:"error"};if(e.type==="context_compaction")return{status:"compacting",actionInfo:{actionType:"context_compaction",actionLabel:e.data.actionLabel,actionDetail:e.data.actionDetail,...e.data.actionId?{actionId:e.data.actionId}:{},...e.data.parentId?{parentId:e.data.parentId}:{}}};if(e.type==="runtime_capabilities")return{status:n||"waiting_input",actionInfo:{actionType:"runtime_capabilities",actionLabel:e.data.actionLabel||"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:e.data.actionDetail}}}}const x=new Map,ae=new Map,ce=new Map,J=new Map,An=20,Tn=500,kn=3e4;async function ue(e,n=kn,t=2){for(let r=0;r<=t;r++){const o=new AbortController;let s;try{const i=e(o.signal);i.catch(()=>{}),await Promise.race([i,new Promise((a,c)=>{s=setTimeout(()=>{o.abort(),c(new Error(`sendOutput timeout after ${n}ms`))},n)})]),s&&clearTimeout(s);return}catch(i){s&&clearTimeout(s);const a=i instanceof Error?i.message:String(i);if(r<t){const c=1e3*(r+1);m.warn(`sendOutput attempt ${r+1}/${t+1} failed (${a}), retrying in ${c}ms...`),await new Promise(d=>setTimeout(d,c));continue}m.warn(`sendOutput failed after ${t+1} attempts (${a}), giving up to unblock serial queue`)}}}function de(e,n){const t=n?`${e}:${n}`:void 0;let r,o;if(t)r=J.get(t),o=t;else{const g=[];for(const[T,h]of J)T.startsWith(e+":")&&h.buffer&&g.push(h.sourceEventType);for(const T of g)de(e,T);return}if(!r||!r.buffer)return;r.timer=null;const s=r.buffer,i=r.seq,a=r.entry,c=r.sourceEventType;r.buffer="",o&&J.delete(o);const d={sourceEventType:c,logCategory:"acode"},u={runtimeAccessToken:a.runtimeAccessToken,schedulerBaseUrl:a.schedulerBaseUrl},f=(x.get(e)??Promise.resolve()).then(()=>ue(g=>G(a.agentId,s,e,i,d,u,g)),()=>ue(g=>G(a.agentId,s,e,i,d,u,g)));x.set(e,f),f.finally(()=>{x.get(e)===f&&x.delete(e)})}function bn(e,n){const t=rn(e);if(!t)return;n.seq+=1;const r=n.seq,o=on(e),s={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),Tn)}J.set(c,d);return}de(e.sessionId);const a=(x.get(e.sessionId)??Promise.resolve()).then(()=>ue(c=>G(n.agentId,t,e.sessionId,r,o,s,c)),()=>ue(c=>G(n.agentId,t,e.sessionId,r,o,s,c)));x.set(e.sessionId,a),a.finally(()=>{x.get(e.sessionId)===a&&x.delete(e.sessionId)})}function ze(e){return Ze(e)}let He=!1;function wn(){He||(Ye(b,_n),ot(),He=!0)}function _n(e,n){e.on("event",t=>{const r=p.get(t.sessionId);if(r){if(t.type==="tool_use_start"?ht(r.sessionId,t.data.toolUseId||t.data.actionId,t.data.toolInput,t.data.toolName,r.workspacePath):t.type==="tool_use_end"&&yt(t,{sessionId:r.sessionId,agentId:r.agentId,workspacePath:r.workspacePath,providerId:r.providerId}),m.info(`[${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&&C(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)}bn(t,r);const s=nn(t);if(s){const i={runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},a=t.timestamp?new Date(t.timestamp).getTime():void 0,c=String(t.data?.toolName||"").toLowerCase()==="browser_launch",d=t.type==="tool_use_end"&&String(t.data?.rawToolName||t.data?.toolName||"").toLowerCase().replace(/[_-]/g,"").includes("todowrite");c?(async()=>{for(let l=0;l<3;l++){if(await C(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)!==void 0)return;l<2&&await new Promise(g=>setTimeout(g,3e3*(l+1)))}})().catch(u=>console.warn("[Runtime] browser_launch sendStatus retry exhausted:",u)):d?(async()=>{for(let l=0;l<3;l++){if(await C(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)!==void 0)return;l<2&&await new Promise(g=>setTimeout(g,1e3*(l+1)))}})().catch(u=>console.warn("[Runtime] todo_write sendStatus retry exhausted:",u)):C(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)}}}),e.on("status-change",(t,r,o)=>{const s=p.get(t);if(s){de(t),r==="thinking"||r==="tool_using"||r==="compacting"?$t(t):L(t);const i=xt(r,o);s.currentRuntimeStatus=i.status;const a=s.currentRuntimeActionDetail??"",c=a.includes("poll_message")||a.includes("get_message"),u=!(i.actionInfo?.actionType==="ai_request")&&(i.status==="thinking"||i.status==="waiting_input")&&(s.currentRuntimeActionType==="idle"||s.currentRuntimeActionType==="mcp")&&c;(i.actionInfo?.actionType||!u)&&(s.currentRuntimeActionType=i.actionInfo?.actionType,s.currentRuntimeActionLabel=i.actionInfo?.actionLabel,s.currentRuntimeActionDetail=i.actionInfo?.actionDetail,s.currentRuntimeActionInput=i.actionInfo?.actionInput),m.info(`[${n.displayName} Adapter] Status changed: ${i.status} for agent ${s.agentId}`,i.actionInfo||""),bt(t,{runtimeStatus:i.status,runtimeActionType:s.currentRuntimeActionType,runtimeActionLabel:s.currentRuntimeActionLabel,runtimeActionDetail:s.currentRuntimeActionDetail});const l=i.actionInfo?.actionType?i.actionInfo:s.currentRuntimeActionType?{actionType:s.currentRuntimeActionType,actionLabel:s.currentRuntimeActionLabel??"",actionDetail:s.currentRuntimeActionDetail,actionInput:s.currentRuntimeActionInput}:void 0;if(i.status==="compacting"){const g=(ae.get(t)??Promise.resolve()).then(async()=>{for(let h=0;h<=2;h++){if(await C(s.agentId,t,i.status,l,re(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})!==void 0)return;h<2&&(m.warn(`[${n.displayName}] compaction sendStatus attempt ${h+1} failed (HTTP), retrying in ${1e3*(h+1)}ms...`),await new Promise(_=>setTimeout(_,1e3*(h+1))))}m.warn(`[${n.displayName}] compaction sendStatus failed after 3 attempts, event may be lost`)}).catch(T=>{m.warn(`[${n.displayName}] compaction status chain error:`,T)});ae.set(t,g),g.finally(()=>{ae.get(t)===g&&ae.delete(t)})}else{const f=u&&!i.actionInfo?.actionType;if(l?.actionType==="idle"||s.currentRuntimeActionType==="idle"&&u){const h=(ce.get(t)??Promise.resolve()).then(async()=>{for(let _=0;_<=2;_++){if(await C(s.agentId,t,i.status,f?void 0:l,re(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})!==void 0)return;_<2&&await new Promise(M=>setTimeout(M,1e3*(_+1)))}m.warn(`[${n.displayName}] idle tool sendStatus failed after 3 attempts, status may be stale (frontend will fall back to timeline tool_use event)`)}).catch(y=>{m.warn(`[${n.displayName}] idle status chain error:`,y)});ce.set(t,h),h.finally(()=>{ce.get(t)===h&&ce.delete(t)})}else C(s.agentId,t,i.status,f?void 0:l,re(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}if(i.status==="waiting_input"&&s.cachedCapabilitiesActionDetail){const f=s.cachedCapabilitiesActionDetail;s.cachedCapabilitiesActionDetail=void 0,m.info(`[${n.displayName} Adapter] Re-sending cached runtime_capabilities for agent ${s.agentId} (session stabilized to waiting_input)`),C(s.agentId,t,"waiting_input",{actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:f},void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}}}),e.on("ask-user-question",t=>{const r=p.get(t.sessionId);r&&(m.info(`[${n.displayName} Adapter] AskUserQuestion for agent ${r.agentId}`),It(r.agentId,t.sessionId,Array.isArray(t.questions)?t.questions:[],{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},t.toolCallId))}),e.on("tool-permission-request",t=>{const r=p.get(t.sessionId);r&&t.requestId&&(m.info(`[${n.displayName} Adapter] Tool permission request (${t.capability}) for agent ${r.agentId}`),St(r.agentId,t.sessionId,{requestId:t.requestId,capability:t.capability,...t.detail||{}},{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl}))}),e.on("permission-request",t=>{const r=p.get(t.sessionId);if(r){m.info(`[${n.displayName} Adapter] Permission request: ${t.toolName} for agent ${r.agentId}`);const o=t.toolInput?v(JSON.stringify(t.toolInput).slice(0,400)):void 0;C(r.agentId,t.sessionId,"waiting_input",{actionType:"other",actionLabel:"\u6743\u9650\u786E\u8BA4",actionDetail:o||t.toolName},void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl})}})}S.post("/start",I,async(e,n)=>{const{agentId:t,workspacePath:r,mode:o="sdk"}=e.body||{};if(!t||!r){n.status(400).json({error:"agentId and workspacePath are required"});return}const s=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||De(Pe(e))||void 0;mt({agentId:String(t),workspacePath:String(r),serverUrl:e.body?.serverUrl||s,runtimeAccessToken:e.body?.runtimeAccessToken,userId:e.body?.userId,schedulerBaseUrl:s}),e.body?.runtimeFeatures!==null&&e.body?.runtimeFeatures!==void 0&&(it(String(t),e.body.runtimeFeatures),m.info(`[Runtime] agent ${t} \u542F\u52A8\u4E0B\u53D1\u80FD\u529B\u5F00\u5173: ${JSON.stringify(ct(String(t)))}`)),e.body?.capabilities!==void 0&&at(String(t),e.body.capabilities),e.body?.envVars!==null&&e.body?.envVars!==void 0&&typeof e.body.envVars=="object"&&(ft(e.body.envVars),m.info(`[Runtime] agent ${t} \u4E0B\u53D1\u9762\u677F\u73AF\u5883\u53D8\u91CF: ${Object.keys(e.body.envVars).length} \u9879 \u2192 \u684C\u9762\u5DE5\u5177\u5B50\u8FDB\u7A0B`)),e.body?.changeCacheRetentionDays!==void 0&&(nt(e.body.changeCacheRetentionDays),m.info(`[Runtime] agent ${t} \u4E0B\u53D1\u53D8\u66F4\u7F13\u5B58\u4FDD\u7559\u5929\u6570: ${e.body.changeCacheRetentionDays??"\u4E0D\u6E05\u7406"}`)),o&&o!=="sdk"&&console.warn(`[Runtime] Unsupported runtime mode "${o}" requested for agent ${t}; starting SDK session instead.`),await Cn(e,n)});async function Cn(e,n){const{agentId:t,workspacePath:r,command:o,autoAccept:s=!0,initialPrompt:i,systemPrompt:a,globalPrompt:c,rolePrompt:d,memory:u,mcpConfigPath:l,extraMcpServers:f,envOverrides:g,idleInputAutoCommand:T,nonInputAutoCommand:h,model:y,instanceAiConfig:_,subAgentModel:$,subAgentEffort:M,scopeKey:Te,browserAllowPrivate:ke}=e.body||{},H=_t();H.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:_?te(_):null,perAgentModel:y??null}});let D=null;const A=String(t||"").trim(),le=String(e.body?.runtimeAccessToken||"").trim()||void 0,O=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||De(Pe(e))||void 0;O?m.info(`[startSdkSession] \u56DE\u8C03\u76EE\u6807 server: ${O} (agentId=${A})`):m.warn(`[startSdkSession] \u672A\u89E3\u6790\u5230 schedulerBaseUrl\uFF0C\u5C06\u56DE\u9000\u5230\u9ED8\u8BA4\u5730\u5740 (agentId=${A})`);try{if(wn(),!A){n.status(400).json({error:"agentId is required"});return}const N=Oe(A);if(N){n.json(await Ht(N));return}const k=await At(A);if(k){const R=Wt(k);if(!R.reusable)console.warn(`[Runtime] Ignoring stale persisted SDK session for agentId=${A}, sessionId=${k.sessionId}, reason=${R.reason}`),await K(k.sessionId);else{const P=se(k.runtimeStatus,k.runtimeStatus,k.runtimeActionType);n.json({sessionId:k.sessionId,status:P,runtimeStatus:P,runtimeActionType:k.runtimeActionType,runtimeActionLabel:k.runtimeActionLabel,runtimeActionDetail:k.runtimeActionDetail,agentId:k.agentId,workspacePath:k.workspacePath,command:k.command,mode:k.mode||"sdk",pid:k.pid,reused:!0,persistedOnly:!0});return}}if(z.has(A)){n.status(409).json({error:"SDK session is already starting for this agent"});return}z.add(A);const E=ze(o),We=b.get(E);D=Je();const Xe=E==="claude-code"?await Yt():null,Y=qe(E==="claude-code"?Xe:null,g),W=E==="acode"?y?String(y).trim():void 0:(()=>{const R=y?String(y).trim():void 0,P=Y.model?String(Y.model).trim():void 0;return R||P})();H.log({level:"info",category:"resolve",message:"\u6A21\u578B\u89E3\u6790\u7ED3\u679C",source:"bridge",agentId:A,sessionId:D??void 0,details:{perAgentModel:y??null,globalModel:Y.model??null,resolvedModel:W??null,providerId:E,note:E==="acode"?"adapter handles full priority":"request > global"}});const me={...Y.envOverrides};W&&(me.ANTHROPIC_MODEL=W,me.CODEX_MODEL=W);let X,fe=l;if(E==="acode"){const R=_||{},P=await st({apiOverrides:Me(R)??void 0,agentId:A,sessionId:D??void 0,runtimeBridgeBaseUrl:O});X=P.instanceConfig.config,fe=P.perInstanceConfigPath,H.log({level:"info",category:"apply",message:"prepareAcodeInstanceConfig \u5B8C\u6210",source:"bridge",agentId:A,sessionId:D??void 0,details:{sanitizedApiOverrides:(()=>{const j=Me(R);return j?te(j):null})(),resolvedInstanceAiConfig:X?te(X):null,perInstanceConfigPath:fe,instanceConfigSources:P.instanceConfig.source??null}})}let be=a||void 0,pe,ge,Z;if(E==="acode")if(pe=typeof c=="string"&&c.trim()||void 0,ge=typeof d=="string"&&d.trim()||void 0,typeof u=="string"&&u.trim())Z=u.trim();else{const R=await Pt(r,{schedulerBaseUrl:O,runtimeAccessToken:le,agentId:A});R&&(Z=R,m.info(`[startSdkSession] Auto-loaded memories for ACode agent ${A}`))}else if(typeof c=="string"&&c.trim()||typeof d=="string"&&d.trim()||typeof u=="string"&&u.trim()){const P=[c,d,u,a].filter(j=>typeof j=="string"&&j.trim().length>0).map(j=>j.trim());be=P.length>0?P.join(`
|
|
48
|
+
`:void 0}function sn(e){const n=un(e);return{sourceEventType:e.type,logCategory:"acode",...cn(e),...n?{logLevel:an(e),logMessage:n}:{}}}function an(e){return e.type==="error"?"error":e.type==="command_output"&&e.data.stream==="stderr"?"warn":"info"}function cn(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 un(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 He(e,"\u5F00\u59CB");if(e.type==="tool_use_end")return He(e,"\u5B8C\u6210");if(e.type==="command_output")return mn(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 dn=/\x1b\[[0-9;?]*[a-zA-Z]/g;function ln(e){return e.replace(dn,"")}function mn(e){const n=typeof e.data.stream=="string"?e.data.stream:"mixed",t=typeof e.data.sequence=="number"?` #${e.data.sequence}`:"",r=ln(String(e.data.text||"")).replace(/\s+/g," ").trim(),o=r.length>240?`${r.slice(0,240)}...`:r;return`\u547D\u4EE4\u8F93\u51FA(${n}${t}): ${o||"(empty)"}`}function He(e,n){const t=he(e.data.toolName,e.data.toolInput),r=e.data.actionLabel||t.actionLabel||"\u8C03\u7528\u5DE5\u5177",o=We(e,t);return o?`${n}${r}: ${o}`:`${n}${r}: ${e.data.actionDetail||e.data.toolName||"tool"}`}function We(e,n){const t=e.data.toolInput;return n.actionType==="bash"?fn(t)||e.data.actionDetail||n.actionDetail:n.actionType==="read_file"||n.actionType==="edit_file"||n.actionType==="write_file"?pn(t)||e.data.actionDetail||n.actionDetail:e.data.actionDetail||n.actionDetail}function fn(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?F(t):void 0}return Ae(e?.args)}function pn(e){const n=Xe(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 F(n.trim());if(Array.isArray(n)){const t=Xe(n)[0];if(t)return t}}}function Xe(e){return Array.isArray(e)?e.map(n=>typeof n=="string"?n.trim():"").filter(Boolean).map(n=>F(n)):[]}function gn(e){if(!(!e||Object.keys(e).length===0))try{const n=F(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 yn(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=hn(e.requestHeaders),r=n.join(`
|
|
50
|
+
`)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",o=t.length>0?`${Pt}${t.join(`
|
|
51
|
+
`)}`:"",s=e.requestBody?`${Rt}${e.requestBody}`:"";return`${r}${o}${s}`}function hn(e){return e?Object.entries(e).map(([n,t])=>`${n}: ${t}`).filter(n=>n.trim().length>0):[]}function In(e,n){return String(n||"").trim().toLowerCase()!=="waiting_input"?!1:e.type==="thinking"||e.type==="text_delta"}function Sn(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 An(e,n){if(!In(e,n)){if(e.type==="ai_request"){const t=Sn(e.data);return{status:"thinking",actionInfo:{actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:yn(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=he(e.data.toolName,e.data.toolInput),r=We(e,t),o=gn(e.data.toolInput);return e.data.actionType==="idle"||t.actionType==="idle"?{status:"waiting_input",actionInfo:{actionType:e.data.actionType||t.actionType,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:r||e.data.actionDetail||t.actionDetail||e.data.toolName,actionInput:o,actionId:e.data.actionId||e.data.toolUseId}}:{status:"tool_using",actionInfo:{actionType:e.data.actionType||t.actionType,actionLabel:e.data.actionLabel||t.actionLabel,actionDetail:r||e.data.actionDetail||t.actionDetail||e.data.toolName,actionInput:o,actionId:e.data.actionId||e.data.toolUseId}}}if(e.type==="turn_complete")return{status:"waiting_input",actionInfo:e.data.usage?{usage:e.data.usage}:void 0};if(e.type==="error")return{status:"error"};if(e.type==="context_compaction")return{status:"compacting",actionInfo:{actionType:"context_compaction",actionLabel:e.data.actionLabel,actionDetail:e.data.actionDetail,...e.data.actionId?{actionId:e.data.actionId}:{},...e.data.parentId?{parentId:e.data.parentId}:{}}};if(e.type==="runtime_capabilities")return{status:n||"waiting_input",actionInfo:{actionType:"runtime_capabilities",actionLabel:e.data.actionLabel||"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:e.data.actionDetail}}}}const U=new Map,ce=new Map,ue=new Map,J=new Map,Tn=20,kn=500,bn=3e4;async function de(e,n=bn,t=2){for(let r=0;r<=t;r++){const o=new AbortController;let s;try{const i=e(o.signal);i.catch(()=>{}),await Promise.race([i,new Promise((a,c)=>{s=setTimeout(()=>{o.abort(),c(new Error(`sendOutput timeout after ${n}ms`))},n)})]),s&&clearTimeout(s);return}catch(i){s&&clearTimeout(s);const a=i instanceof Error?i.message:String(i);if(r<t){const c=1e3*(r+1);m.warn(`sendOutput attempt ${r+1}/${t+1} failed (${a}), retrying in ${c}ms...`),await new Promise(d=>setTimeout(d,c));continue}m.warn(`sendOutput failed after ${t+1} attempts (${a}), giving up to unblock serial queue`)}}}function le(e,n){const t=n?`${e}:${n}`:void 0;let r,o;if(t)r=J.get(t),o=t;else{const g=[];for(const[T,h]of J)T.startsWith(e+":")&&h.buffer&&g.push(h.sourceEventType);for(const T of g)le(e,T);return}if(!r||!r.buffer)return;r.timer=null;const s=r.buffer,i=r.seq,a=r.entry,c=r.sourceEventType;r.buffer="",o&&J.delete(o);const d={sourceEventType:c,logCategory:"acode"},u={runtimeAccessToken:a.runtimeAccessToken,schedulerBaseUrl:a.schedulerBaseUrl},f=(U.get(e)??Promise.resolve()).then(()=>de(g=>Q(a.agentId,s,e,i,d,u,g)),()=>de(g=>Q(a.agentId,s,e,i,d,u,g)));U.set(e,f),f.finally(()=>{U.get(e)===f&&U.delete(e)})}function wn(e,n){const t=on(e);if(!t)return;n.seq+=1;const r=n.seq,o=sn(e),s={runtimeAccessToken:n.runtimeAccessToken,schedulerBaseUrl:n.schedulerBaseUrl};if((e.type==="command_output"||e.type==="text_delta"||e.type==="thinking")&&t.length<Tn){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(()=>le(u,l),kn)}J.set(c,d);return}le(e.sessionId);const a=(U.get(e.sessionId)??Promise.resolve()).then(()=>de(c=>Q(n.agentId,t,e.sessionId,r,o,s,c)),()=>de(c=>Q(n.agentId,t,e.sessionId,r,o,s,c)));U.set(e.sessionId,a),a.finally(()=>{U.get(e.sessionId)===a&&U.delete(e.sessionId)})}function Ge(e){return rt(e)}let Qe=!1;function _n(){Qe||(nt(b,Cn),ct(),Qe=!0)}function Cn(e,n){e.on("event",t=>{const r=p.get(t.sessionId);if(r){if(t.type==="tool_use_start"?It(r.sessionId,t.data.toolUseId||t.data.actionId,t.data.toolInput,t.data.toolName,r.workspacePath):t.type==="tool_use_end"&&ht(t,{sessionId:r.sessionId,agentId:r.agentId,workspacePath:r.workspacePath,providerId:r.providerId}),m.info(`[${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=An(t,r.currentRuntimeStatus);i&&C(r.agentId,t.sessionId,i.status,i.actionInfo,oe(i.actionInfo),{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},t.timestamp?new Date(t.timestamp).getTime():void 0,t.type)}wn(t,r);const s=rn(t);if(s){const i={runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},a=t.timestamp?new Date(t.timestamp).getTime():void 0,c=String(t.data?.toolName||"").toLowerCase()==="browser_launch",d=t.type==="tool_use_end"&&String(t.data?.rawToolName||t.data?.toolName||"").toLowerCase().replace(/[_-]/g,"").includes("todowrite");c?(async()=>{for(let l=0;l<3;l++){if(await C(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)!==void 0)return;l<2&&await new Promise(g=>setTimeout(g,3e3*(l+1)))}})().catch(u=>console.warn("[Runtime] browser_launch sendStatus retry exhausted:",u)):d?(async()=>{for(let l=0;l<3;l++){if(await C(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)!==void 0)return;l<2&&await new Promise(g=>setTimeout(g,1e3*(l+1)))}})().catch(u=>console.warn("[Runtime] todo_write sendStatus retry exhausted:",u)):C(r.agentId,t.sessionId,"tool_result",s,void 0,i,a,t.type)}}}),e.on("status-change",(t,r,o)=>{const s=p.get(t);if(s){le(t),r==="thinking"||r==="tool_using"||r==="compacting"?Dt(t):L(t);const i=Ut(r,o);s.currentRuntimeStatus=i.status;const a=s.currentRuntimeActionDetail??"",c=a.includes("poll_message")||a.includes("get_message"),u=!(i.actionInfo?.actionType==="ai_request")&&(i.status==="thinking"||i.status==="waiting_input")&&(s.currentRuntimeActionType==="idle"||s.currentRuntimeActionType==="mcp")&&c;(i.actionInfo?.actionType||!u)&&(s.currentRuntimeActionType=i.actionInfo?.actionType,s.currentRuntimeActionLabel=i.actionInfo?.actionLabel,s.currentRuntimeActionDetail=i.actionInfo?.actionDetail,s.currentRuntimeActionInput=i.actionInfo?.actionInput),m.info(`[${n.displayName} Adapter] Status changed: ${i.status} for agent ${s.agentId}`,i.actionInfo||""),wt(t,{runtimeStatus:i.status,runtimeActionType:s.currentRuntimeActionType,runtimeActionLabel:s.currentRuntimeActionLabel,runtimeActionDetail:s.currentRuntimeActionDetail});const l=i.actionInfo?.actionType?i.actionInfo:s.currentRuntimeActionType?{actionType:s.currentRuntimeActionType,actionLabel:s.currentRuntimeActionLabel??"",actionDetail:s.currentRuntimeActionDetail,actionInput:s.currentRuntimeActionInput}:void 0;if(i.status==="compacting"){const g=(ce.get(t)??Promise.resolve()).then(async()=>{for(let h=0;h<=2;h++){if(await C(s.agentId,t,i.status,l,oe(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})!==void 0)return;h<2&&(m.warn(`[${n.displayName}] compaction sendStatus attempt ${h+1} failed (HTTP), retrying in ${1e3*(h+1)}ms...`),await new Promise(_=>setTimeout(_,1e3*(h+1))))}m.warn(`[${n.displayName}] compaction sendStatus failed after 3 attempts, event may be lost`)}).catch(T=>{m.warn(`[${n.displayName}] compaction status chain error:`,T)});ce.set(t,g),g.finally(()=>{ce.get(t)===g&&ce.delete(t)})}else{const f=u&&!i.actionInfo?.actionType;if(l?.actionType==="idle"||s.currentRuntimeActionType==="idle"&&u){const h=(ue.get(t)??Promise.resolve()).then(async()=>{for(let _=0;_<=2;_++){if(await C(s.agentId,t,i.status,f?void 0:l,oe(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})!==void 0)return;_<2&&await new Promise(M=>setTimeout(M,1e3*(_+1)))}m.warn(`[${n.displayName}] idle tool sendStatus failed after 3 attempts, status may be stale (frontend will fall back to timeline tool_use event)`)}).catch(y=>{m.warn(`[${n.displayName}] idle status chain error:`,y)});ue.set(t,h),h.finally(()=>{ue.get(t)===h&&ue.delete(t)})}else C(s.agentId,t,i.status,f?void 0:l,oe(i.actionInfo),{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}if(i.status==="waiting_input"&&s.cachedCapabilitiesActionDetail){const f=s.cachedCapabilitiesActionDetail;s.cachedCapabilitiesActionDetail=void 0,m.info(`[${n.displayName} Adapter] Re-sending cached runtime_capabilities for agent ${s.agentId} (session stabilized to waiting_input)`),C(s.agentId,t,"waiting_input",{actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:f},void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}}}),e.on("ask-user-question",t=>{const r=p.get(t.sessionId);r&&(m.info(`[${n.displayName} Adapter] AskUserQuestion for agent ${r.agentId}`),St(r.agentId,t.sessionId,Array.isArray(t.questions)?t.questions:[],{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl},t.toolCallId))}),e.on("tool-permission-request",t=>{const r=p.get(t.sessionId);r&&t.requestId&&(m.info(`[${n.displayName} Adapter] Tool permission request (${t.capability}) for agent ${r.agentId}`),At(r.agentId,t.sessionId,{requestId:t.requestId,capability:t.capability,...t.detail||{}},{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl}))}),e.on("permission-request",t=>{const r=p.get(t.sessionId);if(r){m.info(`[${n.displayName} Adapter] Permission request: ${t.toolName} for agent ${r.agentId}`);const o=t.toolInput?F(JSON.stringify(t.toolInput).slice(0,400)):void 0;C(r.agentId,t.sessionId,"waiting_input",{actionType:"other",actionLabel:"\u6743\u9650\u786E\u8BA4",actionDetail:o||t.toolName},void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl})}})}S.post("/start",I,async(e,n)=>{const{agentId:t,workspacePath:r,mode:o="sdk"}=e.body||{};if(!t||!r){n.status(400).json({error:"agentId and workspacePath are required"});return}const s=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||De(xe(e))||void 0;ft({agentId:String(t),workspacePath:String(r),serverUrl:e.body?.serverUrl||s,runtimeAccessToken:e.body?.runtimeAccessToken,userId:e.body?.userId,schedulerBaseUrl:s}),e.body?.runtimeFeatures!==null&&e.body?.runtimeFeatures!==void 0&&(dt(String(t),e.body.runtimeFeatures),m.info(`[Runtime] agent ${t} \u542F\u52A8\u4E0B\u53D1\u80FD\u529B\u5F00\u5173: ${JSON.stringify(mt(String(t)))}`)),e.body?.capabilities!==void 0&<(String(t),e.body.capabilities),e.body?.envVars!==null&&e.body?.envVars!==void 0&&typeof e.body.envVars=="object"&&(pt(e.body.envVars),m.info(`[Runtime] agent ${t} \u4E0B\u53D1\u9762\u677F\u73AF\u5883\u53D8\u91CF: ${Object.keys(e.body.envVars).length} \u9879 \u2192 \u684C\u9762\u5DE5\u5177\u5B50\u8FDB\u7A0B`)),e.body?.changeCacheRetentionDays!==void 0&&(it(e.body.changeCacheRetentionDays),m.info(`[Runtime] agent ${t} \u4E0B\u53D1\u53D8\u66F4\u7F13\u5B58\u4FDD\u7559\u5929\u6570: ${e.body.changeCacheRetentionDays??"\u4E0D\u6E05\u7406"}`)),o&&o!=="sdk"&&console.warn(`[Runtime] Unsupported runtime mode "${o}" requested for agent ${t}; starting SDK session instead.`),await $n(e,n)});async function $n(e,n){const{agentId:t,workspacePath:r,command:o,autoAccept:s=!0,initialPrompt:i,systemPrompt:a,globalPrompt:c,rolePrompt:d,memory:u,mcpConfigPath:l,extraMcpServers:f,envOverrides:g,idleInputAutoCommand:T,nonInputAutoCommand:h,model:y,instanceAiConfig:_,subAgentModel:$,subAgentEffort:M,scopeKey:Te,browserAllowPrivate:ke}=e.body||{},W=Ct();W.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:_?ne(_):null,perAgentModel:y??null}});let D=null;const A=String(t||"").trim(),me=String(e.body?.runtimeAccessToken||"").trim()||void 0,N=String(e.body?.schedulerBaseUrl||"").trim()||String(e.header("x-bridge-tunnel-source")||"").trim()||De(xe(e))||void 0;N?m.info(`[startSdkSession] \u56DE\u8C03\u76EE\u6807 server: ${N} (agentId=${A})`):m.warn(`[startSdkSession] \u672A\u89E3\u6790\u5230 schedulerBaseUrl\uFF0C\u5C06\u56DE\u9000\u5230\u9ED8\u8BA4\u5730\u5740 (agentId=${A})`);try{if(_n(),!A){n.status(400).json({error:"agentId is required"});return}const q=Fe(A);if(q){n.json(await Wt(q));return}const k=await Tt(A);if(k){const R=Xt(k);if(!R.reusable)console.warn(`[Runtime] Ignoring stale persisted SDK session for agentId=${A}, sessionId=${k.sessionId}, reason=${R.reason}`),await z(k.sessionId);else{const P=ie(k.runtimeStatus,k.runtimeStatus,k.runtimeActionType);n.json({sessionId:k.sessionId,status:P,runtimeStatus:P,runtimeActionType:k.runtimeActionType,runtimeActionLabel:k.runtimeActionLabel,runtimeActionDetail:k.runtimeActionDetail,agentId:k.agentId,workspacePath:k.workspacePath,command:k.command,mode:k.mode||"sdk",pid:k.pid,reused:!0,persistedOnly:!0});return}}if(H.has(A)){n.status(409).json({error:"SDK session is already starting for this agent"});return}H.add(A);const E=Ge(o),Ve=b.get(E);D=tt();const Ye=E==="claude-code"?await Zt():null,Z=ze(E==="claude-code"?Ye:null,g),X=E==="acode"?y?String(y).trim():void 0:(()=>{const R=y?String(y).trim():void 0,P=Z.model?String(Z.model).trim():void 0;return R||P})();W.log({level:"info",category:"resolve",message:"\u6A21\u578B\u89E3\u6790\u7ED3\u679C",source:"bridge",agentId:A,sessionId:D??void 0,details:{perAgentModel:y??null,globalModel:Z.model??null,resolvedModel:X??null,providerId:E,note:E==="acode"?"adapter handles full priority":"request > global"}});const fe={...Z.envOverrides};X&&(fe.ANTHROPIC_MODEL=X,fe.CODEX_MODEL=X);let G,pe=l;if(E==="acode"){const R=_||{},P=await ut({apiOverrides:je(R)??void 0,agentId:A,sessionId:D??void 0,runtimeBridgeBaseUrl:N});G=P.instanceConfig.config,pe=P.perInstanceConfigPath,W.log({level:"info",category:"apply",message:"prepareAcodeInstanceConfig \u5B8C\u6210",source:"bridge",agentId:A,sessionId:D??void 0,details:{sanitizedApiOverrides:(()=>{const O=je(R);return O?ne(O):null})(),resolvedInstanceAiConfig:G?ne(G):null,perInstanceConfigPath:pe,instanceConfigSources:P.instanceConfig.source??null}})}let be=a||void 0,ge,ye,ee;if(E==="acode")if(ge=typeof c=="string"&&c.trim()||void 0,ye=typeof d=="string"&&d.trim()||void 0,typeof u=="string"&&u.trim())ee=u.trim();else{const R=await Et(r,{schedulerBaseUrl:N,runtimeAccessToken:me,agentId:A});R&&(ee=R,m.info(`[startSdkSession] Auto-loaded memories for ACode agent ${A}`))}else if(typeof c=="string"&&c.trim()||typeof d=="string"&&d.trim()||typeof u=="string"&&u.trim()){const P=[c,d,u,a].filter(O=>typeof O=="string"&&O.trim().length>0).map(O=>O.trim());be=P.length>0?P.join(`
|
|
52
52
|
|
|
53
|
-
`):void 0}const U={command:o||"acode",workingDirectory:r,agentId:A,...Te?{scopeKey:Te}:{},...typeof ke=="boolean"?{browserAllowPrivate:ke}:{},autoAccept:!!s,initialPrompt:i,systemPrompt:be,...pe!==void 0?{globalPrompt:pe}:{},...ge!==void 0?{rolePrompt:ge}:{},...Z!==void 0?{memory:Z}:{},model:W,mcpConfigPath:fe,...X?{instanceAiConfig:X}:{},...typeof $=="string"&&$.trim()?{subAgentModel:$.trim()}:{},...typeof M=="string"&&M.trim()?{subAgentEffort:M.trim()}:{},extraMcpServers:f||{},envOverrides:Ne(String(t),String(r),process.env,me)};H.log({level:"info",category:"launch",message:"\u4F20\u9012\u7ED9 Adapter \u7684\u5B8C\u6574 AdapterSessionConfig",source:"bridge",agentId:A,sessionId:D,details:{adapterModel:U.model??null,adapterInstanceAiConfig:U.instanceAiConfig?te(U.instanceAiConfig):null,adapterMcpConfigPath:U.mcpConfigPath??null}}),await H.flush(),p.set(D,{agentId:A,workspacePath:r,sessionId:D,config:U,providerId:E,seq:0,runtimeAccessToken:le,schedulerBaseUrl:O}),n.json({sessionId:D,status:"starting",runtimeStatus:"starting",agentId:A,workspacePath:r,command:U.command,mode:"sdk"}),$n({sessionId:D,agentId:A,config:U,adapter:We,providerId:E,idleInputAutoCommand:T,nonInputAutoCommand:h,runtimeAccessToken:le,requestedSchedulerBaseUrl:O})}catch(N){if(D&&(L(D),p.delete(D),F(D)),A&&z.delete(A),!n.headersSent){const k=N instanceof Error?N.message:String(N);n.status(500).json({error:`Failed to start SDK session: ${k}`})}}}async function $n(e){const{sessionId:n,agentId:t,config:r,adapter:o,providerId:s,idleInputAutoCommand:i,nonInputAutoCommand:a,runtimeAccessToken:c,requestedSchedulerBaseUrl:d}=e;try{await o.startSession(n,r),o.setIdleCommands?.(n,{idleInputCommand:i||Ce,nonInputCommand:a||""});let u;if(Mt(s))try{if(await new Promise(f=>setTimeout(f,500)),u=o.getSessionPid?.(n),!u){const g=(await pt()).find(T=>T.agentId===t||T.cwd===r.workingDirectory||T.command.includes(r.workingDirectory));g&&(u=g.pid,m.info(`[Runtime] Found SDK process PID: ${u} for agentId=${t}`))}}catch(f){console.warn(`[Runtime] Failed to get SDK PID for agentId=${t}:`,f)}const l=se(o.getSessionStatus(n),p.get(n)?.currentRuntimeStatus,p.get(n)?.currentRuntimeActionType);await wt({sessionId:n,agentId:t,workspacePath:r.workingDirectory,command:r.command,startedAt:new Date().toISOString(),status:"running",runtimeStatus:l,mode:"sdk",pid:u,providerSessionId:o.getProviderSessionId(n)}),u&&await he().startProcess({agentId:t,sessionId:n,pid:u,mode:"sdk",workspacePath:r.workingDirectory,command:r.command}),await Dn({agentId:t,sessionId:n,sdkPid:u,status:l,schedulerBaseUrl:d,runtimeAccessToken:c})}catch(u){L(n),p.delete(n),F(n),await K(n);const l=u instanceof Error?u.message:String(u);console.error(`[Runtime] Background SDK session startup failed for agentId=${t}: ${l}`),await Rn({agentId:t,sessionId:n,schedulerBaseUrl:d,runtimeAccessToken:c,errorMessage:l})}finally{z.delete(t)}}async function Dn(e){const{agentId:n,sessionId:t,sdkPid:r,status:o,schedulerBaseUrl:s,runtimeAccessToken:i}=e;if(!s||!i){m.debug(`[Runtime] notifyServerSessionReady skipped: missing schedulerBaseUrl or runtimeAccessToken for agentId=${n}`);return}const a=`${s.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await we.post(a,{agentId:n,sessionId:t,status:o,pid:r},{headers:{"X-Runtime-Token":i,"Content-Type":"application/json"},timeout:5e3}),m.debug(`[Runtime] Notified server session ready: agentId=${n}, sessionId=${t}, status=${o}`)}catch(c){const d=c instanceof Error?c.message:String(c);m.warn(`[Runtime] Failed to notify server session ready: agentId=${n}, error=${d}`)}}async function Rn(e){const{agentId:n,sessionId:t,schedulerBaseUrl:r,runtimeAccessToken:o}=e;if(!r||!o)return;const s=`${r.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await we.post(s,{agentId:n,sessionId:t,status:"stopped"},{headers:{"X-Runtime-Token":o,"Content-Type":"application/json"},timeout:5e3}),m.debug(`[Runtime] Notified server session failed: agentId=${n}, sessionId=${t}`)}catch(i){const a=i instanceof Error?i.message:String(i);m.warn(`[Runtime] Failed to notify server session failed: agentId=${n}, error=${a}`)}}S.post("/sdk/message",I,async(e,n)=>{const{sessionId:t,message:r}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and message are required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code";await b.get(s).sendMessage(t,r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),S.post("/sdk/answer",I,async(e,n)=>{const{sessionId:t,answers:r}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and answers are required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code",i=b.get(s);i.sendQuestionAnswer&&await i.sendQuestionAnswer(t,r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),S.post("/tool-auth/answer",I,async(e,n)=>{const{sessionId:t,requestId:r,allowed:o}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and requestId are required"});return}const s=p.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const i=s.providerId||"claude-code",a=b.get(i);if(!a.submitToolPermissionDecision){n.status(400).json({error:"adapter does not support tool authorization"});return}const c=a.submitToolPermissionDecision(t,String(r),!!o);n.json({ok:!0,existed:c})}catch(i){const a=i instanceof Error?i.message:String(i);n.status(500).json({error:a})}}),S.get("/tool-auth/pending/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=b.get(o).getPendingToolAuthRequests?.(t)??[];n.json({ok:!0,sessionId:t,agentId:r.agentId,pendingRequests:i,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/sdk/confirm",I,async(e,n)=>{const{sessionId:t,accept:r}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code";await b.get(s).sendConfirmation(t,!!r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),S.post("/sdk/abort",I,async(e,n)=>{const{sessionId:t}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code";await b.get(o).abortCurrentTurn(t),n.json({ok:!0})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/sdk/stop",I,async(e,n)=>{const{sessionId:t}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.json({ok:!0,status:"stopped"});return}try{const o=r.providerId||"claude-code",s=b.get(o);s.abortCurrentTurn(t).catch(()=>{}),await s.terminateSession(t),L(t),p.delete(t),F(t),ie(t),await K(t),await he().removeProcess(r.agentId),await C(r.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl}),n.json({ok:!0,status:"stopped"})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.get("/sdk/status/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",s=b.get(o),i=s.getSessionStatus(t),a=s.getConversation(t);n.json({sessionId:t,status:i,agentId:r.agentId,workspacePath:r.workspacePath,messageCount:a.length})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.get("/sdk/capabilities/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=b.get(o).getCapabilities?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,capabilities:i,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.get("/sdk/pending-questions/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=b.get(o).getPendingQuestion?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,pendingQuestion:i?{toolCallId:i.toolCallId,questions:i.questions}:null,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/command",I,async(e,n)=>{const{sessionId:t,command:r}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and command are required"});return}try{const o=await Qt(String(t),r);n.json({ok:!0,mode:"terminal",...o})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/input",I,async(e,n)=>{const{sessionId:t,input:r,mode:o}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and input are required"});return}const s=p.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const i=s.providerId||"claude-code",a=b.get(i);if(o==="shortcut"){if(!a.sendShortcutInput){n.status(400).json({error:"shortcut input is not supported by this SDK provider"});return}await a.sendShortcutInput(t,String(r)),n.json({ok:!0,mode:"shortcut"});return}await a.sendMessage(t,await Jt(r)),n.json({ok:!0,mode:"sdk"})}catch(i){const a=i instanceof Error?i.message:String(i);n.status(500).json({error:a})}}),S.post("/update-auto-commands",I,async(e,n)=>{const{agentId:t,idleInputAutoCommand:r="",nonInputAutoCommand:o=""}=e.body||{},s=String(t||"").trim();if(!s){n.status(400).json({error:"agentId is required"});return}const i=[...p.values()].find(c=>c.agentId===s),a={idleInputCommand:String(r||"").trim()||Ce,nonInputCommand:String(o||"")};try{let c=!1;i&&(b.get(i.providerId||"claude-code").setIdleCommands?.(i.sessionId,a),c=!0);const d=await kt(s,{idleInputAutoCommand:a.idleInputCommand,nonInputAutoCommand:a.nonInputCommand});n.json({ok:!0,mode:"sdk",sessionUpdated:c,persistedUpdated:d})}catch(c){const d=c instanceof Error?c.message:String(c);n.status(500).json({ok:!1,mode:"sdk",error:d})}}),S.post("/resize",I,(e,n)=>{const{sessionId:t,cols:r,rows:o}=e.body||{};if(!t||!r||!o){n.status(400).json({error:"sessionId, cols, rows are required"});return}if(!p.has(t)){n.status(404).json({error:"SDK session not found"});return}n.json({ok:!0,mode:"sdk",noop:!0,cols:Number(r),rows:Number(o)})}),S.post("/reset-context",I,async(e,n)=>{const{sessionId:t,reason:r}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}const s=o.providerId||"claude-code",i=b.get(s),a=i.resetContext?.bind(i),c=Et(s,!!a);if(!c.supported){n.status(c.statusCode).json({error:c.error});return}if(!a){n.status(500).json({error:"ACode adapter does not expose resetContext"});return}try{await a(String(t));const d=se(i.getSessionStatus(String(t)),o.currentRuntimeStatus,o.currentRuntimeActionType);n.json({ok:!0,contextReset:!0,sessionId:t,status:d,runtimeStatus:d,agentId:o.agentId,mode:"sdk",providerId:s,reason:typeof r=="string"&&r.trim()?r.trim():void 0})}catch(d){const u=d instanceof Error?d.message:String(d);n.status(500).json({ok:!1,contextReset:!1,mode:"sdk",error:u})}}),S.post("/stop",I,async(e,n)=>{const{sessionId:t}=e.body||{},r=Lt(e.body);if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){await K(t),n.json({ok:!0,status:"stopped",mode:"none",statusNotified:!1,reason:r.reason});return}const s=o.agentId;try{m.info(`[Runtime] Stopping SDK session ${t}; suppressStatus=${!r.statusNotified}, reason=${r.reason||"unspecified"}`);const i=o.providerId||"claude-code",a=b.get(i);a.abortCurrentTurn(t).catch(()=>{}),await a.terminateSession(t),L(t),p.delete(t),F(t),ie(t),await K(t),await he().removeProcess(s),r.statusNotified?await C(s,null,"stopped",void 0,void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl}):m.info(`[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})}}),S.post("/stop-all",I,async(e,n)=>{const t=[],r=[];for(const[o,s]of p.entries())try{const i=s.providerId||"claude-code",a=b.get(i);a.abortCurrentTurn(o).catch(()=>{}),await a.terminateSession(o),L(o),p.delete(o),F(o),ie(o),t.push(o),await C(s.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}catch(i){const a=i instanceof Error?i.message:String(i);r.push(`SDK ${o}: ${a}`)}try{await Tt([]),m.info("[Runtime] \u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD")}catch(o){const s=o instanceof Error?o.message:String(o);r.push(`Persistence: ${s}`)}n.json({ok:!0,stopped:{sdk:t.length},errors:r.length>0?r:void 0})}),S.get("/events/last/:n",I,(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=Re.getLastN(t);n.json({ok:!0,count:r.length,entries:r})}),S.get("/events/since/:index",I,(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=Re.getSinceIndex(t);n.json({ok:!0,entries:r.entries,nextIndex:r.nextIndex,oldestIndex:r.oldestIndex,dataLoss:r.oldestIndex>t+1})}),S.get("/events/push-stats",I,(e,n)=>{const t=rt();n.json({ok:!0,count:t.length,agents:t})});export{jt as buildAcodeCommandOutputPath,qe as buildClaudeCodeLaunchConfig,Ne as buildRuntimeEnv,on as buildSdkOutputMetadata,nn as buildToolResultTimelineActionInfo,rr as cleanupSdkSessionByAgentId,Bt as countTerminalOutputLines,Be as createTerminalOutputDecoder,oe as decodeTerminalOutputChunk,Wt as evaluatePersistedSessionReuse,Nt as formatCommandInactivityTimeoutNotice,Ot as formatCommandOutputSpilloverNotice,rn as formatSdkOutputEvent,Se as formatTerminalPrompt,qt as normalizeTerminalCommandInput,Lt as parseRuntimeStopOptions,Kt as parseTerminalDirectoryChangeTarget,ue as raceSendOutputWithRetry,Et as resolveRuntimeContextResetSupport,Sn as resolveRuntimeStatusFromProviderEvent,Jt as resolveSdkInputMessage,ze as resolveSdkProviderId,se as resolveSdkSessionDisplayStatus,xt as resolveStatusChangeRuntimeState,re as resolveStatusChangeUsage,vt as resolveTerminalOutputEncoding,p as sdkSessions,Mt as shouldProbeSdkProcessPid,S as terminalRouter};
|
|
53
|
+
`):void 0}const j={command:o||"acode",workingDirectory:r,agentId:A,...Te?{scopeKey:Te}:{},...typeof ke=="boolean"?{browserAllowPrivate:ke}:{},autoAccept:!!s,initialPrompt:i,systemPrompt:be,...ge!==void 0?{globalPrompt:ge}:{},...ye!==void 0?{rolePrompt:ye}:{},...ee!==void 0?{memory:ee}:{},model:X,mcpConfigPath:pe,...G?{instanceAiConfig:G}:{},...typeof $=="string"&&$.trim()?{subAgentModel:$.trim()}:{},...typeof M=="string"&&M.trim()?{subAgentEffort:M.trim()}:{},extraMcpServers:f||{},envOverrides:Ke(String(t),String(r),process.env,fe)};W.log({level:"info",category:"launch",message:"\u4F20\u9012\u7ED9 Adapter \u7684\u5B8C\u6574 AdapterSessionConfig",source:"bridge",agentId:A,sessionId:D,details:{adapterModel:j.model??null,adapterInstanceAiConfig:j.instanceAiConfig?ne(j.instanceAiConfig):null,adapterMcpConfigPath:j.mcpConfigPath??null}}),await W.flush(),p.set(D,{agentId:A,workspacePath:r,sessionId:D,config:j,providerId:E,seq:0,runtimeAccessToken:me,schedulerBaseUrl:N}),n.json({sessionId:D,status:"starting",runtimeStatus:"starting",agentId:A,workspacePath:r,command:j.command,mode:"sdk"}),Dn({sessionId:D,agentId:A,config:j,adapter:Ve,providerId:E,idleInputAutoCommand:T,nonInputAutoCommand:h,runtimeAccessToken:me,requestedSchedulerBaseUrl:N})}catch(q){if(D&&(L(D),p.delete(D),K(D)),A&&H.delete(A),!n.headersSent){const k=q instanceof Error?q.message:String(q);n.status(500).json({error:`Failed to start SDK session: ${k}`})}}}async function Dn(e){const{sessionId:n,agentId:t,config:r,adapter:o,providerId:s,idleInputAutoCommand:i,nonInputAutoCommand:a,runtimeAccessToken:c,requestedSchedulerBaseUrl:d}=e;try{await o.startSession(n,r),o.setIdleCommands?.(n,{idleInputCommand:i||Ce,nonInputCommand:a||""});let u;if(Lt(s))try{if(await new Promise(f=>setTimeout(f,500)),u=o.getSessionPid?.(n),!u){const g=(await gt()).find(T=>T.agentId===t||T.cwd===r.workingDirectory||T.command.includes(r.workingDirectory));g&&(u=g.pid,m.info(`[Runtime] Found SDK process PID: ${u} for agentId=${t}`))}}catch(f){console.warn(`[Runtime] Failed to get SDK PID for agentId=${t}:`,f)}const l=ie(o.getSessionStatus(n),p.get(n)?.currentRuntimeStatus,p.get(n)?.currentRuntimeActionType);await _t({sessionId:n,agentId:t,workspacePath:r.workingDirectory,command:r.command,startedAt:new Date().toISOString(),status:"running",runtimeStatus:l,mode:"sdk",pid:u,providerSessionId:o.getProviderSessionId(n)}),u&&await Ie().startProcess({agentId:t,sessionId:n,pid:u,mode:"sdk",workspacePath:r.workingDirectory,command:r.command}),await Rn({agentId:t,sessionId:n,sdkPid:u,status:l,schedulerBaseUrl:d,runtimeAccessToken:c})}catch(u){L(n),p.delete(n),K(n),await z(n);const l=u instanceof Error?u.message:String(u);console.error(`[Runtime] Background SDK session startup failed for agentId=${t}: ${l}`),await Pn({agentId:t,sessionId:n,schedulerBaseUrl:d,runtimeAccessToken:c,errorMessage:l})}finally{H.delete(t)}}async function Rn(e){const{agentId:n,sessionId:t,sdkPid:r,status:o,schedulerBaseUrl:s,runtimeAccessToken:i}=e;if(!s||!i){m.debug(`[Runtime] notifyServerSessionReady skipped: missing schedulerBaseUrl or runtimeAccessToken for agentId=${n}`);return}const a=`${s.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await we.post(a,{agentId:n,sessionId:t,status:o,pid:r},{headers:{"X-Runtime-Token":i,"Content-Type":"application/json"},timeout:5e3}),m.debug(`[Runtime] Notified server session ready: agentId=${n}, sessionId=${t}, status=${o}`)}catch(c){const d=c instanceof Error?c.message:String(c);m.warn(`[Runtime] Failed to notify server session ready: agentId=${n}, error=${d}`)}}async function Pn(e){const{agentId:n,sessionId:t,schedulerBaseUrl:r,runtimeAccessToken:o}=e;if(!r||!o)return;const s=`${r.replace(/\/+$/,"")}/api/runtime/callback/status`;try{await we.post(s,{agentId:n,sessionId:t,status:"stopped"},{headers:{"X-Runtime-Token":o,"Content-Type":"application/json"},timeout:5e3}),m.debug(`[Runtime] Notified server session failed: agentId=${n}, sessionId=${t}`)}catch(i){const a=i instanceof Error?i.message:String(i);m.warn(`[Runtime] Failed to notify server session failed: agentId=${n}, error=${a}`)}}S.post("/sdk/message",I,async(e,n)=>{const{sessionId:t,message:r}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and message are required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code";await b.get(s).sendMessage(t,r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),S.post("/sdk/answer",I,async(e,n)=>{const{sessionId:t,answers:r}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and answers are required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code",i=b.get(s);i.sendQuestionAnswer&&await i.sendQuestionAnswer(t,r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),S.post("/tool-auth/answer",I,async(e,n)=>{const{sessionId:t,requestId:r,allowed:o}=e.body||{};if(!t||!r){n.status(400).json({error:"sessionId and requestId are required"});return}const s=p.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const i=s.providerId||"claude-code",a=b.get(i);if(!a.submitToolPermissionDecision){n.status(400).json({error:"adapter does not support tool authorization"});return}const c=a.submitToolPermissionDecision(t,String(r),!!o);n.json({ok:!0,existed:c})}catch(i){const a=i instanceof Error?i.message:String(i);n.status(500).json({error:a})}}),S.get("/tool-auth/pending/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=b.get(o).getPendingToolAuthRequests?.(t)??[];n.json({ok:!0,sessionId:t,agentId:r.agentId,pendingRequests:i,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/sdk/confirm",I,async(e,n)=>{const{sessionId:t,accept:r}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}try{const s=o.providerId||"claude-code";await b.get(s).sendConfirmation(t,!!r),n.json({ok:!0})}catch(s){const i=s instanceof Error?s.message:String(s);n.status(500).json({error:i})}}),S.post("/sdk/abort",I,async(e,n)=>{const{sessionId:t}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code";await b.get(o).abortCurrentTurn(t),n.json({ok:!0})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/sdk/stop",I,async(e,n)=>{const{sessionId:t}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.json({ok:!0,status:"stopped"});return}try{const o=r.providerId||"claude-code",s=b.get(o);s.abortCurrentTurn(t).catch(()=>{}),await s.terminateSession(t),L(t),p.delete(t),K(t),ae(t),await z(t),await Ie().removeProcess(r.agentId),await C(r.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:r.runtimeAccessToken,schedulerBaseUrl:r.schedulerBaseUrl}),n.json({ok:!0,status:"stopped"})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.get("/sdk/status/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",s=b.get(o),i=s.getSessionStatus(t),a=s.getConversation(t);n.json({sessionId:t,status:i,agentId:r.agentId,workspacePath:r.workspacePath,messageCount:a.length})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.get("/sdk/capabilities/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=b.get(o).getCapabilities?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,capabilities:i,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.get("/sdk/pending-questions/:sessionId",I,(e,n)=>{const t=e.params.sessionId;if(!t){n.status(400).json({error:"sessionId is required"});return}const r=p.get(t);if(!r){n.status(404).json({error:"SDK session not found"});return}try{const o=r.providerId||"claude-code",i=b.get(o).getPendingQuestion?.(t)??null;n.json({ok:!0,sessionId:t,agentId:r.agentId,pendingQuestion:i?{toolCallId:i.toolCallId,questions:i.questions}:null,fetchedAt:Date.now()})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/command",I,async(e,n)=>{const{sessionId:t,command:r}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and command are required"});return}try{const o=await Vt(String(t),r);n.json({ok:!0,mode:"terminal",...o})}catch(o){const s=o instanceof Error?o.message:String(o);n.status(500).json({error:s})}}),S.post("/input",I,async(e,n)=>{const{sessionId:t,input:r,mode:o}=e.body||{};if(!t||r===void 0||r===null){n.status(400).json({error:"sessionId and input are required"});return}const s=p.get(t);if(!s){n.status(404).json({error:"SDK session not found"});return}try{const i=s.providerId||"claude-code",a=b.get(i);if(o==="shortcut"){if(!a.sendShortcutInput){n.status(400).json({error:"shortcut input is not supported by this SDK provider"});return}await a.sendShortcutInput(t,String(r)),n.json({ok:!0,mode:"shortcut"});return}await a.sendMessage(t,await Jt(r)),n.json({ok:!0,mode:"sdk"})}catch(i){const a=i instanceof Error?i.message:String(i);n.status(500).json({error:a})}}),S.post("/update-auto-commands",I,async(e,n)=>{const{agentId:t,idleInputAutoCommand:r="",nonInputAutoCommand:o=""}=e.body||{},s=String(t||"").trim();if(!s){n.status(400).json({error:"agentId is required"});return}const i=[...p.values()].find(c=>c.agentId===s),a={idleInputCommand:String(r||"").trim()||Ce,nonInputCommand:String(o||"")};try{let c=!1;i&&(b.get(i.providerId||"claude-code").setIdleCommands?.(i.sessionId,a),c=!0);const d=await bt(s,{idleInputAutoCommand:a.idleInputCommand,nonInputAutoCommand:a.nonInputCommand});n.json({ok:!0,mode:"sdk",sessionUpdated:c,persistedUpdated:d})}catch(c){const d=c instanceof Error?c.message:String(c);n.status(500).json({ok:!1,mode:"sdk",error:d})}}),S.post("/resize",I,(e,n)=>{const{sessionId:t,cols:r,rows:o}=e.body||{};if(!t||!r||!o){n.status(400).json({error:"sessionId, cols, rows are required"});return}if(!p.has(t)){n.status(404).json({error:"SDK session not found"});return}n.json({ok:!0,mode:"sdk",noop:!0,cols:Number(r),rows:Number(o)})}),S.post("/reset-context",I,async(e,n)=>{const{sessionId:t,reason:r}=e.body||{};if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){n.status(404).json({error:"SDK session not found"});return}const s=o.providerId||"claude-code",i=b.get(s),a=i.resetContext?.bind(i),c=Mt(s,!!a);if(!c.supported){n.status(c.statusCode).json({error:c.error});return}if(!a){n.status(500).json({error:"ACode adapter does not expose resetContext"});return}try{await a(String(t));const d=ie(i.getSessionStatus(String(t)),o.currentRuntimeStatus,o.currentRuntimeActionType);n.json({ok:!0,contextReset:!0,sessionId:t,status:d,runtimeStatus:d,agentId:o.agentId,mode:"sdk",providerId:s,reason:typeof r=="string"&&r.trim()?r.trim():void 0})}catch(d){const u=d instanceof Error?d.message:String(d);n.status(500).json({ok:!1,contextReset:!1,mode:"sdk",error:u})}}),S.post("/stop",I,async(e,n)=>{const{sessionId:t}=e.body||{},r=xt(e.body);if(!t){n.status(400).json({error:"sessionId is required"});return}const o=p.get(t);if(!o){await z(t),n.json({ok:!0,status:"stopped",mode:"none",statusNotified:!1,reason:r.reason});return}const s=o.agentId;try{m.info(`[Runtime] Stopping SDK session ${t}; suppressStatus=${!r.statusNotified}, reason=${r.reason||"unspecified"}`);const i=o.providerId||"claude-code",a=b.get(i);a.abortCurrentTurn(t).catch(()=>{}),await a.terminateSession(t),L(t),p.delete(t),K(t),ae(t),await z(t),await Ie().removeProcess(s),r.statusNotified?await C(s,null,"stopped",void 0,void 0,{runtimeAccessToken:o.runtimeAccessToken,schedulerBaseUrl:o.schedulerBaseUrl}):m.info(`[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})}}),S.post("/stop-all",I,async(e,n)=>{const t=[],r=[];for(const[o,s]of p.entries())try{const i=s.providerId||"claude-code",a=b.get(i);a.abortCurrentTurn(o).catch(()=>{}),await a.terminateSession(o),L(o),p.delete(o),K(o),ae(o),t.push(o),await C(s.agentId,null,"stopped",void 0,void 0,{runtimeAccessToken:s.runtimeAccessToken,schedulerBaseUrl:s.schedulerBaseUrl})}catch(i){const a=i instanceof Error?i.message:String(i);r.push(`SDK ${o}: ${a}`)}try{await kt([]),m.info("[Runtime] \u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD")}catch(o){const s=o instanceof Error?o.message:String(o);r.push(`Persistence: ${s}`)}n.json({ok:!0,stopped:{sdk:t.length},errors:r.length>0?r:void 0})}),S.get("/events/last/:n",I,(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=Le.getLastN(t);n.json({ok:!0,count:r.length,entries:r})}),S.get("/events/since/:index",I,(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=Le.getSinceIndex(t);n.json({ok:!0,entries:r.entries,nextIndex:r.nextIndex,oldestIndex:r.oldestIndex,dataLoss:r.oldestIndex>t+1})}),S.get("/events/push-stats",I,(e,n)=>{const t=at();n.json({ok:!0,count:t.length,agents:t})});export{Ot as buildAcodeCommandOutputPath,ze as buildClaudeCodeLaunchConfig,Ke as buildRuntimeEnv,sn as buildSdkOutputMetadata,rn as buildToolResultTimelineActionInfo,or as cleanupSdkSessionByAgentId,Bt as countTerminalOutputLines,ve as createTerminalOutputDecoder,se as decodeTerminalOutputChunk,Xt as evaluatePersistedSessionReuse,qt as formatCommandInactivityTimeoutNotice,Nt as formatCommandOutputSpilloverNotice,on as formatSdkOutputEvent,Se as formatTerminalPrompt,vt as normalizeTerminalCommandInput,xt as parseRuntimeStopOptions,zt as parseTerminalDirectoryChangeTarget,de as raceSendOutputWithRetry,Mt as resolveRuntimeContextResetSupport,An as resolveRuntimeStatusFromProviderEvent,Jt as resolveSdkInputMessage,Ge as resolveSdkProviderId,ie as resolveSdkSessionDisplayStatus,Ut as resolveStatusChangeRuntimeState,oe as resolveStatusChangeUsage,Ft as resolveTerminalOutputEncoding,p as sdkSessions,Lt as shouldProbeSdkProcessPid,S as terminalRouter};
|
|
54
54
|
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { ToolPermissionPolicy } from "@agentswork/acode";
|
|
2
2
|
|
|
3
|
+
export type FeatureState = "disabled" | "collapsed" | "expanded";
|
|
4
|
+
|
|
5
|
+
export declare function normalizeFeatureState(raw: unknown): FeatureState | undefined;
|
|
6
|
+
|
|
7
|
+
export declare function isFeatureActive(state: FeatureState): boolean;
|
|
8
|
+
|
|
3
9
|
export declare const DESKTOP_FEATURE_KEY = "desktop";
|
|
4
10
|
|
|
5
11
|
export declare const BROWSER_FEATURE_KEY = "browser";
|
|
@@ -10,9 +16,13 @@ export declare const HIRE_FEATURE_KEY = "agentSys.hire";
|
|
|
10
16
|
|
|
11
17
|
export declare const PENCIL_FEATURE_KEY = "pencil";
|
|
12
18
|
|
|
19
|
+
export declare const DRAW_FEATURE_KEY = "draw";
|
|
20
|
+
|
|
13
21
|
export declare function setAgentFeatures(agentId: string, features: unknown): void;
|
|
14
22
|
|
|
15
|
-
export declare function getAgentFeatures(agentId: string): Record<string,
|
|
23
|
+
export declare function getAgentFeatures(agentId: string): Record<string, FeatureState>;
|
|
24
|
+
|
|
25
|
+
export declare function getFeatureState(agentId: string, key: string): FeatureState;
|
|
16
26
|
|
|
17
27
|
export declare function isFeatureEnabled(agentId: string, key: string): boolean;
|
|
18
28
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{getEffective as T,hasAnyDefault as
|
|
1
|
+
import{getEffective as T,hasAnyDefault as _}from"./capability-config.js";const F=new Set(["disabled","collapsed","expanded"]);function R(e){if(e===!0)return"expanded";if(e===!1)return"disabled";if(typeof e=="string"&&F.has(e))return e}function J(e){return e!=="disabled"}const E={},h="desktop",O="browser",L="agentSys.launchItem",P="agentSys.hire",W="pencil",k="draw",U=new Set,M=new Set([O,h,L,P]),j=new Set,d=new Map,c=new Map,D=["fileReadOutside","commandExecution","fileModification"],v=new Set(["allow","ask","deny"]);function C(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;const t=e,n={};let o=!1;for(const r of D){const s=t[r];typeof s=="string"&&v.has(s)?(n[r]=s,o=!0):n[r]="allow"}return o?n:null}function B(e){if(e==null)return{...E};let t=e;if(typeof e=="string")try{t=JSON.parse(e)}catch{t=null}if(typeof t!="object"||t===null||Array.isArray(t))return{...E};const n={};for(const[o,r]of Object.entries(t)){if(j.has(o))continue;const s=R(r);s!==void 0&&(n[o]=s)}return n}function V(e,t){if(!e)return;d.set(e,B(t));let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n=="object"&&n!==null&&!Array.isArray(n)){const o=C(n.toolPermissions);o?c.set(e,o):c.delete(e)}else c.delete(e)}function N(e){return d.get(e)??{...E}}function Y(e,t){const n=N(e);if(t.startsWith("agentSys.")&&n.agentSys==="disabled")return"disabled";const o=n[t];return o!==void 0?o:U.has(t)?"expanded":M.has(t)?"collapsed":"disabled"}function q(e,t){return Y(e,t)!=="disabled"}function G(e){d.delete(e),c.delete(e),u.delete(e),A.delete(e)}function I(e){return c.get(e)??null}function Q(e){return c.get(e)??{fileReadOutside:"allow",commandExecution:"allow",fileModification:"allow"}}const z=["skills","mcp","plugins"],u=new Map,A=new Map;function K(e){if(typeof e!="object"||e===null||Array.isArray(e))return;const t={};for(const[n,o]of Object.entries(e))n.trim()&&typeof o=="boolean"&&(t[n.trim()]=o);return t}function X(e,t){if(!e)return;if(t==null){u.delete(e);return}let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=null}if(typeof n!="object"||n===null||Array.isArray(n)){u.delete(e);return}const o=n,r={};let s=!1;for(const a of z){const i=K(o[a]);i&&(r[a]=i,s=!0)}s?u.set(e,r):u.delete(e);const f=o.plugins,y={};let S=!1;if(typeof f=="object"&&f!==null&&!Array.isArray(f))for(const[a,i]of Object.entries(f)){const p=a.trim();if(p){if(typeof i=="boolean"){const l=r.plugins??{};l[p]=i,r.plugins=l,s=!0;continue}if(i!==null&&typeof i=="object"&&!Array.isArray(i)){const l=i,m=l.enabled!==!1,g=typeof l.url=="string"?l.url:void 0,x=typeof l.sha256=="string"?l.sha256:void 0,b=r.plugins??{};b[p]=m,r.plugins=b,s=!0,g&&(y[p]={url:g,sha256:x},S=!0)}}}S?A.set(e,y):A.delete(e)}function Z(e){return u.get(e)??null}function $(e){return A.get(e)??null}function w(e,t,n){if(_(t))return T(e,t,n);const o=u.get(e);if(!o)return!0;const r=o[t];if(!r)return!0;const s=r[n];return s===void 0?!0:s}function ee(){return d.size}export{O as BROWSER_FEATURE_KEY,z as CAPABILITY_TYPES,h as DESKTOP_FEATURE_KEY,k as DRAW_FEATURE_KEY,P as HIRE_FEATURE_KEY,L as LAUNCH_ITEM_FEATURE_KEY,W as PENCIL_FEATURE_KEY,G as clearAgentFeatures,Z as getAgentCapabilities,N as getAgentFeatures,$ as getAgentPluginSources,I as getAgentToolPermissions,Y as getFeatureState,ee as instanceFeaturesCacheSize,w as isCapabilityEnabled,J as isFeatureActive,q as isFeatureEnabled,R as normalizeFeatureState,Q as resolveAgentToolPermissions,X as setAgentCapabilities,V as setAgentFeatures};
|
|
2
2
|
|
|
@@ -8,6 +8,8 @@ export declare function sanitizeAgentId(agentId: string): string;
|
|
|
8
8
|
export declare function sanitizeArchiveFileName(fileName: string, fallback: string): string;
|
|
9
9
|
export declare function atomicWriteFile(targetPath: string, content: string): Promise<void>;
|
|
10
10
|
|
|
11
|
+
export declare function renameFileWithRetry(fromPath: string, toPath: string, attempts?: number): Promise<void>;
|
|
12
|
+
|
|
11
13
|
export declare function atomicWriteFileSync(targetPath: string, content: string): void;
|
|
12
14
|
export declare function atomicWriteJsonFile(targetPath: string, value: unknown): Promise<void>;
|
|
13
15
|
export declare function downloadSkillZip(skillPackage: SkillPackage, targetDir: string): Promise<DownloadResult | null>;
|
package/dist/utils/file-utils.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{spawn as
|
|
2
|
-
`}function
|
|
1
|
+
import{spawn as $}from"node:child_process";import{createHash as h}from"node:crypto";import{createWriteStream as B,mkdirSync as b,renameSync as z,rmSync as U,writeFileSync as k,promises as l}from"node:fs";import a from"node:path";import{Readable as T,Transform as y}from"node:stream";import{pipeline as F}from"node:stream/promises";import S from"axios";import v from"unzipper";import{DEFAULT_SCHEDULER_BASE_URL as L,schedulerBaseUrl as _}from"../config.js";import{getRuntimeAccessToken as p,loadRuntimeBinding as A}from"../services/runtime-binding.js";const d=new Map;function g(){const e=String(process.env.AWS_RUNTIME_SCHEDULER_BASE_URL||"").trim();if(e)return e;const t=A(),r=String(t.schedulerBaseUrl||"").trim();return t.status==="paired"&&r?r:_||L}async function W(e){return await l.mkdir(e,{recursive:!0}),e}async function Q(e,t){const r=a.resolve(e),n=d.get(r)??Promise.resolve();let i;const o=new Promise(u=>{i=u}),s=n.then(()=>o);d.set(r,s),await n;try{return await t()}finally{i(),d.get(r)===s&&d.delete(r)}}function j(e){if(!e||typeof e!="object")return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function w(e){return Array.isArray(e)?e.map(t=>w(t)):j(e)?Object.keys(e).sort().reduce((t,r)=>(t[r]=w(e[r]),t),{}):e}function C(e){return`${JSON.stringify(w(e),null,2)}
|
|
2
|
+
`}function P(e){return String(e??"").replace(/[^a-zA-Z0-9_.-]/g,"_").replace(/^\.+/g,"").slice(0,128)}function E(e,t){const r=String(e??"").trim();if(!r||/[\\/]/.test(r))return t;const n=a.basename(r);return!n||n==="."||n===".."?t:n}async function N(e,t){await W(a.dirname(e));const r=a.dirname(e),n=a.basename(e),i=a.join(r,`.${n}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`);try{await l.writeFile(i,t,"utf-8"),await D(i,e)}catch(o){throw await l.rm(i,{force:!0}).catch(()=>{}),o}}async function D(e,t,r=3){for(let n=1;;n++)try{await l.rename(e,t);return}catch(i){const o=i.code,s=o==="EPERM"||o==="EBUSY"||o==="EACCES";if(n>=r||!s)throw i;await new Promise(u=>setTimeout(u,40*n))}}function ee(e,t){b(a.dirname(e),{recursive:!0});const r=a.dirname(e),n=a.basename(e),i=a.join(r,`.${n}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`);try{k(i,t,"utf-8"),z(i,e)}catch(o){try{U(i,{force:!0})}catch{}throw o}}async function re(e,t){await N(e,C(t))}async function te(e,t){if(!e||!e.downloadUrl)return null;const r=String(e.downloadUrl).trim();if(!r)return null;const n=g();let i=r;i.startsWith("/")&&(i=`${n}${i}`);const o=E(e.fileName,"skill-package.zip"),s=a.join(t,o),u=p(n)||p();if(!u)throw new Error("runtime access token is required to download skill package");const c=await S.get(i,{responseType:"arraybuffer",timeout:3e4,headers:{"X-Runtime-Token":u}}),m=Buffer.from(c.data);if(await l.writeFile(s,m),e.sha256&&h("sha256").update(m).digest("hex")!==String(e.sha256).trim().toLowerCase())throw new Error("skill zip checksum mismatch");return{fileName:o,outputPath:s,bytes:m.length}}async function ne(e,t){await new Promise((r,n)=>{const i=$(e,t,{stdio:["ignore","pipe","pipe"]});let o="";i.stderr?.on("data",s=>{o+=String(s||"")}),i.on("error",s=>{n(s)}),i.on("close",s=>{if(s!==0){n(new Error(o||`${e} exited with code ${s}`));return}r()})})}function ie(e){return String(e||"").replace(/'/g,"''")}const f={maxEntries:2e3,maxFileBytes:100*1024*1024,maxTotalBytes:200*1024*1024,maxPathLength:400,maxPathDepth:24};function I(e,t){const r=String(t||"").replace(/\\/g,"/");if(!r||r.startsWith("/")||/^[A-Za-z]:/.test(r)||r.split("/").includes(".."))throw new Error(`skill zip \u6761\u76EE\u8DEF\u5F84\u975E\u6CD5: ${t}`);if(r.length>f.maxPathLength)throw new Error(`skill zip \u6761\u76EE\u8DEF\u5F84\u8FC7\u957F: ${t}`);if(r.split("/").filter(Boolean).length>f.maxPathDepth)throw new Error(`skill zip \u6761\u76EE\u8DEF\u5F84\u8FC7\u6DF1: ${t}`);const n=a.resolve(e,r),i=a.resolve(e)+a.sep;if(n!==a.resolve(e)&&!n.startsWith(i))throw new Error(`skill zip \u6761\u76EE\u8D8A\u754C\uFF08zip-slip\uFF09: ${t}`);return n}function R(e,t){let r=0;return new y({transform(n,i,o){if(r+=n.length,r>e){o(new Error(`${t} \u8D85\u51FA\u4E0A\u9650\uFF08${e} \u5B57\u8282\uFF09`));return}o(null,n)}})}function M(e,t){let r=0;return{transform(){return new y({transform(n,i,o){if(r+=n.length,r>e){o(new Error(`${t} \u8D85\u51FA\u603B\u91CF\u4E0A\u9650\uFF08${e} \u5B57\u8282\uFF09`));return}o(null,n)}})}}}async function oe(e,t){await l.rm(t,{recursive:!0,force:!0}),await l.mkdir(t,{recursive:!0});const r=await l.readFile(e),n=T.from([r]),i=n.pipe(v.Parse({forceStream:!0}));let o=0,s=0;const u=M(f.maxTotalBytes,"skill zip \u89E3\u538B\u603B\u91CF");try{for await(const c of i){const m=I(t,c.path);if(c.type==="Directory"){await l.mkdir(m,{recursive:!0}),c.autodrain?.();continue}if(c.type!=="File"){c.autodrain?.();continue}if(o++,o>f.maxEntries)throw new Error(`skill zip \u6761\u76EE\u6570\u8D85\u51FA\u4E0A\u9650\uFF08${f.maxEntries}\uFF09`);if(s+=Number(c.size??0),s>f.maxTotalBytes)throw new Error(`skill zip \u603B\u91CF\u8D85\u51FA\u4E0A\u9650\uFF08${f.maxTotalBytes} \u5B57\u8282\uFF09`);await l.mkdir(a.dirname(m),{recursive:!0}),await F(c,R(f.maxFileBytes,`skill zip \u6761\u76EE ${c.path}`),u.transform(),B(m))}}catch(c){throw await l.rm(t,{recursive:!0,force:!0}).catch(()=>{}),c}finally{n.destroy(),i.destroy?.()}}async function se(e){const r=(await l.readdir(e,{withFileTypes:!0})).filter(n=>!n.name.startsWith("."));return r.length===1&&r[0].isDirectory()?a.join(e,r[0].name):e}async function ae(e,t){if(!e||!e.downloadUrl)return null;const r=String(e.downloadUrl).trim();if(!r)return null;const n=g();let i=r;i.startsWith("/")&&(i=`${n}${i}`);const o=E(e.fileName,"plugin-package.zip"),s=a.join(t,o),u=p(n)||p();if(!u)throw new Error("runtime access token is required to download plugin package");const c=await S.get(i,{responseType:"arraybuffer",timeout:3e4,headers:{"X-Runtime-Token":u}}),m=Buffer.from(c.data);if(await l.writeFile(s,m),e.sha256&&h("sha256").update(m).digest("hex")!==String(e.sha256).trim().toLowerCase())throw new Error(`plugin package sha256 mismatch: ${o}`);return{fileName:o,outputPath:s,bytes:m.length}}export{N as atomicWriteFile,ee as atomicWriteFileSync,re as atomicWriteJsonFile,ae as downloadPluginZip,te as downloadSkillZip,W as ensureDir,ie as escapePowerShellLiteral,oe as extractSkillZip,D as renameFileWithRetry,se as resolveSkillSourceDirFromExtractRoot,ne as runCommand,P as sanitizeAgentId,E as sanitizeArchiveFileName,C as stringifyStableJson,Q as withFileLock};
|
|
3
3
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export type CapabilityState = "disabled" | "collapsed" | "expanded";
|
|
4
|
+
|
|
5
|
+
export interface CapabilityPromptEntry {
|
|
6
|
+
|
|
7
|
+
featureKey: string;
|
|
8
|
+
|
|
9
|
+
label: string;
|
|
10
|
+
|
|
11
|
+
summary: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export declare const CAPABILITY_PROMPT_ENTRIES: readonly CapabilityPromptEntry[];
|
|
15
|
+
|
|
16
|
+
export declare function buildCapabilityPrompt(stateOf: (featureKey: string) => CapabilityState | undefined): string;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const o=[{featureKey:"agentSys.launchItem",label:"\u542F\u52A8\u9879\u7BA1\u7406",summary:"\u7BA1\u7406\u5F00\u53D1\u670D\u52A1\u8FDB\u7A0B\uFF08\u542F\u52A8 / \u505C\u6B62 / \u91CD\u542F / \u67E5\u770B\u65E5\u5FD7\uFF09"},{featureKey:"agentSys.hire",label:"\u62DB\u8058\u5DE5\u5177",summary:"\u62DB\u8058\u65B0\u7684\u540C\u4E8B Agent"},{featureKey:"pencil",label:"\u8BBE\u8BA1\u753B\u5E03(pencil)",summary:"UI design editor. Open-source Figma alternative."},{featureKey:"draw",label:"\u7ED8\u56FE",summary:"\u7ED8\u5236 draw.io \u6D41\u7A0B\u56FE / \u6CF3\u9053\u56FE\uFF0C\u5BFC\u51FA XML"},{featureKey:"browser",label:"\u6D4F\u89C8\u5668\u64CD\u4F5C",summary:"\u542F\u52A8\u6D4F\u89C8\u5668\u4F1A\u8BDD\u3001\u5BFC\u822A\u3001\u622A\u56FE\u4E0E\u9875\u9762\u4EA4\u4E92"},{featureKey:"desktop",label:"\u684C\u9762\u64CD\u4F5C",summary:"\u622A\u5C4F\u3001\u9F20\u6807\u952E\u76D8\u63A7\u5236\u4E0E UI \u81EA\u52A8\u5316\uFF08Computer Use\uFF09"}];function u(n){const l=[],a=[],t=[];for(const e of o){const r=n(e.featureKey)??"disabled";r==="disabled"?t.push(e):r==="collapsed"?a.push(e):l.push(e)}const s=["## \u53EF\u7528\u80FD\u529B",""];if(l.length>0||a.length>0){s.push("\u5DF2\u5F00\u542F\uFF1A");for(const e of l)s.push(`- ${e.label}\uFF1A${e.summary}\uFF08\u5DE5\u5177\u5DF2\u53EF\u76F4\u63A5\u8C03\u7528\uFF09`);for(const e of a)s.push(`- ${e.label}\uFF1A${e.summary}\uFF08\u5DE5\u5177\u5DF2\u6536\u8D77\uFF09`);a.length>0&&(s.push(""),s.push("\u6807\u8BB0\u300C\u5DE5\u5177\u5DF2\u6536\u8D77\u300D\u7684\u80FD\u529B\uFF1A\u5DE5\u5177\u9ED8\u8BA4\u6536\u8D77\u4EE5\u4FDD\u6301\u5DE5\u5177\u5217\u8868\u7A33\u5B9A\u5E76\u8282\u7701\u4E0A\u4E0B\u6587\uFF0C\u4EFB\u52A1\u9700\u8981\u65F6\u5148\u8C03\u7528 expand_tools \u5C55\u5F00\uFF0C\u5DE5\u5177\u5B9A\u4E49\u968F\u7ED3\u679C\u8FD4\u56DE\u540E\u5373\u53EF\u7ECF call_tool \u8C03\u7528\u3002"))}else s.push("\u5F53\u524D\u6CA1\u6709\u5DF2\u5F00\u542F\u7684\u6269\u5C55\u80FD\u529B\u3002");if(t.length>0){s.push(""),s.push("\u672A\u5F00\u542F\uFF08\u5DE5\u5177\u4E0D\u5728\u4F60\u7684\u5217\u8868\u4E2D\uFF09\u3002\u82E5\u4EFB\u52A1\u786E\u5B9E\u9700\u8981\uFF0C\u8BF7\u544A\u77E5\u7528\u6237\u53BB\u300C\u80FD\u529B\u914D\u7F6E\u300D\u4E2D\u5F00\u542F\u5BF9\u5E94\u5F00\u5173\uFF0C\u4E0D\u8981\u81EA\u884C\u5047\u8BBE\u4F60\u6709\u8BE5\u80FD\u529B\uFF1A");for(const e of t)s.push(`- ${e.label}\uFF1A${e.summary}`)}return s.join(`
|
|
2
|
+
`)}export{o as CAPABILITY_PROMPT_ENTRIES,u as buildCapabilityPrompt};
|
|
3
|
+
|
|
@@ -203,6 +203,12 @@ export declare class ACodeRuntime extends EventEmitter {
|
|
|
203
203
|
requestMcpToolsRefresh(serverName?: string): void;
|
|
204
204
|
|
|
205
205
|
private refreshMcpConnectionTools;
|
|
206
|
+
|
|
207
|
+
private recoverHiddenMcpTool;
|
|
208
|
+
|
|
209
|
+
private recoveredToolNames;
|
|
210
|
+
|
|
211
|
+
private static readonly MAX_RECOVERY_ATTEMPTS;
|
|
206
212
|
private createMcpTransport;
|
|
207
213
|
|
|
208
214
|
private fetchProfilePrompt;
|