blade-code 0.10.13 → 0.10.14
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/dist/blade.js +2 -2
- package/dist/{chunk-x9t4ryyf.js → chunk-0hbvc51n.js} +1 -1
- package/dist/{chunk-5vgjhqk9.js → chunk-2cgcht30.js} +1 -1
- package/dist/{chunk-k653znk8.js → chunk-2z6261pz.js} +1 -1
- package/dist/{chunk-74wm5qnw.js → chunk-321n9hem.js} +1 -1
- package/dist/{chunk-nsxkd8bq.js → chunk-3be2feze.js} +1 -1
- package/dist/{chunk-820ek28g.js → chunk-3jnhd81j.js} +3 -3
- package/dist/{chunk-p42cz164.js → chunk-4rn3r12e.js} +24 -24
- package/dist/{chunk-ab4sp3m4.js → chunk-8y2zs0p0.js} +2 -2
- package/dist/{chunk-c477j84k.js → chunk-8zr7h97n.js} +1 -1
- package/dist/chunk-99tdg2ny.js +1 -0
- package/dist/{chunk-9ac3eajy.js → chunk-9ajyeqa7.js} +1 -1
- package/dist/{chunk-8p5a371t.js → chunk-avsv4e5g.js} +1 -1
- package/dist/{chunk-4em4jxj5.js → chunk-cyhmfcqq.js} +48 -48
- package/dist/{chunk-45wpygt9.js → chunk-e0y9nb0a.js} +1 -1
- package/dist/chunk-g3w00xb7.js +5 -0
- package/dist/{chunk-zgg0y0sy.js → chunk-hpbyvwhm.js} +1 -1
- package/dist/{chunk-5wnxafpf.js → chunk-hrmfhv8k.js} +1 -1
- package/dist/{chunk-cx0tdprs.js → chunk-j7k5x43d.js} +1 -1
- package/dist/{chunk-9cnm1hgp.js → chunk-k5fw5abr.js} +1 -1
- package/dist/{chunk-97fyx4hr.js → chunk-kesgbws4.js} +1 -1
- package/dist/{chunk-hf3dwmfa.js → chunk-m088381q.js} +1 -1
- package/dist/{chunk-7s99zkve.js → chunk-m2b2w90y.js} +1 -1
- package/dist/{chunk-8yypkbew.js → chunk-mcqe9km3.js} +1 -1
- package/dist/{chunk-a3mwn9zj.js → chunk-pt0en61h.js} +1 -1
- package/dist/{chunk-j4rfyz81.js → chunk-qb076ca2.js} +4 -4
- package/dist/{chunk-097zrzyy.js → chunk-r6bha0vm.js} +1 -1
- package/dist/{chunk-nysyp11q.js → chunk-rbph12qe.js} +3 -3
- package/dist/{chunk-cy6emyt9.js → chunk-se1tfys3.js} +1 -1
- package/dist/{chunk-ke4n1nv5.js → chunk-sntbbkbf.js} +20 -20
- package/dist/{chunk-pmz455nq.js → chunk-snv4bpbv.js} +1 -1
- package/dist/{chunk-j8fkhkan.js → chunk-wj4cjb73.js} +1 -1
- package/dist/{chunk-0q7pvmvz.js → chunk-wznyzdtg.js} +1 -1
- package/dist/{chunk-c9m16hqc.js → chunk-xk7svrdb.js} +1 -1
- package/dist/{chunk-xjyctv33.js → chunk-xq403rac.js} +7 -7
- package/dist/{chunk-kfgv64hg.js → chunk-zvt8ngpt.js} +1 -1
- package/dist/web/assets/ChatView-CxSysoN5.js +7 -0
- package/dist/web/assets/{CodeBlockHighlighter-GS19h8wb.js → CodeBlockHighlighter-a5UaDQQg.js} +2 -2
- package/dist/web/assets/{FilePreview-BIjFuDdg.js → FilePreview-CvGTS9CJ.js} +3 -3
- package/dist/web/assets/{MarkdownRenderer-D-NrQgb1.js → MarkdownRenderer-D50Cw9OM.js} +3 -3
- package/dist/web/assets/{SettingsModal-BNz9vyER.js → SettingsModal-DtREOjs-.js} +2 -2
- package/dist/web/assets/TaskSwitcher-BlMvq8mt.js +1 -0
- package/dist/web/assets/TerminalPanel-B8LccKzq.js +1 -0
- package/dist/web/assets/index-CQP8XT9a.js +11 -0
- package/dist/web/assets/session-events-_Kir2HH_.js +22 -0
- package/dist/web/index.html +2 -1
- package/package.json +1 -1
- package/dist/chunk-ah97bmns.js +0 -5
- package/dist/chunk-m6sg36pw.js +0 -1
- package/dist/web/assets/ChatView-ucu62nNl.js +0 -7
- package/dist/web/assets/TaskSwitcher-HnRA3Mj8.js +0 -1
- package/dist/web/assets/TerminalPanel-Df2CK9n_.js +0 -1
- package/dist/web/assets/index-DWTihvUI.js +0 -32
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{ca as j,da as x0,ia as KJ,ja as O8,ka as P0}from"./chunk-
|
|
1
|
+
import{ca as j,da as x0,ia as KJ,ja as O8,ka as P0}from"./chunk-8zr7h97n.js";import{Ea as J7,la as $7,na as Z7,oa as r6}from"./chunk-p4zt7ts9.js";import{Fa as _$,Ga as o1,Ha as eZ,Ia as E1,Ja as Z8,Ka as J8,La as U8,Oa as V2,Qa as $6,Ra as E2,Sa as _2,Va as r0,Ya as Q0,cb as M2,db as YJ,eb as M9,gb as G8,ob as M8}from"./chunk-4rn3r12e.js";import{pb as g8,qb as p8,rb as J2}from"./chunk-095x2ykj.js";import{$b as c,Hb as A2,Ib as V0,Jb as p0,Nb as f8,Pb as p2,Qb as c$,Rb as p9,Sb as i9,Vb as VJ,Yb as c9,Zb as l9,xb as X0,yb as m9,zb as g9}from"./chunk-kesgbws4.js";import{ac as Y7,dc as H7,lc as z7,rc as Q7}from"./chunk-4hawehmd.js";import{Cc as g4,Dc as d4}from"./chunk-ktf3bpmw.js";import{Pc as O2,Qc as z0,Rc as P,Uc as W0,Vc as X2,Wc as n$,Xc as F$,Yc as B6,Zc as M$,_c as T8,dd as p$}from"./chunk-xq403rac.js";import{ed as k$}from"./chunk-vmq248m7.js";import{fd as Y$}from"./chunk-ybvdac8k.js";import{jd as t9,kd as Y2}from"./chunk-g3w00xb7.js";import{md as A0,nd as j$}from"./chunk-2mzcxq6c.js";import{od as zJ}from"./chunk-8j01ssaf.js";import{qd as y9,rd as x9,sd as h9}from"./chunk-2z6261pz.js";import{Ad as q7,Bd as S0,Cd as h0,Dd as r2,Ed as N2,Fd as $$,Gd as u$,Hd as d$,Id as d9,Jd as M6,Ld as $0,Md as H2,Nd as r9,td as W2,ud as B2,wd as L$,xd as r8,zd as C0}from"./chunk-j7k5x43d.js";import{Pd as a$,Rd as q$,Sd as s1}from"./chunk-9tnaads5.js";import{Td as TJ,Vd as u9,Wd as L2,Xd as p4}from"./chunk-heqs3xan.js";import{$d as K0,Zd as g6}from"./chunk-zvt8ngpt.js";import{ae as u0}from"./chunk-7wjy6kgt.js";import{ee as g}from"./chunk-4dq9y7zn.js";import{Be as oZ,Ce as tZ,Je as K4,Ke as a9,Le as v9,Me as F8,Ne as q8,Oe as w8,Pe as D8,Qe as b8,Re as L8,Se as e,he as f4,me as M4,oe as x6,te as GJ,xe as C4,ze as P9}from"./chunk-hrmfhv8k.js";import{$e as a8,Ye as I1,Ze as B4,_e as _,af as S,bf as m}from"./chunk-kvx3sb3z.js";import{df as T9,ef as f9}from"./chunk-f4z3gkbs.js";import{gf as u1,if as A}from"./chunk-5s123nbs.js";import{mf as I9,nf as k9}from"./chunk-s5666ta0.js";import{of as MJ,rf as NJ}from"./chunk-dsj62dcg.js";import{vf as PJ}from"./chunk-se1tfys3.js";import{Af as f0}from"./chunk-gav4hxcv.js";import{Df as X7,Ff as P$,Hf as S9,If as W4,Kf as O0}from"./chunk-363pgv1e.js";import{Mf as t0}from"./chunk-g11hq0e5.js";import{randomUUID as T7}from"crypto";import{mkdir as S1,realpath as m2}from"node:fs/promises";import D7 from"node:os";import W$ from"node:path";import{Mutex as b7}from"async-mutex";var o6=new b7,B$,u2;function L7(){return import("@anthropic-ai/sandbox-runtime")}async function X1(){if(B$)return B$;if(!u2)u2=L7();return B$=await u2,B$}var A7={isSupportedPlatform:async()=>(await X1()).SandboxManager.isSupportedPlatform(),checkDependencies:async()=>(await X1()).SandboxManager.checkDependencies(),getDefaultWritePaths:async()=>(await X1()).getDefaultWritePaths(),initialize:async($)=>(await X1()).SandboxManager.initialize($),updateConfig:($)=>{if(!B$)throw Error("Sandbox runtime is not initialized");B$.SandboxManager.updateConfig($)},wrapWithSandboxArgv:async($,Z,J,U,X)=>(await X1()).SandboxManager.wrapWithSandboxArgv($,Z,J,U,X),cleanupAfterCommand:()=>B$?.SandboxManager.cleanupAfterCommand(),reset:async()=>{await B$?.SandboxManager.reset()}};function d2($){return{network:{allowedDomains:$,deniedDomains:[],strictAllowlist:!0},filesystem:{denyRead:[],allowRead:[],allowWrite:[],denyWrite:[]},enableWeakerNestedSandbox:!0}}class T$ extends Error{constructor($){super($);this.name="WorkspaceSandboxUnavailableError"}}class m$ extends Error{constructor($){super($);this.name="WorkspaceSandboxBoundaryError"}}class t6{backend;constructor($){this.backend=$}async prepare($){let Z=W$.resolve($.workspaceRoot),J=W$.resolve($.cwd);if(!X0.isWithinWorkspace(J,Z))throw new m$(`Bash cwd is outside the workspace sandbox: ${$.cwd}`);let U,X;try{[U,X]=await Promise.all([m2(Z),m2(J)])}catch(Y){throw new m$(`Workspace sandbox path cannot be resolved: ${Y instanceof Error?Y.message:String(Y)}`)}if(!X0.isWithinWorkspace(X,U))throw new m$(`Bash cwd resolves outside the workspace sandbox: ${$.cwd}`);return this.backend.prepare({...$,cwd:X,workspaceRoot:U})}}class e6{runtime;tempRoot;defaultWritePaths;initialization;constructor($={}){this.runtime=$.runtime??A7,this.tempRoot=$.tempRoot??W$.join(O0(),"sandbox-tmp"),this.defaultWritePaths=$.defaultWritePaths}async prepare($){await this.ensureInitialized();let Z=await this.prepareTempRoot(),J=W$.join(Z,"tmp"),U=W$.join(Z,"cache"),X=W$.join(U,"npm"),Y=W$.join(U,"bun");await Promise.all([S1(J,{recursive:!0}),S1(X,{recursive:!0}),S1(Y,{recursive:!0})]);let z=(this.defaultWritePaths??await this.runtime.getDefaultWritePaths()).filter((F)=>!F.startsWith("/dev/")),Q=$.access==="workspace-read-only",W=Q?[D7.homedir(),O0(),process.env.BLADE_REAL_API_CREDENTIALS_FILE].filter((F)=>typeof F==="string"&&F.trim().length>0).map((F)=>W$.resolve(F)).filter((F,w,q)=>q.indexOf(F)===w):[],B=process.platform==="win32"?"bash":"/bin/bash",V,E,O=()=>{if(!E)return;let F=E;E=void 0;try{this.runtime.updateConfig(d2(["*"]))}finally{F()}},G=async()=>{let F=process.env.CLAUDE_CODE_TMPDIR;process.env.CLAUDE_CODE_TMPDIR=J;try{return await this.runtime.wrapWithSandboxArgv($.command,B,{network:Q?{allowedDomains:[],deniedDomains:[],strictAllowlist:!0}:{allowedDomains:["*"],deniedDomains:[],strictAllowlist:!0},filesystem:{denyRead:W,allowRead:Q?[$.workspaceRoot]:[],allowWrite:Q?[Z]:[$.workspaceRoot,Z],denyWrite:Q?[$.workspaceRoot,...z]:z},git:{safeDirectories:[$.workspaceRoot]}},$.signal,$.cwd)}finally{if(F===void 0)delete process.env.CLAUDE_CODE_TMPDIR;else process.env.CLAUDE_CODE_TMPDIR=F}};try{if(Q)E=await o6.acquire(),this.runtime.updateConfig(d2([])),V=await G();else V=await o6.runExclusive(G)}catch(F){if(O(),F instanceof Error&&F.name==="AbortError")throw F;throw new T$(`Workspace sandbox failed to prepare the command: ${F instanceof Error?F.message:String(F)}`)}let K=!1;return{executable:V.argv[0]??B,args:V.argv.slice(1),env:{...V.env,TMPDIR:J,TMP:J,TEMP:J,XDG_CACHE_HOME:U,npm_config_cache:X,BUN_INSTALL_CACHE_DIR:Y},sandboxed:!0,inheritProcessEnv:!Q,cleanup:()=>{if(K)return;K=!0;try{this.runtime.cleanupAfterCommand()}finally{O()}}}}async dispose(){this.initialization=void 0,await this.runtime.reset()}async ensureInitialized(){if(!this.initialization)this.initialization=this.initializeRuntime().catch(($)=>{throw this.initialization=void 0,$});return this.initialization}async initializeRuntime(){if(!await this.runtime.isSupportedPlatform())throw new T$(`Workspace sandbox is unsupported on ${process.platform}`);let $=await this.runtime.checkDependencies();if($.errors.length>0)throw new T$(`Workspace sandbox dependencies are unavailable: ${$.errors.join("; ")}`);try{await this.runtime.initialize(d2(["*"]))}catch(Z){throw new T$(`Workspace sandbox failed to initialize: ${Z instanceof Error?Z.message:String(Z)}`)}}async prepareTempRoot(){return await S1(this.tempRoot,{recursive:!0}),m2(this.tempRoot)}}function P1($,Z){let J=Z.toLowerCase();return $===71&&J.includes("sandbox-exec")||J.includes("sandbox_apply: operation not permitted")||J.includes("bwrap: creating new namespace failed")||J.includes("failed to create new user namespace")||J.includes("srt-win sandbox failed")}var N7=new e6,j7={prepare:($)=>N7.prepare($)},g2=new t6(j7);class t{static instance=null;processes=new Map;static getInstance(){if(!t.instance)t.instance=new t;return t.instance}startBackgroundProcess($){let Z=`bash_${T7()}`,J={};for(let[Q,W]of Object.entries({...process.env,...$.env,...$.sandboxedCommand?.env,BLADE_CLI:"1"}))if(W!==void 0)J[Q]=W;let U=$.sandboxedCommand?.executable??"bash",X=$.sandboxedCommand?.args??["-c",$.command],{child:Y,processTree:H}=u0(U,X,{cwd:$.cwd||A(),env:J,stdio:["pipe","pipe","pipe"]}),z={id:Z,command:$.command,sessionId:$.sessionId,cwd:$.cwd,env:$.env,process:Y,processTree:H,pid:Y.pid,status:"running",startTime:Date.now(),pendingStdout:new p2,pendingStderr:new p2,sandboxed:Boolean($.sandboxedCommand)};return Y.stdout?.setEncoding("utf8"),Y.stderr?.setEncoding("utf8"),Y.stdout?.on("data",(Q)=>{z.pendingStdout.append(Q)}),Y.stderr?.on("data",(Q)=>{z.pendingStderr.append(Q)}),Y.on("close",(Q,W)=>{$.sandboxedCommand?.cleanup();let B=z.sandboxed&&P1(Q,z.pendingStderr.peek().content);if(z.status=z.status==="killed"?"killed":B?"error":"exited",z.exitCode=Q,z.signal=W,B)z.errorMessage="Workspace sandbox failed to start; command was not executed";z.endTime=Date.now(),z.process=void 0}),Y.on("error",(Q)=>{$.sandboxedCommand?.cleanup(),z.status="error",z.errorMessage=Q.message,z.endTime=Date.now(),z.process=void 0,z.pendingStderr.append(`
|
|
2
2
|
[error] ${Q.message}`)}),this.processes.set(Z,z),z}consumeOutput($,Z){let J=this.getProcess($,Z);if(!J)return;let U=J.pendingStdout.consume(),X=J.pendingStderr.consume();return{id:J.id,command:J.command,status:J.status,stdout:U.content,stderr:X.content,stdoutOmittedBytes:U.omittedBytes,stderrOmittedBytes:X.omittedBytes,exitCode:J.exitCode,signal:J.signal,pid:J.pid,startedAt:J.startTime,endedAt:J.endTime,errorMessage:J.errorMessage,sandboxed:J.sandboxed}}getProcess($,Z){let J=this.processes.get($);return J?.sessionId===Z?J:void 0}listForSession($){return Array.from(this.processes.values()).filter((Z)=>Z.sessionId===$)}async writeInput($,Z,J,U=!1){let X=this.getProcess($,Z);if(!X)return;let Y=X.process?.stdin;if(X.status!=="running"||!Y||Y.destroyed||Y.writableEnded)return{success:!1,status:X.status,bytesWritten:0,stdinClosed:!Y||Y.destroyed||Y.writableEnded,errorMessage:"Shell stdin is not writable"};try{return await new Promise((H,z)=>{let Q=(B)=>{Y.off("error",Q),z(B)},W=(B)=>{if(Y.off("error",Q),B)z(B);else H()};if(Y.once("error",Q),U)Y.end(J,W);else Y.write(J,W)}),{success:!0,status:X.status,bytesWritten:Buffer.byteLength(J),stdinClosed:U}}catch(H){return{success:!1,status:X.status,bytesWritten:0,stdinClosed:Y.destroyed||Y.writableEnded,errorMessage:H instanceof Error?H.message:"Failed to write stdin"}}}async kill($,Z){let J=this.getProcess($,Z);if(!J)return;return this.terminateProcess(J)}async killSession($){let Z=this.listForSession($);await Promise.all(Z.map((J)=>this.terminateProcess(J)));for(let J of Z)this.processes.delete(J.id)}async terminateProcess($){if($.status!=="running"||!$.process)return{success:!1,alreadyExited:!0,status:$.status,pid:$.pid,exitCode:$.exitCode,signal:$.signal};$.status="killed",$.endTime=Date.now();let Z=await $.processTree?.terminate();if(!Z?.success)return $.status="error",$.errorMessage="Failed to terminate owned process tree",{success:!1,alreadyExited:Z?.alreadyExited??!1,status:$.status,pid:$.pid,exitCode:$.exitCode,signal:$.signal};return{success:!0,alreadyExited:Z.alreadyExited,status:$.status,pid:$.pid,exitCode:$.exitCode,signal:$.signal}}async killAll(){await Promise.all(Array.from(this.processes.values()).map(($)=>this.terminateProcess($))),this.processes.clear()}}import{stat as qH}from"node:fs/promises";import{Mutex as wH}from"async-mutex";import{nanoid as DH}from"nanoid";import*as n9 from"os";import*as U0 from"path";import*as k0 from"fs/promises";class f${async readTextFile($){return k0.readFile($,"utf-8")}async writeTextFile($,Z){await k0.writeFile($,Z,"utf-8")}async exists($){try{return await k0.access($),!0}catch{return!1}}async readBinaryFile($){return k0.readFile($)}async stat($){try{let Z=await k0.stat($);return{size:Z.size,isDirectory:Z.isDirectory(),isFile:Z.isFile(),mtime:Z.mtime}}catch{return null}}async mkdir($,Z){await k0.mkdir($,{recursive:Z?.recursive??!1,mode:Z?.mode??493})}}var f7=new f$;function V$(){return f7}var D0=g("Agent");class Y1{connection;sessionId;capabilities;fallback;constructor($,Z,J,U=new f$){this.connection=$;this.sessionId=Z;this.capabilities=J;this.fallback=U}async readTextFile($){if(!this.capabilities.readTextFile)return D0.debug(`[AcpFileSystem] readTextFile fallback: ${$}`),this.fallback.readTextFile($);try{return D0.debug(`[AcpFileSystem] readTextFile via ACP: ${$}`),(await this.connection.readTextFile({path:$,sessionId:this.sessionId})).content}catch(Z){throw D0.warn(`[AcpFileSystem] readTextFile ACP failed: ${Z}`),Z}}async writeTextFile($,Z){if(!this.capabilities.writeTextFile)return D0.debug(`[AcpFileSystem] writeTextFile fallback: ${$}`),this.fallback.writeTextFile($,Z);try{D0.debug(`[AcpFileSystem] writeTextFile via ACP: ${$}`),await this.connection.writeTextFile({path:$,content:Z,sessionId:this.sessionId})}catch(J){throw D0.warn(`[AcpFileSystem] writeTextFile ACP failed: ${J}`),J}}async exists($){if(!this.capabilities.readTextFile)return D0.debug(`[AcpFileSystem] exists fallback to local: ${$}`),this.fallback.exists($);try{return await this.connection.readTextFile({path:$,sessionId:this.sessionId}),D0.debug(`[AcpFileSystem] exists(${$}): true (ACP read success)`),!0}catch(Z){let J=String(Z).toLowerCase();if(["not found","no such file","enoent","does not exist","file not found","path not found"].some((H)=>J.includes(H)))return D0.debug(`[AcpFileSystem] exists(${$}): false (ACP: not found)`),!1;let Y=M7(J);return D0.warn(`[AcpFileSystem] exists(${$}): assuming exists due to ${Y} error`,{error:String(Z),errorType:Y,filePath:$}),!0}}async readBinaryFile($){return D0.debug(`[AcpFileSystem] readBinaryFile fallback: ${$}`),this.fallback.readBinaryFile($)}async stat($){return D0.debug(`[AcpFileSystem] stat fallback: ${$}`),this.fallback.stat($)}async mkdir($,Z){return D0.debug(`[AcpFileSystem] mkdir fallback: ${$}`),this.fallback.mkdir($,Z)}getCapabilities(){return this.capabilities}canReadTextFile(){return this.capabilities.readTextFile??!1}canWriteTextFile(){return this.capabilities.writeTextFile??!1}usesRemoteFiles(){return this.canReadTextFile()||this.canWriteTextFile()}}function M7($){if($.includes("permission")||$.includes("access denied"))return"permission";if($.includes("timeout")||$.includes("timed out"))return"timeout";if($.includes("binary")||$.includes("encoding"))return"binary";if($.includes("too large")||$.includes("size"))return"size";if($.includes("connection")||$.includes("network"))return"network";return"unknown"}var d0=g("Agent");class i2{async execute($,Z){return new Promise((J)=>{let U=process.platform==="win32"?"cmd.exe":"/bin/bash",X=process.platform==="win32"?["/c",$]:["-c",$],{child:Y,processTree:H}=u0(U,X,{cwd:Z?.cwd||A(),env:{...process.env,...Z?.env},stdio:["pipe","pipe","pipe"]}),z,Q=()=>{return z??=H.terminate(),z},W="",B="",V=!1,E=Z?.timeout?setTimeout(()=>{V=!0,Q()},Z.timeout):null,O=null,G=()=>{if(E)clearTimeout(E);if(O&&Z?.signal)Z.signal.removeEventListener("abort",O),O=null};if(Z?.signal){if(O=()=>{V=!0,Q()},Z.signal.addEventListener("abort",O),Z.signal.aborted)O()}Y.stdout?.on("data",(K)=>{let F=K.toString();W+=F,Z?.onOutput?.(F)}),Y.stderr?.on("data",(K)=>{let F=K.toString();B+=F,Z?.onOutput?.(F)}),Y.on("close",async(K)=>{if(G(),V)await Q();J({success:K===0&&!V,stdout:W,stderr:B,exitCode:K,error:V?"Command was terminated":void 0})}),Y.on("error",(K)=>{G(),J({success:!1,stdout:W,stderr:B,exitCode:null,error:K.message})})})}isAvailable(){return!0}}class $4{connection;sessionId;fallback;constructor($,Z,J=new i2){this.connection=$;this.sessionId=Z;this.fallback=J}async execute($,Z){try{d0.debug(`[AcpTerminal] Executing command via ACP: ${$}`);let J=await this.connection.createTerminal({sessionId:this.sessionId,command:$,cwd:Z?.cwd,env:Z?.env?Object.entries(Z.env).map(([W,B])=>({name:W,value:B})):void 0}),U=0,X=null;if(Z?.onOutput)X=setInterval(async()=>{try{let B=(await J.currentOutput()).output||"";if(B.length>U){let V=B.slice(U);U=B.length,Z.onOutput?.(V)}}catch{}},100);let Y=(W=!1)=>{if(X)clearInterval(X),X=null;(W?J.kill().then(()=>d0.debug("[AcpTerminal] Killed remote command")).catch(()=>{}).then(()=>J.release()).catch(()=>{}):J.release().catch(()=>{})).catch(()=>{})},H=[];if(H.push(J.waitForExit().then((W)=>({type:"completed",exitCode:W.exitCode??null}))),Z?.timeout)H.push(new Promise((W)=>{setTimeout(()=>W({type:"timeout"}),Z.timeout)}));if(Z?.signal)H.push(new Promise((W)=>{if(Z.signal.aborted)W({type:"aborted"});else Z.signal.addEventListener("abort",()=>W({type:"aborted"}),{once:!0})}));let z=await Promise.race(H),Q="";try{if(Q=(await J.currentOutput()).output||"",Z?.onOutput&&Q.length>U)Z.onOutput(Q.slice(U))}catch{}switch(z.type){case"completed":return Y(!1),{success:z.exitCode===0,stdout:Q,stderr:"",exitCode:z.exitCode};case"timeout":return d0.debug(`[AcpTerminal] Command timed out, killing: ${$}`),Y(!0),{success:!1,stdout:Q,stderr:"",exitCode:null,error:"Command timed out"};case"aborted":return d0.debug(`[AcpTerminal] Command aborted, killing: ${$}`),Y(!0),{success:!1,stdout:Q,stderr:"",exitCode:null,error:"Command was aborted"}}}catch(J){if(Z?.allowLocalFallback===!1)return{success:!1,stdout:"",stderr:"",exitCode:null,error:J instanceof Error?`ACP terminal unavailable: ${J.message}`:"ACP terminal unavailable"};return d0.warn("[AcpTerminal] ACP terminal failed, using fallback:",J),this.fallback.execute($,Z)}}isAvailable(){return!0}}class y{static sessions=new Map;static currentSessionId=null;constructor(){}static getInstance(){return new y}static initializeSession($,Z,J,U){let X=J?.fs?new Y1($,Z,J.fs):new f$;if(J?.fs)d0.debug(`[AcpServiceContext:${Z}] Using ACP file system service`);let Y=new $4($,Z);d0.debug(`[AcpServiceContext:${Z}] Using ACP terminal service`),y.sessions.set(Z,{fileSystemService:X,terminalService:Y,connection:$,clientCapabilities:J||null,cwd:U}),y.currentSessionId=Z,d0.debug(`[AcpServiceContext:${Z}] Initialized with capabilities:`,{fs:!!J?.fs,readTextFile:J?.fs?.readTextFile,writeTextFile:J?.fs?.writeTextFile,cwd:U})}static destroySession($){if(y.sessions.delete($),y.currentSessionId===$){let Z=Array.from(y.sessions.keys());y.currentSessionId=Z[0]||null}d0.debug(`[AcpServiceContext:${$}] Session destroyed`)}static getSessionServices($){return y.sessions.get($)||null}static setCurrentSession($){if(y.sessions.has($))y.currentSessionId=$}static getCurrentSessionId(){return y.currentSessionId}initialize($,Z,J,U){y.initializeSession($,Z,J,U||A())}reset(){if(y.currentSessionId)y.destroySession(y.currentSessionId)}isAcpMode(){return y.currentSessionId!==null}getFileSystemService($){let Z=$??y.currentSessionId;if(Z){let J=y.sessions.get(Z);if(J)return J.fileSystemService}return new f$}getTerminalService($){let Z=$??y.currentSessionId;if(Z){let J=y.sessions.get(Z);if(J)return J.terminalService}return new i2}getConnection(){if(y.currentSessionId){let $=y.sessions.get(y.currentSessionId);if($)return $.connection}return null}getSessionId(){return y.currentSessionId}getClientCapabilities(){if(y.currentSessionId){let $=y.sessions.get(y.currentSessionId);if($)return $.clientCapabilities}return null}async sendToolUpdate($,Z,J,U,X){let Y=y.currentSessionId;if(!Y)return;let H=y.sessions.get(Y);if(!H)return;try{await H.connection.sessionUpdate({sessionId:Y,update:{sessionUpdate:"tool_call",toolCallId:$,status:Z,title:J,content:U||[],kind:X||"other"}})}catch(z){d0.warn("[AcpServiceContext] Failed to send tool update:",z)}}}function E$($){return y.getInstance().getFileSystemService($)}function Z4($){return y.getInstance().getTerminalService($)}function a($){return $?y.getSessionServices($)!==null:y.getInstance().isAcpMode()}import*as m0 from"node:fs/promises";import*as V4 from"node:path";import{Mutex as C7}from"async-mutex";import{nanoid as R7}from"nanoid";import S7 from"write-file-atomic";var J4=["active","verifying","paused","blocked","usage_limited","budget_limited","complete"],U4=["pending","pass","fail","partial"];var X4=1048576,c2=1e5,E4=4000,P7=_.Object({attempt:_.Integer({minimum:1}),status:m(U4),requestedAt:_.String({format:"date-time"}),completedAt:_.Optional(_.String({format:"date-time"})),verifierSessionId:_.Optional(_.String({minLength:1})),summary:_.Optional(_.String({maxLength:E4})),evidenceSha256:_.Optional(_.String({pattern:"^[a-f0-9]{64}$"}))}),Y4=_.Object({version:_.Literal(1),sessionId:_.String({minLength:1}),goalId:_.String({minLength:1}),objective:_.String({minLength:1,maxLength:c2}),status:m(J4),tokenBudget:_.Optional(_.Integer({minimum:1})),tokensUsed:_.Integer({minimum:0}),timeUsedSeconds:_.Integer({minimum:0}),continuationCount:_.Integer({minimum:0}),statusReason:_.Optional(_.String()),completionVerification:_.Optional(P7),createdAt:_.String({format:"date-time"}),updatedAt:_.String({format:"date-time"})});function H4($,Z){return $ instanceof Error&&"code"in $&&$.code===Z}function z4($){let Z=$.trim();if(!Z)throw Error("Goal objective must not be empty");if(Z.length>c2)throw Error(`Goal objective exceeds ${c2} characters`);return Z}function I7($){if($===void 0)return;if(!Number.isInteger($)||$<=0)throw Error("Goal token budget must be a positive integer");return $}function Q4($){let Z=$?.trim();if(!Z)return;return Z.slice(0,E4)}class T0{workspaceRoot;sessionId;static mutexes=new Map;static listeners=new Set;filePath;mutex;constructor($,Z){this.workspaceRoot=$;this.sessionId=Z;this.filePath=W4($,Z);let J=T0.mutexes.get(this.filePath);if(!J)J=new C7,T0.mutexes.set(this.filePath,J);this.mutex=J}static subscribe($){return this.listeners.add($),()=>this.listeners.delete($)}static async hasActiveGoal($,Z){let J=(await new T0($,Z).get())?.status;return J==="active"||J==="verifying"}async get(){return this.mutex.runExclusive(()=>this.readUnlocked())}async create($){return this.mutex.runExclusive(async()=>{let Z=await this.readUnlocked();if(Z&&Z.status!=="complete")throw Error(`Session already has an unfinished goal (${Z.status}); clear or complete it first`);let J=new Date().toISOString(),U=I7($.tokenBudget),X={version:1,sessionId:this.sessionId,goalId:R7(12),objective:z4($.objective),status:"active",...U===void 0?{}:{tokenBudget:U},tokensUsed:0,timeUsedSeconds:0,continuationCount:0,createdAt:J,updatedAt:J};return await this.persistUnlocked(X),this.emit(X),X})}async edit($){return this.updateExisting((Z)=>{if(!["active","verifying","paused","blocked"].includes(Z.status))throw Error(`Cannot edit goal while status is ${Z.status}`);return{...Z,objective:z4($),completionVerification:void 0,status:Z.status==="verifying"?"active":Z.status,statusReason:Z.status==="verifying"?void 0:Z.statusReason,updatedAt:new Date().toISOString()}})}async pause($="paused by user"){return this.updateExisting((Z)=>{if(Z.status!=="active"&&Z.status!=="verifying"&&Z.status!=="blocked")throw Error(`Cannot pause goal while status is ${Z.status}`);return{...Z,status:"paused",statusReason:$,updatedAt:new Date().toISOString()}})}async pauseIfActive($){return this.mutex.runExclusive(async()=>{let Z=await this.readUnlocked();if(!Z||Z.status!=="active"&&Z.status!=="verifying")return Z;let J={...Z,status:"paused",statusReason:$,updatedAt:new Date().toISOString()};return await this.persistUnlocked(J),this.emit(J),J})}async resume(){return this.updateExisting(($)=>{if($.status!=="paused"&&$.status!=="blocked")throw Error(`Cannot resume goal while status is ${$.status}`);let Z=$.completionVerification?.status==="pending"||$.completionVerification?.status==="pass";return{...$,status:Z?"verifying":"active",statusReason:void 0,updatedAt:new Date().toISOString()}})}async requestCompletion(){return this.updateExisting(($)=>{if($.status!=="active"&&$.status!=="verifying")throw Error(`Cannot request goal completion while status is ${$.status}`);if($.status==="verifying"&&($.completionVerification?.status==="pending"||$.completionVerification?.status==="pass"))return $;let Z=new Date().toISOString();return{...$,status:"verifying",statusReason:"awaiting independent completion verification",completionVerification:{attempt:($.completionVerification?.attempt??0)+1,status:"pending",requestedAt:Z},updatedAt:Z}})}async recordCompletionVerification($){let Z=$.verifierSessionId?.trim();if(!Z)throw Error("Goal verification requires a verifier Session identity");if(!/^[a-f0-9]{64}$/.test($.evidenceSha256??""))throw Error("Goal verification requires a SHA-256 evidence digest");return this.updateExisting((J)=>{if(J.status!=="verifying"||!J.completionVerification)throw Error(`Cannot record goal verification while status is ${J.status}`);let U=new Date().toISOString();return{...J,statusReason:$.verdict==="pass"?"independent completion verification passed":`independent completion verification returned ${$.verdict}`,completionVerification:{...J.completionVerification,status:$.verdict,completedAt:U,verifierSessionId:Z,...Q4($.summary)?{summary:Q4($.summary)}:{},evidenceSha256:$.evidenceSha256},updatedAt:U}})}async invalidateCompletionVerification($){return this.updateExisting((Z)=>{if(Z.status!=="verifying"||!Z.completionVerification)return Z;let J=$.trim()||"goal completion evidence became stale";return{...Z,statusReason:J,completionVerification:{attempt:Z.completionVerification.attempt,status:"pending",requestedAt:Z.completionVerification.requestedAt},updatedAt:new Date().toISOString()}})}async finalizeVerifiedCompletion(){return this.updateExisting(($)=>{if($.status!=="verifying"||$.completionVerification?.status!=="pass"||!$.completionVerification.verifierSessionId||!$.completionVerification.evidenceSha256)throw Error("Goal completion requires a persisted independent PASS verdict");return{...$,status:"complete",statusReason:void 0,updatedAt:new Date().toISOString()}})}async block($){return this.updateExisting((Z)=>{if(Z.status!=="active"&&Z.status!=="verifying")throw Error(`Cannot block goal while status is ${Z.status}`);let J=$.trim();if(!J)throw Error("Blocked goal requires a reason");return{...Z,status:"blocked",statusReason:J,completionVerification:void 0,updatedAt:new Date().toISOString()}})}async recordProgress($){return this.mutex.runExclusive(async()=>{let Z=await this.readUnlocked();if(!Z||Z.status!=="active"&&Z.status!=="verifying")return Z;let J=Math.max(0,Math.round($.tokens)),U=Math.max(0,Math.round($.elapsedMs/1000)),X=Z.tokensUsed+J,Y=Z.tokenBudget!==void 0&&X>=Z.tokenBudget,H={...Z,tokensUsed:X,timeUsedSeconds:Z.timeUsedSeconds+U,status:Y?"budget_limited":Z.status,statusReason:Y?"token budget exhausted":Z.statusReason,updatedAt:new Date().toISOString()};return await this.persistUnlocked(H),this.emit(H),H})}async beginContinuation(){return this.updateExisting(($)=>{if($.status!=="active"&&$.status!=="verifying")throw Error(`Cannot continue goal while status is ${$.status}`);return{...$,continuationCount:$.continuationCount+1,updatedAt:new Date().toISOString()}})}async tryBeginContinuation(){return this.mutex.runExclusive(async()=>{let $=await this.readUnlocked();if(!$||$.status!=="active"&&$.status!=="verifying")return null;let Z={...$,continuationCount:$.continuationCount+1,updatedAt:new Date().toISOString()};return await this.persistUnlocked(Z),this.emit(Z),Z})}async clear(){return this.mutex.runExclusive(async()=>{try{await m0.unlink(this.filePath)}catch($){if(H4($,"ENOENT"))return!1;throw $}return this.emit(null),!0})}async updateExisting($){return this.mutex.runExclusive(async()=>{let Z=await this.readUnlocked();if(!Z)throw Error("Session has no goal");let J=B4(Y4,$(Z));return await this.persistUnlocked(J),this.emit(J),J})}async readUnlocked(){try{if((await m0.stat(this.filePath)).size>X4)throw Error(`Goal state exceeds ${X4} bytes`);await m0.chmod(this.filePath,384);let Z=I1(Y4,JSON.parse(await m0.readFile(this.filePath,"utf8")));if(!Z.success||Z.data.sessionId!==this.sessionId)throw Error(`Invalid goal state: ${this.filePath}`);return Z.data}catch($){if(H4($,"ENOENT"))return null;if($ instanceof SyntaxError)throw Error(`Invalid goal state JSON: ${this.filePath}`,{cause:$});throw $}}async persistUnlocked($){await m0.mkdir(V4.dirname(this.filePath),{recursive:!0,mode:448}),await S7(this.filePath,`${JSON.stringify($)}
|
|
3
3
|
`,{encoding:"utf8",mode:384,fsync:!0})}emit($){let Z={workspaceRoot:this.workspaceRoot,sessionId:this.sessionId,goal:$?{...$}:null};for(let J of T0.listeners)try{J(Z)}catch{}}}import{createHash as k7}from"node:crypto";import{promises as k1,realpathSync as v7}from"node:fs";import l from"node:path";import{fileURLToPath as y7,pathToFileURL as e0}from"node:url";var _4=g("Service"),O4=65536;class l2{name;onCrash;child;processTree;connection;closePromise;crashCleanup;capabilities;initialized=!1;stopping=!1;notificationHandlers=new Map;requestHandlers=new Map;constructor($,Z){this.name=$;this.onCrash=Z}get serverCapabilities(){return this.capabilities}get isInitialized(){return this.initialized}async start($){if(await this.crashCleanup,this.crashCleanup=void 0,this.connection)return;let Z=await import("vscode-jsonrpc/node.js"),{child:J,processTree:U}=u0($.command,[...$.args],{cwd:$.cwd,env:{...$.environment,PATH:$.environment.PATH??process.env.PATH??"",HOME:$.environment.HOME??process.env.HOME??"",USER:$.environment.USER??process.env.USER??"",SHELL:$.environment.SHELL??process.env.SHELL??"/bin/sh",BLADE_CLI:"1"},stdio:["pipe","pipe","pipe"]},{releaseOnExit:!1});this.child=J,this.processTree=U;try{if(await new Promise((H,z)=>{let Q=()=>{J.removeListener("spawn",W),J.removeListener("error",B)},W=()=>{Q(),H()},B=(V)=>{Q(),z(V)};J.once("spawn",W),J.once("error",B)}),!J.stdout||!J.stdin)throw Error("LSP server stdio is unavailable");let X="";J.stderr?.setEncoding("utf8"),J.stderr?.on("data",(H)=>{if(X.length<O4)X+=H.slice(0,O4-X.length)}),J.stdin.on("error",(H)=>{if(!this.stopping)_4.debug(`[LSP ${this.name}] stdin closed: ${H.message}`)}),this.closePromise=new Promise((H)=>{J.once("close",(z,Q)=>{this.initialized=!1;let W=!this.stopping;if(!this.stopping){let B=X.trim()?`: ${X.trim().slice(0,512)}`:Q?` (${Q})`:"";this.onCrash(Error(`LSP server "${this.name}" exited with code ${z}${B}`))}if(this.child===J){let B=this.processTree;try{this.connection?.dispose()}catch{}if(this.connection=void 0,this.child=void 0,this.closePromise=void 0,W&&B)this.crashCleanup=B.terminate().then(()=>{return}),this.processTree=void 0}H()})});let Y=Z.createMessageConnection(new Z.StreamMessageReader(J.stdout),new Z.StreamMessageWriter(J.stdin));this.connection=Y,Y.onError(([H])=>{if(!this.stopping)_4.warn(`[LSP ${this.name}] connection error: ${H.message}`)}),Y.onClose(()=>{this.initialized=!1});for(let[H,z]of this.notificationHandlers)for(let Q of z)Y.onNotification(H,Q);for(let[H,z]of this.requestHandlers)Y.onRequest(H,z);Y.listen()}catch(X){throw await this.disposeTransport(),X}}async initialize($,Z,J){let U=await this.request("initialize",$,Z,J,!1);return this.capabilities=U.capabilities,await this.notify("initialized",{}),this.initialized=!0,U}async request($,Z,J,U,X=!0){let Y=this.connection;if(!Y)throw Error(`LSP server "${this.name}" is not started`);if(X&&!this.initialized)throw Error(`LSP server "${this.name}" is not initialized`);let z=new(await import("vscode-jsonrpc/node.js")).CancellationTokenSource;return this.awaitRequest(Y.sendRequest($,Z,z.token),z,J,U,$)}async notify($,Z){if(!this.connection)throw Error(`LSP server "${this.name}" is not started`);await this.connection.sendNotification($,Z)}onNotification($,Z){let J=this.notificationHandlers.get($)??[];J.push(Z),this.notificationHandlers.set($,J),this.connection?.onNotification($,Z)}onRequest($,Z){this.requestHandlers.set($,Z),this.connection?.onRequest($,Z)}async stop($){if(!this.child&&!this.connection){await this.crashCleanup,this.crashCleanup=void 0;return}this.stopping=!0;let Z=this.connection;try{if(Z&&this.initialized){let U=new(await import("vscode-jsonrpc/node.js")).CancellationTokenSource;await this.awaitRequest(Z.sendRequest("shutdown",U.token),U,$,void 0,"shutdown").catch(()=>{return}),await Z.sendNotification("exit").catch(()=>{return})}await Promise.race([this.closePromise??Promise.resolve(),new Promise((J)=>setTimeout(J,Math.min($,500)))])}finally{await this.disposeTransport(),this.stopping=!1,this.initialized=!1,this.capabilities=void 0}}awaitRequest($,Z,J,U,X){return new Promise((Y,H)=>{let z=!1,Q=(V)=>{if(z)return;z=!0,clearTimeout(B),U?.removeEventListener("abort",W),V()},W=()=>{Z.cancel(),Q(()=>H(Error(`LSP request "${X}" was aborted`)))},B=setTimeout(()=>{Z.cancel(),Q(()=>H(Error(`LSP request "${X}" timed out after ${J}ms`)))},J);if(U?.addEventListener("abort",W,{once:!0}),U?.aborted)W();$.then((V)=>Q(()=>Y(V)),(V)=>Q(()=>H(V)))})}async disposeTransport(){let $=this.connection,Z=this.processTree;this.connection=void 0,this.processTree=void 0,this.child=void 0,this.closePromise=void 0;try{$?.dispose()}catch{}await Z?.terminate(),await this.crashCleanup,this.crashCleanup=void 0}}var x7=g("Service"),h7=10485760,u7=10,G4=30,d7=-32801;class n2{options;workspaceRoot;servers=new Map;diagnostics=new Map;delivered=new Map;waiters=new Map;disposeController=new AbortController;diagnosticSequence=0;disposed=!1;constructor($){this.options=$;let Z=l.resolve($.workspaceRoot);try{this.workspaceRoot=v7.native(Z)}catch{this.workspaceRoot=Z}for(let[J,U]of Object.entries($.servers)){if(U.enabled===!1)continue;let X={name:J,config:structuredClone(U),state:"stopped",restartCount:0,openedFiles:new Map,client:new l2(J,(Y)=>{X.state="error",X.lastError=Y.message,X.openedFiles.clear()})};X.client.onNotification("textDocument/publishDiagnostics",(Y)=>{this.captureDiagnostics(J,Y)}),X.client.onRequest("workspace/configuration",(Y)=>this.resolveWorkspaceConfiguration(U.settings,Y)),X.client.onRequest("workspace/workspaceFolders",()=>[{uri:e0(this.workspaceRoot).href,name:l.basename(this.workspaceRoot)}]),X.client.onRequest("window/workDoneProgress/create",()=>null),this.servers.set(J,X)}}get available(){return this.servers.size>0&&!this.isRemoteSession()&&!this.disposed}get workspacePath(){return this.workspaceRoot}getStatus(){return[...this.servers.values()].map(($)=>({name:$.name,state:$.state,restartCount:$.restartCount,extensions:Object.keys($.config.extensionToLanguage).sort(),...$.lastError?{lastError:$.lastError}:{}})).sort(($,Z)=>$.name.localeCompare(Z.name))}async afterToolUse($,Z,J,U){if(!this.available||this.disposed)return;let X;if(J.success&&($==="Write"||$==="Edit")&&typeof Z.file_path==="string")X=await this.syncAfterWrite(Z.file_path,U.signal);else if(J.success&&$==="ApplyPatch"){let Y=Array.isArray(J.metadata?.changes)?J.metadata.changes:[];for(let H of Y){if(!H||typeof H!=="object"||!("path"in H)||typeof H.path!=="string")continue;if("newContent"in H&&H.newContent===null)await this.syncAfterDelete(H.path);else X=await this.syncAfterWrite(H.path,U.signal)??X}}this.attachPendingDiagnostics(J,X)}async query($,Z){if(!this.available)throw Error(this.isRemoteSession()?"LSP is unavailable for ACP-owned remote files":"No LSP servers are configured for this Session");let J=await this.resolveFile($.filePath);if($.operation==="diagnostics")return{operation:$.operation,filePath:J,result:this.getCurrentDiagnostics(J)};let U=await this.ensureFileOpen(J,void 0,Z);if(!U)throw Error(`No LSP server handles ${l.extname(J)||"this file"}`);let X={line:Math.max(0,($.line??1)-1),character:Math.max(0,($.character??1)-1)},Y={uri:e0(J).href},H={goToDefinition:{method:"textDocument/definition",params:{textDocument:Y,position:X}},findReferences:{method:"textDocument/references",params:{textDocument:Y,position:X,context:{includeDeclaration:!0}}},hover:{method:"textDocument/hover",params:{textDocument:Y,position:X}},documentSymbol:{method:"textDocument/documentSymbol",params:{textDocument:Y}},workspaceSymbol:{method:"workspace/symbol",params:{query:$.query??""}},goToImplementation:{method:"textDocument/implementation",params:{textDocument:Y,position:X}},prepareCallHierarchy:{method:"textDocument/prepareCallHierarchy",params:{textDocument:Y,position:X}}},z;if($.operation==="incomingCalls"||$.operation==="outgoingCalls"){let W=(await this.requestWithRetry(U,"textDocument/prepareCallHierarchy",{textDocument:Y,position:X},Z))?.[0];z=W?await this.requestWithRetry(U,$.operation==="incomingCalls"?"callHierarchy/incomingCalls":"callHierarchy/outgoingCalls",{item:W},Z):[]}else{let Q=H[$.operation];z=await this.requestWithRetry(U,Q.method,Q.params,Z)}return{operation:$.operation,filePath:J,serverName:U.name,result:z}}async dispose(){if(this.disposed)return;this.disposed=!0,this.disposeController.abort();for(let $ of this.waiters.values())for(let Z of $)clearTimeout(Z.timer),Z.resolve();this.waiters.clear(),await Promise.allSettled([...this.servers.values()].map(async($)=>{$.state="stopping",await $.client.stop($.config.shutdownTimeout??2000),$.state="stopped",$.openedFiles.clear()})),this.diagnostics.clear(),this.delivered.clear()}isRemoteSession(){return this.options.isRemoteSession?.()??a(this.options.sessionId)}selectServer($){let Z=l.extname($).toLowerCase();return[...this.servers.values()].filter((J)=>(Z in J.config.extensionToLanguage)).sort((J,U)=>(U.config.priority??0)-(J.config.priority??0)||J.name.localeCompare(U.name))[0]}async ensureFileOpen($,Z,J){let U=this.selectServer($);if(!U)return;await this.ensureStarted(U,J);let X=e0($).href;if(U.openedFiles.has(X))return U;let Y=Z??await this.readBoundedFile($);return await U.client.notify("textDocument/didOpen",{textDocument:{uri:X,languageId:U.config.extensionToLanguage[l.extname($).toLowerCase()],version:1,text:Y}}),U.openedFiles.set(X,1),U}async syncAfterWrite($,Z){try{let J=await this.resolveFile($),U=await this.readBoundedFile(J),X=await this.ensureFileOpen(J,U,Z);if(!X)return;let Y=e0(J).href,H=this.diagnostics.get(Y)?.sequence??0;this.delivered.delete(Y);let z=X.openedFiles.get(Y)??0;if(z>0){let Q=z+1;await X.client.notify("textDocument/didChange",{textDocument:{uri:Y,version:Q},contentChanges:[{text:U}]}),X.openedFiles.set(Y,Q)}return await X.client.notify("textDocument/didSave",{textDocument:{uri:Y},text:U}),await this.waitForDiagnostics(Y,H,X.config.diagnosticWaitTimeout??750,Z),J}catch(J){if(!Z?.aborted&&!this.disposeController.signal.aborted)x7.debug(`[LSP] post-edit sync skipped: ${J instanceof Error?J.message:String(J)}`);return}}async syncAfterDelete($){let Z=await this.resolveMissingFile($).catch(()=>{return});if(!Z)return;if(!this.isInsideWorkspace(Z))return;let J=e0(Z).href;for(let U of this.servers.values()){if(!U.openedFiles.has(J))continue;await U.client.notify("textDocument/didClose",{textDocument:{uri:J}}).catch(()=>{return}),U.openedFiles.delete(J)}this.diagnostics.delete(J),this.delivered.delete(J)}async ensureStarted($,Z){if($.state==="running")return;if($.startPromise)return $.startPromise;if($.state==="error"){if($.restartCount>=($.config.maxRestarts??3))throw Error(`LSP server "${$.name}" exceeded its restart limit`);$.restartCount++}let J=this.startServer($,Z).finally(()=>{$.startPromise=void 0});return $.startPromise=J,J}async startServer($,Z){$.state="starting";try{await $.client.start({command:$.config.command,args:$.config.args??[],cwd:this.workspaceRoot,environment:{...this.options.environment,...$.config.env,BLADE_SESSION_ID:this.options.sessionId}});let J=e0(this.workspaceRoot).href,U={processId:process.pid,rootPath:this.workspaceRoot,rootUri:J,workspaceFolders:[{uri:J,name:l.basename(this.workspaceRoot)}],initializationOptions:$.config.initializationOptions??{},capabilities:{workspace:{configuration:!0,workspaceFolders:!0,symbol:{dynamicRegistration:!1}},textDocument:{synchronization:{dynamicRegistration:!1,willSave:!1,willSaveWaitUntil:!1,didSave:!0},publishDiagnostics:{relatedInformation:!0,versionSupport:!1},hover:{dynamicRegistration:!1,contentFormat:["markdown","plaintext"]},definition:{dynamicRegistration:!1,linkSupport:!0},references:{dynamicRegistration:!1},implementation:{dynamicRegistration:!1,linkSupport:!0},documentSymbol:{dynamicRegistration:!1,hierarchicalDocumentSymbolSupport:!0},callHierarchy:{dynamicRegistration:!1}},general:{positionEncodings:["utf-16"]}}};if(await $.client.initialize(U,$.config.startupTimeout??1e4,Z),$.config.settings!==void 0)await $.client.notify("workspace/didChangeConfiguration",{settings:$.config.settings});$.state="running",$.lastError=void 0}catch(J){throw $.state="error",$.lastError=J instanceof Error?J.message:String(J),await $.client.stop($.config.shutdownTimeout??2000).catch(()=>{return}),J}}async requestWithRetry($,Z,J,U){let X;for(let Y=0;Y<4;Y++)try{return await $.client.request(Z,J,$.config.requestTimeout??1e4,U)}catch(H){if(X=H,H.code!==d7||Y===3)break;await new Promise((z)=>setTimeout(z,100*2**Y))}throw X}captureDiagnostics($,Z){if(this.disposed||!Z||typeof Z!=="object"||!("uri"in Z)||!("diagnostics"in Z))return;let J=Z;if(!Array.isArray(J.diagnostics))return;let U;try{U=J.uri.startsWith("file:")?y7(J.uri):l.resolve(J.uri)}catch{return}if(!this.isInsideWorkspace(U))return;let X=e0(l.resolve(U)).href,Y={sequence:++this.diagnosticSequence,serverName:$,filePath:l.resolve(U),diagnostics:J.diagnostics.filter((Q)=>Q&&typeof Q.message==="string"&&Q.range!==void 0).slice(0,100).map((Q)=>structuredClone(Q))};this.diagnostics.set(X,Y);let H=this.waiters.get(X)??[],z=[];for(let Q of H)if(Y.sequence>Q.afterSequence)clearTimeout(Q.timer),Q.resolve();else z.push(Q);if(z.length>0)this.waiters.set(X,z);else this.waiters.delete(X)}waitForDiagnostics($,Z,J,U){if(J===0||(this.diagnostics.get($)?.sequence??0)>Z)return Promise.resolve();return new Promise((X)=>{let Y=!1,H,z=()=>{if(Y)return;Y=!0,clearTimeout(H.timer),U?.removeEventListener("abort",z);let B=(this.waiters.get($)??[]).filter((V)=>V!==H);if(B.length>0)this.waiters.set($,B);else this.waiters.delete($);X()},Q=setTimeout(z,J);H={afterSequence:Z,resolve:z,timer:Q};let W=this.waiters.get($)??[];if(W.push(H),this.waiters.set($,W),U?.addEventListener("abort",z,{once:!0}),U?.aborted)z()})}attachPendingDiagnostics($,Z){let J=[...this.diagnostics.values()].sort((z,Q)=>{if(Z){if(z.filePath===Z&&Q.filePath!==Z)return-1;if(Q.filePath===Z&&z.filePath!==Z)return 1}return Q.sequence-z.sequence}),U=[],X=[],Y=0;for(let z of J){let Q=e0(z.filePath).href,W=this.delivered.get(Q)??new Set,B=z.diagnostics.sort((E,O)=>(E.severity??4)-(O.severity??4)).filter((E)=>!W.has(this.diagnosticKey(E))).slice(0,Math.min(u7,G4-Y));if(B.length===0)continue;let V=l.relative(this.workspaceRoot,z.filePath);U.push(`${V}:`);for(let E of B){let O=E.range.start.line+1,G=E.range.start.character+1,K=["Error","Warning","Info","Hint"][(E.severity??1)-1],F=E.message.replace(/\s+/g," ").slice(0,500);U.push(` ${K??"Error"} ${O}:${G} ${F}`+(E.code!==void 0?` [${String(E.code)}]`:"")),W.add(this.diagnosticKey(E)),X.push({file:V,line:O,character:G,severity:K??"Error",message:F,server:z.serverName}),Y++}if(this.delivered.set(Q,W),Y>=G4)break}if(U.length===0)return;let H=typeof $.llmContent==="string"?$.llmContent:JSON.stringify($.llmContent);$.llmContent=`${H}
|
|
4
4
|
|
|
@@ -657,7 +657,7 @@ ${o}
|
|
|
657
657
|
</approved-plan>
|
|
658
658
|
|
|
659
659
|
IMPORTANT: Execute according to the approved plan above. Follow the steps exactly as specified.`;if(typeof E==="string")w0=E+H0;else w0=[...E,{type:"text",text:H0}]}M=yield*this.runLoop(w0,O,{...f,inputMessageId:void 0})}if(!this.sessionRuntime||!R)return M;if(M.success&&!O.signal?.aborted)await this.sessionRuntime.acknowledgeTurn(R);let h=await this.sessionRuntime.recordGoalProgress({tokens:M.metadata?.tokensUsed??0,elapsedMs:M.metadata?.duration??0});if(h)yield{kind:"goal_updated",goal:h};if(!M.success||O.signal?.aborted){if(h=await this.sessionRuntime.pauseActiveGoal(O.signal?.aborted?"goal paused after user cancellation":M.error?.message??"goal paused after turn failure"),h)yield{kind:"goal_updated",goal:h}}let p=M.success&&!O.signal?.aborted&&D<20;if(b=await this.sessionRuntime.finishTurn(R,{continuePending:p,outcome:M.success&&!O.signal?.aborted?{status:"completed",turnsCount:M.metadata?.turnsCount??0,toolCallsCount:M.metadata?.toolCallsCount??0,durationMs:M.metadata?.duration??0}:{status:"aborted",cause:O.signal?.aborted?"cancelled":"failed",turnsCount:M.metadata?.turnsCount??0,toolCallsCount:M.metadata?.toolCallsCount??0,durationMs:M.metadata?.duration??0}}),b){D++,G=!0,K=!1,w=null,E="",q=void 0,F=N(),yield{kind:"follow_up_started",queued:this.sessionRuntime.getPendingSteeringCount(),recovered:this.sessionRuntime.getRecoveredSteeringCount(),messages:L()};continue}if(!M.success||O.signal?.aborted)return M;if(h=await this.sessionRuntime.getGoal(),!h||h.status!=="active"&&h.status!=="verifying")return M;if(w=await this.sessionRuntime.beginGoalContinuation(),!w)return M;b=await this.sessionRuntime.beginTurn("goal"),G=!1,K=!0,E=w5(w),q=void 0,F=void 0,yield{kind:"goal_continuation_started",goal:w,continuation:w.continuationCount},yield{kind:"goal_updated",goal:w}}}finally{if(this.sessionRuntime&&b)await this.sessionRuntime.finishTurn(b)}}let W=typeof z==="string"?z:z.filter((E)=>E.type==="text").map((E)=>E.text).join(`
|
|
660
|
-
`),B={id:this.generateTaskId(),type:"simple",prompt:W};return{success:!0,finalMessage:(await this.executeTask(B)).content,metadata:{turnsCount:1,toolCallsCount:0,duration:0}}}async chat($,Z,J){let{drainLoop:U}=await import("./chunk-
|
|
660
|
+
`),B={id:this.generateTaskId(),type:"simple",prompt:W};return{success:!0,finalMessage:(await this.executeTask(B)).content,metadata:{turnsCount:1,toolCallsCount:0,duration:0}}}async chat($,Z,J){let{drainLoop:U}=await import("./chunk-avsv4e5g.js");return U(this.chatStream($,Z,J))}async*runPlanLoop($,Z,J){x.debug("Processing Plan mode message...");let{prompt:U}=await C$({projectPath:Z.workspaceRoot||A(),mode:"plan",includeEnvironment:!0,language:this.config.language,availableSkills:this.agentResources?.skills.generateAvailableSkillsList(),communicationStyle:this.sessionRuntime?.getCommunicationStyleConfiguration().selection,communicationStyleCatalog:this.sessionRuntime?.getCommunicationStyleCatalog(),projectRuleCatalog:this.sessionRuntime?.getProjectRuleCatalog(),projectInstructionSourcePath:this.sessionRuntime?.projectRoot}),X;if(typeof $==="string")X=Q1($);else{let Y=$.filter((H)=>H.type==="text");if(Y.length>0){let H=Y[0];X=$.map((z)=>z===H?{type:"text",text:Q1(H.text)}:z)}else X=[{type:"text",text:Q1("")},...$]}return yield*this.executeLoop(X,Z,J,U)}async*runLoop($,Z,J){x.debug("Processing enhanced chat message...");let U=Z.systemPrompt??await this.buildSystemPromptOnDemand(Z.workspaceRoot||A());return yield*this.executeLoop($,Z,J,U)}async buildSystemPromptOnDemand($){let Z=this.runtimeOptions.systemPrompt,J=this.runtimeOptions.appendSystemPrompt;return(await C$({projectPath:$,replaceDefault:Z,append:J,includeEnvironment:!0,language:this.config.language,availableSkills:this.agentResources?.skills.generateAvailableSkillsList(),communicationStyle:this.sessionRuntime?.getCommunicationStyleConfiguration().selection,communicationStyleCatalog:this.sessionRuntime?.getCommunicationStyleCatalog(),projectRuleCatalog:this.sessionRuntime?.getProjectRuleCatalog(),projectInstructionSourcePath:this.sessionRuntime?.projectRoot})).prompt}executeLoop($,Z,J,U){if(!this.isInitialized)throw Error("Agent未初始化");let X=this.buildLoopDependencies();return M8(X,$,Z,J,U)}buildLoopDependencies(){return{chatService:this.chatService,toolExecutor:this.toolExecutor,executionEngine:this.executionEngine,config:this.config,runtimeOptions:this.runtimeOptions,currentModelMaxContextTokens:this.currentModelMaxContextTokens,activeSkillContext:this.activeSkillContext,onSkillActivated:($)=>{this.activeSkillContext=$,x.debug(`Skill "${$.skillName}" activated`+($.allowedTools?` with allowed tools: ${$.allowedTools.join(", ")}`:""))},onModelSwitch:($)=>this.switchModelIfNeeded($),applySkillToolRestrictions:($)=>this.applySkillToolRestrictions($),staticProjectRules:this.sessionRuntime?.getStaticProjectRules(),hydrateProjectRules:this.sessionRuntime?($)=>this.sessionRuntime.hydrateProjectRules($):void 0,resolveContextualProjectRules:this.sessionRuntime?($,Z,J,U)=>this.sessionRuntime.resolveContextualProjectRules($,Z,J,U):void 0}}async chatWithSystem($,Z){if(!this.isInitialized)throw Error("Agent未初始化");let J=[{role:"system",content:$},{role:"user",content:Z}];return(await this.chatService.chat(J)).content}getActiveTask(){return this.activeTask}getChatService(){return this.chatService}getContextManager(){return this.executionEngine?.getContextManager()}getStats(){return{initialized:this.isInitialized,activeTask:this.activeTask?.id,components:{chatService:this.chatService?"ready":"not_loaded",executionEngine:this.executionEngine?"ready":"not_loaded"}}}getAvailableTools(){return this.toolExecutor?this.toolExecutor.getRegistry().getAll():[]}getToolRegistry(){return this.toolExecutor.getRegistry()}applyToolWhitelist($){let Z=this.toolExecutor.getRegistry(),U=Z.getAll().filter((X)=>!$.includes(X.name));for(let X of U)Z.unregister(X.name);x.debug(`Applied tool whitelist: ${$.join(", ")} (removed ${U.length} tools)`)}applyToolBlacklist($){let Z=this.toolExecutor.getRegistry(),J=new Set($);for(let U of Z.getAll())if(J.has(U.name))Z.unregister(U.name);x.debug(`Applied tool blacklist: ${$.join(", ")}`)}getToolStats(){let $=this.getAvailableTools(),Z=new Map;return $.forEach((J)=>{let U=Z.get(J.kind)||0;Z.set(J.kind,U+1)}),{totalTools:$.length,toolsByKind:Object.fromEntries(Z),toolNames:$.map((J)=>J.name)}}async destroy(){this.log("销毁Agent...");try{await this.legacyMcpRegistry?.disconnectAll(),this.legacyMcpRegistry=void 0,this.log("Agent已销毁")}catch($){throw this.error("Agent销毁失败",$),$}finally{this.toolExecutor.dispose(),this.isInitialized=!1}}syncRuntimeState(){if(!this.sessionRuntime)return;this.chatService=this.sessionRuntime.getChatService(),this.executionEngine=this.sessionRuntime.getExecutionEngine(),this.attachmentCollector=this.sessionRuntime.getAttachmentCollector(),this.currentModelId=this.sessionRuntime.getCurrentModelId(),this.currentModelMaxContextTokens=this.sessionRuntime.getCurrentModelMaxContextTokens()}generateTaskId(){return`task_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}log($,Z){x.debug(`[MainAgent] ${$}`,Z||"")}error($,Z){x.error(`[MainAgent] ${$}`,Z||"")}async initializeSystemPrompt(){try{let $=this.runtimeOptions.systemPrompt,Z=this.runtimeOptions.appendSystemPrompt,J=await C$({projectPath:this.sessionRuntime?.workspaceRoot??A(),replaceDefault:$,append:Z,includeEnvironment:!1,language:this.config.language,availableSkills:this.agentResources?.skills.generateAvailableSkillsList(),communicationStyle:this.sessionRuntime?.getCommunicationStyleConfiguration().selection,communicationStyleCatalog:this.sessionRuntime?.getCommunicationStyleCatalog(),projectRuleCatalog:this.sessionRuntime?.getProjectRuleCatalog(),projectInstructionSourcePath:this.sessionRuntime?.projectRoot});if(J.prompt)this.log("系统提示配置验证成功"),x.debug(`[SystemPrompt] 可用来源: ${J.sources.filter((U)=>U.loaded).map((U)=>U.name).join(", ")}`)}catch($){this.error("系统提示配置验证失败",$)}}async registerBuiltinTools(){try{let $=await z2({sessionId:"default",configDir:R8.join(C8.homedir(),".blade"),workspaceRoot:A(),resourceRoot:A(),agentResources:this.agentResources});x.debug(`Registering ${$.length} builtin tools...`),this.toolExecutor.getRegistry().registerAll($);let Z=this.toolExecutor.getRegistry().getAll().length;x.debug(`Builtin tools registered: ${Z} tools`),x.debug(`[Tools] ${this.toolExecutor.getRegistry().getAll().map((J)=>J.name).join(", ")}`),await this.registerMcpTools()}catch($){throw x.error("Failed to register builtin tools:",$),$}}async registerMcpTools(){try{let $=await d1({workspaceRoot:A(),storeServers:this.config.mcpServers??{},cliConfigs:this.runtimeOptions.mcpConfig,strictCliConfig:this.runtimeOptions.strictMcpConfig});if(Object.keys($).length===0){x.debug("No MCP servers configured");return}let Z=P0.createIsolated({artifactWriter:new z1(`legacy-${TX()}`)});this.legacyMcpRegistry=Z;for(let[Y,H]of Object.entries($))try{x.debug(`Connecting to MCP server: ${Y}`),await Z.registerServer(Y,H),x.debug(`MCP server "${Y}" connected`)}catch(z){x.warn(`Warning: MCP server "${Y}" connection failed:`,z)}let J=this.toolExecutor.getRegistry();J.setMcpCatalogBarrier(()=>Z.waitForCatalogIdle());let U=Z.getCatalogSnapshot();J.replaceMcpTools(U.tools),J.registerAll(O1(Z));let X=Z.getInstructionsSnapshot();if(J.queueMcpInstructionsChange({revision:X.revision,reason:"snapshot",replace:!0,instructions:X.instructions,removed:[]}),Z.on("catalogChanged",(Y)=>{J.replaceMcpTools(Y.tools,Y)}),Z.on("contentCatalogChanged",(Y)=>{J.queueMcpContentChange(Y)}),Z.on("resourceUpdated",(Y)=>{J.queueMcpResourceUpdated(Y)}),Z.on("connectionLifecycleChanged",(Y)=>{J.queueMcpConnectionChange(Y)}),Z.on("log",(Y)=>{J.queueMcpLog(Y)}),Z.on("instructionsChanged",(Y)=>{J.queueMcpInstructionsChange({revision:Y.revision,reason:Y.reason,replace:!1,instructions:Y.action==="added"&&Y.instruction?[{serverName:Y.serverName,...Y.instruction}]:[],removed:Y.action==="removed"?[Y.serverName]:[]})}),U.tools.length>0)x.debug(`Registered ${U.tools.length} MCP tools`),x.debug(`[MCP Tools] ${U.tools.map((Y)=>Y.name).join(", ")}`)}catch($){x.warn("Failed to register MCP tools:",$)}}async loadSubagents(){let $=await $0(A());if(this.agentResources=H2($),this.subagentRegistry=this.agentResources.subagents,this.runtimeOptions.agents?.length)this.subagentRegistry.applyOverrides(this.runtimeOptions.agents);let Z=this.subagentRegistry.getAllNames().length;if(Z>0)x.debug(`Loaded ${Z} subagents: ${this.subagentRegistry.getAllNames().join(", ")}`);else x.debug("No subagents configured")}applySkillToolRestrictions($){if(!this.activeSkillContext?.allowedTools)return $;let Z=this.activeSkillContext.allowedTools;x.debug(`Applying Skill tool restrictions: ${Z.join(", ")}`);let J=$.filter((U)=>{return Z.some((X)=>{if(X===U.name)return!0;let Y=X.match(/^(\w+)\(.*\)$/);if(Y&&Y[1]===U.name)return!0;return!1})});return x.debug(`Filtered tools: ${J.map((U)=>U.name).join(", ")} (${J.length}/${$.length})`),J}clearSkillContext(){if(this.activeSkillContext)x.debug(`Skill "${this.activeSkillContext.skillName}" deactivated`),this.activeSkillContext=void 0}async processAtMentionsForContent($){if(!this.attachmentCollector)return $;if(typeof $==="string")return this.processAtMentions($);let Z=[];for(let U of $)if(U.type==="text")Z.push(U.text);if(Z.length===0)return $;let J=Z.join(`
|
|
661
661
|
`);try{let U=await this.attachmentCollector.collect(J);if(U.length===0)return $;x.debug(`Processed ${U.length} @ file mentions in multimodal message`);let X=this.buildAttachmentText(U);if(!X)return $;return[...$,{type:"text",text:X}]}catch(U){return x.error("Failed to process @ mentions in multimodal message:",U),$}}buildAttachmentText($){let Z=[],J=[];for(let X of $)if(X.type==="file"){let Y=X.metadata?.lineRange?` (lines ${X.metadata.lineRange.start}${X.metadata.lineRange.end?`-${X.metadata.lineRange.end}`:""})`:"";Z.push(`<file path="${X.path}"${Y?` range="${Y}"`:""}>`,X.content,"</file>")}else if(X.type==="directory")Z.push(`<directory path="${X.path}">`,X.content,"</directory>");else if(X.type==="error")J.push(`- @${X.path}: ${X.error}`);let U="";if(Z.length>0)U+=`
|
|
662
662
|
|
|
663
663
|
<system-reminder>
|
|
@@ -1449,7 +1449,7 @@ ${J}
|
|
|
1449
1449
|
`)),{success:!0,message:"Schedules listed",content:Q.join(`
|
|
1450
1450
|
`)}}case"create":{let z=AQ(Y);if("error"in z)return U.sendMessage(`创建失败:${z.error}`),{success:!1,error:z.error};let Q={prompt:z.prompt,projectPath:H,trigger:z.trigger,isolation:"worktree",permissionMode:"default",enabled:!0};try{let W=await $.create(Q),B=W.nextRunAt?new Date(W.nextRunAt).toLocaleString():"(无)";return U.sendMessage(`[OK] 已创建定时任务 \`${W.id}\`
|
|
1451
1451
|
${r6(W.trigger)} · 下次运行: ${B}`),{success:!0,message:`Schedule ${W.id} created`}}catch(W){let B=W instanceof Error?W.message:String(W);return U.sendMessage(`创建失败:${B}`),{success:!1,error:B}}}case"remove":case"rm":{let z=Y[0];if(!z)return U.sendMessage("用法:/schedule remove <id>"),{success:!1,error:"Missing schedule id"};let Q=await $.remove(z);return U.sendMessage(Q?`[OK] 已删除 \`${z}\``:`未找到 \`${z}\``),{success:Q,message:Q?"Removed":"Not found"}}case"enable":case"disable":{let z=Y[0];if(!z)return U.sendMessage(`用法:/schedule ${X} <id>`),{success:!1,error:"Missing schedule id"};let Q=await $.setEnabled(z,X==="enable");return U.sendMessage(Q?`[OK] 已${X==="enable"?"启用":"停用"} \`${z}\``:`未找到 \`${z}\``),{success:Boolean(Q),message:Q?"Updated":"Not found"}}case"run":{let z=Y[0];if(!z)return U.sendMessage("用法:/schedule run <id>"),{success:!1,error:"Missing schedule id"};try{return await NQ(z),U.sendMessage(`[OK] 已触发 \`${z}\``),{success:!0,message:"Schedule triggered"}}catch(Q){let W=Q instanceof Error?Q.message:String(Q);return U.sendMessage(`运行失败:${W}`),{success:!1,error:W}}}default:return U.sendMessage(`未知子命令: ${X}
|
|
1452
|
-
使用 /schedule 查看帮助`),{success:!1,error:`Unknown subcommand: ${X}`}}}}}var U7=jQ();import*as J1 from"node:fs/promises";import*as U1 from"node:path";async function W7($,Z={}){let{maxResults:J=20,caseSensitive:U=!1,projectPath:X,storagePath:Y}=Z,H=Y??X7(X??A());if(!Y){let E=await TQ($,X??A(),J,U);if(E)return E}let z;try{z=(await J1.readdir(H)).filter((O)=>O.endsWith(".jsonl")&&!O.startsWith("agent_")).map((O)=>U1.join(H,O))}catch{return[]}let W=(await Promise.all(z.map(async(E)=>{try{let O=await J1.stat(E);return{path:E,mtime:O.mtimeMs}}catch{return null}}))).filter((E)=>E!==null).sort((E,O)=>O.mtime-E.mtime).map((E)=>E.path),B=[],V=U?$:$.toLowerCase();for(let E of W){if(B.length>=J)break;let O=U1.basename(E,".jsonl"),G=await fQ(E,V,U,O);if(B.push(...G),B.length>=J){B.length=J;break}}return B}async function TQ($,Z,J,U){try{let{syncAll:X}=await import("./chunk-h6w3ggx9.js"),Y=await z7();if(!Y)return null;let{SessionService:H}=await import("./chunk-
|
|
1452
|
+
使用 /schedule 查看帮助`),{success:!1,error:`Unknown subcommand: ${X}`}}}}}var U7=jQ();import*as J1 from"node:fs/promises";import*as U1 from"node:path";async function W7($,Z={}){let{maxResults:J=20,caseSensitive:U=!1,projectPath:X,storagePath:Y}=Z,H=Y??X7(X??A());if(!Y){let E=await TQ($,X??A(),J,U);if(E)return E}let z;try{z=(await J1.readdir(H)).filter((O)=>O.endsWith(".jsonl")&&!O.startsWith("agent_")).map((O)=>U1.join(H,O))}catch{return[]}let W=(await Promise.all(z.map(async(E)=>{try{let O=await J1.stat(E);return{path:E,mtime:O.mtimeMs}}catch{return null}}))).filter((E)=>E!==null).sort((E,O)=>O.mtime-E.mtime).map((E)=>E.path),B=[],V=U?$:$.toLowerCase();for(let E of W){if(B.length>=J)break;let O=U1.basename(E,".jsonl"),G=await fQ(E,V,U,O);if(B.push(...G),B.length>=J){B.length=J;break}}return B}async function TQ($,Z,J,U){try{let{syncAll:X}=await import("./chunk-h6w3ggx9.js"),Y=await z7();if(!Y)return null;let{SessionService:H}=await import("./chunk-r6bha0vm.js");await X(Y,H.projectionDeriverForSearch());let z=U1.resolve(Z),Q=Q7(Y,$,z,J*4),W=U?$:$.toLowerCase(),B=[];for(let V of Q){if(V.role!=="user"&&V.role!=="assistant")continue;let E=a6(V.text,W,U,V.session_id,V.role,V.timestamp??void 0,0);if(E)B.push(E);if(B.length>=J)break}return B}catch{return null}}async function fQ($,Z,J,U){try{let X=await J1.readFile($,"utf8"),H=X.split(`
|
|
1453
1453
|
`).flatMap((V,E)=>{if(!V.trim())return[];try{return[{event:JSON.parse(V),index:E}]}catch{return[]}});if(!H.some(({event:V})=>V.type==="session_created"))return MQ(H,Z,J,U);let Q=new Map(H.flatMap(({event:V,index:E})=>typeof V.id==="string"?[[V.id,E+1]]:[])),W=Y7(H7(X,$)),B=new Map;for(let V of W){if(V.type==="message_created"&&(V.data.role==="user"||V.data.role==="assistant"))B.set(V.data.messageId,{role:V.data.role,content:[],timestamp:V.timestamp,lineNumber:Q.get(V.id)??0});if(V.type==="part_created"&&V.data.partType==="text"){let E=B.get(V.data.messageId),O=V.data.payload.text;if(E&&typeof O==="string")E.content.push(O)}}return[...B.values()].flatMap((V)=>{let E=a6(V.content.join(" "),Z,J,U,V.role,V.timestamp,V.lineNumber);return E?[E]:[]})}catch{return[]}}function MQ($,Z,J,U){return $.flatMap(({event:X,index:Y})=>{if(X.type!=="message")return[];let H=X.message;if(H?.role!=="user"&&H?.role!=="assistant"||!H.content)return[];let z=typeof H.content==="string"?H.content:Array.isArray(H.content)?H.content.filter((W)=>typeof W==="object"&&W!==null&&W.type==="text"&&typeof W.text==="string").map((W)=>W.text).join(" "):"",Q=a6(z,Z,J,U,H.role,typeof X.timestamp==="string"?X.timestamp:void 0,Y+1);return Q?[Q]:[]})}function a6($,Z,J,U,X,Y,H){if(!$)return;let z=J?$:$.toLowerCase();if(!z.includes(Z))return;let Q=z.indexOf(Z),W=Math.max(0,Q-80),B=Math.min($.length,Q+Z.length+80);return{sessionId:U,role:X,content:(W>0?"...":"")+$.slice(W,B).replace(/\n/g," ")+(B<$.length?"...":""),timestamp:Y,lineNumber:H}}function B7($){if($.length===0)return"没有找到匹配的历史记录";let Z=[`**找到 ${$.length} 条匹配:**
|
|
1454
1454
|
`];for(let J of $){let U=J.timestamp?new Date(J.timestamp).toLocaleString("zh-CN",{timeZone:"Asia/Shanghai"}):"?",X=J.role==="user"?"\uD83D\uDC64":"\uD83E\uDD16";Z.push(`${X} \`${J.sessionId.slice(0,8)}\` (${U})`),Z.push(` ${J.content}`),Z.push("")}return Z.join(`
|
|
1455
1455
|
`)}var CQ={name:"search",description:"Search past session transcripts",fullDescription:"搜索历史会话记录,查找过去的对话内容",usage:"/search <keyword>",aliases:["find","history"],category:"Session",examples:['/search 断路器 - 搜索包含"断路器"的历史对话',"/search edit tool - 搜索 edit tool 相关讨论"],async handler($,Z){let J=k(Z);if($.length===0)return J.sendMessage("**用法:** `/search <关键词>`\n\n在历史会话中搜索包含指定关键词的对话"),{success:!0,message:"显示帮助"};let U=$.join(" ");J.sendMessage(`正在搜索: "${U}" ...`);try{let X=await W7(U,{maxResults:15,projectPath:Z.cwd}),Y=B7(X);return J.sendMessage(Y),{success:!0,message:`found ${X.length} results`,data:{matches:X.length}}}catch(X){let Y=X instanceof Error?X.message:"未知错误";return J.sendMessage(`搜索失败: ${Y}`),{success:!1,error:Y}}}},V7=CQ;var RQ={name:"skills",description:"查看所有可用的 Skills",fullDescription:"显示所有已发现的 Skills 及其详细信息,包括名称、描述、来源和允许的工具。",usage:"/skills",category:"system",examples:["/skills"],handler:async($,Z)=>{try{return await C0({cwd:Z.workspaceRoot??Z.cwd}).refresh(),d$(Z.workspaceRoot??Z.cwd),await u$(Z.workspaceRoot??Z.cwd),{success:!0,message:"show_skills_manager",data:{action:"show_skills_manager"}}}catch(J){let U=`获取 Skills 失败: ${J instanceof Error?J.message:"未知错误"}`;return P().addAssistantMessage(U),{success:!1,error:U}}}},E7=RQ;import SQ from"node:path";function y2($){if($<1000)return`${$}ms`;let Z=Math.floor($/1000);if(Z<60)return`${Z}s`;let J=Math.floor(Z/60);if(J<60)return`${J}m ${Z%60}s`;return`${Math.floor(J/60)}h ${J%60}m`}function _7($){switch($){case"running":return"[RUNNING]";case"completed":case"exited":return"[OK]";case"failed":case"error":return"[FAIL]";case"killed":case"cancelled":return"[STOPPED]";default:return"[?]"}}function O7($,Z){if($.length<=Z)return $;return $.slice(0,Z-3)+"..."}async function PQ($,Z){let J=k(Z),U=$[0],X=t.getInstance(),Y=s.getInstance(),H=Z.sessionId??"",z=Z.sessionId?{sessionId:Z.sessionId,projectPath:SQ.resolve(Z.workspaceRoot??Z.cwd)}:void 0;if(U==="resume"){let O=$[1],G=$.slice(2).join(" ").trim();if(!O||!G)return{success:!1,error:"Usage: /tasks resume <agentId> <prompt>"};if(!Z.subagents)return{success:!1,error:"This surface does not own a subagent runtime"};let K=await Z.subagents.resume(O,G),F=`Resumed \`${O}\` as \`${K.session.id}\` (depth ${K.session.resumeDepth}).`;return J.sendMessage(F),{success:!0,message:F,data:{action:"subagent_resumed",sourceAgentId:O,subagent:K.session}}}if(U==="clean"){let O=Y.cleanupExpiredSessionsForParent(z??H,0);return J.sendMessage(`已清理 ${O} 个已完成的 Agent 会话`),{success:!0,message:`Cleaned ${O} agent sessions`}}let Q=[`**后台任务列表**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e={name:"blade-code",version:"0.10.
|
|
1
|
+
var e={name:"blade-code",version:"0.10.14",private:!1,description:"🗡️ Blade Code - 智能代码助手命令行工具",type:"module",bin:{blade:"dist/blade.js"},files:["dist","vendor/ripgrep/**","README.md"],scripts:{dev:"node scripts/run-bun.js --watch src/blade.tsx","dev:serve":"node scripts/run-bun.js --watch src/blade.tsx serve --port 4097",build:"rm -rf dist && node scripts/run-bun.js run scripts/build.ts",start:"node scripts/run-bun.js run dist/blade.js",test:"node scripts/test.js","test:all":"vitest run --config vitest.config.ts --project='!performance' && vitest run --config vitest.config.ts --project=performance","test:unit":"node scripts/test.js unit","test:integration":"node scripts/test.js integration","test:real-api":"node scripts/test.js realApi","test:real-api:qualification":"node scripts/test.js realApiQualification","test:cli":"node scripts/test.js cli","test:headless-core":"node scripts/test.js headlessCore","test:e2e":"node scripts/test.js e2e","test:performance":"node scripts/test.js performance","test:snapshot":"node scripts/test.js snapshot","test:security":"node scripts/test.js security","test:coverage":"node scripts/test.js all --coverage","test:watch":"vitest --watch --config vitest.config.ts","qualify:local":"node scripts/run-bun.js run scripts/qualify.ts local","qualify:production":"node scripts/run-bun.js run scripts/qualify.ts production","benchmark:repo":"node scripts/run-bun.js run scripts/run-real-repo-benchmark.ts","test:update-snapshots":"node scripts/test.js snapshot --update",lint:"biome lint src tests","lint:fix":"biome lint --write src tests","type-check":"tsc --noEmit","format:check":"biome format src tests",ready:"node scripts/run-bun.js run scripts/qualify.ts production","detect-unused":"node scripts/run-bun.js run scripts/detect-unused.ts",release:"node scripts/release.js","release:dry":"node scripts/release.js --dry-run","release:major":"node scripts/release.js --major","release:minor":"node scripts/release.js --minor","release:patch":"node scripts/release.js --patch"},keywords:["cli","blade","ai","assistant","agent","llm"],author:"echoVic",license:"MIT",engines:{node:">=22.19.0"},optionalDependencies:{"@vscode/ripgrep":"^1.18.0","better-sqlite3":"^11.8.1","bun-pty":"^0.4.8","node-pty":"1.1.0"},dependencies:{"@agentclientprotocol/sdk":"^1.3.0","@anthropic-ai/sandbox-runtime":"0.0.67","@earendil-works/pi-ai":"0.83.0","@inkjs/ui":"^2.0.0","@modelcontextprotocol/sdk":"^1.30.0",ahooks:"^3.9.7","ansi-escapes":"^7.3.0",ajv:"^8.17.1","async-mutex":"^0.5.0",axios:"^1.19.0",chalk:"^5.4.1",diff:"^8.0.2","fast-glob":"^3.3.3","fuse.js":"^7.5.0","gray-matter":"^4.0.3",hono:"^4.13.0",ink:"npm:@jrichman/ink@6.4.10","ink-big-text":"^2.0.0","ink-gradient":"^3.0.0","ink-select-input":"^6.2.0","ink-spinner":"^5.0.0","ink-text-input":"^6.0.0","js-tiktoken":"^1.0.21","lodash-es":"^4.18.1",lowlight:"^3.3.0","lru-cache":"^11.5.2",nanoid:"^5.1.6",open:"^10.1.2",picomatch:"^4.0.5",react:"19.2.4","react-dom":"19.2.4",semver:"^7.8.5","string-width":"^8.2.2",typebox:"1.3.10",undici:"^7.16.0","vscode-jsonrpc":"8.2.1","vscode-languageserver-protocol":"3.17.5","vscode-languageserver-types":"3.17.5","write-file-atomic":"^7.0.0",ws:"^8.21.2",yaml:"^2.9.0",yargs:"^18.1.0",zustand:"^5.0.14"},devDependencies:{"@biomejs/biome":"^2.5.7","@types/bun":"^1.3.14","@types/json-schema":"^7.0.15","@types/lodash-es":"^4.17.12","@types/node":"^22.15.24","@types/picomatch":"^4.0.3","@types/react":"19.2.10","@types/react-dom":"19.2.3","@types/semver":"^7.8.0","@types/write-file-atomic":"^4.0.3","@types/ws":"^8.18.1","@types/yargs":"^17.0.35","@vitest/coverage-v8":"^4.1.10",jsdom:"^26.0.0",typescript:"^5.9.2",vitest:"^4.1.10"}};function i(){return{name:e.name,version:e.version,description:e.description}}function n(){return e.version}function o(){return e.name}function c(){return e.description}function a(){return`v${e.version}`}function d(){return`v${e.version} © 2025 Blade Code`}
|
|
2
2
|
export{i as uf,n as vf,o as wf,c as xf,a as yf,d as zf};
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import{r as R}from"./chunk-
|
|
2
|
-
`)}class A{id;cwd;connection;clientCapabilities;options;agent=null;runtime=null;pendingPrompt=null;pendingUserShell=null;pendingResumeRequested=!1;availableCommandsTimer=null;taskStatusUnsubscribe;destroyed=!1;messages;mode;constructor(J,Z,Q,W,H={}){this.id=J;this.cwd=Z;this.connection=Q;this.clientCapabilities=W;this.options=H;this.messages=[...H.initialMessages??[]],this.mode=this.mapPermissionModeToMode(H.permissionMode)}mapPermissionModeToMode(J){switch(J){case"yolo":return"yolo";case"autoEdit":return"auto-edit";case"plan":return"plan";case"default":default:return"default"}}createAgent(){if(!this.runtime)throw Error("Session runtime is unavailable");return l.createWithRuntime(this.runtime,{sessionId:this.id,...this.options.taskWorktree?{toolBlacklist:["EnterWorktree","ExitWorktree"]}:{}})}async initialize(){if(j.debug(`[AcpSession ${this.id}] Initializing...`),await B.setSessionPermissionMode(this.id,this.cwd,this.mapModeToPermissionMode()??"default"),P.initializeSession(this.connection,this.id,this.clientCapabilities,this.cwd),j.debug(`[AcpSession ${this.id}] ACP service context initialized`),await v.resolvePendingWithHandler(this.cwd,this.id,{requestConfirmation:(z)=>this.requestPermission(z)}))this.messages=await B.loadSession(this.id,this.cwd);let Z=this.options.mcpServers?XJ(this.options.mcpServers):void 0,Q=P.getInstance().getTerminalService(this.id);if(this.runtime=await p.create({sessionId:this.id,workspaceRoot:this.cwd,permissionMode:this.mapModeToPermissionMode(),...Z?{mcpServers:Z}:{},...this.options.taskWorktree?{taskWorktree:this.options.taskWorktree}:{},...this.options.taskIsolation?{taskIsolation:this.options.taskIsolation}:{},userShellExecutor:{execute:async(z,$)=>{let G=await Q.execute(z,{cwd:$.cwd,env:$.env,timeout:$.timeoutMs,signal:$.signal,allowLocalFallback:!1,onOutput:(F)=>$.onOutput?.("stdout",F)});return{exitCode:G.exitCode,stdout:G.stdout,stderr:G.stderr,...G.error?{error:G.error}:{},timedOut:G.error==="Command timed out",aborted:G.error==="Command was aborted"}}},...(this.options.initialMessages?.length??0)>0?{sessionStart:{isResume:!0,resumeSessionId:this.id}}:{}}),await R.recoverInterrupted(this.cwd,this.id,this.runtime))this.messages=await B.loadSession(this.id,this.cwd);this.agent=await this.createAgent(),await r(this.cwd),j.debug(`[AcpSession ${this.id}] Agent created successfully`),this.taskStatusUnsubscribe?.(),this.taskStatusUnsubscribe=c.subscribe((z)=>{if(z.sessionId!==this.id||z.projectPath!==this.cwd)return;if(z.type==="task.delivery"){if(!z.properties.taskDelivery||typeof z.properties.taskDelivery!=="object")return;this.sendUpdate({sessionUpdate:"session_info_update",updatedAt:typeof z.properties.updatedAt==="string"?z.properties.updatedAt:new Date().toISOString(),_meta:{"blade/taskDelivery":z.properties.taskDelivery,...z.properties.taskWorktreeRemoved===!0?{"blade/taskWorktreeRemoved":!0}:{}}});return}if(z.type!=="task.status")return;this.sendUpdate({sessionUpdate:"session_info_update",updatedAt:typeof z.properties.updatedAt==="string"?z.properties.updatedAt:new Date().toISOString(),_meta:{"blade/taskStatus":z.properties.taskStatus,...typeof z.properties.taskStatusReason==="string"?{"blade/taskStatusReason":z.properties.taskStatusReason}:{},...z.properties.taskFailure&&typeof z.properties.taskFailure==="object"?{"blade/taskFailure":z.properties.taskFailure}:{},...typeof z.properties.taskStartedAt==="string"?{"blade/taskStartedAt":z.properties.taskStartedAt}:{},...typeof z.properties.taskCompletedAt==="string"?{"blade/taskCompletedAt":z.properties.taskCompletedAt}:{},...z.properties.taskDiffStat&&typeof z.properties.taskDiffStat==="object"?{"blade/taskDiffStat":z.properties.taskDiffStat}:{},...typeof z.properties.taskQueuePosition==="number"?{"blade/taskQueuePosition":z.properties.taskQueuePosition}:{},...typeof z.properties.taskQueueDepth==="number"?{"blade/taskQueueDepth":z.properties.taskQueueDepth}:{},...typeof z.properties.taskConcurrencyLimit==="number"?{"blade/taskConcurrencyLimit":z.properties.taskConcurrencyLimit}:{},...typeof z.properties.taskInFlight==="number"?{"blade/taskInFlight":z.properties.taskInFlight}:{}}})});let H=await this.runtime.getGoal();if(this.runtime.getPendingSteeringCount()>0||H?.status==="active")if(this.options.initialMessages===void 0)this.schedulePendingResume();else this.pendingResumeRequested=!0}async replayHistory(){for(let J of this.messages){if(!this.canSendUpdates())return;let Z=J.role==="user"?"user_message_chunk":J.role==="assistant"?"agent_message_chunk":void 0;if(!Z)continue;for(let Q of jJ(J)){if(!this.canSendUpdates())return;if(!await this.sendUpdateAndWait({sessionUpdate:Z,content:Q}))return}}if(this.pendingResumeRequested)this.schedulePendingResume()}sendAvailableCommandsDelayed(){if(this.destroyed||this.connection.signal.aborted)return;if(this.availableCommandsTimer!==null)clearTimeout(this.availableCommandsTimer);j.debug(`[AcpSession ${this.id}] Scheduling available commands update (500ms delay)`),this.availableCommandsTimer=setTimeout(()=>{if(this.availableCommandsTimer=null,this.destroyed||this.connection.signal.aborted)return;this.sendAvailableCommands()},500)}async handleSlashCommand(J,Z){try{j.debug(`[AcpSession ${this.id}] Executing slash command: ${J}`);let Q={cwd:this.cwd,surface:"acp",workspaceRoot:this.cwd,sessionId:this.id,messages:[...this.messages],rewind:{listCheckpoints:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.listRewindCheckpoints()},execute:async($)=>{if(!this.runtime)throw Error("Session runtime is unavailable");let G=await this.runtime.rewindSession($);return this.messages=[...G.messages],await this.agent?.destroy(),this.agent=await this.createAgent(),G}},reasoning:{get:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getReasoningConfiguration()},set:async($)=>{if(await this.setReasoningEffort($),!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getReasoningConfiguration()}},serviceTier:{get:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getServiceTierConfiguration()},set:async($)=>{if(await this.setServiceTier($),!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getServiceTierConfiguration()}},responseVerbosity:{get:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getResponseVerbosityConfiguration()},set:async($)=>{if(await this.setResponseVerbosity($),!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getResponseVerbosityConfiguration()}},communicationStyle:{get:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getCommunicationStyleConfiguration()},set:async($)=>{if(await this.setCommunicationStyle($),!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getCommunicationStyleConfiguration()}},subagents:{list:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.listSubagents()},resume:async($,G)=>{if(!this.runtime)throw Error("Session runtime is unavailable");let F=!1,X,L=(D)=>{this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:D.id,status:D.status==="completed"?"completed":"failed",content:[{type:"content",content:{type:"text",text:D.result?.message||D.result?.error||`Subagent ${D.status}`}}]})},Y=this.runtime.resumeSubagent({agentId:$,prompt:G,onCompleted:(D)=>{if(F)L(D);else X=D}});if(this.sendUpdate({sessionUpdate:"tool_call",toolCallId:Y.session.id,status:"in_progress",title:`Resuming ${Y.session.subagentType} subagent`,content:[{type:"content",content:{type:"text",text:`Resumed from ${Y.source.id} at depth ${Y.session.resumeDepth}`}}],kind:this.mapToolKind("readonly")}),F=!0,X)L(X);return Y}},mcp:{getCatalog:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getMcpContentCatalog()},refresh:async($)=>{if(!this.runtime)throw Error("Session runtime is unavailable");await this.runtime.refreshMcpContentCatalogs($)},getPrompt:async($,G,F)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getMcpPrompt($,G,F)},complete:async($,G,F)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.completeMcpArgument($,G,F)},listTasks:async($)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.listMcpTasks($)},getTask:async($)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getMcpTask($)},cancelTask:async($,G)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.cancelMcpTask($,G)},getLogs:async($,G)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getMcpLogs($,G)},setLoggingLevel:async($,G)=>{if(!this.runtime)throw Error("Session runtime is unavailable");await this.runtime.setMcpLoggingLevel($,G)},getInstructions:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getMcpInstructions()}},codeReview:{run:async($,G)=>{if(!this.runtime)throw Error("Session runtime is unavailable");let F=await R.start({sessionId:this.id,projectPath:this.cwd,runtime:this.runtime,request:$,signal:G,onEvent:(Y)=>{if(Y.kind==="tool_start")this.sendUpdate({sessionUpdate:"tool_call",toolCallId:Y.toolCall.id,status:"in_progress",title:`Review: ${Y.toolCall.function.name}`,content:[],kind:this.mapToolKind(Y.toolKind)});else if(Y.kind==="tool_result")this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:Y.toolCall.id,status:Y.result.success?"completed":"failed",content:[]})}}),X=await F.completion,L=(await R.list(this.cwd,this.id)).find((Y)=>Y.start.reviewId===F.reviewId);if(!L)throw Error(`Review not found: ${F.reviewId}`);return this.messages=await B.loadSession(this.id,this.cwd),{reviewId:F.reviewId,status:X.status,findings:X.findings.length,content:C(L.start,X)}}},signal:Z,acp:{sendMessage:($)=>{this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:$}})},sendToolStart:($,G,F)=>{let X=`tool_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,L=this.mapToolKind(F);this.sendUpdate({sessionUpdate:"tool_call",toolCallId:X,status:"in_progress",title:`${$}`,content:[{type:"content",content:{type:"text",text:JSON.stringify(G,null,2)}}],kind:L})},sendToolResult:($,G)=>{if(G.summary)this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:G.summary}})}}},W=await a(J,Q),H=W.data?.action;if(H==="start_goal"||H==="resume_goal")this.schedulePendingResume();if(H==="rewind_session"&&Array.isArray(W.data?.messages))this.messages=[...W.data.messages];if((W.message==="compact_completed"||W.message==="compact_fallback")&&W.data?.compactedMessages)this.messages=[...W.data.compactedMessages];let z=W.content||W.message;if(z)this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:z}});if(W.error)this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`[FAIL] ${W.error}`}});return{stopReason:W.success?"end_turn":"cancelled"}}catch(Q){return j.error(`[AcpSession ${this.id}] Slash command error:`,Q),this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`[FAIL] 命令执行失败: ${Q instanceof Error?Q.message:"未知错误"}`}}),{stopReason:"cancelled"}}}async sendAvailableCommands(){try{let J=n(this.cwd),Z=["model","permissions","theme","config","exit","ide"],W=J.filter((H)=>!Z.includes(H.name)).map((H)=>{let z;if(H.usage){let $=H.usage.replace(/^\/\w+\s*/,"").trim();if($)z=$}if(H.aliases?.length){let $=`Aliases: ${H.aliases.join(", ")}`;z=z?`${z} | ${$}`:$}return{name:H.name,description:H.description,input:z?{hint:z}:void 0}});j.info(`[AcpSession ${this.id}] Sending available commands: ${JSON.stringify(W.map((H)=>H.name))}`),this.sendUpdate({sessionUpdate:"available_commands_update",availableCommands:W}),j.info(`[AcpSession ${this.id}] Sent ${W.length} available commands`)}catch(J){j.error(`[AcpSession ${this.id}] Failed to send available commands:`,J)}}async prompt(J,Z={}){if(P.setCurrentSession(this.id),!this.agent||!this.runtime)throw Error("Session not initialized");let Q=this.resolvePrompt(J.prompt),W=Q.content,H=Q.displayText,z=J._meta?.outputSchema??(Z.pendingInputOnly?this.runtime.getPendingSteeringMessages().find((F)=>F.outputSchema)?.outputSchema:void 0),$;if(z!==void 0)$=f(z).schema;if(H.trimStart().startsWith("!")){if($)throw Error("Output schemas cannot be combined with user shell commands");return this.handleUserShellCommand(H)}if(this.pendingPrompt){if($)throw Error("Wait for the active turn to finish before setting an output schema");if(/^\/goal(?:\s|$)/i.test(H.trim()))return this.handleSlashCommand(H,this.pendingPrompt.signal);let F=await this.runtime.enqueueSteering(W,{allowBeforeTurn:!0});if(!F.accepted)throw Error(F.reason==="queue_full"?"Active turn steering queue is full":"Active turn is no longer steerable");if(j.debug(`[AcpSession ${this.id}] Queued steering for active turn (${F.queued})`),F.delivery==="next_turn")this.schedulePendingResume();return{stopReason:"end_turn"}}let G=new AbortController;this.pendingPrompt=G;try{if(j.debug(`[AcpSession ${this.id}] Received prompt: ${H.slice(0,100)}...`),i(H)){if($)throw Error("Output schemas cannot be combined with slash commands");return await this.handleSlashCommand(H,G.signal)}let F={sessionId:this.id,userId:"acp-user",workspaceRoot:this.cwd,messages:[...this.messages],signal:G.signal,permissionMode:this.mapModeToPermissionMode(),onPermissionModeChange:async(Y)=>{this.mode=this.mapPermissionModeToMode(Y),this.sendUpdate({sessionUpdate:"current_mode_update",currentModeId:this.mode})},...this.options.taskWorktree?{worktreeActive:!0}:{},confirmationHandler:{requestConfirmation:async(Y)=>{return this.requestPermission(Y)}}},X=await g(this.agent.chatStream(W,F,{pendingInputOnly:Z.pendingInputOnly,goalContinuationOnly:Z.goalContinuationOnly,outputSchema:$}),async(Y)=>{switch(Y.kind){case"content_delta":if($)break;this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:Y.delta}});break;case"thinking_delta":this.sendUpdate({sessionUpdate:"agent_thought_chunk",content:{type:"text",text:Y.delta}});break;case"tool_start":{let D=Y.toolCall,U=D.function.name;if(U===O)break;let _=this.mapToolKind(Y.toolKind),V=`Executing ${U}`;if(U==="Task"&&"function"in D)try{let N=JSON.parse(D.function.arguments),w=N.resume_from??N.resume;if(typeof w==="string")V=`Resuming ${String(N.subagent_type||"subagent")} from ${w}`}catch{}this.sendUpdate({sessionUpdate:"tool_call",toolCallId:D.id,status:"in_progress",title:V,content:[],kind:_});break}case"tool_progress":{let D=Y.toolCall;if(D.function.name===O)break;this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:D.id,status:"in_progress",content:[{type:"content",content:{type:"text",text:Y.update.message}}]});break}case"tool_result":{let D=Y.toolCall;if(D.function.name===O)break;let U=Y.result,_=[],V=U.metadata;if(V?.kind==="patch"&&Array.isArray(V.changes))for(let w of V.changes){if(!w||typeof w!=="object"||!("path"in w)||typeof w.path!=="string")continue;_.push({type:"diff",path:w.path,oldText:"oldContent"in w&&typeof w.oldContent==="string"?w.oldContent:null,newText:"newContent"in w&&typeof w.newContent==="string"?w.newContent:null})}else if(V?.kind==="edit"&&typeof V.file_path==="string"&&typeof V.oldContent==="string"&&(typeof V.newContent==="string"||V.newContent===void 0))_.push({type:"diff",path:V.file_path,oldText:V.oldContent,newText:V.newContent??null});else{let w=D.function.name,YJ=d(m(w,U));_.push({type:"content",content:{type:"text",text:YJ}})}if(D.function.name==="Task"&&(V?.verificationVerdict==="pass"||V?.verificationVerdict==="fail"||V?.verificationVerdict==="partial"))_.unshift({type:"content",content:{type:"text",text:`Verification result: ${V.verificationVerdict.toUpperCase()}`}});let N=U.success?"completed":"failed";this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:D.id,status:N,content:_});break}case"structured_output":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:JSON.stringify(Y.output)}});break;case"mcp_catalog_changed":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP catalog r${Y.revision} (${Y.serverName}): +${Y.added.length} -${Y.removed.length} ~${Y.updated.length}
|
|
3
|
-
`}});break;case"mcp_content_changed":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP ${
|
|
4
|
-
`}});break;case"mcp_resource_updated":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP resource updated r${
|
|
5
|
-
`}});break;case"mcp_connection_changed":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP connection r${
|
|
6
|
-
`}});break;case"mcp_log":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP log r${
|
|
7
|
-
`}});break;case"mcp_instructions_changed":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP instructions r${
|
|
8
|
-
`}});break;case"mcp_task_changed":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP task r${
|
|
9
|
-
`}});break;case"project_rules_loaded":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`Project rules loaded: ${
|
|
10
|
-
`}});break;case"task_update":this.sendPlanUpdate(
|
|
11
|
-
`}});break;case"goal_updated":if(
|
|
12
|
-
`}});break;case"goal_continuation_started":break;default:break}});if(this.messages=[...F.messages],!X.success){let
|
|
13
|
-
`}),z+=1;if(Q.push(F),F.type==="text")z+=F.text.length};for(let F of J)if(F.type==="text")Z.push(F.text),$({type:"text",text:F.text});else if(F.type==="image"){let X=`data:${F.mimeType};base64,${F.data}`;
|
|
1
|
+
import{r as R}from"./chunk-321n9hem.js";import{s as WJ}from"./chunk-mcqe9km3.js";import{$ as a,F as p,I as m,J as d,L as l,Z as i,_ as r,aa as n,v as P}from"./chunk-rbph12qe.js";import{ka as zJ}from"./chunk-8zr7h97n.js";import"./chunk-p4zt7ts9.js";import{Va as g,Ya as c,hb as v}from"./chunk-4rn3r12e.js";import{sb as y}from"./chunk-095x2ykj.js";import{$b as B,Fb as C,Kb as O,Nb as f,Tb as T,Ub as u,Yb as q}from"./chunk-kesgbws4.js";import"./chunk-4hawehmd.js";import"./chunk-ktf3bpmw.js";import"./chunk-xq403rac.js";import"./chunk-vmq248m7.js";import{fd as QJ}from"./chunk-ybvdac8k.js";import"./chunk-g3w00xb7.js";import"./chunk-2mzcxq6c.js";import{od as ZJ}from"./chunk-8j01ssaf.js";import"./chunk-2z6261pz.js";import"./chunk-j7k5x43d.js";import"./chunk-9tnaads5.js";import{Td as $J}from"./chunk-heqs3xan.js";import"./chunk-dpt56hah.js";import"./chunk-zvt8ngpt.js";import"./chunk-7wjy6kgt.js";import{ee as E}from"./chunk-4dq9y7zn.js";import"./chunk-hrmfhv8k.js";import"./chunk-3aqdjrtm.js";import"./chunk-kvx3sb3z.js";import{cf as h,df as S,ef as I}from"./chunk-f4z3gkbs.js";import{if as s}from"./chunk-5s123nbs.js";import"./chunk-s5666ta0.js";import{of as e,rf as JJ}from"./chunk-dsj62dcg.js";import"./chunk-se1tfys3.js";import"./chunk-gav4hxcv.js";import"./chunk-afkhzdfc.js";import"./chunk-363pgv1e.js";import"./chunk-g11hq0e5.js";import{Readable as BJ,Writable as VJ}from"node:stream";import*as b from"@agentclientprotocol/sdk";import{PROTOCOL_VERSION as LJ}from"@agentclientprotocol/sdk";import t from"node:path";import{RequestError as FJ}from"@agentclientprotocol/sdk";import{nanoid as x}from"nanoid";var j=E("Agent");function k(J){if(!J)return{};return Object.fromEntries(J.map((Z)=>[Z.name,Z.value]))}function GJ(J){if("command"in J)return{type:"stdio",command:J.command,args:J.args,env:k(J.env)};if("url"in J)return{type:J.type,url:J.url,headers:k("headers"in J?J.headers:void 0)};return null}function XJ(J){let Z={};for(let Q of J){let Y=GJ(Q);if(Y)Z[Q.name]=Y}return Z}function o(J){if(typeof J==="string")return J?[{type:"text",text:J}]:[];return J.flatMap((Z)=>{if(Z.type==="text")return Z.text?[{type:"text",text:Z.text}]:[];let Q=Z.image_url.url,Y=/^data:([^;,]+);base64,(.+)$/s.exec(Q);if(!Y)return[{type:"text",text:"[Image]"}];return[{type:"image",mimeType:Y[1]??"image/png",data:Y[2]??""}]})}function jJ(J){let Z=u(J.metadata);return Z?[{type:"text",text:T(Z)}]:o(J.content)}function DJ(J){return[`Status: ${J.status}`,`Exit code: ${J.exitCode??"null"}`,`Duration: ${(J.durationMs/1000).toFixed(3)} seconds`].join(`
|
|
2
|
+
`)}class A{id;cwd;connection;clientCapabilities;options;agent=null;runtime=null;pendingPrompt=null;pendingUserShell=null;pendingResumeRequested=!1;availableCommandsTimer=null;taskStatusUnsubscribe;destroyed=!1;messages;mode;constructor(J,Z,Q,Y,H={}){this.id=J;this.cwd=Z;this.connection=Q;this.clientCapabilities=Y;this.options=H;this.messages=[...H.initialMessages??[]],this.mode=this.mapPermissionModeToMode(H.permissionMode)}mapPermissionModeToMode(J){switch(J){case"yolo":return"yolo";case"autoEdit":return"auto-edit";case"plan":return"plan";case"default":default:return"default"}}createAgent(){if(!this.runtime)throw Error("Session runtime is unavailable");return l.createWithRuntime(this.runtime,{sessionId:this.id,...this.options.taskWorktree?{toolBlacklist:["EnterWorktree","ExitWorktree"]}:{}})}async initialize(){if(j.debug(`[AcpSession ${this.id}] Initializing...`),await B.setSessionPermissionMode(this.id,this.cwd,this.mapModeToPermissionMode()??"default"),P.initializeSession(this.connection,this.id,this.clientCapabilities,this.cwd),j.debug(`[AcpSession ${this.id}] ACP service context initialized`),await v.resolvePendingWithHandler(this.cwd,this.id,{requestConfirmation:(z)=>this.requestPermission(z)}))this.messages=await B.loadSession(this.id,this.cwd);let Z=this.options.mcpServers?XJ(this.options.mcpServers):void 0,Q=P.getInstance().getTerminalService(this.id);if(this.runtime=await p.create({sessionId:this.id,workspaceRoot:this.cwd,permissionMode:this.mapModeToPermissionMode(),...Z?{mcpServers:Z}:{},...this.options.taskWorktree?{taskWorktree:this.options.taskWorktree}:{},...this.options.taskIsolation?{taskIsolation:this.options.taskIsolation}:{},userShellExecutor:{execute:async(z,$)=>{let G=await Q.execute(z,{cwd:$.cwd,env:$.env,timeout:$.timeoutMs,signal:$.signal,allowLocalFallback:!1,onOutput:(F)=>$.onOutput?.("stdout",F)});return{exitCode:G.exitCode,stdout:G.stdout,stderr:G.stderr,...G.error?{error:G.error}:{},timedOut:G.error==="Command timed out",aborted:G.error==="Command was aborted"}}},...(this.options.initialMessages?.length??0)>0?{sessionStart:{isResume:!0,resumeSessionId:this.id}}:{}}),await R.recoverInterrupted(this.cwd,this.id,this.runtime))this.messages=await B.loadSession(this.id,this.cwd);this.agent=await this.createAgent(),await r(this.cwd),j.debug(`[AcpSession ${this.id}] Agent created successfully`),this.taskStatusUnsubscribe?.(),this.taskStatusUnsubscribe=c.subscribe((z)=>{if(z.sessionId!==this.id||z.projectPath!==this.cwd)return;if(z.type==="task.delivery"){if(!z.properties.taskDelivery||typeof z.properties.taskDelivery!=="object")return;this.sendUpdate({sessionUpdate:"session_info_update",updatedAt:typeof z.properties.updatedAt==="string"?z.properties.updatedAt:new Date().toISOString(),_meta:{"blade/taskDelivery":z.properties.taskDelivery,...z.properties.taskWorktreeRemoved===!0?{"blade/taskWorktreeRemoved":!0}:{}}});return}if(z.type!=="task.status")return;this.sendUpdate({sessionUpdate:"session_info_update",updatedAt:typeof z.properties.updatedAt==="string"?z.properties.updatedAt:new Date().toISOString(),_meta:{"blade/taskStatus":z.properties.taskStatus,...typeof z.properties.taskStatusReason==="string"?{"blade/taskStatusReason":z.properties.taskStatusReason}:{},...z.properties.taskFailure&&typeof z.properties.taskFailure==="object"?{"blade/taskFailure":z.properties.taskFailure}:{},...typeof z.properties.taskStartedAt==="string"?{"blade/taskStartedAt":z.properties.taskStartedAt}:{},...typeof z.properties.taskCompletedAt==="string"?{"blade/taskCompletedAt":z.properties.taskCompletedAt}:{},...z.properties.taskDiffStat&&typeof z.properties.taskDiffStat==="object"?{"blade/taskDiffStat":z.properties.taskDiffStat}:{},...typeof z.properties.taskQueuePosition==="number"?{"blade/taskQueuePosition":z.properties.taskQueuePosition}:{},...typeof z.properties.taskQueueDepth==="number"?{"blade/taskQueueDepth":z.properties.taskQueueDepth}:{},...typeof z.properties.taskConcurrencyLimit==="number"?{"blade/taskConcurrencyLimit":z.properties.taskConcurrencyLimit}:{},...typeof z.properties.taskInFlight==="number"?{"blade/taskInFlight":z.properties.taskInFlight}:{}}})});let H=await this.runtime.getGoal();if(this.runtime.getPendingSteeringCount()>0||H?.status==="active")if(this.options.initialMessages===void 0)this.schedulePendingResume();else this.pendingResumeRequested=!0}async replayHistory(){for(let J of this.messages){if(!this.canSendUpdates())return;let Z=J.role==="user"?"user_message_chunk":J.role==="assistant"?"agent_message_chunk":void 0;if(!Z)continue;for(let Q of jJ(J)){if(!this.canSendUpdates())return;if(!await this.sendUpdateAndWait({sessionUpdate:Z,content:Q}))return}}if(this.pendingResumeRequested)this.schedulePendingResume()}sendAvailableCommandsDelayed(){if(this.destroyed||this.connection.signal.aborted)return;if(this.availableCommandsTimer!==null)clearTimeout(this.availableCommandsTimer);j.debug(`[AcpSession ${this.id}] Scheduling available commands update (500ms delay)`),this.availableCommandsTimer=setTimeout(()=>{if(this.availableCommandsTimer=null,this.destroyed||this.connection.signal.aborted)return;this.sendAvailableCommands()},500)}async handleSlashCommand(J,Z){try{j.debug(`[AcpSession ${this.id}] Executing slash command: ${J}`);let Q={cwd:this.cwd,surface:"acp",workspaceRoot:this.cwd,sessionId:this.id,messages:[...this.messages],rewind:{listCheckpoints:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.listRewindCheckpoints()},execute:async($)=>{if(!this.runtime)throw Error("Session runtime is unavailable");let G=await this.runtime.rewindSession($);return this.messages=[...G.messages],await this.agent?.destroy(),this.agent=await this.createAgent(),G}},reasoning:{get:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getReasoningConfiguration()},set:async($)=>{if(await this.setReasoningEffort($),!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getReasoningConfiguration()}},serviceTier:{get:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getServiceTierConfiguration()},set:async($)=>{if(await this.setServiceTier($),!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getServiceTierConfiguration()}},responseVerbosity:{get:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getResponseVerbosityConfiguration()},set:async($)=>{if(await this.setResponseVerbosity($),!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getResponseVerbosityConfiguration()}},communicationStyle:{get:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getCommunicationStyleConfiguration()},set:async($)=>{if(await this.setCommunicationStyle($),!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getCommunicationStyleConfiguration()}},subagents:{list:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.listSubagents()},resume:async($,G)=>{if(!this.runtime)throw Error("Session runtime is unavailable");let F=!1,X,L=(D)=>{this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:D.id,status:D.status==="completed"?"completed":"failed",content:[{type:"content",content:{type:"text",text:D.result?.message||D.result?.error||`Subagent ${D.status}`}}]})},W=this.runtime.resumeSubagent({agentId:$,prompt:G,onCompleted:(D)=>{if(F)L(D);else X=D}});if(this.sendUpdate({sessionUpdate:"tool_call",toolCallId:W.session.id,status:"in_progress",title:`Resuming ${W.session.subagentType} subagent`,content:[{type:"content",content:{type:"text",text:`Resumed from ${W.source.id} at depth ${W.session.resumeDepth}`}}],kind:this.mapToolKind("readonly")}),F=!0,X)L(X);return W}},mcp:{getCatalog:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getMcpContentCatalog()},refresh:async($)=>{if(!this.runtime)throw Error("Session runtime is unavailable");await this.runtime.refreshMcpContentCatalogs($)},getPrompt:async($,G,F)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getMcpPrompt($,G,F)},complete:async($,G,F)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.completeMcpArgument($,G,F)},listTasks:async($)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.listMcpTasks($)},getTask:async($)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getMcpTask($)},cancelTask:async($,G)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.cancelMcpTask($,G)},getLogs:async($,G)=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getMcpLogs($,G)},setLoggingLevel:async($,G)=>{if(!this.runtime)throw Error("Session runtime is unavailable");await this.runtime.setMcpLoggingLevel($,G)},getInstructions:async()=>{if(!this.runtime)throw Error("Session runtime is unavailable");return this.runtime.getMcpInstructions()}},codeReview:{run:async($,G)=>{if(!this.runtime)throw Error("Session runtime is unavailable");let F=await R.start({sessionId:this.id,projectPath:this.cwd,runtime:this.runtime,request:$,signal:G,onEvent:(W)=>{if(W.kind==="tool_start")this.sendUpdate({sessionUpdate:"tool_call",toolCallId:W.toolCall.id,status:"in_progress",title:`Review: ${W.toolCall.function.name}`,content:[],kind:this.mapToolKind(W.toolKind)});else if(W.kind==="tool_result")this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:W.toolCall.id,status:W.result.success?"completed":"failed",content:[]})}}),X=await F.completion,L=(await R.list(this.cwd,this.id)).find((W)=>W.start.reviewId===F.reviewId);if(!L)throw Error(`Review not found: ${F.reviewId}`);return this.messages=await B.loadSession(this.id,this.cwd),{reviewId:F.reviewId,status:X.status,findings:X.findings.length,content:C(L.start,X)}}},signal:Z,acp:{sendMessage:($)=>{this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:$}})},sendToolStart:($,G,F)=>{let X=`tool_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,L=this.mapToolKind(F);this.sendUpdate({sessionUpdate:"tool_call",toolCallId:X,status:"in_progress",title:`${$}`,content:[{type:"content",content:{type:"text",text:JSON.stringify(G,null,2)}}],kind:L})},sendToolResult:($,G)=>{if(G.summary)this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:G.summary}})}}},Y=await a(J,Q),H=Y.data?.action;if(H==="start_goal"||H==="resume_goal")this.schedulePendingResume();if(H==="rewind_session"&&Array.isArray(Y.data?.messages))this.messages=[...Y.data.messages];if((Y.message==="compact_completed"||Y.message==="compact_fallback")&&Y.data?.compactedMessages)this.messages=[...Y.data.compactedMessages];let z=Y.content||Y.message;if(z)this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:z}});if(Y.error)this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`[FAIL] ${Y.error}`}});return{stopReason:Y.success?"end_turn":"cancelled"}}catch(Q){return j.error(`[AcpSession ${this.id}] Slash command error:`,Q),this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`[FAIL] 命令执行失败: ${Q instanceof Error?Q.message:"未知错误"}`}}),{stopReason:"cancelled"}}}async sendAvailableCommands(){try{let J=n(this.cwd),Z=["model","permissions","theme","config","exit","ide"],Y=J.filter((H)=>!Z.includes(H.name)).map((H)=>{let z;if(H.usage){let $=H.usage.replace(/^\/\w+\s*/,"").trim();if($)z=$}if(H.aliases?.length){let $=`Aliases: ${H.aliases.join(", ")}`;z=z?`${z} | ${$}`:$}return{name:H.name,description:H.description,input:z?{hint:z}:void 0}});j.info(`[AcpSession ${this.id}] Sending available commands: ${JSON.stringify(Y.map((H)=>H.name))}`),this.sendUpdate({sessionUpdate:"available_commands_update",availableCommands:Y}),j.info(`[AcpSession ${this.id}] Sent ${Y.length} available commands`)}catch(J){j.error(`[AcpSession ${this.id}] Failed to send available commands:`,J)}}async prompt(J,Z={}){if(P.setCurrentSession(this.id),!this.agent||!this.runtime)throw Error("Session not initialized");let Q=this.resolvePrompt(J.prompt),Y=Q.content,H=Q.displayText,z=J._meta?.outputSchema??(Z.pendingInputOnly?this.runtime.getPendingSteeringMessages().find((F)=>F.outputSchema)?.outputSchema:void 0),$;if(z!==void 0)$=f(z).schema;if(H.trimStart().startsWith("!")){if($)throw Error("Output schemas cannot be combined with user shell commands");return this.handleUserShellCommand(H)}if(this.pendingPrompt){if($)throw Error("Wait for the active turn to finish before setting an output schema");if(/^\/goal(?:\s|$)/i.test(H.trim()))return this.handleSlashCommand(H,this.pendingPrompt.signal);let F=await this.runtime.enqueueSteering(Y,{allowBeforeTurn:!0});if(!F.accepted)throw Error(F.reason==="queue_full"?"Active turn steering queue is full":"Active turn is no longer steerable");if(j.debug(`[AcpSession ${this.id}] Queued steering for active turn (${F.queued})`),F.delivery==="next_turn")this.schedulePendingResume();return{stopReason:"end_turn"}}let G=new AbortController;this.pendingPrompt=G;try{if(j.debug(`[AcpSession ${this.id}] Received prompt: ${H.slice(0,100)}...`),i(H)){if($)throw Error("Output schemas cannot be combined with slash commands");return await this.handleSlashCommand(H,G.signal)}let F={sessionId:this.id,userId:"acp-user",workspaceRoot:this.cwd,messages:[...this.messages],signal:G.signal,permissionMode:this.mapModeToPermissionMode(),onPermissionModeChange:async(W)=>{this.mode=this.mapPermissionModeToMode(W),this.sendUpdate({sessionUpdate:"current_mode_update",currentModeId:this.mode})},...this.options.taskWorktree?{worktreeActive:!0}:{},confirmationHandler:{requestConfirmation:async(W)=>{return this.requestPermission(W)}}},X=await g(this.agent.chatStream(Y,F,{pendingInputOnly:Z.pendingInputOnly,goalContinuationOnly:Z.goalContinuationOnly,outputSchema:$}),async(W)=>{switch(W.kind){case"content_delta":if($)break;this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:W.delta}});break;case"thinking_delta":this.sendUpdate({sessionUpdate:"agent_thought_chunk",content:{type:"text",text:W.delta}});break;case"tool_start":{let D=W.toolCall,U=D.function.name;if(U===O)break;let _=this.mapToolKind(W.toolKind),V=`Executing ${U}`;if(U==="Task"&&"function"in D)try{let N=JSON.parse(D.function.arguments),w=N.resume_from??N.resume;if(typeof w==="string")V=`Resuming ${String(N.subagent_type||"subagent")} from ${w}`}catch{}this.sendUpdate({sessionUpdate:"tool_call",toolCallId:D.id,status:"in_progress",title:V,content:[],kind:_});break}case"tool_progress":{let D=W.toolCall;if(D.function.name===O)break;this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:D.id,status:"in_progress",content:[{type:"content",content:{type:"text",text:W.update.message}}]});break}case"tool_result":{let D=W.toolCall;if(D.function.name===O)break;let U=W.result,_=[],V=U.metadata;if(V?.kind==="patch"&&Array.isArray(V.changes))for(let w of V.changes){if(!w||typeof w!=="object"||!("path"in w)||typeof w.path!=="string")continue;_.push({type:"diff",path:w.path,oldText:"oldContent"in w&&typeof w.oldContent==="string"?w.oldContent:null,newText:"newContent"in w&&typeof w.newContent==="string"?w.newContent:null})}else if(V?.kind==="edit"&&typeof V.file_path==="string"&&typeof V.oldContent==="string"&&(typeof V.newContent==="string"||V.newContent===void 0))_.push({type:"diff",path:V.file_path,oldText:V.oldContent,newText:V.newContent??null});else{let w=D.function.name,YJ=d(m(w,U));_.push({type:"content",content:{type:"text",text:YJ}})}if(D.function.name==="Task"&&(V?.verificationVerdict==="pass"||V?.verificationVerdict==="fail"||V?.verificationVerdict==="partial"))_.unshift({type:"content",content:{type:"text",text:`Verification result: ${V.verificationVerdict.toUpperCase()}`}});let N=U.success?"completed":"failed";this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:D.id,status:N,content:_});break}case"structured_output":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:JSON.stringify(W.output)}});break;case"mcp_catalog_changed":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP catalog r${W.revision} (${W.serverName}): +${W.added.length} -${W.removed.length} ~${W.updated.length}
|
|
3
|
+
`}});break;case"mcp_content_changed":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP ${W.contentKind} r${W.revision} (${W.serverName}): +${W.added.length} -${W.removed.length} ~${W.updated.length}
|
|
4
|
+
`}});break;case"mcp_resource_updated":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP resource updated r${W.revision} (${W.serverName}): ${W.uri}
|
|
5
|
+
`}});break;case"mcp_connection_changed":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP connection r${W.revision} (${W.serverName}): ${W.phase} ${W.attempt}/${W.maxAttempts}
|
|
6
|
+
`}});break;case"mcp_log":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP log r${W.revision} (${W.serverName}) ${W.level}${W.logger?` logger=${W.logger}`:""}: ${W.message}
|
|
7
|
+
`}});break;case"mcp_instructions_changed":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP instructions r${W.revision} (${W.serverName}): ${W.action}${W.detailsOmitted?" details-omitted":""}
|
|
8
|
+
`}});break;case"mcp_task_changed":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`MCP task r${W.revision} ${W.taskId} (${W.serverName}/${W.toolName}): ${W.status}${W.hasResult?" result-available":""}
|
|
9
|
+
`}});break;case"project_rules_loaded":this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`Project rules loaded: ${W.files.length}${W.blockedWrite?" (write retry required)":""}
|
|
10
|
+
`}});break;case"provider_retry":this.sendUpdate({sessionUpdate:"session_info_update",updatedAt:new Date().toISOString(),_meta:{"blade/providerRetry":{phase:W.phase,attempt:W.attempt,maxRetries:W.maxRetries,reason:W.reason,...W.statusCode!==void 0?{statusCode:W.statusCode}:{},...W.delayMs!==void 0?{delayMs:W.delayMs}:{},...W.nextRetryAt!==void 0?{nextRetryAt:W.nextRetryAt}:{}}}});break;case"task_update":this.sendPlanUpdate(W.tasks);break;case"steering_applied":break;case"follow_up_started":for(let D of W.messages){if(!D.recovered||D.persisted)continue;for(let U of o(D.content))this.sendUpdate({sessionUpdate:"user_message_chunk",content:U})}if(W.recovered>0)this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`[Resuming ${W.recovered} queued instruction${W.recovered===1?"":"s"} recovered after restart]
|
|
11
|
+
`}});break;case"goal_updated":if(W.goal&&W.goal.status!=="active")this.sendUpdate({sessionUpdate:"agent_message_chunk",content:{type:"text",text:`[Goal ${W.goal.status}: ${W.goal.objective}]
|
|
12
|
+
`}});break;case"goal_continuation_started":break;default:break}});if(this.messages=[...F.messages],!X.success){let W=X.error?.type??"unknown";throw FJ.internalError({failureType:W},`Agent turn failed (${W})`)}if(G.signal.aborted)return{stopReason:"cancelled"};let L={...X.metadata?.structuredOutput?{structuredOutput:X.metadata.structuredOutput,outputSchemaDigest:X.metadata.structuredOutputSchemaDigest}:{},...X.metadata?.goalCompletionVerified?{goalCompletion:{verified:!0,verdict:X.metadata.goalVerificationVerdict,...X.metadata.goalVerifierSessionId?{verifierSessionId:X.metadata.goalVerifierSessionId}:{},...X.metadata.goalVerificationEvidenceSha256?{evidenceSha256:X.metadata.goalVerificationEvidenceSha256}:{}}}:{}};return{stopReason:"end_turn",...Object.keys(L).length>0?{_meta:L}:{}}}catch(F){if(G.signal.aborted||F instanceof Error&&F.name==="AbortError")return{stopReason:"cancelled"};throw j.error(`[AcpSession ${this.id}] Prompt error:`,F),F}finally{if(this.pendingPrompt===G){if(this.pendingPrompt=null,!this.destroyed&&this.pendingResumeRequested)this.schedulePendingResume()}}}async handleUserShellCommand(J){if(!this.runtime)throw Error("Session runtime is unavailable");if(this.pendingUserShell)throw Error("A user shell command is already running");let Z=J.trimStart().slice(1).trim();if(!Z)throw Error("User shell command cannot be empty");let Q=new AbortController;this.pendingUserShell=Q;let Y,H="";try{let z=await this.runtime.executeUserShellCommand(Z,{signal:Q.signal,onEvent:async($)=>{if(Y=$.executionId,$.type==="started"){this.sendUpdate({sessionUpdate:"tool_call",toolCallId:$.executionId,status:"in_progress",title:`! ${$.command}`,content:[],kind:"execute"});return}if($.type==="output"){H+=$.chunk,this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:$.executionId,status:"in_progress",content:[{type:"content",content:{type:"text",text:$.chunk}}]});return}let G=T($.record);this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:$.executionId,status:$.record.status==="completed"?"completed":"failed",content:[{type:"content",content:{type:"text",text:H?DJ($.record):G}}]})}});if(this.messages.push({role:"user",content:z.modelContent,metadata:{userShellCommand:JSON.parse(JSON.stringify(z.record))}}),z.delivery==="next_turn")this.schedulePendingResume();return{stopReason:z.record.status==="aborted"?"cancelled":"end_turn"}}catch(z){if(Y)this.sendUpdate({sessionUpdate:"tool_call_update",toolCallId:Y,status:"failed",content:[{type:"content",content:{type:"text",text:z instanceof Error?z.message:String(z)}}]});if(Q.signal.aborted)return{stopReason:"cancelled"};throw z}finally{if(this.pendingUserShell===Q)this.pendingUserShell=null}}schedulePendingResume(){if(this.destroyed||this.connection.signal.aborted)return;this.pendingResumeRequested=!0,queueMicrotask(()=>{this.resumePendingIfIdle()})}async resumePendingIfIdle(){if(this.destroyed||this.connection.signal.aborted)return;if(this.pendingPrompt||this.pendingUserShell||!this.runtime||!this.agent)return;let J=this.runtime.getPendingSteeringCount()>0,Q=(J?null:await this.runtime.getGoal())?.status==="active";if(!J&&!Q){this.pendingResumeRequested=!1;return}this.pendingResumeRequested=!1,await this.prompt({sessionId:this.id,prompt:[]},{pendingInputOnly:J,goalContinuationOnly:Q}).catch((Y)=>{j.error(`[AcpSession ${this.id}] Failed to resume pending input:`,Y)})}cancel(){j.info(`[AcpSession ${this.id}] Cancel requested`),this.pendingResumeRequested=!1;let J=!1;if(this.pendingPrompt)this.pendingPrompt.abort(),this.pendingPrompt=null,J=!0;if(this.pendingUserShell)this.pendingUserShell.abort(),this.pendingUserShell=null,J=!0;if(!J)j.warn(`[AcpSession ${this.id}] No pending prompt to cancel`)}async setMode(J){let Q=["default","auto-edit","yolo","plan"].includes(J)?J:"default",Y=this.mapModeIdToPermissionMode(Q);await B.setSessionPermissionMode(this.id,this.cwd,Y),this.mode=Q,j.info(`[AcpSession ${this.id}] Mode set to: ${this.mode}`),this.sendUpdate({sessionUpdate:"current_mode_update",currentModeId:this.mode})}mapModeToPermissionMode(){return this.mapModeIdToPermissionMode(this.mode)}mapModeIdToPermissionMode(J){switch(J){case"yolo":return"yolo";case"auto-edit":return"autoEdit";case"plan":return"plan";case"default":default:return"default"}}shouldAutoApprove(J){switch(this.mode){case"yolo":return!0;case"auto-edit":return J==="readonly"||J==="write";case"plan":return J==="readonly";case"default":default:return!1}}async setModel(J){if(j.info(`[AcpSession ${this.id}] Model set to: ${J}`),this.pendingPrompt)throw Error("Cannot switch models while a prompt is active");if(!this.agent)throw Error("Session not initialized");if(!this.runtime)throw Error("Session runtime is unavailable");let Z=this.runtime.getCurrentModelId();await this.agent.switchModel(J);try{try{await B.updateSessionMetadata(this.id,this.cwd,{selectedModelId:J})}catch(Q){if(!(Q instanceof q)&&Q.code!=="ENOENT")throw Q;await B.createSessionMetadata(this.id,this.cwd,{taskStatus:"completed",selectedModelId:J})}}catch(Q){if(Z&&Z!==J)await this.agent.switchModel(Z).catch((Y)=>{j.error(`[AcpSession ${this.id}] Failed to roll back a non-durable model switch:`,Y)});throw Q}}getCurrentModelId(){return this.runtime?.getCurrentModelId()}async setReasoningEffort(J){if(this.pendingPrompt)throw Error("Cannot switch reasoning effort while a prompt is active");if(!this.runtime)throw Error("Session runtime is unavailable");let Z=this.runtime.getReasoningConfiguration();try{this.runtime.resolveReasoningConfiguration(J)}catch(Q){throw Error(Q instanceof Error?Q.message:"Invalid reasoning effort")}if(Z.selection===J)return;await this.runtime.refresh({reasoningEffort:J});try{try{await B.updateSessionMetadata(this.id,this.cwd,{reasoningEffort:J})}catch(Q){if(!(Q instanceof q)&&Q.code!=="ENOENT")throw Q;await B.createSessionMetadata(this.id,this.cwd,{taskStatus:"completed",selectedModelId:this.runtime.getCurrentModelId(),reasoningEffort:J})}}catch(Q){throw await this.runtime.refresh({reasoningEffort:Z.selection}),Q}}async setServiceTier(J){if(this.pendingPrompt)throw Error("Cannot switch service tier while a prompt is active");if(!this.runtime)throw Error("Session runtime is unavailable");let Z=this.runtime.getServiceTierConfiguration();try{this.runtime.resolveServiceTierConfiguration(J)}catch(Q){throw Error(Q instanceof Error?Q.message:"Invalid service tier")}if(Z.selection===J)return;await this.runtime.refresh({serviceTier:J});try{try{await B.updateSessionMetadata(this.id,this.cwd,{serviceTier:J})}catch(Q){if(!(Q instanceof q)&&Q.code!=="ENOENT")throw Q;await B.createSessionMetadata(this.id,this.cwd,{taskStatus:"completed",selectedModelId:this.runtime.getCurrentModelId(),serviceTier:J})}}catch(Q){throw await this.runtime.refresh({serviceTier:Z.selection}),Q}}async setResponseVerbosity(J){if(this.pendingPrompt)throw Error("Cannot switch response verbosity while a prompt is active");if(!this.runtime)throw Error("Session runtime is unavailable");let Z=this.runtime.getResponseVerbosityConfiguration();try{this.runtime.resolveResponseVerbosityConfiguration(J)}catch(Q){throw Error(Q instanceof Error?Q.message:"Invalid response verbosity")}if(Z.selection===J)return;await this.runtime.refresh({responseVerbosity:J});try{try{await B.updateSessionMetadata(this.id,this.cwd,{responseVerbosity:J})}catch(Q){if(!(Q instanceof q)&&Q.code!=="ENOENT")throw Q;await B.createSessionMetadata(this.id,this.cwd,{taskStatus:"completed",selectedModelId:this.runtime.getCurrentModelId(),responseVerbosity:J})}}catch(Q){throw await this.runtime.refresh({responseVerbosity:Z.selection}),Q}}async setCommunicationStyle(J){if(this.pendingPrompt)throw Error("Cannot switch communication style while a prompt is active");if(!this.runtime)throw Error("Session runtime is unavailable");let Z=this.runtime.getCommunicationStyleConfiguration(),Q=this.runtime.resolveCommunicationStyleConfiguration(J);if(Q.source!=="built-in"&&!Q.contentSha256)throw Error("Custom communication style has no provenance");if(Z.selection===J)return;await this.runtime.refresh({communicationStyle:J});try{try{await B.updateSessionMetadata(this.id,this.cwd,{communicationStyle:J,communicationStyleDigest:Q.source==="built-in"?null:Q.contentSha256})}catch(Y){if(!(Y instanceof q)&&Y.code!=="ENOENT")throw Y;await B.createSessionMetadata(this.id,this.cwd,{taskStatus:"completed",selectedModelId:this.runtime.getCurrentModelId(),communicationStyle:J,...Q.source!=="built-in"&&Q.contentSha256?{communicationStyleDigest:Q.contentSha256}:{}})}}catch(Y){throw await this.runtime.refresh({communicationStyle:Z.selection}),Y}}getModelConfiguration(){if(!this.runtime)return;let J=this.runtime.getConfig();return{currentModelId:this.runtime.getCurrentModelId()??J.currentModelId,models:J.models.map((Z)=>structuredClone(Z)),modelProviders:structuredClone(J.modelProviders),reasoning:this.runtime.getReasoningConfiguration(),serviceTier:this.runtime.getServiceTierConfiguration(),responseVerbosity:this.runtime.getResponseVerbosityConfiguration(),communicationStyle:this.runtime.getCommunicationStyleConfiguration()}}getMode(){return this.mode}async destroy(){if(this.destroyed)return;if(this.destroyed=!0,this.availableCommandsTimer!==null)clearTimeout(this.availableCommandsTimer),this.availableCommandsTimer=null;this.taskStatusUnsubscribe?.(),this.taskStatusUnsubscribe=void 0;let J=this.agent,Z=this.runtime;this.agent=null,this.runtime=null;let Q,Y=async(H)=>{try{await H()}catch(z){Q??=z}};if(await Y(()=>this.cancel()),J)await Y(()=>J.destroy());if(Z)await Y(()=>Z.dispose());if(await Y(()=>P.destroySession(this.id)),j.debug(`[AcpSession ${this.id}] Destroyed`),Q!==void 0)throw Q}resolvePrompt(J){let Z=[],Q=[],Y=0,H=0,z=0,$=(F)=>{if(Q.length>0)Q.push({type:"text",text:`
|
|
13
|
+
`}),z+=1;if(Q.push(F),F.type==="text")z+=F.text.length};for(let F of J)if(F.type==="text")Z.push(F.text),$({type:"text",text:F.text});else if(F.type==="image"){let X=`data:${F.mimeType};base64,${F.data}`;Y+=1,H+=X.length,Z.push(`[Image: ${F.mimeType}]`),$({type:"image_url",image_url:{url:X}})}else if(F.type==="resource"){let X=F.resource;if("text"in X){let L=`<file path="${X.uri}">
|
|
14
14
|
${X.text}
|
|
15
|
-
</file>`;Z.push(L),$({type:"text",text:L})}}else if(F.type==="resource_link"){let X=`[Resource: ${F.uri}]`;Z.push(X),$({type:"text",text:X})}if(
|
|
16
|
-
`);return{content:
|
|
15
|
+
</file>`;Z.push(L),$({type:"text",text:L})}}else if(F.type==="resource_link"){let X=`[Resource: ${F.uri}]`;Z.push(X),$({type:"text",text:X})}if(Y>h)throw Error(`ACP prompt contains more than ${h} images`);if(H>S)throw Error("ACP prompt images exceed the 5 MiB limit");if(z>I)throw Error(`ACP prompt text exceeds ${I} characters`);let G=Z.join(`
|
|
16
|
+
`);return{content:Y>0?Q:G,displayText:G}}canSendUpdates(){return!this.destroyed&&!this.connection.signal.aborted}async sendUpdateAndWait(J){if(!this.canSendUpdates())return!1;return await this.connection.sessionUpdate({sessionId:this.id,update:J}),this.canSendUpdates()}sendUpdate(J){if(!this.canSendUpdates())return;let Z={sessionId:this.id,update:J};this.connection.sessionUpdate(Z).catch((Q)=>{j.warn(`[AcpSession ${this.id}] Failed to send update:`,Q)})}sendPlanUpdate(J){let Z=J.map((Q)=>({content:Q.subject,priority:Q.priority,status:Q.status}));j.debug(`[AcpSession ${this.id}] Sending plan update with ${Z.length} entries`),this.sendUpdate({sessionUpdate:"plan",entries:Z})}async requestPermission(J){let Z=this.pendingPrompt?.signal;if(J.type==="askUserQuestion")return this.requestUserQuestions(J,Z);if(J.type==="mcpElicitation")return this.requestMcpElicitation(J,Z);let Q=J.kind?.toLowerCase()||"execute";if(J.type!=="mcpSampling"&&this.shouldAutoApprove(Q))return j.debug(`[AcpSession ${this.id}] Auto-approving ${Q} in mode: ${this.mode}`),{approved:!0};if(this.mode==="plan"&&(Q==="write"||Q==="execute"))return j.debug(`[AcpSession ${this.id}] Rejecting ${Q} in plan mode`),{approved:!1,reason:"Write and execute operations are not allowed in Plan mode"};try{let Y=x(),H=[];if(J.message)H.push({type:"content",content:{type:"text",text:J.message}});if(J.details)H.push({type:"content",content:{type:"text",text:J.details}});if(J.risks&&J.risks.length>0)H.push({type:"content",content:{type:"text",text:`Risks:
|
|
17
17
|
- ${J.risks.join(`
|
|
18
|
-
- `)}`}});let z=this.mapToolKind(Q),$={sessionId:this.id,options:J.type==="mcpSampling"?[{optionId:"allow_once",name:"Allow this sampling request",kind:"allow_once"},{optionId:"reject_once",name:"Deny",kind:"reject_once"}]:[{optionId:"allow_once",name:"Allow once",kind:"allow_once"},{optionId:"allow_always",name:"Always allow",kind:"allow_always"},{optionId:"reject_once",name:"Deny once",kind:"reject_once"},{optionId:"reject_always",name:"Always deny",kind:"reject_always"}],toolCall:{toolCallId:
|
|
19
|
-
`)}}]}}),Z);if(!F)return{approved:!1,reason:y};if(F.outcome.outcome!=="selected")return{approved:!1,reason:"User cancelled the question prompt"};let X=$.indexOf(F.outcome.optionId);if(X<0)return{approved:!1,reason:"User cancelled the question prompt"};
|
|
20
|
-
`),[{id:"accept",label:"I will open this URL"},{id:"decline",label:"Decline"}],Z);if(H==="accept")return{approved:!0,elicitation:{action:"accept"}};return{approved:!1,reason:H==="decline"?"User declined URL":"User cancelled",elicitation:{action:H==="decline"?"decline":"cancel"}}}let
|
|
21
|
-
`),[...Q.map((z)=>({id:z.id,label:z.label})),...!J.required?[{id:"skip",label:"Skip"}]:[]],Z);if(
|
|
22
|
-
`),[{id:"default",label:"Use default"},...!J.required?[{id:"skip",label:"Skip"}]:[]],Z);if(Q==="default")return{cancelled:!1,value:J.defaultValue};if(Q==="skip")return{cancelled:!1};return{cancelled:!0,reason:"User cancelled MCP elicitation"}}if(!J.required)return{cancelled:!1};return{cancelled:!0,reason:`ACP cannot collect required ${J.type} field "${J.name}"`}}async requestElicitationChoice(J,Z,Q,W){let H=await this.waitForClientInteraction(this.connection.requestPermission({sessionId:this.id,options:[...Q.map((z)=>({optionId:z.id,name:z.label,kind:"allow_once"})),{optionId:"cancel",name:"Cancel",kind:"reject_once"}],toolCall:{toolCallId:x(),status:"pending",title:J,kind:"think",content:[{type:"content",content:{type:"text",text:Z}}]}}),W);return H?.outcome.outcome==="selected"?H.outcome.optionId:void 0}async waitForClientInteraction(J,Z){if(!Z)return J;if(Z.aborted)return;return new Promise((Q,W)=>{let H=!1,z=(G)=>{if(H)return;H=!0,Z.removeEventListener("abort",$),G()},$=()=>z(()=>Q(void 0));if(Z.addEventListener("abort",$,{once:!0}),Z.aborted)$();J.then((G)=>z(()=>Q(G)),(G)=>z(()=>W(G)))})}mapToolKind(J){return{readonly:"read",write:"edit",execute:"execute",read:"read",edit:"edit",delete:"delete",move:"move",search:"search",think:"think",fetch:"fetch"}[J||""]||"other"}}var K=E("Agent");class M{connection;sessions=new Map;sessionLoadQueues=new Map;clientCapabilities;destroyed=!1;constructor(J){this.connection=J}async initialize(J){return K.info("[BladeAgent] Initializing ACP connection"),K.debug(`[BladeAgent] Client capabilities: ${JSON.stringify(J.clientCapabilities)}`),this.clientCapabilities=J.clientCapabilities,{protocolVersion:LJ,agentCapabilities:{loadSession:!0,sessionCapabilities:{list:{},fork:{}},promptCapabilities:{image:!0,audio:!1,embeddedContext:!0},mcpCapabilities:{http:!0,sse:!0}}}}async authenticate(J){return}async newSession(J){this.assertNotDestroyed();let Z=QJ("acp"),Q=J.cwd||s(),W=J._meta?.["blade/taskIsolation"],H=W==="local"||W==="worktree"?W:void 0,z=J._meta?.["blade/taskPrompt"],$=H?await WJ.createSessionTask({sessionId:Z,prompt:typeof z==="string"&&z.trim()?z:"ACP task session",sourceProjectPath:Q,isolation:H}):void 0,G=$?.metadata.projectPath??Q;K.info(`[BladeAgent] Creating new session: ${Z}`),K.debug(`[BladeAgent] Session cwd: ${G}`);let F=new A(Z,G,this.connection,this.clientCapabilities,{mcpServers:J.mcpServers,...$?.taskWorktree?{taskWorktree:$.taskWorktree}:{},...$?.metadata.taskIsolation?{taskIsolation:$.metadata.taskIsolation}:{}});try{await F.initialize(),this.assertNotDestroyed()}catch(X){throw await F.destroy().catch(()=>{return}),X}return this.sessions.set(Z,F),K.info(`[BladeAgent] Session ${Z} created, scheduling available commands update`),F.sendAvailableCommandsDelayed(),this.buildChildSessionResponse(Z,$?.metadata,F.getModelConfiguration())}async listSessions(J){if(J.cwd!=null&&!t.isAbsolute(J.cwd))throw Error("ACP session list cwd must be absolute");let Z=await B.listSessionPage({cwd:J.cwd??void 0,cursor:J.cursor??void 0,limit:50,includeSubagents:!1});return{sessions:Z.sessions.map((Q)=>({sessionId:Q.sessionId,cwd:Q.projectPath,title:Q.title??null,updatedAt:Q.lastMessageTime,_meta:{"blade/taskStatus":Q.taskStatus,...Q.taskStatusReason?{"blade/taskStatusReason":Q.taskStatusReason}:{},...Q.taskFailure?{"blade/taskFailure":Q.taskFailure}:{},...Q.taskStartedAt?{"blade/taskStartedAt":Q.taskStartedAt}:{},...Q.taskCompletedAt?{"blade/taskCompletedAt":Q.taskCompletedAt}:{},...Q.taskModelId?{"blade/taskModelId":Q.taskModelId}:{},...Q.taskRetryAvailable?{"blade/taskRetryAvailable":!0}:{},...Q.taskRetriedFrom?{"blade/taskRetriedFrom":Q.taskRetriedFrom}:{},...Q.taskDelivery?{"blade/taskDelivery":Q.taskDelivery}:{},...Q.taskIsolation?{"blade/taskIsolation":Q.taskIsolation}:{},...Q.taskSourceProjectPath?{"blade/taskSourceProjectPath":Q.taskSourceProjectPath}:{},...Q.taskWorktreeBranch?{"blade/taskWorktreeBranch":Q.taskWorktreeBranch}:{},...Q.taskBaseCommit?{"blade/taskBaseCommit":Q.taskBaseCommit}:{},...Q.taskDiffStat?{"blade/taskDiffStat":Q.taskDiffStat}:{},...Q.taskQueuePosition?{"blade/taskQueuePosition":Q.taskQueuePosition}:{},...Q.taskQueueDepth!==void 0?{"blade/taskQueueDepth":Q.taskQueueDepth}:{},...Q.taskConcurrencyLimit!==void 0?{"blade/taskConcurrencyLimit":Q.taskConcurrencyLimit}:{}}})),nextCursor:Z.nextCursor}}async unstable_forkSession(J){if(this.assertNotDestroyed(),!t.isAbsolute(J.cwd))throw Error("ACP session fork cwd must be absolute");let Z=await B.forkSession(J.sessionId,{sourceProjectPath:J.cwd,targetProjectPath:J.cwd});this.assertNotDestroyed();let Q=new A(Z.sessionId,J.cwd,this.connection,this.clientCapabilities,{initialMessages:Z.messages,permissionMode:Z.metadata.permissionMode,mcpServers:J.mcpServers});try{await Q.initialize(),this.assertNotDestroyed()}catch(W){throw await Q.destroy().catch(()=>{return}),W}return this.sessions.set(Z.sessionId,Q),Q.sendAvailableCommandsDelayed(),this.buildChildSessionResponse(Z.sessionId,Z.metadata,Q.getModelConfiguration())}async loadSession(J){this.assertNotDestroyed(),K.info(`[BladeAgent] Loading session: ${J.sessionId}`);let Q=(this.sessionLoadQueues.get(J.sessionId)??Promise.resolve()).then(()=>this.replaceSession(J)),W=Q.then(()=>{return},()=>{return});this.sessionLoadQueues.set(J.sessionId,W);try{return await Q}finally{if(this.sessionLoadQueues.get(J.sessionId)===W)this.sessionLoadQueues.delete(J.sessionId)}}async replaceSession(J){this.assertNotDestroyed(),await B.assertSessionWritable(J.sessionId,J.cwd);let Z=this.sessions.get(J.sessionId);if(Z)try{await Z.destroy()}finally{if(this.sessions.get(J.sessionId)===Z)this.sessions.delete(J.sessionId)}let[Q,W]=await Promise.all([B.loadSession(J.sessionId,J.cwd),B.findSessionMetadata(J.sessionId,J.cwd)]);if(!W)throw Error(`Session not found: ${J.sessionId}`);let H=new A(J.sessionId,J.cwd,this.connection,this.clientCapabilities,{initialMessages:Q,permissionMode:W.permissionMode,mcpServers:J.mcpServers});try{await H.initialize(),await H.replayHistory(),this.assertNotDestroyed()}catch(z){throw await H.destroy().catch(()=>{return}),z}return this.sessions.set(J.sessionId,H),H.sendAvailableCommandsDelayed(),this.buildSessionSetup(H.getModelConfiguration(),H.getMode())}buildChildSessionResponse(J,Z,Q){return{sessionId:J,...this.buildSessionSetup(Q,Z?.permissionMode==="autoEdit"?"auto-edit":Z?.permissionMode),...Z?{_meta:{"blade/taskIsolation":Z.taskIsolation,"blade/taskSourceProjectPath":Z.taskSourceProjectPath,"blade/taskProjectPath":Z.projectPath,...Z.taskModelId?{"blade/taskModelId":Z.taskModelId}:{},...Z.taskRetryAvailable?{"blade/taskRetryAvailable":!0}:{},...Z.taskRetriedFrom?{"blade/taskRetriedFrom":Z.taskRetriedFrom}:{},...Z.taskDelivery?{"blade/taskDelivery":Z.taskDelivery}:{},...Z.taskWorktreeBranch?{"blade/taskWorktreeBranch":Z.taskWorktreeBranch}:{},...Z.taskBaseCommit?{"blade/taskBaseCommit":Z.taskBaseCommit}:{}}}:{}}}assertNotDestroyed(){if(this.destroyed)throw Error("BladeAgent is destroyed")}buildSessionSetup(J,Z="default"){let Q=J?.models??[],W=(J?.currentModelId&&Q.some(($)=>$.id===J.currentModelId)?J.currentModelId:void 0)??Q[0]?.id,H=[{id:"default",name:"Default",description:"Ask for confirmation before all file edits and commands"},{id:"auto-edit",name:"Auto Edit",description:"Auto-approve file edits, ask for shell commands"},{id:"yolo",name:"Full Auto",description:"Auto-approve everything without confirmation"},{id:"plan",name:"Plan Only",description:"Read-only mode, no file changes or commands"}],z=[];if(Q.length>0)z.push({type:"select",id:"model",name:"Model",description:"Active language model",category:"model",currentValue:W,options:Q.map(($)=>({value:$.id,name:$.displayName??$.model,description:`${J?.modelProviders[$.provider]?.name??$.provider} · ${$.model}`}))});if(J?.reasoning)z.push({type:"select",id:"reasoning_effort",name:"Reasoning effort",description:"Session-owned model reasoning intensity",category:"model",currentValue:J.reasoning.selection,options:[{value:"auto",name:"Auto",description:`Resolve near high for this model (currently ${J.reasoning.effective})`},...J.reasoning.supported.map(($)=>({value:$,name:$[0].toUpperCase()+$.slice(1),description:$==="off"?"Disable model reasoning":`Use ${$} reasoning effort`}))]});if(J?.serviceTier)z.push({type:"select",id:"service_tier",name:"Service tier",description:"Session-owned provider latency and pricing tier",category:"model",currentValue:J.serviceTier.selection,options:[{value:"auto",name:"Auto",description:"Use the provider or model default tier"},...J.serviceTier.supported.map(($)=>({value:$,name:$[0].toUpperCase()+$.slice(1),description:$==="fast"?"Use the provider priority tier":$==="flex"?"Use the lower-cost flexible tier":"Use the standard provider tier"}))]});if(J?.responseVerbosity)z.push({type:"select",id:"response_verbosity",name:"Response verbosity",description:"Session-owned model response detail",category:"model",currentValue:J.responseVerbosity.selection,options:[{value:"auto",name:"Auto",description:"Use the provider or model default verbosity"},...J.responseVerbosity.supported.map(($)=>({value:$,name:$[0].toUpperCase()+$.slice(1),description:`Use ${$} response verbosity`}))]});if(J?.communicationStyle)z.push({type:"select",id:"communication_style",name:"Communication style",description:"Session-owned tone and explanatory framing",category:"model",currentValue:J.communicationStyle.selection,options:J.communicationStyle.supported.map(($)=>({value:$.id,name:$.name,description:`${$.description} · ${$.source}`}))});return{modes:{availableModes:H,currentModeId:Z},configOptions:z.length>0?z:void 0}}async prompt(J){let Z=this.sessions.get(J.sessionId);if(!Z)throw Error(`Session not found: ${J.sessionId}`);return Z.prompt(J)}async cancel(J){K.info(`[BladeAgent] Cancel notification received for session: ${J.sessionId}`);let Z=this.sessions.get(J.sessionId);if(Z)K.info("[BladeAgent] Found session, calling session.cancel()"),Z.cancel();else K.warn(`[BladeAgent] Session not found for cancel: ${J.sessionId}`)}async setSessionMode(J){K.info(`[BladeAgent] Setting session mode: ${J.modeId}`);let Z=this.sessions.get(J.sessionId);if(Z)await Z.setMode(J.modeId);return{}}async setSessionConfigOption(J){let Z=this.sessions.get(J.sessionId);if(!Z)throw Error(`Session not found: ${J.sessionId}`);if(J.configId==="model"&&"value"in J&&typeof J.value==="string")K.info(`[BladeAgent] Setting session model: ${J.value}`),await Z.setModel(J.value);else if(J.configId==="reasoning_effort"&&"value"in J&&ZJ(J.value))K.info(`[BladeAgent] Setting reasoning effort: ${J.value}`),await Z.setReasoningEffort(J.value);else if(J.configId==="service_tier"&&"value"in J&&JJ(J.value))K.info(`[BladeAgent] Setting service tier: ${J.value}`),await Z.setServiceTier(J.value);else if(J.configId==="response_verbosity"&&"value"in J&&e(J.value))K.info(`[BladeAgent] Setting response verbosity: ${J.value}`),await Z.setResponseVerbosity(J.value);else if(J.configId==="communication_style"&&"value"in J&&$J(J.value))K.info(`[BladeAgent] Setting communication style: ${J.value}`),await Z.setCommunicationStyle(J.value);else throw Error(`Invalid session config option: ${J.configId}`);return{configOptions:this.buildSessionSetup(Z.getModelConfiguration(),Z.getMode()).configOptions??[]}}async destroy(){this.destroyed=!0,await Promise.all([...this.sessionLoadQueues.values()]),this.sessionLoadQueues.clear();let J;for(let Z of this.sessions.values())try{await Z.destroy()}catch(Q){J??=Q}this.sessions.clear();try{await zJ.getInstance().disconnectAll()}catch(Z){J??=Z}if(J!==void 0)throw J}}async function sJ(){let J=VJ.toWeb(process.stdout),Z=BJ.toWeb(process.stdin),Q=b.ndJsonStream(J,Z);await new b.AgentSideConnection((H)=>new M(H),Q).closed}export{sJ as runAcpIntegration};
|
|
18
|
+
- `)}`}});let z=this.mapToolKind(Q),$={sessionId:this.id,options:J.type==="mcpSampling"?[{optionId:"allow_once",name:"Allow this sampling request",kind:"allow_once"},{optionId:"reject_once",name:"Deny",kind:"reject_once"}]:[{optionId:"allow_once",name:"Allow once",kind:"allow_once"},{optionId:"allow_always",name:"Always allow",kind:"allow_always"},{optionId:"reject_once",name:"Deny once",kind:"reject_once"},{optionId:"reject_always",name:"Always deny",kind:"reject_always"}],toolCall:{toolCallId:Y,status:"pending",title:J.title||"Permission Required",content:H,kind:z}},G=await this.waitForClientInteraction(this.connection.requestPermission($),Z);if(!G)return{approved:!1,reason:y};let F=G.outcome;if(F.outcome==="cancelled")return{approved:!1,reason:"User cancelled the permission request"};let X=F.optionId;if(X==="allow_always")return{approved:!0,scope:"project"};if(X==="reject_always")return{approved:!1,scope:"project",reason:"User permanently denied the permission request"};let L=X==="allow_once";return{approved:L,scope:"once",reason:L?void 0:"User denied the operation"}}catch(Y){return j.warn(`[AcpSession ${this.id}] Permission request failed:`,Y),{approved:!1,reason:"Permission request failed"}}}async requestUserQuestions(J,Z){let Q=J.questions??[];if(Q.length===0)return{approved:!1,reason:"No structured questions were provided"};if(Q.some((H)=>H.multiSelect))return{approved:!1,reason:"ACP does not support multi-select question responses"};let Y={};try{for(let[H,z]of Q.entries()){let $=z.options.map((L,W)=>`answer:${H}:${W}`),G=`answer:${H}:cancel`,F=await this.waitForClientInteraction(this.connection.requestPermission({sessionId:this.id,options:[...z.options.map((L,W)=>({optionId:$[W],name:L.label,kind:"allow_once"})),{optionId:G,name:"Cancel",kind:"reject_once"}],toolCall:{toolCallId:x(),status:"pending",title:z.header,kind:"think",content:[{type:"content",content:{type:"text",text:[z.question,...z.options.map((L)=>`${L.label}: ${L.description}`)].join(`
|
|
19
|
+
`)}}]}}),Z);if(!F)return{approved:!1,reason:y};if(F.outcome.outcome!=="selected")return{approved:!1,reason:"User cancelled the question prompt"};let X=$.indexOf(F.outcome.optionId);if(X<0)return{approved:!1,reason:"User cancelled the question prompt"};Y[z.header]=z.options[X].label}return{approved:!0,answers:Y}}catch(H){return j.warn(`[AcpSession ${this.id}] Question request failed:`,H),{approved:!1,reason:"Question request failed"}}}async requestMcpElicitation(J,Z){let Q=J.mcpElicitation;if(!Q)return{approved:!1,reason:"MCP elicitation details are missing",elicitation:{action:"cancel"}};try{if(Q.mode==="url"){let H=await this.requestElicitationChoice("MCP external authorization",[Q.message,`Server: ${Q.serverName}`,`Domain: ${Q.domain??"unknown"}`,`URL: ${Q.url??""}`,"Open this URL yourself only if you trust the MCP server."].join(`
|
|
20
|
+
`),[{id:"accept",label:"I will open this URL"},{id:"decline",label:"Decline"}],Z);if(H==="accept")return{approved:!0,elicitation:{action:"accept"}};return{approved:!1,reason:H==="decline"?"User declined URL":"User cancelled",elicitation:{action:H==="decline"?"decline":"cancel"}}}let Y=Object.create(null);for(let H of Q.fields??[]){let z=await this.collectAcpElicitationField(H,Z);if(z.cancelled)return{approved:!1,reason:z.reason,elicitation:{action:"cancel"}};if(z.value!==void 0)Y[H.name]=z.value}return{approved:!0,elicitation:{action:"accept",content:Y}}}catch(Y){return j.warn(`[AcpSession ${this.id}] MCP elicitation failed:`,Y),{approved:!1,reason:"MCP elicitation failed",elicitation:{action:"cancel"}}}}async collectAcpElicitationField(J,Z){if(J.type==="select"||J.type==="boolean"){let Q=J.type==="boolean"?[{id:"true",label:"Yes",value:!0},{id:"false",label:"No",value:!1}]:(J.options??[]).map((z,$)=>({id:`option:${$}`,label:z.label,value:z.value})),Y=await this.requestElicitationChoice(J.title,[J.description,J.required?"Required":"Optional"].filter(Boolean).join(`
|
|
21
|
+
`),[...Q.map((z)=>({id:z.id,label:z.label})),...!J.required?[{id:"skip",label:"Skip"}]:[]],Z);if(Y==="skip")return{cancelled:!1};let H=Q.find((z)=>z.id===Y);if(!H)return{cancelled:!0,reason:"User cancelled MCP elicitation"};return{cancelled:!1,value:H.value}}if(J.defaultValue!==void 0){let Q=await this.requestElicitationChoice(J.title,[J.description,`ACP cannot collect ${J.type} input. Use the server default: ${String(J.defaultValue)}?`].filter(Boolean).join(`
|
|
22
|
+
`),[{id:"default",label:"Use default"},...!J.required?[{id:"skip",label:"Skip"}]:[]],Z);if(Q==="default")return{cancelled:!1,value:J.defaultValue};if(Q==="skip")return{cancelled:!1};return{cancelled:!0,reason:"User cancelled MCP elicitation"}}if(!J.required)return{cancelled:!1};return{cancelled:!0,reason:`ACP cannot collect required ${J.type} field "${J.name}"`}}async requestElicitationChoice(J,Z,Q,Y){let H=await this.waitForClientInteraction(this.connection.requestPermission({sessionId:this.id,options:[...Q.map((z)=>({optionId:z.id,name:z.label,kind:"allow_once"})),{optionId:"cancel",name:"Cancel",kind:"reject_once"}],toolCall:{toolCallId:x(),status:"pending",title:J,kind:"think",content:[{type:"content",content:{type:"text",text:Z}}]}}),Y);return H?.outcome.outcome==="selected"?H.outcome.optionId:void 0}async waitForClientInteraction(J,Z){if(!Z)return J;if(Z.aborted)return;return new Promise((Q,Y)=>{let H=!1,z=(G)=>{if(H)return;H=!0,Z.removeEventListener("abort",$),G()},$=()=>z(()=>Q(void 0));if(Z.addEventListener("abort",$,{once:!0}),Z.aborted)$();J.then((G)=>z(()=>Q(G)),(G)=>z(()=>Y(G)))})}mapToolKind(J){return{readonly:"read",write:"edit",execute:"execute",read:"read",edit:"edit",delete:"delete",move:"move",search:"search",think:"think",fetch:"fetch"}[J||""]||"other"}}var K=E("Agent");class M{connection;sessions=new Map;sessionLoadQueues=new Map;clientCapabilities;destroyed=!1;constructor(J){this.connection=J}async initialize(J){return K.info("[BladeAgent] Initializing ACP connection"),K.debug(`[BladeAgent] Client capabilities: ${JSON.stringify(J.clientCapabilities)}`),this.clientCapabilities=J.clientCapabilities,{protocolVersion:LJ,agentCapabilities:{loadSession:!0,sessionCapabilities:{list:{},fork:{}},promptCapabilities:{image:!0,audio:!1,embeddedContext:!0},mcpCapabilities:{http:!0,sse:!0}}}}async authenticate(J){return}async newSession(J){this.assertNotDestroyed();let Z=QJ("acp"),Q=J.cwd||s(),Y=J._meta?.["blade/taskIsolation"],H=Y==="local"||Y==="worktree"?Y:void 0,z=J._meta?.["blade/taskPrompt"],$=H?await WJ.createSessionTask({sessionId:Z,prompt:typeof z==="string"&&z.trim()?z:"ACP task session",sourceProjectPath:Q,isolation:H}):void 0,G=$?.metadata.projectPath??Q;K.info(`[BladeAgent] Creating new session: ${Z}`),K.debug(`[BladeAgent] Session cwd: ${G}`);let F=new A(Z,G,this.connection,this.clientCapabilities,{mcpServers:J.mcpServers,...$?.taskWorktree?{taskWorktree:$.taskWorktree}:{},...$?.metadata.taskIsolation?{taskIsolation:$.metadata.taskIsolation}:{}});try{await F.initialize(),this.assertNotDestroyed()}catch(X){throw await F.destroy().catch(()=>{return}),X}return this.sessions.set(Z,F),K.info(`[BladeAgent] Session ${Z} created, scheduling available commands update`),F.sendAvailableCommandsDelayed(),this.buildChildSessionResponse(Z,$?.metadata,F.getModelConfiguration())}async listSessions(J){if(J.cwd!=null&&!t.isAbsolute(J.cwd))throw Error("ACP session list cwd must be absolute");let Z=await B.listSessionPage({cwd:J.cwd??void 0,cursor:J.cursor??void 0,limit:50,includeSubagents:!1});return{sessions:Z.sessions.map((Q)=>({sessionId:Q.sessionId,cwd:Q.projectPath,title:Q.title??null,updatedAt:Q.lastMessageTime,_meta:{"blade/taskStatus":Q.taskStatus,...Q.taskStatusReason?{"blade/taskStatusReason":Q.taskStatusReason}:{},...Q.taskFailure?{"blade/taskFailure":Q.taskFailure}:{},...Q.taskStartedAt?{"blade/taskStartedAt":Q.taskStartedAt}:{},...Q.taskCompletedAt?{"blade/taskCompletedAt":Q.taskCompletedAt}:{},...Q.taskModelId?{"blade/taskModelId":Q.taskModelId}:{},...Q.taskRetryAvailable?{"blade/taskRetryAvailable":!0}:{},...Q.taskRetriedFrom?{"blade/taskRetriedFrom":Q.taskRetriedFrom}:{},...Q.taskDelivery?{"blade/taskDelivery":Q.taskDelivery}:{},...Q.taskIsolation?{"blade/taskIsolation":Q.taskIsolation}:{},...Q.taskSourceProjectPath?{"blade/taskSourceProjectPath":Q.taskSourceProjectPath}:{},...Q.taskWorktreeBranch?{"blade/taskWorktreeBranch":Q.taskWorktreeBranch}:{},...Q.taskBaseCommit?{"blade/taskBaseCommit":Q.taskBaseCommit}:{},...Q.taskDiffStat?{"blade/taskDiffStat":Q.taskDiffStat}:{},...Q.taskQueuePosition?{"blade/taskQueuePosition":Q.taskQueuePosition}:{},...Q.taskQueueDepth!==void 0?{"blade/taskQueueDepth":Q.taskQueueDepth}:{},...Q.taskConcurrencyLimit!==void 0?{"blade/taskConcurrencyLimit":Q.taskConcurrencyLimit}:{}}})),nextCursor:Z.nextCursor}}async unstable_forkSession(J){if(this.assertNotDestroyed(),!t.isAbsolute(J.cwd))throw Error("ACP session fork cwd must be absolute");let Z=await B.forkSession(J.sessionId,{sourceProjectPath:J.cwd,targetProjectPath:J.cwd});this.assertNotDestroyed();let Q=new A(Z.sessionId,J.cwd,this.connection,this.clientCapabilities,{initialMessages:Z.messages,permissionMode:Z.metadata.permissionMode,mcpServers:J.mcpServers});try{await Q.initialize(),this.assertNotDestroyed()}catch(Y){throw await Q.destroy().catch(()=>{return}),Y}return this.sessions.set(Z.sessionId,Q),Q.sendAvailableCommandsDelayed(),this.buildChildSessionResponse(Z.sessionId,Z.metadata,Q.getModelConfiguration())}async loadSession(J){this.assertNotDestroyed(),K.info(`[BladeAgent] Loading session: ${J.sessionId}`);let Q=(this.sessionLoadQueues.get(J.sessionId)??Promise.resolve()).then(()=>this.replaceSession(J)),Y=Q.then(()=>{return},()=>{return});this.sessionLoadQueues.set(J.sessionId,Y);try{return await Q}finally{if(this.sessionLoadQueues.get(J.sessionId)===Y)this.sessionLoadQueues.delete(J.sessionId)}}async replaceSession(J){this.assertNotDestroyed(),await B.assertSessionWritable(J.sessionId,J.cwd);let Z=this.sessions.get(J.sessionId);if(Z)try{await Z.destroy()}finally{if(this.sessions.get(J.sessionId)===Z)this.sessions.delete(J.sessionId)}let[Q,Y]=await Promise.all([B.loadSession(J.sessionId,J.cwd),B.findSessionMetadata(J.sessionId,J.cwd)]);if(!Y)throw Error(`Session not found: ${J.sessionId}`);let H=new A(J.sessionId,J.cwd,this.connection,this.clientCapabilities,{initialMessages:Q,permissionMode:Y.permissionMode,mcpServers:J.mcpServers});try{await H.initialize(),await H.replayHistory(),this.assertNotDestroyed()}catch(z){throw await H.destroy().catch(()=>{return}),z}return this.sessions.set(J.sessionId,H),H.sendAvailableCommandsDelayed(),this.buildSessionSetup(H.getModelConfiguration(),H.getMode())}buildChildSessionResponse(J,Z,Q){return{sessionId:J,...this.buildSessionSetup(Q,Z?.permissionMode==="autoEdit"?"auto-edit":Z?.permissionMode),...Z?{_meta:{"blade/taskIsolation":Z.taskIsolation,"blade/taskSourceProjectPath":Z.taskSourceProjectPath,"blade/taskProjectPath":Z.projectPath,...Z.taskModelId?{"blade/taskModelId":Z.taskModelId}:{},...Z.taskRetryAvailable?{"blade/taskRetryAvailable":!0}:{},...Z.taskRetriedFrom?{"blade/taskRetriedFrom":Z.taskRetriedFrom}:{},...Z.taskDelivery?{"blade/taskDelivery":Z.taskDelivery}:{},...Z.taskWorktreeBranch?{"blade/taskWorktreeBranch":Z.taskWorktreeBranch}:{},...Z.taskBaseCommit?{"blade/taskBaseCommit":Z.taskBaseCommit}:{}}}:{}}}assertNotDestroyed(){if(this.destroyed)throw Error("BladeAgent is destroyed")}buildSessionSetup(J,Z="default"){let Q=J?.models??[],Y=(J?.currentModelId&&Q.some(($)=>$.id===J.currentModelId)?J.currentModelId:void 0)??Q[0]?.id,H=[{id:"default",name:"Default",description:"Ask for confirmation before all file edits and commands"},{id:"auto-edit",name:"Auto Edit",description:"Auto-approve file edits, ask for shell commands"},{id:"yolo",name:"Full Auto",description:"Auto-approve everything without confirmation"},{id:"plan",name:"Plan Only",description:"Read-only mode, no file changes or commands"}],z=[];if(Q.length>0)z.push({type:"select",id:"model",name:"Model",description:"Active language model",category:"model",currentValue:Y,options:Q.map(($)=>({value:$.id,name:$.displayName??$.model,description:`${J?.modelProviders[$.provider]?.name??$.provider} · ${$.model}`}))});if(J?.reasoning)z.push({type:"select",id:"reasoning_effort",name:"Reasoning effort",description:"Session-owned model reasoning intensity",category:"model",currentValue:J.reasoning.selection,options:[{value:"auto",name:"Auto",description:`Resolve near high for this model (currently ${J.reasoning.effective})`},...J.reasoning.supported.map(($)=>({value:$,name:$[0].toUpperCase()+$.slice(1),description:$==="off"?"Disable model reasoning":`Use ${$} reasoning effort`}))]});if(J?.serviceTier)z.push({type:"select",id:"service_tier",name:"Service tier",description:"Session-owned provider latency and pricing tier",category:"model",currentValue:J.serviceTier.selection,options:[{value:"auto",name:"Auto",description:"Use the provider or model default tier"},...J.serviceTier.supported.map(($)=>({value:$,name:$[0].toUpperCase()+$.slice(1),description:$==="fast"?"Use the provider priority tier":$==="flex"?"Use the lower-cost flexible tier":"Use the standard provider tier"}))]});if(J?.responseVerbosity)z.push({type:"select",id:"response_verbosity",name:"Response verbosity",description:"Session-owned model response detail",category:"model",currentValue:J.responseVerbosity.selection,options:[{value:"auto",name:"Auto",description:"Use the provider or model default verbosity"},...J.responseVerbosity.supported.map(($)=>({value:$,name:$[0].toUpperCase()+$.slice(1),description:`Use ${$} response verbosity`}))]});if(J?.communicationStyle)z.push({type:"select",id:"communication_style",name:"Communication style",description:"Session-owned tone and explanatory framing",category:"model",currentValue:J.communicationStyle.selection,options:J.communicationStyle.supported.map(($)=>({value:$.id,name:$.name,description:`${$.description} · ${$.source}`}))});return{modes:{availableModes:H,currentModeId:Z},configOptions:z.length>0?z:void 0}}async prompt(J){let Z=this.sessions.get(J.sessionId);if(!Z)throw Error(`Session not found: ${J.sessionId}`);return Z.prompt(J)}async cancel(J){K.info(`[BladeAgent] Cancel notification received for session: ${J.sessionId}`);let Z=this.sessions.get(J.sessionId);if(Z)K.info("[BladeAgent] Found session, calling session.cancel()"),Z.cancel();else K.warn(`[BladeAgent] Session not found for cancel: ${J.sessionId}`)}async setSessionMode(J){K.info(`[BladeAgent] Setting session mode: ${J.modeId}`);let Z=this.sessions.get(J.sessionId);if(Z)await Z.setMode(J.modeId);return{}}async setSessionConfigOption(J){let Z=this.sessions.get(J.sessionId);if(!Z)throw Error(`Session not found: ${J.sessionId}`);if(J.configId==="model"&&"value"in J&&typeof J.value==="string")K.info(`[BladeAgent] Setting session model: ${J.value}`),await Z.setModel(J.value);else if(J.configId==="reasoning_effort"&&"value"in J&&ZJ(J.value))K.info(`[BladeAgent] Setting reasoning effort: ${J.value}`),await Z.setReasoningEffort(J.value);else if(J.configId==="service_tier"&&"value"in J&&JJ(J.value))K.info(`[BladeAgent] Setting service tier: ${J.value}`),await Z.setServiceTier(J.value);else if(J.configId==="response_verbosity"&&"value"in J&&e(J.value))K.info(`[BladeAgent] Setting response verbosity: ${J.value}`),await Z.setResponseVerbosity(J.value);else if(J.configId==="communication_style"&&"value"in J&&$J(J.value))K.info(`[BladeAgent] Setting communication style: ${J.value}`),await Z.setCommunicationStyle(J.value);else throw Error(`Invalid session config option: ${J.configId}`);return{configOptions:this.buildSessionSetup(Z.getModelConfiguration(),Z.getMode()).configOptions??[]}}async destroy(){this.destroyed=!0,await Promise.all([...this.sessionLoadQueues.values()]),this.sessionLoadQueues.clear();let J;for(let Z of this.sessions.values())try{await Z.destroy()}catch(Q){J??=Q}this.sessions.clear();try{await zJ.getInstance().disconnectAll()}catch(Z){J??=Z}if(J!==void 0)throw J}}async function sJ(){let J=VJ.toWeb(process.stdout),Z=BJ.toWeb(process.stdin),Q=b.ndJsonStream(J,Z);await new b.AgentSideConnection((H)=>new M(H),Q).closed}export{sJ as runAcpIntegration};
|