@blade-ai/agent-sdk 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/dist/index.js +212 -206
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,13 +1,19 @@
1
- import{createRequire as i5}from"node:module";var d5=Object.create;var{getPrototypeOf:m5,defineProperty:S4,getOwnPropertyNames:g5}=Object;var c5=Object.prototype.hasOwnProperty;var Q1=($,W,Q)=>{Q=$!=null?d5(m5($)):{};let Z=W||!$||!$.__esModule?S4(Q,"default",{value:$,enumerable:!0}):Q;for(let V of g5($))if(!c5.call(Z,V))S4(Z,V,{get:()=>$[V],enumerable:!0});return Z};var j0=i5(import.meta.url);import{nanoid as wW}from"nanoid";import*as T5 from"os";import*as P5 from"path";import{nanoid as w0}from"nanoid";var G$;((Y)=>{Y.DEFAULT="default";Y.AUTO_EDIT="autoEdit";Y.YOLO="yolo";Y.BYPASSALL="bypassAll";Y.PLAN="plan";Y.SPEC="spec"})(G$||={});import{nanoid as F$}from"nanoid";var g1={enabled:!1,defaultTimeout:60,timeoutBehavior:"ignore",failureBehavior:"ignore",maxConcurrentHooks:5,PreToolUse:[],PostToolUse:[],PostToolUseFailure:[],PermissionRequest:[],UserPromptSubmit:[],SessionStart:[],SessionEnd:[],Stop:[],SubagentStop:[],Notification:[],Compaction:[]};function c1($,W){return{...$,...W,PreToolUse:W.PreToolUse??$.PreToolUse,PostToolUse:W.PostToolUse??$.PostToolUse,PostToolUseFailure:W.PostToolUseFailure??$.PostToolUseFailure,PermissionRequest:W.PermissionRequest??$.PermissionRequest,UserPromptSubmit:W.UserPromptSubmit??$.UserPromptSubmit,SessionStart:W.SessionStart??$.SessionStart,SessionEnd:W.SessionEnd??$.SessionEnd,Stop:W.Stop??$.Stop,SubagentStop:W.SubagentStop??$.SubagentStop,Notification:W.Notification??$.Notification,Compaction:W.Compaction??$.Compaction}}function v4(){let $={};if(process.env.BLADE_DISABLE_HOOKS==="true")$.enabled=!1;if(process.env.BLADE_HOOK_TIMEOUT){let W=parseInt(process.env.BLADE_HOOK_TIMEOUT,10);if(!isNaN(W)&&W>0)$.defaultTimeout=W}return $}class i1{executedHooks=new Map;canExecute($,W){if(!this.executedHooks.has($))this.executedHooks.set($,new Set);if(this.executedHooks.get($).has(W))return console.warn(`[HookGuard] Hook ${W} for tool ${$} already executed, skipping`),!1;return!0}markExecuted($,W){let Q=this.executedHooks.get($);if(Q)Q.add(W)}cleanup($){this.executedHooks.delete($)}cleanupAll(){this.executedHooks.clear()}}import{z as H}from"zod";var Z1;((q)=>{q.PreToolUse="PreToolUse";q.PostToolUse="PostToolUse";q.PostToolUseFailure="PostToolUseFailure";q.PermissionRequest="PermissionRequest";q.UserPromptSubmit="UserPromptSubmit";q.SessionStart="SessionStart";q.SessionEnd="SessionEnd";q.Stop="Stop";q.SubagentStop="SubagentStop";q.Notification="Notification";q.Compaction="Compaction"})(Z1||={});var l1;((Z)=>{Z.Approve="approve";Z.Block="block";Z.Async="async"})(l1||={});var n1;((Z)=>{Z.Allow="allow";Z.Deny="deny";Z.Ask="ask"})(n1||={});var b$=H.object({hook_event_name:H.nativeEnum(Z1),hook_execution_id:H.string(),timestamp:H.string(),project_dir:H.string(),session_id:H.string(),permission_mode:H.enum(["default","autoEdit","yolo","plan"]),_metadata:H.object({blade_version:H.string(),hook_timeout_ms:H.number()}).optional()}),n5=b$.extend({hook_event_name:H.literal("PreToolUse"),tool_name:H.string(),tool_use_id:H.string(),tool_input:H.record(H.unknown())}),a5=b$.extend({hook_event_name:H.literal("PostToolUse"),tool_name:H.string(),tool_use_id:H.string(),tool_input:H.record(H.unknown()),tool_response:H.unknown()}),r5=b$.extend({hook_event_name:H.literal("Stop"),reason:H.string().optional()}),s5=b$.extend({hook_event_name:H.literal("PostToolUseFailure"),tool_name:H.string(),tool_use_id:H.string(),tool_input:H.record(H.unknown()),error:H.string(),error_type:H.string().optional(),is_interrupt:H.boolean(),is_timeout:H.boolean()}),o5=b$.extend({hook_event_name:H.literal("PermissionRequest"),tool_name:H.string(),tool_use_id:H.string(),tool_input:H.record(H.unknown())}),t5=b$.extend({hook_event_name:H.literal("UserPromptSubmit"),user_prompt:H.string(),has_images:H.boolean(),image_count:H.number()}),e5=b$.extend({hook_event_name:H.literal("SessionStart"),is_resume:H.boolean(),resume_session_id:H.string().optional()}),$7=b$.extend({hook_event_name:H.literal("SessionEnd"),reason:H.enum(["user_exit","error","max_turns","idle_timeout","ctrl_c","clear","logout","other"])}),W7=b$.extend({hook_event_name:H.literal("SubagentStop"),agent_type:H.string(),task_description:H.string().optional(),success:H.boolean(),result_summary:H.string().optional(),error:H.string().optional()}),Q7=b$.extend({hook_event_name:H.literal("Notification"),notification_type:H.enum(["permission_prompt","idle_prompt","auth_success","elicitation_dialog","info","warning","error"]),title:H.string().optional(),message:H.string()}),Z7=b$.extend({hook_event_name:H.literal("Compaction"),trigger:H.enum(["manual","auto"]),messages_before:H.number(),tokens_before:H.number()}),EW=H.discriminatedUnion("hook_event_name",[n5,a5,r5,s5,o5,t5,e5,$7,W7,Q7,Z7]),V7=H.object({hookEventName:H.literal("PreToolUse"),permissionDecision:H.nativeEnum(n1).optional(),permissionDecisionReason:H.string().optional(),updatedInput:H.record(H.unknown()).optional()}),X7=H.object({hookEventName:H.literal("PostToolUse"),additionalContext:H.string().optional(),updatedOutput:H.unknown().optional()}),Y7=H.object({hookEventName:H.literal("Stop"),continue:H.boolean().optional(),continueReason:H.string().optional()}),J7=H.object({hookEventName:H.literal("SubagentStop"),continue:H.boolean().optional(),continueReason:H.string().optional(),additionalContext:H.string().optional()}),G7=H.object({hookEventName:H.literal("PermissionRequest"),permissionDecision:H.enum(["approve","deny","ask"]).optional(),permissionDecisionReason:H.string().optional()}),B7=H.object({hookEventName:H.literal("UserPromptSubmit"),updatedPrompt:H.string().optional(),contextInjection:H.string().optional()}),K7=H.object({hookEventName:H.literal("SessionStart"),env:H.record(H.string()).optional()}),q7=H.object({hookEventName:H.literal("Compaction"),blockCompaction:H.boolean().optional(),blockReason:H.string().optional()}),w7=H.object({decision:H.object({behavior:H.nativeEnum(l1)}).optional(),systemMessage:H.string().optional(),hookSpecificOutput:H.discriminatedUnion("hookEventName",[V7,X7,Y7,J7,G7,B7,K7,q7]).optional(),suppressOutput:H.boolean().optional()}),O7=H.object({type:H.literal("command"),command:H.string(),timeout:H.number().positive().optional(),statusMessage:H.string().optional()}),U7=H.object({type:H.literal("prompt"),prompt:H.string(),timeout:H.number().positive().optional()}),H7=H.discriminatedUnion("type",[O7,U7]),a1=H.union([H.string(),H.array(H.string())]),b7=H.object({tools:a1.optional(),paths:a1.optional(),commands:a1.optional()}),H$=H.object({name:H.string().optional(),matcher:b7.optional(),hooks:H.array(H7)}),CW=H.object({enabled:H.boolean().optional(),defaultTimeout:H.number().positive().optional(),timeoutBehavior:H.enum(["ignore","deny","ask"]).optional(),failureBehavior:H.enum(["ignore","deny","ask"]).optional(),maxConcurrentHooks:H.number().positive().optional(),PreToolUse:H.array(H$).optional(),PostToolUse:H.array(H$).optional(),PostToolUseFailure:H.array(H$).optional(),PermissionRequest:H.array(H$).optional(),UserPromptSubmit:H.array(H$).optional(),SessionStart:H.array(H$).optional(),SessionEnd:H.array(H$).optional(),Stop:H.array(H$).optional(),SubagentStop:H.array(H$).optional(),Notification:H.array(H$).optional(),Compaction:H.array(H$).optional()});function y4($){let W=w7.safeParse($);if(W.success)return{success:!0,data:W.data};return{success:!1,error:W.error}}class r1{parse($,W,Q){if($.timedOut){let V=Q?.timeoutBehavior||"ignore",X="Hook timeout";if(V==="deny")return{success:!1,blocking:!0,error:"Hook timeout",stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};else if(V==="ask")return{success:!1,blocking:!1,needsConfirmation:!0,warning:"Hook timeout. Continue?",stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};else return{success:!1,blocking:!1,warning:"Hook timeout",stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W}}let Z=this.tryParseJSON($.stdout);if(Z){let V=y4(Z);if(!V.success){let Y="error"in V?V.error.message:"Unknown validation error",J=Q?.failureBehavior||"ignore",G=`Invalid hook output JSON: ${Y}`;if(J==="deny")return{success:!1,blocking:!0,error:G,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};else if(J==="ask")return{success:!1,blocking:!1,needsConfirmation:!0,warning:`${G}. Continue?`,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};else return{success:!1,blocking:!1,warning:G,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W}}let X=V.data;if(X.decision?.behavior==="block")return{success:!1,blocking:!0,error:X.systemMessage||"Hook blocked execution",output:X,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};if(X.decision?.behavior==="async")return{success:!0,output:X,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};return{success:!0,output:X,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W}}return this.parseByExitCode($,W,Q)}parseByExitCode($,W,Q){let Z=$.exitCode;switch(Z){case 0:return{success:!0,stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};case 2:return{success:!1,blocking:!0,error:$.stderr||$.stdout||"Hook returned exit code 2",stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};case 124:{let V=Q?.timeoutBehavior||"ignore",X="Hook timeout";if(V==="deny")return{success:!1,blocking:!0,error:"Hook timeout",stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};else if(V==="ask")return{success:!1,blocking:!1,needsConfirmation:!0,warning:"Hook timeout. Continue?",stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};else return{success:!1,blocking:!1,warning:"Hook timeout",stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W}}default:{let V=Q?.failureBehavior||"ignore",X=$.stderr||$.stdout||`Hook failed with exit code ${Z}`;if(V==="deny")return{success:!1,blocking:!0,error:X,stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};else if(V==="ask")return{success:!1,blocking:!1,needsConfirmation:!0,warning:`${X}. Continue?`,stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};else return{success:!1,blocking:!1,warning:X,stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W}}}}tryParseJSON($){try{let W=$.trim();if(!W)return null;let Q=W.match(/^\s*(\{[\s\S]*\})\s*$/);if(!Q)return null;return JSON.parse(Q[1])}catch{return null}}}import{spawn as F7}from"child_process";class s1{content="";maxSize;constructor($){this.maxSize=$}append($){if(this.content.length<this.maxSize){let W=this.maxSize-this.content.length;this.content+=$.substring(0,W)}}getContent(){return this.content}isFull(){return this.content.length>=this.maxSize}}class o1{MAX_STDOUT_SIZE=1048576;MAX_STDERR_SIZE=1048576;MAX_INPUT_SIZE=102400;async execute($,W,Q,Z){let V=JSON.stringify(W);if(V.length>this.MAX_INPUT_SIZE)throw Error(`Hook input too large: ${V.length} bytes (max ${this.MAX_INPUT_SIZE})`);let X=this.createSafeEnv(W),Y=F7($,[],{shell:!0,env:X,cwd:Q.projectDir,timeout:Z}),J=new s1(this.MAX_STDOUT_SIZE),G=new s1(this.MAX_STDERR_SIZE);Y.stdout.setEncoding("utf8"),Y.stderr.setEncoding("utf8"),Y.stdout.on("data",(B)=>{J.append(B)}),Y.stderr.on("data",(B)=>{G.append(B)});try{Y.stdin.write(V),Y.stdin.end()}catch(B){throw Y.kill("SIGTERM"),Error(`Failed to write hook input: ${B}`)}return new Promise((B,K)=>{let q=!1,w=!1,O=null,b=()=>{if(O&&Q.abortSignal)Q.abortSignal.removeEventListener("abort",O),O=null},U=setTimeout(()=>{q=!0,Y.kill("SIGKILL")},Z);if(Y.on("close",(F)=>{if(w)return;w=!0,clearTimeout(U),b(),B({stdout:J.getContent(),stderr:G.getContent(),exitCode:q?124:F??1,timedOut:q})}),Y.on("error",(F)=>{if(w)return;w=!0,clearTimeout(U),b(),K(F)}),Q.abortSignal)O=()=>{if(w)return;w=!0,clearTimeout(U),b(),Y.kill("SIGTERM"),B({stdout:J.getContent(),stderr:"Hook cancelled by abort signal",exitCode:1,timedOut:!1})},Q.abortSignal.addEventListener("abort",O)})}createSafeEnv($){return{BLADE_PROJECT_DIR:$.project_dir,BLADE_SESSION_ID:$.session_id,BLADE_HOOK_EVENT:$.hook_event_name,BLADE_TOOL_NAME:"tool_name"in $?$.tool_name:"",BLADE_TOOL_USE_ID:"tool_use_id"in $?$.tool_use_id:"",PATH:process.env.PATH||"",HOME:process.env.HOME||"",USER:process.env.USER||"",SHELL:process.env.SHELL||"/bin/sh"}}}class t1{processExecutor=new o1;outputParser=new r1;async executePreToolHooks($,W,Q){if($.length===0)return{decision:"allow"};let Z="tool_input"in W?W.tool_input:{},V=[];for(let X of $)try{let Y={...W,...Z&&{tool_input:Z}},J=await this.executeHook(X,Y,Q);if(!J.success){if(J.blocking)return{decision:"deny",reason:J.error};if(J.needsConfirmation)return{decision:"ask",reason:J.warning||J.error};if(J.warning)V.push(J.warning);continue}let G=J.output?.hookSpecificOutput;if(G&&"permissionDecision"in G){switch(G.permissionDecision){case"deny":return{decision:"deny",reason:G.permissionDecisionReason};case"ask":return{decision:"ask",reason:G.permissionDecisionReason};case"allow":break}if("updatedInput"in G&&G.updatedInput)Z={...Z,...G.updatedInput}}}catch(Y){let J=Y instanceof Error?Y.message:String(Y);if(V.push(`Hook failed: ${J}`),Q.config.failureBehavior==="deny")return{decision:"deny",reason:J};else if(Q.config.failureBehavior==="ask")return{decision:"ask",reason:`Hook failed: ${J}. Continue?`}}return{decision:"allow",modifiedInput:Z,warning:V.length>0?V.join(`
2
- `):void 0}}async executePostToolHooks($,W,Q){if($.length===0)return{};let Z=Q.config.maxConcurrentHooks||5,V=await this.executeHooksConcurrently($,W,Q,Z),X=[],Y,J=[];for(let G of V){if(!G.success&&G.warning){J.push(G.warning);continue}let B=G.output?.hookSpecificOutput;if(B&&"additionalContext"in B){if(B.additionalContext)X.push(B.additionalContext);if("updatedOutput"in B&&B.updatedOutput!==void 0)Y=B.updatedOutput}}return{additionalContext:X.length>0?X.join(`
1
+ import{createRequire as i5}from"node:module";var d5=Object.create;var{getPrototypeOf:m5,defineProperty:S4,getOwnPropertyNames:g5}=Object;var c5=Object.prototype.hasOwnProperty;var W1=($,W,Q)=>{Q=$!=null?d5(m5($)):{};let Z=W||!$||!$.__esModule?S4(Q,"default",{value:$,enumerable:!0}):Q;for(let V of g5($))if(!c5.call(Z,V))S4(Z,V,{get:()=>$[V],enumerable:!0});return Z};var j0=i5(import.meta.url);import{nanoid as HW}from"nanoid";import*as T5 from"os";import*as P5 from"path";import{nanoid as w0}from"nanoid";var q$;((Y)=>{Y.DEFAULT="default";Y.AUTO_EDIT="autoEdit";Y.YOLO="yolo";Y.BYPASSALL="bypassAll";Y.PLAN="plan";Y.SPEC="spec"})(q$||={});import{nanoid as G$}from"nanoid";var g1={enabled:!1,defaultTimeout:60,timeoutBehavior:"ignore",failureBehavior:"ignore",maxConcurrentHooks:5,PreToolUse:[],PostToolUse:[],PostToolUseFailure:[],PermissionRequest:[],UserPromptSubmit:[],SessionStart:[],SessionEnd:[],Stop:[],SubagentStart:[],SubagentStop:[],TaskCompleted:[],Notification:[],Compaction:[]};function c1($,W){return{...$,...W,PreToolUse:W.PreToolUse??$.PreToolUse,PostToolUse:W.PostToolUse??$.PostToolUse,PostToolUseFailure:W.PostToolUseFailure??$.PostToolUseFailure,PermissionRequest:W.PermissionRequest??$.PermissionRequest,UserPromptSubmit:W.UserPromptSubmit??$.UserPromptSubmit,SessionStart:W.SessionStart??$.SessionStart,SessionEnd:W.SessionEnd??$.SessionEnd,Stop:W.Stop??$.Stop,SubagentStart:W.SubagentStart??$.SubagentStart,SubagentStop:W.SubagentStop??$.SubagentStop,TaskCompleted:W.TaskCompleted??$.TaskCompleted,Notification:W.Notification??$.Notification,Compaction:W.Compaction??$.Compaction}}function v4(){let $={};if(process.env.BLADE_DISABLE_HOOKS==="true")$.enabled=!1;if(process.env.BLADE_HOOK_TIMEOUT){let W=parseInt(process.env.BLADE_HOOK_TIMEOUT,10);if(!isNaN(W)&&W>0)$.defaultTimeout=W}return $}class i1{executedHooks=new Map;canExecute($,W){if(!this.executedHooks.has($))this.executedHooks.set($,new Set);if(this.executedHooks.get($).has(W))return console.warn(`[HookGuard] Hook ${W} for tool ${$} already executed, skipping`),!1;return!0}markExecuted($,W){let Q=this.executedHooks.get($);if(Q)Q.add(W)}cleanup($){this.executedHooks.delete($)}cleanupAll(){this.executedHooks.clear()}}import{z as F}from"zod";var Q1;((O)=>{O.PreToolUse="PreToolUse";O.PostToolUse="PostToolUse";O.PostToolUseFailure="PostToolUseFailure";O.PermissionRequest="PermissionRequest";O.UserPromptSubmit="UserPromptSubmit";O.SessionStart="SessionStart";O.SessionEnd="SessionEnd";O.Stop="Stop";O.SubagentStart="SubagentStart";O.SubagentStop="SubagentStop";O.TaskCompleted="TaskCompleted";O.Notification="Notification";O.Compaction="Compaction"})(Q1||={});var l1;((Z)=>{Z.Approve="approve";Z.Block="block";Z.Async="async"})(l1||={});var n1;((Z)=>{Z.Allow="allow";Z.Deny="deny";Z.Ask="ask"})(n1||={});var J$=F.object({hook_event_name:F.nativeEnum(Q1),hook_execution_id:F.string(),timestamp:F.string(),project_dir:F.string(),session_id:F.string(),permission_mode:F.enum(["default","autoEdit","yolo","plan"]),_metadata:F.object({blade_version:F.string(),hook_timeout_ms:F.number()}).optional()}),n5=J$.extend({hook_event_name:F.literal("PreToolUse"),tool_name:F.string(),tool_use_id:F.string(),tool_input:F.record(F.unknown())}),a5=J$.extend({hook_event_name:F.literal("PostToolUse"),tool_name:F.string(),tool_use_id:F.string(),tool_input:F.record(F.unknown()),tool_response:F.unknown()}),r5=J$.extend({hook_event_name:F.literal("Stop"),reason:F.string().optional()}),s5=J$.extend({hook_event_name:F.literal("PostToolUseFailure"),tool_name:F.string(),tool_use_id:F.string(),tool_input:F.record(F.unknown()),error:F.string(),error_type:F.string().optional(),is_interrupt:F.boolean(),is_timeout:F.boolean()}),o5=J$.extend({hook_event_name:F.literal("PermissionRequest"),tool_name:F.string(),tool_use_id:F.string(),tool_input:F.record(F.unknown())}),t5=J$.extend({hook_event_name:F.literal("UserPromptSubmit"),user_prompt:F.string(),has_images:F.boolean(),image_count:F.number()}),e5=J$.extend({hook_event_name:F.literal("SessionStart"),is_resume:F.boolean(),resume_session_id:F.string().optional()}),$7=J$.extend({hook_event_name:F.literal("SessionEnd"),reason:F.enum(["user_exit","error","max_turns","idle_timeout","ctrl_c","clear","logout","other"])}),W7=J$.extend({hook_event_name:F.literal("SubagentStart"),agent_type:F.string(),task_description:F.string().optional(),parent_agent_id:F.string().optional()}),Q7=J$.extend({hook_event_name:F.literal("SubagentStop"),agent_type:F.string(),task_description:F.string().optional(),success:F.boolean(),result_summary:F.string().optional(),error:F.string().optional()}),Z7=J$.extend({hook_event_name:F.literal("TaskCompleted"),task_id:F.string(),task_description:F.string(),result_summary:F.string().optional(),success:F.boolean()}),V7=J$.extend({hook_event_name:F.literal("Notification"),notification_type:F.enum(["permission_prompt","idle_prompt","auth_success","elicitation_dialog","info","warning","error"]),title:F.string().optional(),message:F.string()}),X7=J$.extend({hook_event_name:F.literal("Compaction"),trigger:F.enum(["manual","auto"]),messages_before:F.number(),tokens_before:F.number()}),vW=F.discriminatedUnion("hook_event_name",[n5,a5,r5,s5,o5,t5,e5,$7,W7,Q7,Z7,V7,X7]),Y7=F.object({hookEventName:F.literal("PreToolUse"),permissionDecision:F.nativeEnum(n1).optional(),permissionDecisionReason:F.string().optional(),updatedInput:F.record(F.unknown()).optional()}),J7=F.object({hookEventName:F.literal("PostToolUse"),additionalContext:F.string().optional(),updatedOutput:F.unknown().optional()}),G7=F.object({hookEventName:F.literal("Stop"),continue:F.boolean().optional(),continueReason:F.string().optional()}),K7=F.object({hookEventName:F.literal("SubagentStart"),additionalContext:F.string().optional()}),B7=F.object({hookEventName:F.literal("SubagentStop"),continue:F.boolean().optional(),continueReason:F.string().optional(),additionalContext:F.string().optional()}),q7=F.object({hookEventName:F.literal("TaskCompleted"),blockCompletion:F.boolean().optional(),blockReason:F.string().optional()}),w7=F.object({hookEventName:F.literal("PermissionRequest"),permissionDecision:F.enum(["approve","deny","ask"]).optional(),permissionDecisionReason:F.string().optional()}),O7=F.object({hookEventName:F.literal("UserPromptSubmit"),updatedPrompt:F.string().optional(),contextInjection:F.string().optional()}),U7=F.object({hookEventName:F.literal("SessionStart"),env:F.record(F.string()).optional()}),F7=F.object({hookEventName:F.literal("Compaction"),blockCompaction:F.boolean().optional(),blockReason:F.string().optional()}),H7=F.object({decision:F.object({behavior:F.nativeEnum(l1)}).optional(),systemMessage:F.string().optional(),hookSpecificOutput:F.discriminatedUnion("hookEventName",[Y7,J7,G7,K7,B7,q7,w7,O7,U7,F7]).optional(),suppressOutput:F.boolean().optional()}),A7=F.object({type:F.literal("command"),command:F.string(),timeout:F.number().positive().optional(),statusMessage:F.string().optional()}),D7=F.object({type:F.literal("prompt"),prompt:F.string(),timeout:F.number().positive().optional()}),b7=F.discriminatedUnion("type",[A7,D7]),a1=F.union([F.string(),F.array(F.string())]),_7=F.object({tools:a1.optional(),paths:a1.optional(),commands:a1.optional()}),Y$=F.object({name:F.string().optional(),matcher:_7.optional(),hooks:F.array(b7)}),yW=F.object({enabled:F.boolean().optional(),defaultTimeout:F.number().positive().optional(),timeoutBehavior:F.enum(["ignore","deny","ask"]).optional(),failureBehavior:F.enum(["ignore","deny","ask"]).optional(),maxConcurrentHooks:F.number().positive().optional(),PreToolUse:F.array(Y$).optional(),PostToolUse:F.array(Y$).optional(),PostToolUseFailure:F.array(Y$).optional(),PermissionRequest:F.array(Y$).optional(),UserPromptSubmit:F.array(Y$).optional(),SessionStart:F.array(Y$).optional(),SessionEnd:F.array(Y$).optional(),Stop:F.array(Y$).optional(),SubagentStart:F.array(Y$).optional(),SubagentStop:F.array(Y$).optional(),TaskCompleted:F.array(Y$).optional(),Notification:F.array(Y$).optional(),Compaction:F.array(Y$).optional()});function y4($){let W=H7.safeParse($);if(W.success)return{success:!0,data:W.data};return{success:!1,error:W.error}}class r1{parse($,W,Q){if($.timedOut){let V=Q?.timeoutBehavior||"ignore",X="Hook timeout";if(V==="deny")return{success:!1,blocking:!0,error:"Hook timeout",stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};else if(V==="ask")return{success:!1,blocking:!1,needsConfirmation:!0,warning:"Hook timeout. Continue?",stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};else return{success:!1,blocking:!1,warning:"Hook timeout",stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W}}let Z=this.tryParseJSON($.stdout);if(Z){let V=y4(Z);if(!V.success){let Y="error"in V?V.error.message:"Unknown validation error",J=Q?.failureBehavior||"ignore",G=`Invalid hook output JSON: ${Y}`;if(J==="deny")return{success:!1,blocking:!0,error:G,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};else if(J==="ask")return{success:!1,blocking:!1,needsConfirmation:!0,warning:`${G}. Continue?`,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};else return{success:!1,blocking:!1,warning:G,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W}}let X=V.data;if(X.decision?.behavior==="block")return{success:!1,blocking:!0,error:X.systemMessage||"Hook blocked execution",output:X,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};if(X.decision?.behavior==="async")return{success:!0,output:X,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W};return{success:!0,output:X,stdout:$.stdout,stderr:$.stderr,exitCode:$.exitCode,hook:W}}return this.parseByExitCode($,W,Q)}parseByExitCode($,W,Q){let Z=$.exitCode;switch(Z){case 0:return{success:!0,stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};case 2:return{success:!1,blocking:!0,error:$.stderr||$.stdout||"Hook returned exit code 2",stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};case 124:{let V=Q?.timeoutBehavior||"ignore",X="Hook timeout";if(V==="deny")return{success:!1,blocking:!0,error:"Hook timeout",stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};else if(V==="ask")return{success:!1,blocking:!1,needsConfirmation:!0,warning:"Hook timeout. Continue?",stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};else return{success:!1,blocking:!1,warning:"Hook timeout",stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W}}default:{let V=Q?.failureBehavior||"ignore",X=$.stderr||$.stdout||`Hook failed with exit code ${Z}`;if(V==="deny")return{success:!1,blocking:!0,error:X,stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};else if(V==="ask")return{success:!1,blocking:!1,needsConfirmation:!0,warning:`${X}. Continue?`,stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W};else return{success:!1,blocking:!1,warning:X,stdout:$.stdout,stderr:$.stderr,exitCode:Z,hook:W}}}}tryParseJSON($){try{let W=$.trim();if(!W)return null;let Q=W.match(/^\s*(\{[\s\S]*\})\s*$/);if(!Q)return null;return JSON.parse(Q[1])}catch{return null}}}import{spawn as L7}from"child_process";class s1{content="";maxSize;constructor($){this.maxSize=$}append($){if(this.content.length<this.maxSize){let W=this.maxSize-this.content.length;this.content+=$.substring(0,W)}}getContent(){return this.content}isFull(){return this.content.length>=this.maxSize}}class o1{MAX_STDOUT_SIZE=1048576;MAX_STDERR_SIZE=1048576;MAX_INPUT_SIZE=102400;async execute($,W,Q,Z){let V=JSON.stringify(W);if(V.length>this.MAX_INPUT_SIZE)throw Error(`Hook input too large: ${V.length} bytes (max ${this.MAX_INPUT_SIZE})`);let X=this.createSafeEnv(W),Y=L7($,[],{shell:!0,env:X,cwd:Q.projectDir,timeout:Z}),J=new s1(this.MAX_STDOUT_SIZE),G=new s1(this.MAX_STDERR_SIZE);Y.stdout.setEncoding("utf8"),Y.stderr.setEncoding("utf8"),Y.stdout.on("data",(K)=>{J.append(K)}),Y.stderr.on("data",(K)=>{G.append(K)});try{Y.stdin.write(V),Y.stdin.end()}catch(K){throw Y.kill("SIGTERM"),Error(`Failed to write hook input: ${K}`)}return new Promise((K,B)=>{let q=!1,w=!1,O=null,H=()=>{if(O&&Q.abortSignal)Q.abortSignal.removeEventListener("abort",O),O=null},U=setTimeout(()=>{q=!0,Y.kill("SIGKILL")},Z);if(Y.on("close",(A)=>{if(w)return;w=!0,clearTimeout(U),H(),K({stdout:J.getContent(),stderr:G.getContent(),exitCode:q?124:A??1,timedOut:q})}),Y.on("error",(A)=>{if(w)return;w=!0,clearTimeout(U),H(),B(A)}),Q.abortSignal)O=()=>{if(w)return;w=!0,clearTimeout(U),H(),Y.kill("SIGTERM"),K({stdout:J.getContent(),stderr:"Hook cancelled by abort signal",exitCode:1,timedOut:!1})},Q.abortSignal.addEventListener("abort",O)})}createSafeEnv($){return{BLADE_PROJECT_DIR:$.project_dir,BLADE_SESSION_ID:$.session_id,BLADE_HOOK_EVENT:$.hook_event_name,BLADE_TOOL_NAME:"tool_name"in $?$.tool_name:"",BLADE_TOOL_USE_ID:"tool_use_id"in $?$.tool_use_id:"",PATH:process.env.PATH||"",HOME:process.env.HOME||"",USER:process.env.USER||"",SHELL:process.env.SHELL||"/bin/sh"}}}class t1{processExecutor=new o1;outputParser=new r1;async executePreToolHooks($,W,Q){if($.length===0)return{decision:"allow"};let Z="tool_input"in W?W.tool_input:{},V=[];for(let X of $)try{let Y={...W,...Z&&{tool_input:Z}},J=await this.executeHook(X,Y,Q);if(!J.success){if(J.blocking)return{decision:"deny",reason:J.error};if(J.needsConfirmation)return{decision:"ask",reason:J.warning||J.error};if(J.warning)V.push(J.warning);continue}let G=J.output?.hookSpecificOutput;if(G&&"permissionDecision"in G){switch(G.permissionDecision){case"deny":return{decision:"deny",reason:G.permissionDecisionReason};case"ask":return{decision:"ask",reason:G.permissionDecisionReason};case"allow":break}if("updatedInput"in G&&G.updatedInput)Z={...Z,...G.updatedInput}}}catch(Y){let J=Y instanceof Error?Y.message:String(Y);if(V.push(`Hook failed: ${J}`),Q.config.failureBehavior==="deny")return{decision:"deny",reason:J};else if(Q.config.failureBehavior==="ask")return{decision:"ask",reason:`Hook failed: ${J}. Continue?`}}return{decision:"allow",modifiedInput:Z,warning:V.length>0?V.join(`
2
+ `):void 0}}async executePostToolHooks($,W,Q){if($.length===0)return{};let Z=Q.config.maxConcurrentHooks||5,V=await this.executeHooksConcurrently($,W,Q,Z),X=[],Y,J=[];for(let G of V){if(!G.success&&G.warning){J.push(G.warning);continue}let K=G.output?.hookSpecificOutput;if(K&&"additionalContext"in K){if(K.additionalContext)X.push(K.additionalContext);if("updatedOutput"in K&&K.updatedOutput!==void 0)Y=K.updatedOutput}}return{additionalContext:X.length>0?X.join(`
3
3
 
4
4
  `):void 0,modifiedOutput:Y,warning:J.length>0?J.join(`
5
5
  `):void 0}}async executeStopHooks($,W,Q){if($.length===0)return{shouldStop:!0};let Z=[];for(let V of $)try{let X=await this.executeHook(V,W,Q);if(!X.success){if(X.warning)Z.push(X.warning);continue}let Y=X.output?.hookSpecificOutput;if(Y&&"continue"in Y&&Y.continue===!1)return{shouldStop:!1,continueReason:Y.continueReason,warning:Z.length>0?Z.join(`
6
6
  `):void 0}}catch(X){let Y=X instanceof Error?X.message:String(X);Z.push(`Hook failed: ${Y}`)}return{shouldStop:!0,warning:Z.length>0?Z.join(`
7
+ `):void 0}}async executeSubagentStartHooks($,W,Q){if($.length===0)return{proceed:!0};let Z=[],V=[];for(let X of $)try{let Y=await this.executeHook(X,W,Q);if(!Y.success){if(Y.blocking)return{proceed:!1,warning:Y.error};if(Y.warning)Z.push(Y.warning);continue}let J=Y.output?.hookSpecificOutput;if(J&&"additionalContext"in J&&J.additionalContext)V.push(J.additionalContext)}catch(Y){let J=Y instanceof Error?Y.message:String(Y);Z.push(`Hook failed: ${J}`)}return{proceed:!0,additionalContext:V.length>0?V.join(`
8
+
9
+ `):void 0,warning:Z.length>0?Z.join(`
7
10
  `):void 0}}async executeSubagentStopHooks($,W,Q){if($.length===0)return{shouldStop:!0};let Z=[],V=[];for(let X of $)try{let Y=await this.executeHook(X,W,Q);if(!Y.success){if(Y.warning)Z.push(Y.warning);continue}let J=Y.output?.hookSpecificOutput;if(J&&"continue"in J){if(J.continue===!1)return{shouldStop:!1,continueReason:J.continueReason,warning:Z.length>0?Z.join(`
8
11
  `):void 0};if("additionalContext"in J&&J.additionalContext)V.push(J.additionalContext)}}catch(Y){let J=Y instanceof Error?Y.message:String(Y);Z.push(`Hook failed: ${J}`)}return{shouldStop:!0,additionalContext:V.length>0?V.join(`
9
12
 
10
13
  `):void 0,warning:Z.length>0?Z.join(`
14
+ `):void 0}}async executeTaskCompletedHooks($,W,Q){if($.length===0)return{allowCompletion:!0};let Z=[];for(let V of $)try{let X=await this.executeHook(V,W,Q);if(!X.success){if(X.blocking)return{allowCompletion:!1,blockReason:X.error,warning:Z.length>0?Z.join(`
15
+ `):void 0};if(X.warning)Z.push(X.warning);continue}let Y=X.output?.hookSpecificOutput;if(Y&&"blockCompletion"in Y&&Y.blockCompletion)return{allowCompletion:!1,blockReason:Y.blockReason,warning:Z.length>0?Z.join(`
16
+ `):void 0}}catch(X){let Y=X instanceof Error?X.message:String(X);Z.push(`Hook failed: ${Y}`)}return{allowCompletion:!0,warning:Z.length>0?Z.join(`
11
17
  `):void 0}}async executePermissionRequestHooks($,W,Q){if($.length===0)return{decision:"ask"};let Z=[];for(let V of $)try{let X=await this.executeHook(V,W,Q);if(!X.success){if(X.warning)Z.push(X.warning);continue}let Y=X.output?.hookSpecificOutput;if(Y&&"permissionDecision"in Y){let J=Y.permissionDecision;if(J==="approve"||J==="deny")return{decision:J,reason:Y.permissionDecisionReason,warning:Z.length>0?Z.join(`
12
18
  `):void 0}}}catch(X){let Y=X instanceof Error?X.message:String(X);Z.push(`Hook failed: ${Y}`)}return{decision:"ask",warning:Z.length>0?Z.join(`
13
19
  `):void 0}}async executeUserPromptSubmitHooks($,W,Q){if($.length===0)return{proceed:!0};let Z=[],V=[],X;for(let Y of $)try{let J=await this.executeHook(Y,W,Q);if(!J.success){if(J.blocking)return{proceed:!1,warning:J.error};if(J.warning)Z.push(J.warning);continue}if(J.stdout&&J.stdout.trim())V.push(J.stdout.trim());let G=J.output?.hookSpecificOutput;if(G&&"updatedPrompt"in G){if(G.updatedPrompt)X=G.updatedPrompt;if(G.contextInjection)V.push(G.contextInjection)}}catch(J){let G=J instanceof Error?J.message:String(J);Z.push(`Hook failed: ${G}`)}return{proceed:!0,updatedPrompt:X,contextInjection:V.length>0?V.join(`
@@ -18,13 +24,13 @@ import{createRequire as i5}from"node:module";var d5=Object.create;var{getPrototy
18
24
  `):void 0}}async executePostToolUseFailureHooks($,W,Q){if($.length===0)return{};let Z=[],V=[],X=Q.config.maxConcurrentHooks||5,Y=await this.executeHooksConcurrently($,W,Q,X);for(let J of Y){if(!J.success&&J.warning){Z.push(J.warning);continue}if(J.stdout&&J.stdout.trim())V.push(J.stdout.trim())}return{additionalContext:V.length>0?V.join(`
19
25
 
20
26
  `):void 0,warning:Z.length>0?Z.join(`
21
- `):void 0}}async executeNotificationHooks($,W,Q){let Z="message"in W?W.message:"";if($.length===0)return{suppress:!1,message:Z};let V=[],X=!1,Y=Z;for(let J of $)try{let G=await this.executeHook(J,W,Q);if(!G.success){if(G.warning)V.push(G.warning);continue}if(G.output?.suppressOutput){X=!0;break}if(G.stdout&&G.stdout.trim())Y=G.stdout.trim()}catch(G){let B=G instanceof Error?G.message:String(G);V.push(`Hook failed: ${B}`)}return{suppress:X,message:Y,warning:V.length>0?V.join(`
27
+ `):void 0}}async executeNotificationHooks($,W,Q){let Z="message"in W?W.message:"";if($.length===0)return{suppress:!1,message:Z};let V=[],X=!1,Y=Z;for(let J of $)try{let G=await this.executeHook(J,W,Q);if(!G.success){if(G.warning)V.push(G.warning);continue}if(G.output?.suppressOutput){X=!0;break}if(G.stdout&&G.stdout.trim())Y=G.stdout.trim()}catch(G){let K=G instanceof Error?G.message:String(G);V.push(`Hook failed: ${K}`)}return{suppress:X,message:Y,warning:V.length>0?V.join(`
22
28
  `):void 0}}async executeCompactionHooks($,W,Q){if($.length===0)return{blockCompaction:!1};let Z=[];for(let V of $)try{let X=await this.executeHook(V,W,Q);if(!X.success){if(X.warning)Z.push(X.warning);continue}let Y=X.output?.hookSpecificOutput;if(Y&&"blockCompaction"in Y&&Y.blockCompaction)return{blockCompaction:!0,blockReason:Y.blockReason,warning:Z.length>0?Z.join(`
23
29
  `):void 0}}catch(X){let Y=X instanceof Error?X.message:String(X);Z.push(`Hook failed: ${Y}`)}return{blockCompaction:!1,warning:Z.length>0?Z.join(`
24
- `):void 0}}async executeHook($,W,Q){if($.type==="command")return this.executeCommandHook($,W,Q);throw Error(`Hook type ${$.type} not yet implemented`)}async executeCommandHook($,W,Q){let Z=($.timeout??Q.config.defaultTimeout??60)*1000;try{let V=await this.processExecutor.execute($.command,W,Q,Z);return this.outputParser.parse(V,$,{timeoutBehavior:Q.config.timeoutBehavior,failureBehavior:Q.config.failureBehavior})}catch(V){return{success:!1,blocking:!1,error:V instanceof Error?V.message:String(V),hook:$}}}async executeHooksConcurrently($,W,Q,Z){let V=[],X=new Set;for(let Y of $){if(X.size>=Z)await Promise.race(X);let J=this.executeHook(Y,W,Q).catch((B)=>({success:!1,blocking:!1,error:B instanceof Error?B.message:String(B),hook:Y})),G=J.then(()=>{X.delete(G)}).catch(()=>{X.delete(G)});X.add(G),V.push(J)}return Promise.all(V)}}import e1 from"picomatch";var A7=/^([A-Za-z0-9_|]+)\((.+)\)$/;class $2{matches($,W){if(!$)return!0;if($.tools&&W.toolName){if(!this.matchTools($.tools,W))return!1}if($.paths&&W.filePath){if(!this.matchPaths($.paths,W.filePath))return!1}if($.commands&&W.command){if(!this.matchCommands($.commands,W.command))return!1}return!0}matchTools($,W){if(Array.isArray($))return $.some((Q)=>this.matchToolWithParams(Q,W));return this.matchToolWithParams($,W)}matchPaths($,W){if(Array.isArray($))return $.some((Z)=>{return e1(Z)(W)});return e1($)(W)}matchCommands($,W){if(Array.isArray($))return $.some((Q)=>this.matchPattern(W,Q));return this.matchPattern(W,$)}matchToolWithParams($,W){let{toolName:Q,command:Z,filePath:V}=W,X=A7.exec($);if(!X)return this.matchPattern(Q,$);let[,Y,J]=X;if(!this.matchPattern(Q,Y))return!1;let G=this.getArgValue(Q,Z,V);if(!G)return!1;return this.matchGlobOrPattern(G,J)}getArgValue($,W,Q){if($==="Bash"||$==="BashTool")return W;if(["Read","Edit","Write","Glob","Grep"].includes($))return Q;return W||Q}matchGlobOrPattern($,W){if(/[*?[\]{}!]/.test(W))try{return e1(W,{bash:!0,dot:!0})($)}catch{}if(W.endsWith("*")){let Q=W.slice(0,-1);return $.startsWith(Q)}return $===W}matchPattern($,W){if(W==="*")return!0;if(!W.includes("|")&&!/[.*+?^${}()|[\]\\]/.test(W))return $===W;if(W.includes("|"))return W.split("|").map((Z)=>Z.trim()).includes($);try{return new RegExp(W).test($)}catch{return $===W}}}class i{static instance=null;config=g1;executor=new t1;guard=new i1;matcher=new $2;sessionDisabled=!1;constructor(){}static getInstance(){if(!i.instance)i.instance=new i;return i.instance}loadConfig($){let W=c1(g1,$),Q=v4();W=c1(W,Q),this.config=W}isEnabled(){if(!this.config.enabled)return!1;if(this.sessionDisabled)return!1;return!0}disable(){this.sessionDisabled=!0,console.log("[HookManager] Hooks disabled for this session")}enable(){this.sessionDisabled=!1,console.log("[HookManager] Hooks enabled for this session")}getConfig(){return this.config}async reloadConfig(){let $=await import("node:fs/promises"),W=await import("node:path");try{let Q=W.join(process.cwd(),".blade","settings.local.json"),Z=await $.readFile(Q,"utf-8"),V=JSON.parse(Z);if(V.hooks)this.loadConfig(V.hooks)}catch{}}async executePreToolHooks($,W,Q,Z){if(!this.isEnabled())return{decision:"allow"};if(Z.permissionMode==="plan")return{decision:"allow"};if(!this.guard.canExecute(W,"PreToolUse"))return{decision:"allow"};let V={hook_event_name:"PreToolUse",hook_execution_id:F$(),timestamp:new Date().toISOString(),tool_name:$,tool_use_id:W,tool_input:Q,project_dir:Z.projectDir,session_id:Z.sessionId,permission_mode:Z.permissionMode},X=this.getMatchingHooks("PreToolUse",{toolName:$,filePath:this.extractFilePath(Q),command:this.extractCommand($,Q)});if(X.length===0)return{decision:"allow"};let Y={projectDir:Z.projectDir,sessionId:Z.sessionId,permissionMode:Z.permissionMode,config:this.config,abortSignal:Z.abortSignal};try{let J=await this.executor.executePreToolHooks(X,V,Y);if(this.guard.markExecuted(W,"PreToolUse"),Z.permissionMode==="yolo"){if(J.decision==="deny")return J;return{decision:"allow",modifiedInput:J.modifiedInput,warning:J.warning,reason:J.reason}}return J}catch(J){return console.error("[HookManager] Error executing PreToolUse hooks:",J),{decision:"allow",warning:`Hook execution failed: ${J instanceof Error?J.message:String(J)}`}}}async executePostToolHooks($,W,Q,Z,V){if(!this.isEnabled())return{};if(V.permissionMode==="plan")return{};if(!this.guard.canExecute(W,"PostToolUse"))return{};let X={hook_event_name:"PostToolUse",hook_execution_id:F$(),timestamp:new Date().toISOString(),tool_name:$,tool_use_id:W,tool_input:Q,tool_response:Z,project_dir:V.projectDir,session_id:V.sessionId,permission_mode:V.permissionMode},Y=this.getMatchingHooks("PostToolUse",{toolName:$,filePath:this.extractFilePath(Q),command:this.extractCommand($,Q)});if(Y.length===0)return{};let J={projectDir:V.projectDir,sessionId:V.sessionId,permissionMode:V.permissionMode,config:this.config,abortSignal:V.abortSignal};try{let G=await this.executor.executePostToolHooks(Y,X,J);return this.guard.markExecuted(W,"PostToolUse"),G}catch(G){return console.error("[HookManager] Error executing PostToolUse hooks:",G),{warning:`Hook execution failed: ${G instanceof Error?G.message:String(G)}`}}finally{this.guard.cleanup(W)}}async executeStopHooks($){if(!this.isEnabled())return{shouldStop:!0};let W={hook_event_name:"Stop",hook_execution_id:F$(),timestamp:new Date().toISOString(),project_dir:$.projectDir,session_id:$.sessionId,permission_mode:$.permissionMode,reason:$.reason},Q=this.getMatchingHooks("Stop",{});if(Q.length===0)return{shouldStop:!0};let Z={projectDir:$.projectDir,sessionId:$.sessionId,permissionMode:$.permissionMode,config:this.config,abortSignal:$.abortSignal};try{return await this.executor.executeStopHooks(Q,W,Z)}catch(V){return console.error("[HookManager] Error executing Stop hooks:",V),{shouldStop:!0,warning:`Hook execution failed: ${V instanceof Error?V.message:String(V)}`}}}async executeSubagentStopHooks($,W){if(!this.isEnabled())return{shouldStop:!0};let Q={hook_event_name:"SubagentStop",hook_execution_id:F$(),timestamp:new Date().toISOString(),project_dir:W.projectDir,session_id:W.sessionId,permission_mode:W.permissionMode,agent_type:$,task_description:W.taskDescription,success:W.success,result_summary:W.resultSummary,error:W.error},Z=this.getMatchingHooks("SubagentStop",{});if(Z.length===0)return{shouldStop:!0};let V={projectDir:W.projectDir,sessionId:W.sessionId,permissionMode:W.permissionMode,config:this.config,abortSignal:W.abortSignal};try{return await this.executor.executeSubagentStopHooks(Z,Q,V)}catch(X){return console.error("[HookManager] Error executing SubagentStop hooks:",X),{shouldStop:!0,warning:`Hook execution failed: ${X instanceof Error?X.message:String(X)}`}}}async executePermissionRequestHooks($,W,Q,Z){if(!this.isEnabled())return{decision:"ask"};let V={hook_event_name:"PermissionRequest",hook_execution_id:F$(),timestamp:new Date().toISOString(),tool_name:$,tool_use_id:W,tool_input:Q,project_dir:Z.projectDir,session_id:Z.sessionId,permission_mode:Z.permissionMode},X=this.getMatchingHooks("PermissionRequest",{toolName:$,filePath:this.extractFilePath(Q),command:this.extractCommand($,Q)});if(X.length===0)return{decision:"ask"};let Y={projectDir:Z.projectDir,sessionId:Z.sessionId,permissionMode:Z.permissionMode,config:this.config,abortSignal:Z.abortSignal};try{return await this.executor.executePermissionRequestHooks(X,V,Y)}catch(J){return console.error("[HookManager] Error executing PermissionRequest hooks:",J),{decision:"ask",warning:`Hook execution failed: ${J instanceof Error?J.message:String(J)}`}}}async executeUserPromptSubmitHooks($,W){if(!this.isEnabled())return{proceed:!0};let Q={hook_event_name:"UserPromptSubmit",hook_execution_id:F$(),timestamp:new Date().toISOString(),user_prompt:$,has_images:W.hasImages,image_count:W.imageCount,project_dir:W.projectDir,session_id:W.sessionId,permission_mode:W.permissionMode},Z=this.getMatchingHooks("UserPromptSubmit",{});if(Z.length===0)return{proceed:!0};let V={projectDir:W.projectDir,sessionId:W.sessionId,permissionMode:W.permissionMode,config:this.config,abortSignal:W.abortSignal};try{return await this.executor.executeUserPromptSubmitHooks(Z,Q,V)}catch(X){return console.error("[HookManager] Error executing UserPromptSubmit hooks:",X),{proceed:!0,warning:`Hook execution failed: ${X instanceof Error?X.message:String(X)}`}}}async executeSessionStartHooks($){if(!this.isEnabled())return{proceed:!0};let W={hook_event_name:"SessionStart",hook_execution_id:F$(),timestamp:new Date().toISOString(),project_dir:$.projectDir,session_id:$.sessionId,permission_mode:$.permissionMode,is_resume:$.isResume,resume_session_id:$.resumeSessionId},Q=this.getMatchingHooks("SessionStart",{});if(Q.length===0)return{proceed:!0};let Z={projectDir:$.projectDir,sessionId:$.sessionId,permissionMode:$.permissionMode,config:this.config,abortSignal:$.abortSignal};try{return await this.executor.executeSessionStartHooks(Q,W,Z)}catch(V){return console.error("[HookManager] Error executing SessionStart hooks:",V),{proceed:!0,warning:`Hook execution failed: ${V instanceof Error?V.message:String(V)}`}}}async executeSessionEndHooks($,W){if(!this.isEnabled())return{};let Q={hook_event_name:"SessionEnd",hook_execution_id:F$(),timestamp:new Date().toISOString(),project_dir:W.projectDir,session_id:W.sessionId,permission_mode:W.permissionMode,reason:$},Z=this.getMatchingHooks("SessionEnd",{});if(Z.length===0)return{};let V={projectDir:W.projectDir,sessionId:W.sessionId,permissionMode:W.permissionMode,config:this.config,abortSignal:W.abortSignal};try{return await this.executor.executeSessionEndHooks(Z,Q,V),{}}catch(X){return console.error("[HookManager] Error executing SessionEnd hooks:",X),{warning:`Hook execution failed: ${X instanceof Error?X.message:String(X)}`}}}async executePostToolUseFailureHooks($,W,Q,Z,V){if(!this.isEnabled())return{};let X={hook_event_name:"PostToolUseFailure",hook_execution_id:F$(),timestamp:new Date().toISOString(),tool_name:$,tool_use_id:W,tool_input:Q,error:Z,error_type:V.errorType,is_interrupt:V.isInterrupt,is_timeout:V.isTimeout,project_dir:V.projectDir,session_id:V.sessionId,permission_mode:V.permissionMode},Y=this.getMatchingHooks("PostToolUseFailure",{toolName:$,filePath:this.extractFilePath(Q),command:this.extractCommand($,Q)});if(Y.length===0)return{};let J={projectDir:V.projectDir,sessionId:V.sessionId,permissionMode:V.permissionMode,config:this.config,abortSignal:V.abortSignal};try{return await this.executor.executePostToolUseFailureHooks(Y,X,J)}catch(G){return console.error("[HookManager] Error executing PostToolUseFailure hooks:",G),{warning:`Hook execution failed: ${G instanceof Error?G.message:String(G)}`}}}async executeNotificationHooks($,W,Q){if(!this.isEnabled())return{suppress:!1,message:W};let Z={hook_event_name:"Notification",hook_execution_id:F$(),timestamp:new Date().toISOString(),project_dir:Q.projectDir,session_id:Q.sessionId,permission_mode:Q.permissionMode,notification_type:$,title:Q.title,message:W},V=this.getMatchingHooks("Notification",{});if(V.length===0)return{suppress:!1,message:W};let X={projectDir:Q.projectDir,sessionId:Q.sessionId,permissionMode:Q.permissionMode,config:this.config,abortSignal:Q.abortSignal};try{return await this.executor.executeNotificationHooks(V,Z,X)}catch(Y){return console.error("[HookManager] Error executing Notification hooks:",Y),{suppress:!1,message:W,warning:`Hook execution failed: ${Y instanceof Error?Y.message:String(Y)}`}}}async executeCompactionHooks($,W){if(!this.isEnabled())return{blockCompaction:!1};let Q={hook_event_name:"Compaction",hook_execution_id:F$(),timestamp:new Date().toISOString(),project_dir:W.projectDir,session_id:W.sessionId,permission_mode:W.permissionMode,trigger:$,messages_before:W.messagesBefore,tokens_before:W.tokensBefore},Z=this.getMatchingHooks("Compaction",{});if(Z.length===0)return{blockCompaction:!1};let V={projectDir:W.projectDir,sessionId:W.sessionId,permissionMode:W.permissionMode,config:this.config,abortSignal:W.abortSignal};try{return await this.executor.executeCompactionHooks(Z,Q,V)}catch(X){return console.error("[HookManager] Error executing Compaction hooks:",X),{blockCompaction:!1,warning:`Hook execution failed: ${X instanceof Error?X.message:String(X)}`}}}getMatchingHooks($,W){let Q=this.config[$]||[],Z=[];for(let V of Q)if(this.matcher.matches(V.matcher,W))Z.push(...V.hooks);return Z}extractFilePath($){let W=["file_path","path","filePath","source","target"];for(let Q of W){let Z=$[Q];if(typeof Z==="string")return Z}return}extractCommand($,W){if($==="Bash"||$==="BashTool"){let Q=W.command;if(typeof Q==="string")return Q}return}cleanup(){this.guard.cleanupAll()}}import{appendFileSync as D7,existsSync as _7,mkdirSync as L7,readdirSync as j7,statSync as k4,unlinkSync as z7}from"node:fs";import N7 from"node:os";import Q2 from"node:path";var Z2;((V)=>{V[V.DEBUG=0]="DEBUG";V[V.INFO=1]="INFO";V[V.WARN=2]="WARN";V[V.ERROR=3]="ERROR"})(Z2||={});var m;((w)=>{w.AGENT="Agent";w.UI="UI";w.TOOL="Tool";w.SERVICE="Service";w.CONFIG="Config";w.CONTEXT="Context";w.EXECUTION="Execution";w.LOOP="Loop";w.CHAT="Chat";w.GENERAL="General";w.PROMPTS="Prompts";w.SPEC="Spec"})(m||={});var W2=null,T4=null,P4=!1;function rW($){if(W2!==$)W2=$}async function sW(){}function R7(){if(P4)return T4;P4=!0;try{let $=Q2.join(N7.homedir(),".blade","logs");if(!_7($))L7($,{recursive:!0,mode:493});if(k4($).uid===0&&process.getuid&&process.getuid()!==0)return console.error(""),console.error("❌ 权限错误:~/.blade/logs 目录属于 root 用户"),console.error(""),console.error("这通常是因为您曾经使用 sudo 运行过 blade。"),console.error(""),console.error("解决方法:"),console.error(" sudo chown -R $USER:$USER ~/.blade/"),console.error(""),console.error("然后重新运行 blade(不要使用 sudo)"),console.error(""),null;return E7($,30),T4=$,$}catch($){return console.error("[Logger] 无法创建日志目录:",$),null}}function E7($,W){try{let Q=j7($),Z=Date.now(),V=W*24*60*60*1000;for(let X of Q){if(!X.startsWith("blade-")||!X.endsWith(".log")&&!X.endsWith(".jsonl"))continue;let Y=Q2.join($,X);try{let J=k4(Y);if(Z-J.mtimeMs>V)z7(Y)}catch(J){}}}catch(Q){}}function C7(){let $=R7();if(!$)return null;let W=W2||"default";return Q2.join($,`blade-${W}.jsonl`)}function M7($,W,Q){let Z=C7();if(!Z)return;try{let V={timestamp:new Date().toISOString(),level:Z2[W],category:$,message:Q};D7(Z,JSON.stringify(V)+`
25
- `)}catch(V){}}class P${static globalDebugConfig=null;enabled;minLevel;category;constructor($={}){if($.enabled!==void 0)this.enabled=$.enabled;else if(P$.globalDebugConfig!==null)this.enabled=Boolean(P$.globalDebugConfig);else this.enabled=!1;this.minLevel=$.minLevel??0,this.category=$.category??"General"}static setGlobalDebug($){P$.globalDebugConfig=$}static clearGlobalDebug(){P$.globalDebugConfig=null}setEnabled($){this.enabled=$}parseDebugFilter($){if(!$)return{enabled:!1};if($===!0||$==="true"||$==="1")return{enabled:!0};let W=String($).trim();if(!W)return{enabled:!0};if(W.startsWith("!"))return{enabled:!0,filter:{mode:"exclude",categories:W.split(",").map((V)=>V.trim().replace(/^!/,"")).filter(Boolean)}};return{enabled:!0,filter:{mode:"include",categories:W.split(",").map((Z)=>Z.trim()).filter(Boolean)}}}shouldLogCategory($){if(!$)return!0;let W=this.category.toLowerCase();if($.mode==="include")return $.categories.some((Q)=>W.includes(Q.toLowerCase()));return!$.categories.some((Q)=>W.includes(Q.toLowerCase()))}shouldLogToConsole($){if(P$.globalDebugConfig!==null){let{enabled:W,filter:Q}=this.parseDebugFilter(P$.globalDebugConfig);if(!W)return!1;if($<this.minLevel)return!1;return this.shouldLogCategory(Q)}return this.enabled&&$>=this.minLevel}log($,...W){let Q=W.map((Z)=>typeof Z==="object"?JSON.stringify(Z):String(Z)).join(" ");if(M7(this.category,$,Q),this.shouldLogToConsole($)){let Z=Z2[$],V=`[${this.category}] [${Z}]`;console.error(V,...W)}}debug(...$){this.log(0,...$)}info(...$){this.log(1,...$)}warn(...$){this.log(2,...$)}error(...$){this.log(3,...$)}}function M($,W){return new P$({...W,category:$})}var oW=new P$({category:"General"});import{ProxyAgent as S7,fetch as v7}from"undici";function y7(){return process.env.HTTPS_PROXY||process.env.HTTP_PROXY||process.env.https_proxy||process.env.http_proxy}function T7(){let $=y7();if($)try{return new S7($)}catch(W){console.warn(`[proxyFetch] Invalid proxy URL: ${$}`)}return}async function r($,W={}){let{timeout:Q=30000,signal:Z,...V}=W;if(Z?.aborted)throw new DOMException("The operation was aborted.","AbortError");let X=T7(),Y=new AbortController,J=!1,G=setTimeout(()=>{J=!0,Y.abort()},Q),B=()=>Y.abort();Z?.addEventListener("abort",B);try{let K={method:V.method,headers:V.headers,body:V.body,signal:Y.signal,dispatcher:X};return await v7($.toString(),K)}catch(K){if(K instanceof Error&&K.name==="AbortError"){if(J)throw Error(`Request timeout after ${Q}ms`);throw K}throw K}finally{clearTimeout(G),Z?.removeEventListener("abort",B)}}import{spawn as P7}from"child_process";import*as E0 from"crypto";import*as u$ from"fs/promises";import*as h4 from"http";import*as R0 from"path";import{URL as k7}from"url";var I4={authorizationUrl:"https://accounts.google.com/o/oauth2/v2/auth",tokenUrl:"https://oauth2.googleapis.com/token",scopes:["https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/userinfo.profile","https://www.googleapis.com/auth/cclog","https://www.googleapis.com/auth/experimentsandconfigs"],clientId:process.env.ANTIGRAVITY_CLIENT_ID||"",clientSecret:process.env.ANTIGRAVITY_CLIENT_SECRET||"",redirectPort:51121,redirectPath:"/oauth-callback"},f4={authorizationUrl:"https://accounts.google.com/o/oauth2/v2/auth",tokenUrl:"https://oauth2.googleapis.com/token",scopes:["https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/userinfo.profile"],clientId:process.env.GEMINI_CLI_CLIENT_ID||"",clientSecret:process.env.GEMINI_CLI_CLIENT_SECRET||"",redirectPort:45289,redirectPath:"/"},z0={production:"https://cloudcode-pa.googleapis.com",sandbox:"https://daily-cloudcode-pa.sandbox.googleapis.com"},N0={generateContent:"/v1internal:generateContent",streamGenerateContent:"/v1internal:streamGenerateContent",loadCodeAssist:"/v1internal:loadCodeAssist",onboardUser:"/v1internal:onboardUser"};var p$=M("Service"),V2="antigravity-token.json";function x4($){return $==="gemini-cli"?f4:I4}function X2(){let $=process.env.HOME||process.env.USERPROFILE||"";return R0.join($,".blade")}class s${static instance=null;cachedToken=null;constructor(){}static getInstance(){if(!s$.instance)s$.instance=new s$;return s$.instance}async isLoggedIn(){let $=await this.loadToken();if(!$)return!1;let W=300000;if($.expiresAt&&Date.now()>$.expiresAt-W){if($.refreshToken)try{return await this.refreshToken(),!0}catch{return!1}return!1}return!0}async login($="antigravity"){let W=$==="gemini-cli"?"Gemini CLI":"Antigravity";p$.info(`\uD83D\uDD10 Starting ${W} OAuth login...`);let Q=x4($),Z=this.generatePKCEParams(),V=this.buildAuthorizationUrl(Z,Q);console.log(`
30
+ `):void 0}}async executeHook($,W,Q){if($.type==="command")return this.executeCommandHook($,W,Q);throw Error(`Hook type ${$.type} not yet implemented`)}async executeCommandHook($,W,Q){let Z=($.timeout??Q.config.defaultTimeout??60)*1000;try{let V=await this.processExecutor.execute($.command,W,Q,Z);return this.outputParser.parse(V,$,{timeoutBehavior:Q.config.timeoutBehavior,failureBehavior:Q.config.failureBehavior})}catch(V){return{success:!1,blocking:!1,error:V instanceof Error?V.message:String(V),hook:$}}}async executeHooksConcurrently($,W,Q,Z){let V=[],X=new Set;for(let Y of $){if(X.size>=Z)await Promise.race(X);let J=this.executeHook(Y,W,Q).catch((K)=>({success:!1,blocking:!1,error:K instanceof Error?K.message:String(K),hook:Y})),G=J.then(()=>{X.delete(G)}).catch(()=>{X.delete(G)});X.add(G),V.push(J)}return Promise.all(V)}}import e1 from"picomatch";var j7=/^([A-Za-z0-9_|]+)\((.+)\)$/;class $2{matches($,W){if(!$)return!0;if($.tools&&W.toolName){if(!this.matchTools($.tools,W))return!1}if($.paths&&W.filePath){if(!this.matchPaths($.paths,W.filePath))return!1}if($.commands&&W.command){if(!this.matchCommands($.commands,W.command))return!1}return!0}matchTools($,W){if(Array.isArray($))return $.some((Q)=>this.matchToolWithParams(Q,W));return this.matchToolWithParams($,W)}matchPaths($,W){if(Array.isArray($))return $.some((Z)=>{return e1(Z)(W)});return e1($)(W)}matchCommands($,W){if(Array.isArray($))return $.some((Q)=>this.matchPattern(W,Q));return this.matchPattern(W,$)}matchToolWithParams($,W){let{toolName:Q,command:Z,filePath:V}=W,X=j7.exec($);if(!X)return this.matchPattern(Q,$);let[,Y,J]=X;if(!this.matchPattern(Q,Y))return!1;let G=this.getArgValue(Q,Z,V);if(!G)return!1;return this.matchGlobOrPattern(G,J)}getArgValue($,W,Q){if($==="Bash"||$==="BashTool")return W;if(["Read","Edit","Write","Glob","Grep"].includes($))return Q;return W||Q}matchGlobOrPattern($,W){if(/[*?[\]{}!]/.test(W))try{return e1(W,{bash:!0,dot:!0})($)}catch{}if(W.endsWith("*")){let Q=W.slice(0,-1);return $.startsWith(Q)}return $===W}matchPattern($,W){if(W==="*")return!0;if(!W.includes("|")&&!/[.*+?^${}()|[\]\\]/.test(W))return $===W;if(W.includes("|"))return W.split("|").map((Z)=>Z.trim()).includes($);try{return new RegExp(W).test($)}catch{return $===W}}}class a{static instance=null;config=g1;executor=new t1;guard=new i1;matcher=new $2;sessionDisabled=!1;constructor(){}static getInstance(){if(!a.instance)a.instance=new a;return a.instance}loadConfig($){let W=c1(g1,$),Q=v4();W=c1(W,Q),this.config=W}isEnabled(){if(!this.config.enabled)return!1;if(this.sessionDisabled)return!1;return!0}disable(){this.sessionDisabled=!0,console.log("[HookManager] Hooks disabled for this session")}enable(){this.sessionDisabled=!1,console.log("[HookManager] Hooks enabled for this session")}getConfig(){return this.config}async reloadConfig(){let $=await import("node:fs/promises"),W=await import("node:path");try{let Q=W.join(process.cwd(),".blade","settings.local.json"),Z=await $.readFile(Q,"utf-8"),V=JSON.parse(Z);if(V.hooks)this.loadConfig(V.hooks)}catch{}}async executePreToolHooks($,W,Q,Z){if(!this.isEnabled())return{decision:"allow"};if(Z.permissionMode==="plan")return{decision:"allow"};if(!this.guard.canExecute(W,"PreToolUse"))return{decision:"allow"};let V={hook_event_name:"PreToolUse",hook_execution_id:G$(),timestamp:new Date().toISOString(),tool_name:$,tool_use_id:W,tool_input:Q,project_dir:Z.projectDir,session_id:Z.sessionId,permission_mode:Z.permissionMode},X=this.getMatchingHooks("PreToolUse",{toolName:$,filePath:this.extractFilePath(Q),command:this.extractCommand($,Q)});if(X.length===0)return{decision:"allow"};let Y={projectDir:Z.projectDir,sessionId:Z.sessionId,permissionMode:Z.permissionMode,config:this.config,abortSignal:Z.abortSignal};try{let J=await this.executor.executePreToolHooks(X,V,Y);if(this.guard.markExecuted(W,"PreToolUse"),Z.permissionMode==="yolo"){if(J.decision==="deny")return J;return{decision:"allow",modifiedInput:J.modifiedInput,warning:J.warning,reason:J.reason}}return J}catch(J){return console.error("[HookManager] Error executing PreToolUse hooks:",J),{decision:"allow",warning:`Hook execution failed: ${J instanceof Error?J.message:String(J)}`}}}async executePostToolHooks($,W,Q,Z,V){if(!this.isEnabled())return{};if(V.permissionMode==="plan")return{};if(!this.guard.canExecute(W,"PostToolUse"))return{};let X={hook_event_name:"PostToolUse",hook_execution_id:G$(),timestamp:new Date().toISOString(),tool_name:$,tool_use_id:W,tool_input:Q,tool_response:Z,project_dir:V.projectDir,session_id:V.sessionId,permission_mode:V.permissionMode},Y=this.getMatchingHooks("PostToolUse",{toolName:$,filePath:this.extractFilePath(Q),command:this.extractCommand($,Q)});if(Y.length===0)return{};let J={projectDir:V.projectDir,sessionId:V.sessionId,permissionMode:V.permissionMode,config:this.config,abortSignal:V.abortSignal};try{let G=await this.executor.executePostToolHooks(Y,X,J);return this.guard.markExecuted(W,"PostToolUse"),G}catch(G){return console.error("[HookManager] Error executing PostToolUse hooks:",G),{warning:`Hook execution failed: ${G instanceof Error?G.message:String(G)}`}}finally{this.guard.cleanup(W)}}async executeStopHooks($){if(!this.isEnabled())return{shouldStop:!0};let W={hook_event_name:"Stop",hook_execution_id:G$(),timestamp:new Date().toISOString(),project_dir:$.projectDir,session_id:$.sessionId,permission_mode:$.permissionMode,reason:$.reason},Q=this.getMatchingHooks("Stop",{});if(Q.length===0)return{shouldStop:!0};let Z={projectDir:$.projectDir,sessionId:$.sessionId,permissionMode:$.permissionMode,config:this.config,abortSignal:$.abortSignal};try{return await this.executor.executeStopHooks(Q,W,Z)}catch(V){return console.error("[HookManager] Error executing Stop hooks:",V),{shouldStop:!0,warning:`Hook execution failed: ${V instanceof Error?V.message:String(V)}`}}}async executeSubagentStartHooks($,W){if(!this.isEnabled())return{proceed:!0};let Q={hook_event_name:"SubagentStart",hook_execution_id:G$(),timestamp:new Date().toISOString(),project_dir:W.projectDir,session_id:W.sessionId,permission_mode:W.permissionMode,agent_type:$,task_description:W.taskDescription,parent_agent_id:W.parentAgentId},Z=this.getMatchingHooks("SubagentStart",{toolName:$});if(Z.length===0)return{proceed:!0};let V={projectDir:W.projectDir,sessionId:W.sessionId,permissionMode:W.permissionMode,config:this.config,abortSignal:W.abortSignal};try{return await this.executor.executeSubagentStartHooks(Z,Q,V)}catch(X){return console.error("[HookManager] Error executing SubagentStart hooks:",X),{proceed:!0,warning:`Hook execution failed: ${X instanceof Error?X.message:String(X)}`}}}async executeSubagentStopHooks($,W){if(!this.isEnabled())return{shouldStop:!0};let Q={hook_event_name:"SubagentStop",hook_execution_id:G$(),timestamp:new Date().toISOString(),project_dir:W.projectDir,session_id:W.sessionId,permission_mode:W.permissionMode,agent_type:$,task_description:W.taskDescription,success:W.success,result_summary:W.resultSummary,error:W.error},Z=this.getMatchingHooks("SubagentStop",{});if(Z.length===0)return{shouldStop:!0};let V={projectDir:W.projectDir,sessionId:W.sessionId,permissionMode:W.permissionMode,config:this.config,abortSignal:W.abortSignal};try{return await this.executor.executeSubagentStopHooks(Z,Q,V)}catch(X){return console.error("[HookManager] Error executing SubagentStop hooks:",X),{shouldStop:!0,warning:`Hook execution failed: ${X instanceof Error?X.message:String(X)}`}}}async executeTaskCompletedHooks($,W){if(!this.isEnabled())return{allowCompletion:!0};let Q={hook_event_name:"TaskCompleted",hook_execution_id:G$(),timestamp:new Date().toISOString(),project_dir:W.projectDir,session_id:W.sessionId,permission_mode:W.permissionMode,task_id:$,task_description:W.taskDescription,result_summary:W.resultSummary,success:W.success},Z=this.getMatchingHooks("TaskCompleted",{});if(Z.length===0)return{allowCompletion:!0};let V={projectDir:W.projectDir,sessionId:W.sessionId,permissionMode:W.permissionMode,config:this.config,abortSignal:W.abortSignal};try{return await this.executor.executeTaskCompletedHooks(Z,Q,V)}catch(X){return console.error("[HookManager] Error executing TaskCompleted hooks:",X),{allowCompletion:!0,warning:`Hook execution failed: ${X instanceof Error?X.message:String(X)}`}}}async executePermissionRequestHooks($,W,Q,Z){if(!this.isEnabled())return{decision:"ask"};let V={hook_event_name:"PermissionRequest",hook_execution_id:G$(),timestamp:new Date().toISOString(),tool_name:$,tool_use_id:W,tool_input:Q,project_dir:Z.projectDir,session_id:Z.sessionId,permission_mode:Z.permissionMode},X=this.getMatchingHooks("PermissionRequest",{toolName:$,filePath:this.extractFilePath(Q),command:this.extractCommand($,Q)});if(X.length===0)return{decision:"ask"};let Y={projectDir:Z.projectDir,sessionId:Z.sessionId,permissionMode:Z.permissionMode,config:this.config,abortSignal:Z.abortSignal};try{return await this.executor.executePermissionRequestHooks(X,V,Y)}catch(J){return console.error("[HookManager] Error executing PermissionRequest hooks:",J),{decision:"ask",warning:`Hook execution failed: ${J instanceof Error?J.message:String(J)}`}}}async executeUserPromptSubmitHooks($,W){if(!this.isEnabled())return{proceed:!0};let Q={hook_event_name:"UserPromptSubmit",hook_execution_id:G$(),timestamp:new Date().toISOString(),user_prompt:$,has_images:W.hasImages,image_count:W.imageCount,project_dir:W.projectDir,session_id:W.sessionId,permission_mode:W.permissionMode},Z=this.getMatchingHooks("UserPromptSubmit",{});if(Z.length===0)return{proceed:!0};let V={projectDir:W.projectDir,sessionId:W.sessionId,permissionMode:W.permissionMode,config:this.config,abortSignal:W.abortSignal};try{return await this.executor.executeUserPromptSubmitHooks(Z,Q,V)}catch(X){return console.error("[HookManager] Error executing UserPromptSubmit hooks:",X),{proceed:!0,warning:`Hook execution failed: ${X instanceof Error?X.message:String(X)}`}}}async executeSessionStartHooks($){if(!this.isEnabled())return{proceed:!0};let W={hook_event_name:"SessionStart",hook_execution_id:G$(),timestamp:new Date().toISOString(),project_dir:$.projectDir,session_id:$.sessionId,permission_mode:$.permissionMode,is_resume:$.isResume,resume_session_id:$.resumeSessionId},Q=this.getMatchingHooks("SessionStart",{});if(Q.length===0)return{proceed:!0};let Z={projectDir:$.projectDir,sessionId:$.sessionId,permissionMode:$.permissionMode,config:this.config,abortSignal:$.abortSignal};try{return await this.executor.executeSessionStartHooks(Q,W,Z)}catch(V){return console.error("[HookManager] Error executing SessionStart hooks:",V),{proceed:!0,warning:`Hook execution failed: ${V instanceof Error?V.message:String(V)}`}}}async executeSessionEndHooks($,W){if(!this.isEnabled())return{};let Q={hook_event_name:"SessionEnd",hook_execution_id:G$(),timestamp:new Date().toISOString(),project_dir:W.projectDir,session_id:W.sessionId,permission_mode:W.permissionMode,reason:$},Z=this.getMatchingHooks("SessionEnd",{});if(Z.length===0)return{};let V={projectDir:W.projectDir,sessionId:W.sessionId,permissionMode:W.permissionMode,config:this.config,abortSignal:W.abortSignal};try{return await this.executor.executeSessionEndHooks(Z,Q,V),{}}catch(X){return console.error("[HookManager] Error executing SessionEnd hooks:",X),{warning:`Hook execution failed: ${X instanceof Error?X.message:String(X)}`}}}async executePostToolUseFailureHooks($,W,Q,Z,V){if(!this.isEnabled())return{};let X={hook_event_name:"PostToolUseFailure",hook_execution_id:G$(),timestamp:new Date().toISOString(),tool_name:$,tool_use_id:W,tool_input:Q,error:Z,error_type:V.errorType,is_interrupt:V.isInterrupt,is_timeout:V.isTimeout,project_dir:V.projectDir,session_id:V.sessionId,permission_mode:V.permissionMode},Y=this.getMatchingHooks("PostToolUseFailure",{toolName:$,filePath:this.extractFilePath(Q),command:this.extractCommand($,Q)});if(Y.length===0)return{};let J={projectDir:V.projectDir,sessionId:V.sessionId,permissionMode:V.permissionMode,config:this.config,abortSignal:V.abortSignal};try{return await this.executor.executePostToolUseFailureHooks(Y,X,J)}catch(G){return console.error("[HookManager] Error executing PostToolUseFailure hooks:",G),{warning:`Hook execution failed: ${G instanceof Error?G.message:String(G)}`}}}async executeNotificationHooks($,W,Q){if(!this.isEnabled())return{suppress:!1,message:W};let Z={hook_event_name:"Notification",hook_execution_id:G$(),timestamp:new Date().toISOString(),project_dir:Q.projectDir,session_id:Q.sessionId,permission_mode:Q.permissionMode,notification_type:$,title:Q.title,message:W},V=this.getMatchingHooks("Notification",{});if(V.length===0)return{suppress:!1,message:W};let X={projectDir:Q.projectDir,sessionId:Q.sessionId,permissionMode:Q.permissionMode,config:this.config,abortSignal:Q.abortSignal};try{return await this.executor.executeNotificationHooks(V,Z,X)}catch(Y){return console.error("[HookManager] Error executing Notification hooks:",Y),{suppress:!1,message:W,warning:`Hook execution failed: ${Y instanceof Error?Y.message:String(Y)}`}}}async executeCompactionHooks($,W){if(!this.isEnabled())return{blockCompaction:!1};let Q={hook_event_name:"Compaction",hook_execution_id:G$(),timestamp:new Date().toISOString(),project_dir:W.projectDir,session_id:W.sessionId,permission_mode:W.permissionMode,trigger:$,messages_before:W.messagesBefore,tokens_before:W.tokensBefore},Z=this.getMatchingHooks("Compaction",{});if(Z.length===0)return{blockCompaction:!1};let V={projectDir:W.projectDir,sessionId:W.sessionId,permissionMode:W.permissionMode,config:this.config,abortSignal:W.abortSignal};try{return await this.executor.executeCompactionHooks(Z,Q,V)}catch(X){return console.error("[HookManager] Error executing Compaction hooks:",X),{blockCompaction:!1,warning:`Hook execution failed: ${X instanceof Error?X.message:String(X)}`}}}getMatchingHooks($,W){let Q=this.config[$]||[],Z=[];for(let V of Q)if(this.matcher.matches(V.matcher,W))Z.push(...V.hooks);return Z}extractFilePath($){let W=["file_path","path","filePath","source","target"];for(let Q of W){let Z=$[Q];if(typeof Z==="string")return Z}return}extractCommand($,W){if($==="Bash"||$==="BashTool"){let Q=W.command;if(typeof Q==="string")return Q}return}cleanup(){this.guard.cleanupAll()}}import{appendFileSync as N7,existsSync as z7,mkdirSync as R7,readdirSync as E7,statSync as k4,unlinkSync as C7}from"node:fs";import M7 from"node:os";import Q2 from"node:path";var Z2;((V)=>{V[V.DEBUG=0]="DEBUG";V[V.INFO=1]="INFO";V[V.WARN=2]="WARN";V[V.ERROR=3]="ERROR"})(Z2||={});var m;((w)=>{w.AGENT="Agent";w.UI="UI";w.TOOL="Tool";w.SERVICE="Service";w.CONFIG="Config";w.CONTEXT="Context";w.EXECUTION="Execution";w.LOOP="Loop";w.CHAT="Chat";w.GENERAL="General";w.PROMPTS="Prompts";w.SPEC="Spec"})(m||={});var W2=null,T4=null,P4=!1;function eW($){if(W2!==$)W2=$}async function $Q(){}function S7(){if(P4)return T4;P4=!0;try{let $=Q2.join(M7.homedir(),".blade","logs");if(!z7($))R7($,{recursive:!0,mode:493});if(k4($).uid===0&&process.getuid&&process.getuid()!==0)return console.error(""),console.error("❌ 权限错误:~/.blade/logs 目录属于 root 用户"),console.error(""),console.error("这通常是因为您曾经使用 sudo 运行过 blade。"),console.error(""),console.error("解决方法:"),console.error(" sudo chown -R $USER:$USER ~/.blade/"),console.error(""),console.error("然后重新运行 blade(不要使用 sudo)"),console.error(""),null;return v7($,30),T4=$,$}catch($){return console.error("[Logger] 无法创建日志目录:",$),null}}function v7($,W){try{let Q=E7($),Z=Date.now(),V=W*24*60*60*1000;for(let X of Q){if(!X.startsWith("blade-")||!X.endsWith(".log")&&!X.endsWith(".jsonl"))continue;let Y=Q2.join($,X);try{let J=k4(Y);if(Z-J.mtimeMs>V)C7(Y)}catch(J){}}}catch(Q){}}function y7(){let $=S7();if(!$)return null;let W=W2||"default";return Q2.join($,`blade-${W}.jsonl`)}function T7($,W,Q){let Z=y7();if(!Z)return;try{let V={timestamp:new Date().toISOString(),level:Z2[W],category:$,message:Q};N7(Z,JSON.stringify(V)+`
31
+ `)}catch(V){}}class T${static globalDebugConfig=null;enabled;minLevel;category;constructor($={}){if($.enabled!==void 0)this.enabled=$.enabled;else if(T$.globalDebugConfig!==null)this.enabled=Boolean(T$.globalDebugConfig);else this.enabled=!1;this.minLevel=$.minLevel??0,this.category=$.category??"General"}static setGlobalDebug($){T$.globalDebugConfig=$}static clearGlobalDebug(){T$.globalDebugConfig=null}setEnabled($){this.enabled=$}parseDebugFilter($){if(!$)return{enabled:!1};if($===!0||$==="true"||$==="1")return{enabled:!0};let W=String($).trim();if(!W)return{enabled:!0};if(W.startsWith("!"))return{enabled:!0,filter:{mode:"exclude",categories:W.split(",").map((V)=>V.trim().replace(/^!/,"")).filter(Boolean)}};return{enabled:!0,filter:{mode:"include",categories:W.split(",").map((Z)=>Z.trim()).filter(Boolean)}}}shouldLogCategory($){if(!$)return!0;let W=this.category.toLowerCase();if($.mode==="include")return $.categories.some((Q)=>W.includes(Q.toLowerCase()));return!$.categories.some((Q)=>W.includes(Q.toLowerCase()))}shouldLogToConsole($){if(T$.globalDebugConfig!==null){let{enabled:W,filter:Q}=this.parseDebugFilter(T$.globalDebugConfig);if(!W)return!1;if($<this.minLevel)return!1;return this.shouldLogCategory(Q)}return this.enabled&&$>=this.minLevel}log($,...W){let Q=W.map((Z)=>typeof Z==="object"?JSON.stringify(Z):String(Z)).join(" ");if(T7(this.category,$,Q),this.shouldLogToConsole($)){let Z=Z2[$],V=`[${this.category}] [${Z}]`;console.error(V,...W)}}debug(...$){this.log(0,...$)}info(...$){this.log(1,...$)}warn(...$){this.log(2,...$)}error(...$){this.log(3,...$)}}function M($,W){return new T$({...W,category:$})}var WQ=new T$({category:"General"});import{ProxyAgent as P7,fetch as k7}from"undici";function I7(){return process.env.HTTPS_PROXY||process.env.HTTP_PROXY||process.env.https_proxy||process.env.http_proxy}function f7(){let $=I7();if($)try{return new P7($)}catch(W){console.warn(`[proxyFetch] Invalid proxy URL: ${$}`)}return}async function r($,W={}){let{timeout:Q=30000,signal:Z,...V}=W;if(Z?.aborted)throw new DOMException("The operation was aborted.","AbortError");let X=f7(),Y=new AbortController,J=!1,G=setTimeout(()=>{J=!0,Y.abort()},Q),K=()=>Y.abort();Z?.addEventListener("abort",K);try{let B={method:V.method,headers:V.headers,body:V.body,signal:Y.signal,dispatcher:X};return await k7($.toString(),B)}catch(B){if(B instanceof Error&&B.name==="AbortError"){if(J)throw Error(`Request timeout after ${Q}ms`);throw B}throw B}finally{clearTimeout(G),Z?.removeEventListener("abort",K)}}import{spawn as x7}from"child_process";import*as E0 from"crypto";import*as p$ from"fs/promises";import*as h4 from"http";import*as R0 from"path";import{URL as h7}from"url";var I4={authorizationUrl:"https://accounts.google.com/o/oauth2/v2/auth",tokenUrl:"https://oauth2.googleapis.com/token",scopes:["https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/userinfo.profile","https://www.googleapis.com/auth/cclog","https://www.googleapis.com/auth/experimentsandconfigs"],clientId:process.env.ANTIGRAVITY_CLIENT_ID||"",clientSecret:process.env.ANTIGRAVITY_CLIENT_SECRET||"",redirectPort:51121,redirectPath:"/oauth-callback"},f4={authorizationUrl:"https://accounts.google.com/o/oauth2/v2/auth",tokenUrl:"https://oauth2.googleapis.com/token",scopes:["https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/userinfo.profile"],clientId:process.env.GEMINI_CLI_CLIENT_ID||"",clientSecret:process.env.GEMINI_CLI_CLIENT_SECRET||"",redirectPort:45289,redirectPath:"/"},N0={production:"https://cloudcode-pa.googleapis.com",sandbox:"https://daily-cloudcode-pa.sandbox.googleapis.com"},z0={generateContent:"/v1internal:generateContent",streamGenerateContent:"/v1internal:streamGenerateContent",loadCodeAssist:"/v1internal:loadCodeAssist",onboardUser:"/v1internal:onboardUser"};var h$=M("Service"),V2="antigravity-token.json";function x4($){return $==="gemini-cli"?f4:I4}function X2(){let $=process.env.HOME||process.env.USERPROFILE||"";return R0.join($,".blade")}class r${static instance=null;cachedToken=null;constructor(){}static getInstance(){if(!r$.instance)r$.instance=new r$;return r$.instance}async isLoggedIn(){let $=await this.loadToken();if(!$)return!1;let W=300000;if($.expiresAt&&Date.now()>$.expiresAt-W){if($.refreshToken)try{return await this.refreshToken(),!0}catch{return!1}return!1}return!0}async login($="antigravity"){let W=$==="gemini-cli"?"Gemini CLI":"Antigravity";h$.info(`\uD83D\uDD10 Starting ${W} OAuth login...`);let Q=x4($),Z=this.generatePKCEParams(),V=this.buildAuthorizationUrl(Z,Q);console.log(`
26
32
  \uD83C\uDF10 Opening browser for Google authentication...`),console.log(`
27
- If the browser does not open automatically, copy and paste this URL:`),console.log(V),console.log("");let X=this.startCallbackServer(Z.state,Q);try{await this.openBrowser(V)}catch(B){p$.warn("Failed to open browser automatically:",B)}let Y=await X;console.log("✅ Authorization code received, exchanging for tokens...");let J=await this.exchangeCodeForToken(Y,Z.codeVerifier,Q),G={accessToken:J.access_token,refreshToken:J.refresh_token||"",expiresAt:Date.now()+J.expires_in*1000,tokenType:J.token_type||"Bearer",scope:J.scope,configType:$};await this.saveToken(G),this.cachedToken=G,console.log(`✅ ${W} login successful!`),p$.info(`${W} OAuth login completed`)}async logout(){let $=R0.join(X2(),V2);try{await u$.unlink($),this.cachedToken=null,console.log("✅ Logged out from Antigravity"),p$.info("Antigravity logout completed")}catch(W){if(W.code!=="ENOENT")throw W;this.cachedToken=null}}async getAccessToken(){if(this.cachedToken){if(this.cachedToken.expiresAt>Date.now()+300000)return this.cachedToken.accessToken}let $=await this.loadToken();if(!$)throw Error("Not logged in. Please run /login first.");let W=300000;if($.expiresAt<=Date.now()+W){if(!$.refreshToken)throw Error("Token expired and no refresh token available. Please run /login again.");return await this.refreshToken(),this.cachedToken.accessToken}return this.cachedToken=$,$.accessToken}async refreshToken(){let $=await this.loadToken();if(!$||!$.refreshToken)throw Error("No refresh token available");let W=$.configType||"antigravity",Q=x4(W),Z=W==="gemini-cli"?"Gemini CLI":"Antigravity";p$.info(`\uD83D\uDD04 Refreshing ${Z} access token...`);let V=new URLSearchParams({grant_type:"refresh_token",refresh_token:$.refreshToken,client_id:Q.clientId,client_secret:Q.clientSecret}),X=await r(Q.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:V.toString()});if(!X.ok){let G=await X.text();throw p$.error("Token refresh failed:",G),Error(`Token refresh failed: ${X.status}`)}let Y=await X.json(),J={accessToken:Y.access_token,refreshToken:Y.refresh_token||$.refreshToken,expiresAt:Date.now()+Y.expires_in*1000,tokenType:Y.token_type||"Bearer",scope:Y.scope||$.scope,configType:W};await this.saveToken(J),this.cachedToken=J,p$.info("✅ Token refreshed successfully")}generatePKCEParams(){let $=E0.randomBytes(32).toString("base64url"),W=E0.createHash("sha256").update($).digest("base64url"),Q=E0.randomBytes(16).toString("base64url");return{codeVerifier:$,codeChallenge:W,state:Q}}buildAuthorizationUrl($,W){let Q=`http://localhost:${W.redirectPort}${W.redirectPath}`,Z=new URLSearchParams({client_id:W.clientId,response_type:"code",redirect_uri:Q,state:$.state,code_challenge:$.codeChallenge,code_challenge_method:"S256",scope:W.scopes.join(" "),access_type:"offline",prompt:"consent"});return`${W.authorizationUrl}?${Z.toString()}`}async startCallbackServer($,W){let{redirectPort:Q,redirectPath:Z}=W;return new Promise((V,X)=>{let Y=null,J=!1,G=()=>{if(Y)clearTimeout(Y),Y=null},B=h4.createServer((K,q)=>{try{let w=new k7(K.url,`http://localhost:${Q}`);if(w.pathname!==Z){q.writeHead(404),q.end("Not found");return}let O=w.searchParams.get("code"),b=w.searchParams.get("state"),U=w.searchParams.get("error");if(U){if(q.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),q.end(`
33
+ If the browser does not open automatically, copy and paste this URL:`),console.log(V),console.log("");let X=this.startCallbackServer(Z.state,Q);try{await this.openBrowser(V)}catch(K){h$.warn("Failed to open browser automatically:",K)}let Y=await X;console.log("✅ Authorization code received, exchanging for tokens...");let J=await this.exchangeCodeForToken(Y,Z.codeVerifier,Q),G={accessToken:J.access_token,refreshToken:J.refresh_token||"",expiresAt:Date.now()+J.expires_in*1000,tokenType:J.token_type||"Bearer",scope:J.scope,configType:$};await this.saveToken(G),this.cachedToken=G,console.log(`✅ ${W} login successful!`),h$.info(`${W} OAuth login completed`)}async logout(){let $=R0.join(X2(),V2);try{await p$.unlink($),this.cachedToken=null,console.log("✅ Logged out from Antigravity"),h$.info("Antigravity logout completed")}catch(W){if(W.code!=="ENOENT")throw W;this.cachedToken=null}}async getAccessToken(){if(this.cachedToken){if(this.cachedToken.expiresAt>Date.now()+300000)return this.cachedToken.accessToken}let $=await this.loadToken();if(!$)throw Error("Not logged in. Please run /login first.");let W=300000;if($.expiresAt<=Date.now()+W){if(!$.refreshToken)throw Error("Token expired and no refresh token available. Please run /login again.");return await this.refreshToken(),this.cachedToken.accessToken}return this.cachedToken=$,$.accessToken}async refreshToken(){let $=await this.loadToken();if(!$||!$.refreshToken)throw Error("No refresh token available");let W=$.configType||"antigravity",Q=x4(W),Z=W==="gemini-cli"?"Gemini CLI":"Antigravity";h$.info(`\uD83D\uDD04 Refreshing ${Z} access token...`);let V=new URLSearchParams({grant_type:"refresh_token",refresh_token:$.refreshToken,client_id:Q.clientId,client_secret:Q.clientSecret}),X=await r(Q.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:V.toString()});if(!X.ok){let G=await X.text();throw h$.error("Token refresh failed:",G),Error(`Token refresh failed: ${X.status}`)}let Y=await X.json(),J={accessToken:Y.access_token,refreshToken:Y.refresh_token||$.refreshToken,expiresAt:Date.now()+Y.expires_in*1000,tokenType:Y.token_type||"Bearer",scope:Y.scope||$.scope,configType:W};await this.saveToken(J),this.cachedToken=J,h$.info("✅ Token refreshed successfully")}generatePKCEParams(){let $=E0.randomBytes(32).toString("base64url"),W=E0.createHash("sha256").update($).digest("base64url"),Q=E0.randomBytes(16).toString("base64url");return{codeVerifier:$,codeChallenge:W,state:Q}}buildAuthorizationUrl($,W){let Q=`http://localhost:${W.redirectPort}${W.redirectPath}`,Z=new URLSearchParams({client_id:W.clientId,response_type:"code",redirect_uri:Q,state:$.state,code_challenge:$.codeChallenge,code_challenge_method:"S256",scope:W.scopes.join(" "),access_type:"offline",prompt:"consent"});return`${W.authorizationUrl}?${Z.toString()}`}async startCallbackServer($,W){let{redirectPort:Q,redirectPath:Z}=W;return new Promise((V,X)=>{let Y=null,J=!1,G=()=>{if(Y)clearTimeout(Y),Y=null},K=h4.createServer((B,q)=>{try{let w=new h7(B.url,`http://localhost:${Q}`);if(w.pathname!==Z){q.writeHead(404),q.end("Not found");return}let O=w.searchParams.get("code"),H=w.searchParams.get("state"),U=w.searchParams.get("error");if(U){if(q.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),q.end(`
28
34
  <html>
29
35
  <head><title>Authentication Failed</title></head>
30
36
  <body style="font-family: system-ui; padding: 40px; text-align: center;">
@@ -33,7 +39,7 @@ If the browser does not open automatically, copy and paste this URL:`),console.l
33
39
  <p>You can close this window.</p>
34
40
  </body>
35
41
  </html>
36
- `),G(),B.close(),!J)J=!0,X(Error(`OAuth error: ${U}`));return}if(!O||!b){q.writeHead(400),q.end("Missing code or state parameter");return}if(b!==$){if(q.writeHead(400),q.end("Invalid state parameter"),G(),B.close(),!J)J=!0,X(Error("State mismatch - possible CSRF attack"));return}if(q.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),q.end(`
42
+ `),G(),K.close(),!J)J=!0,X(Error(`OAuth error: ${U}`));return}if(!O||!H){q.writeHead(400),q.end("Missing code or state parameter");return}if(H!==$){if(q.writeHead(400),q.end("Invalid state parameter"),G(),K.close(),!J)J=!0,X(Error("State mismatch - possible CSRF attack"));return}if(q.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),q.end(`
37
43
  <html>
38
44
  <head><title>Authentication Successful</title></head>
39
45
  <body style="font-family: system-ui; padding: 40px; text-align: center;">
@@ -42,21 +48,21 @@ If the browser does not open automatically, copy and paste this URL:`),console.l
42
48
  <script>setTimeout(() => window.close(), 2000);</script>
43
49
  </body>
44
50
  </html>
45
- `),G(),B.close(),!J)J=!0,V(O)}catch(w){if(G(),B.close(),!J)J=!0,X(w)}});B.on("error",(K)=>{if(G(),!J)if(J=!0,K.code==="EADDRINUSE")X(Error(`Port ${Q} is already in use. Please close other applications using this port.`));else X(K)}),B.listen(Q,()=>{p$.debug(`OAuth callback server listening on port ${Q}`)}),Y=setTimeout(()=>{if(B.close(),!J)J=!0,X(Error("OAuth callback timeout (5 minutes)"))},300000)})}async exchangeCodeForToken($,W,Q){let Z=`http://localhost:${Q.redirectPort}${Q.redirectPath}`,V=new URLSearchParams({grant_type:"authorization_code",code:$,redirect_uri:Z,code_verifier:W,client_id:Q.clientId,client_secret:Q.clientSecret}),X=await r(Q.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:V.toString()});if(!X.ok){let Y=await X.text();throw Error(`Token exchange failed: ${X.status} - ${Y}`)}return await X.json()}async openBrowser($){let W,Q;if(process.platform==="darwin")W="open",Q=[$];else if(process.platform==="win32")W="cmd",Q=["/c","start","",$];else W="xdg-open",Q=[$];await new Promise((Z,V)=>{let X=P7(W,Q,{stdio:"ignore"});X.once("error",V),X.once("close",(Y)=>{if(Y===0||Y===null)Z();else V(Error(`Failed to open browser (exit code ${Y})`))})})}async saveToken($){let W=X2();await u$.mkdir(W,{recursive:!0,mode:493});let Q=R0.join(W,V2);await u$.writeFile(Q,JSON.stringify($,null,2),{mode:384})}async loadToken(){let $=R0.join(X2(),V2);try{let W=await u$.readFile($,"utf-8");return JSON.parse(W)}catch(W){if(W.code==="ENOENT")return null;throw W}}async getStatus(){let $=await this.loadToken();if(!$)return{loggedIn:!1};return{loggedIn:!0,expiresAt:$.expiresAt?new Date($.expiresAt):void 0,configType:$.configType||"antigravity"}}async getConfigType(){let $=await this.loadToken();if(!$)return null;return $.configType||"antigravity"}}var T=M("Chat");function p4($){if($==="antigravity")return{ideType:"ANTIGRAVITY"};return{ideType:"IDE_UNSPECIFIED",platform:"PLATFORM_UNSPECIFIED",pluginType:"GEMINI"}}function V1($){if($==="antigravity")return"antigravity/1.11.3 Darwin/arm64";return"gemini-cli/1.0.0"}function u4($){let W=new Set;for(let Q of $)if(Q.role==="assistant"&&Q.tool_calls)for(let Z of Q.tool_calls)W.add(Z.id);return $.filter((Q)=>{if(Q.role==="tool"){if(!Q.tool_call_id)return!1;return W.has(Q.tool_call_id)}return!0})}function X1($){if(typeof $==="string")return $;return $.filter((W)=>W.type==="text").map((W)=>W.text).join(`
46
- `)}function Y2($){let W=["const","$ref","$defs","$schema","$id","default","examples"],Q={};for(let[Z,V]of Object.entries($)){if(W.includes(Z)){if(Z==="const")Q.enum=[V];continue}if(V&&typeof V==="object"&&!Array.isArray(V))Q[Z]=Y2(V);else if(Array.isArray(V))Q[Z]=V.map((X)=>X&&typeof X==="object"&&!Array.isArray(X)?Y2(X):X);else Q[Z]=V}return Q}class J2{config;auth;projectId;userTier;sessionId;configType="antigravity";projectIdInitialized=!1;constructor($){this.config=$,this.auth=s$.getInstance(),this.projectId=void 0,this.sessionId=`session_${Date.now()}_${Math.random().toString(36).slice(2,11)}`,T.debug("\uD83D\uDE80 [AntigravityChatService] Initializing"),T.debug("⚙️ [AntigravityChatService] Config:",{model:$.model,temperature:$.temperature,maxOutputTokens:$.maxOutputTokens,sessionId:this.sessionId})}async ensureProjectId(){if(this.projectIdInitialized)return;try{let $=await this.auth.getConfigType();this.configType=$||"antigravity",T.debug(`\uD83D\uDD04 [AntigravityChatService] Using OAuth config: ${this.configType}`),T.debug("\uD83D\uDD04 [AntigravityChatService] Setting up user via loadCodeAssist...");let W=await this.auth.getAccessToken(),Q=await this.callLoadCodeAssist(W);if(T.debug("[AntigravityChatService] loadCodeAssist response:",JSON.stringify(Q)),Q.currentTier){if(this.userTier=Q.currentTier.id,Q.cloudaicompanionProject){this.projectId=Q.cloudaicompanionProject,T.debug(`✅ [AntigravityChatService] User already setup: tier=${this.userTier}, project=${this.projectId}`),this.projectIdInitialized=!0;return}let X=process.env.GOOGLE_CLOUD_PROJECT||process.env.GOOGLE_CLOUD_PROJECT_ID;if(X){this.projectId=X,T.debug(`✅ [AntigravityChatService] Using env project: ${this.projectId}`),this.projectIdInitialized=!0;return}T.debug("⚠️ [AntigravityChatService] Has tier but no project, need onboarding...")}let Z=this.getDefaultTier(Q);T.debug(`\uD83D\uDD04 [AntigravityChatService] Onboarding user with tier: ${Z.id}`);let V=await this.callOnboardUser(W,Z.id);this.projectId=V.projectId,this.userTier=Z.id,T.debug(`✅ [AntigravityChatService] User setup complete: tier=${this.userTier}, project=${this.projectId||"(managed)"}`)}catch($){T.warn("Failed to setup user:",$)}this.projectIdInitialized=!0}async callLoadCodeAssist($){let W=`${z0.production}${N0.loadCodeAssist}`,Q=p4(this.configType),Z=V1(this.configType),V=await r(W,{method:"POST",headers:{Authorization:`Bearer ${$}`,"Content-Type":"application/json","User-Agent":Z},body:JSON.stringify({metadata:Q})});if(!V.ok){let X=await V.text();throw Error(`loadCodeAssist failed: ${V.status} - ${X}`)}return await V.json()}getDefaultTier($){for(let W of $.allowedTiers||[])if(W.isDefault)return{id:W.id};return{id:"free-tier"}}async callOnboardUser($,W){let Q=`${z0.production}${N0.onboardUser}`,Z=p4(this.configType),V=V1(this.configType),X={tierId:W,metadata:Z};if(W!=="free-tier"){let G=process.env.GOOGLE_CLOUD_PROJECT||process.env.GOOGLE_CLOUD_PROJECT_ID;if(G)X.cloudaicompanionProject=G,X.metadata={...Z,duetProject:G}}let Y=0,J=30;while(Y<J){let G=await r(Q,{method:"POST",headers:{Authorization:`Bearer ${$}`,"Content-Type":"application/json","User-Agent":V},body:JSON.stringify(X)});if(!G.ok){let K=await G.text();throw Error(`onboardUser failed: ${G.status} - ${K}`)}let B=await G.json();if(T.debug(`[AntigravityChatService] onboardUser attempt ${Y+1}:`,JSON.stringify(B)),B.error)throw Error(`onboardUser error: ${B.error.message||B.error.code}`);if(B.done)return{projectId:B.response?.cloudaicompanionProject?.id};T.debug("[AntigravityChatService] onboardUser not done, waiting 5s..."),await new Promise((K)=>setTimeout(K,5000)),Y++}throw Error("onboardUser timeout: LRO did not complete in time")}convertToAntigravityMessages($){let W=$.find((J)=>J.role==="system"),Q=W?{parts:[{text:X1(W.content)}]}:void 0,Z=[],V=$.filter((J)=>J.role!=="system"),X=new Map;for(let J of V)if(J.role==="assistant"&&J.tool_calls){for(let G of J.tool_calls)if(G.type==="function")X.set(G.id,G.function.name)}for(let J of V)if(J.role==="user"){let G=[];if(Array.isArray(J.content)){for(let B of J.content)if(B.type==="text")G.push({text:B.text})}else G.push({text:J.content});Z.push({role:"user",parts:G})}else if(J.role==="assistant"){let G=[],B=X1(J.content);if(B)G.push({text:B});if(J.tool_calls)for(let K of J.tool_calls){if(K.type!=="function")continue;let q={};try{q=JSON.parse(K.function.arguments||"{}")}catch{T.warn(`Failed to parse tool arguments: ${K.function.arguments}`)}G.push({functionCall:{name:K.function.name,args:q,id:K.id}})}if(G.length>0)Z.push({role:"model",parts:G})}else if(J.role==="tool"){let G=X.get(J.tool_call_id||"");if(G){let B;try{B=JSON.parse(X1(J.content))}catch{B={result:X1(J.content)}}Z.push({role:"user",parts:[{functionResponse:{name:G,id:J.tool_call_id,response:B}}]})}}let Y=[];for(let J of Z){let G=Y[Y.length-1];if(G?.role===J.role)G.parts=[...G.parts,...J.parts];else Y.push(J)}if(Y.length>0&&Y[0].role!=="user")Y.unshift({role:"user",parts:[{text:"[Conversation start]"}]});return{systemInstruction:Q,contents:Y}}convertToAntigravityTools($){if(!$||$.length===0)return;return[{functionDeclarations:$.map((Q)=>({name:Q.name,description:Q.description,parameters:Y2(Q.parameters||{type:"object",properties:{}})}))}]}async makeRequest($,W,Q){let Z=await this.auth.getAccessToken(),V=`${z0.production}${$}`,X=V1(this.configType),Y=await r(V,{method:"POST",headers:{Authorization:`Bearer ${Z}`,"Content-Type":"application/json","User-Agent":X},body:JSON.stringify(W),signal:Q});if(!Y.ok){let J=await Y.text();if(T.error(`Antigravity API error: ${Y.status} - ${J}`),Y.status===401)throw Error("Authentication expired. Please run /login again.");if(Y.status===403)throw Error("Permission denied. Please check your Google account permissions.");if(Y.status===429)throw Error("Rate limit exceeded. Please wait a moment and try again.");throw Error(`Antigravity API error: ${Y.status} - ${J}`)}return Y}async chat($,W,Q){let Z=Date.now();T.debug("\uD83D\uDE80 [AntigravityChatService] Starting chat request"),T.debug("\uD83D\uDCDD [AntigravityChatService] Messages count:",$.length),await this.ensureProjectId();let V=u4($);if(V.length<$.length)T.debug(`Filtered ${$.length-V.length} orphan tool messages`);let{systemInstruction:X,contents:Y}=this.convertToAntigravityMessages(V),J=this.convertToAntigravityTools(W),G=`prompt_${Date.now()}_${Math.random().toString(36).slice(2,9)}`,B={model:this.config.model,project:this.projectId,user_prompt_id:G,request:{contents:Y,systemInstruction:X,generationConfig:{...this.config.maxOutputTokens&&{maxOutputTokens:this.config.maxOutputTokens},temperature:this.config.temperature??0.7},tools:J,session_id:this.sessionId}};T.debug("\uD83D\uDCE4 [AntigravityChatService] Request:",{model:this.config.model,contentsCount:Y.length,hasSystemInstruction:!!X,toolsCount:J?.[0]?.functionDeclarations?.length||0});try{let q=await(await this.makeRequest(N0.generateContent,B,Q)).json(),w=Date.now()-Z;T.debug("\uD83D\uDCE5 [AntigravityChatService] Response received in",w,"ms");let O="",b=[],F=q.response?.candidates?.[0]?.content?.parts||[];for(let N of F)if(N.text)O+=N.text;else if(N.functionCall){let C=N.functionCall;b.push({id:C.id||`call_${Date.now()}_${Math.random().toString(36).slice(2,9)}`,type:"function",function:{name:C.name,arguments:JSON.stringify(C.args||{})}})}let A=q.response?.usageMetadata,D={content:O,toolCalls:b.length>0?b:void 0,usage:{promptTokens:A?.promptTokenCount||0,completionTokens:A?.candidatesTokenCount||0,totalTokens:A?.totalTokenCount||0}};return T.debug("✅ [AntigravityChatService] Chat completed:",{contentLength:D.content.length,toolCallsCount:D.toolCalls?.length||0,usage:D.usage}),D}catch(K){let q=Date.now()-Z;throw T.error("❌ [AntigravityChatService] Chat failed after",q,"ms"),T.error("❌ [AntigravityChatService] Error:",K),K}}async*streamChat($,W,Q){let Z=Date.now();T.debug("\uD83D\uDE80 [AntigravityChatService] Starting stream request"),await this.ensureProjectId();let V=u4($),{systemInstruction:X,contents:Y}=this.convertToAntigravityMessages(V),J=this.convertToAntigravityTools(W),G=`prompt_${Date.now()}_${Math.random().toString(36).slice(2,9)}`,B={model:this.config.model,project:this.projectId,user_prompt_id:G,request:{contents:Y,systemInstruction:X,generationConfig:{...this.config.maxOutputTokens&&{maxOutputTokens:this.config.maxOutputTokens},temperature:this.config.temperature??0.7},tools:J,session_id:this.sessionId}};try{let K=await this.auth.getAccessToken(),q=`${z0.production}${N0.streamGenerateContent}?alt=sse`,w=V1(this.configType),O=await r(q,{method:"POST",headers:{Authorization:`Bearer ${K}`,"Content-Type":"application/json",Accept:"text/event-stream","User-Agent":w},body:JSON.stringify(B),signal:Q});if(!O.ok){let N=await O.text();throw Error(`Antigravity API error: ${O.status} - ${N}`)}let b=O.body?.getReader();if(!b)throw Error("No response body");let U=new TextDecoder,F="",A=0,D=Date.now()-Z;T.debug("\uD83D\uDCE5 [AntigravityChatService] Stream started in",D,"ms");while(!0){let{done:N,value:C}=await b.read();if(N)break;F+=U.decode(C,{stream:!0});let z=F.split(`
47
- `);F=z.pop()||"";for(let y of z)if(y.startsWith("data: ")){let l=y.slice(6);if(l==="[DONE]"){yield{finishReason:"stop"};continue}try{let j=JSON.parse(l);if(A++,j.usageMetadata)yield{usage:{promptTokens:j.usageMetadata.promptTokenCount||0,completionTokens:j.usageMetadata.candidatesTokenCount||0,totalTokens:j.usageMetadata.totalTokenCount||0}};let d=j.candidates?.[0],N$=d?.content?.parts||[];for(let R of N$)if(R.text)yield{content:R.text};else if(R.functionCall){let L=R.functionCall;yield{toolCalls:[{id:L.id||`call_${Date.now()}_${Math.random().toString(36).slice(2,9)}`,type:"function",function:{name:L.name,arguments:JSON.stringify(L.args||{})}}]}}let R$=d?.finishReason;if(R$)yield{finishReason:R$==="STOP"?"stop":R$==="MAX_TOKENS"?"length":R$.toLowerCase()}}catch(j){T.debug("Failed to parse SSE data:",l)}}}T.debug("✅ [AntigravityChatService] Stream completed:",{eventCount:A,duration:Date.now()-Z+"ms"})}catch(K){let q=Date.now()-Z;throw T.error("❌ [AntigravityChatService] Stream failed after",q,"ms"),T.error("❌ [AntigravityChatService] Error:",K),K}}getConfig(){return{...this.config}}updateConfig($){T.debug("\uD83D\uDD04 [AntigravityChatService] Updating configuration"),this.config={...this.config,...$},T.debug("✅ [AntigravityChatService] Configuration updated")}}var C0=M("Service"),I7="https://blade-api-proxy.137844255.workers.dev/v1/get-zhipu-key",d4="blade-free-tier",Y1=null;async function m4($){if($!==d4)return $;if(Y1)return C0.debug("使用缓存的内置 API Key"),Y1;try{C0.info("\uD83D\uDD11 正在从代理服务获取内置 API Key...");let W=await r(I7,{method:"GET",headers:{Authorization:`Bearer ${d4}`,"Content-Type":"application/json"},timeout:1e4});if(!W.ok){let Z=await W.text();throw Error(`获取 API Key 失败: ${W.status} - ${Z}`)}let Q=await W.json();if(!Q.apiKey)throw Error("代理服务返回的数据中没有 apiKey");if(Y1=Q.apiKey,C0.info("✅ 成功获取内置 API Key"),Q.message)C0.debug(`提示: ${Q.message}`);return Y1}catch(W){throw C0.error("❌ 获取内置 API Key 失败:",W),Error(`无法获取内置模型的 API Key: ${W instanceof Error?W.message:"未知错误"}
48
- `+"请检查网络连接或使用自己的 API Key (/config)")}}import{isPlainObject as J1}from"lodash-es";import{spawn as f7}from"child_process";import*as d$ from"fs/promises";import*as v0 from"path";var o$={deviceCodeUrl:"https://github.com/login/device/code",tokenUrl:"https://github.com/login/oauth/access_token",clientId:"01ab8ac9400c4e429b23",scope:"user:email",grantType:"urn:ietf:params:oauth:grant-type:device_code"},M0={tokenExchange:"https://api.github.com/copilot_internal/v2/token",chatCompletions:"https://api.githubcopilot.com/chat/completions",models:"https://api.githubcopilot.com/models"};var S0=M("Service"),G2="copilot-token.json";function B2(){let $=process.env.HOME||process.env.USERPROFILE||"";return v0.join($,".blade")}class t${static instance=null;cachedToken=null;constructor(){}static getInstance(){if(!t$.instance)t$.instance=new t$;return t$.instance}async isLoggedIn(){let $=await this.loadToken();if(!$)return!1;let W=300000;if($.copilotExpiresAt&&Date.now()>$.copilotExpiresAt-W)try{return await this.refreshCopilotToken(),!0}catch{return!1}return!0}async login(){S0.info("\uD83D\uDD10 Starting GitHub Copilot OAuth login..."),console.log(`
51
+ `),G(),K.close(),!J)J=!0,V(O)}catch(w){if(G(),K.close(),!J)J=!0,X(w)}});K.on("error",(B)=>{if(G(),!J)if(J=!0,B.code==="EADDRINUSE")X(Error(`Port ${Q} is already in use. Please close other applications using this port.`));else X(B)}),K.listen(Q,()=>{h$.debug(`OAuth callback server listening on port ${Q}`)}),Y=setTimeout(()=>{if(K.close(),!J)J=!0,X(Error("OAuth callback timeout (5 minutes)"))},300000)})}async exchangeCodeForToken($,W,Q){let Z=`http://localhost:${Q.redirectPort}${Q.redirectPath}`,V=new URLSearchParams({grant_type:"authorization_code",code:$,redirect_uri:Z,code_verifier:W,client_id:Q.clientId,client_secret:Q.clientSecret}),X=await r(Q.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:V.toString()});if(!X.ok){let Y=await X.text();throw Error(`Token exchange failed: ${X.status} - ${Y}`)}return await X.json()}async openBrowser($){let W,Q;if(process.platform==="darwin")W="open",Q=[$];else if(process.platform==="win32")W="cmd",Q=["/c","start","",$];else W="xdg-open",Q=[$];await new Promise((Z,V)=>{let X=x7(W,Q,{stdio:"ignore"});X.once("error",V),X.once("close",(Y)=>{if(Y===0||Y===null)Z();else V(Error(`Failed to open browser (exit code ${Y})`))})})}async saveToken($){let W=X2();await p$.mkdir(W,{recursive:!0,mode:493});let Q=R0.join(W,V2);await p$.writeFile(Q,JSON.stringify($,null,2),{mode:384})}async loadToken(){let $=R0.join(X2(),V2);try{let W=await p$.readFile($,"utf-8");return JSON.parse(W)}catch(W){if(W.code==="ENOENT")return null;throw W}}async getStatus(){let $=await this.loadToken();if(!$)return{loggedIn:!1};return{loggedIn:!0,expiresAt:$.expiresAt?new Date($.expiresAt):void 0,configType:$.configType||"antigravity"}}async getConfigType(){let $=await this.loadToken();if(!$)return null;return $.configType||"antigravity"}}var T=M("Chat");function p4($){if($==="antigravity")return{ideType:"ANTIGRAVITY"};return{ideType:"IDE_UNSPECIFIED",platform:"PLATFORM_UNSPECIFIED",pluginType:"GEMINI"}}function Z1($){if($==="antigravity")return"antigravity/1.11.3 Darwin/arm64";return"gemini-cli/1.0.0"}function u4($){let W=new Set;for(let Q of $)if(Q.role==="assistant"&&Q.tool_calls)for(let Z of Q.tool_calls)W.add(Z.id);return $.filter((Q)=>{if(Q.role==="tool"){if(!Q.tool_call_id)return!1;return W.has(Q.tool_call_id)}return!0})}function V1($){if(typeof $==="string")return $;return $.filter((W)=>W.type==="text").map((W)=>W.text).join(`
52
+ `)}function Y2($){let W=["const","$ref","$defs","$schema","$id","default","examples"],Q={};for(let[Z,V]of Object.entries($)){if(W.includes(Z)){if(Z==="const")Q.enum=[V];continue}if(V&&typeof V==="object"&&!Array.isArray(V))Q[Z]=Y2(V);else if(Array.isArray(V))Q[Z]=V.map((X)=>X&&typeof X==="object"&&!Array.isArray(X)?Y2(X):X);else Q[Z]=V}return Q}class J2{config;auth;projectId;userTier;sessionId;configType="antigravity";projectIdInitialized=!1;constructor($){this.config=$,this.auth=r$.getInstance(),this.projectId=void 0,this.sessionId=`session_${Date.now()}_${Math.random().toString(36).slice(2,11)}`,T.debug("\uD83D\uDE80 [AntigravityChatService] Initializing"),T.debug("⚙️ [AntigravityChatService] Config:",{model:$.model,temperature:$.temperature,maxOutputTokens:$.maxOutputTokens,sessionId:this.sessionId})}async ensureProjectId(){if(this.projectIdInitialized)return;try{let $=await this.auth.getConfigType();this.configType=$||"antigravity",T.debug(`\uD83D\uDD04 [AntigravityChatService] Using OAuth config: ${this.configType}`),T.debug("\uD83D\uDD04 [AntigravityChatService] Setting up user via loadCodeAssist...");let W=await this.auth.getAccessToken(),Q=await this.callLoadCodeAssist(W);if(T.debug("[AntigravityChatService] loadCodeAssist response:",JSON.stringify(Q)),Q.currentTier){if(this.userTier=Q.currentTier.id,Q.cloudaicompanionProject){this.projectId=Q.cloudaicompanionProject,T.debug(`✅ [AntigravityChatService] User already setup: tier=${this.userTier}, project=${this.projectId}`),this.projectIdInitialized=!0;return}let X=process.env.GOOGLE_CLOUD_PROJECT||process.env.GOOGLE_CLOUD_PROJECT_ID;if(X){this.projectId=X,T.debug(`✅ [AntigravityChatService] Using env project: ${this.projectId}`),this.projectIdInitialized=!0;return}T.debug("⚠️ [AntigravityChatService] Has tier but no project, need onboarding...")}let Z=this.getDefaultTier(Q);T.debug(`\uD83D\uDD04 [AntigravityChatService] Onboarding user with tier: ${Z.id}`);let V=await this.callOnboardUser(W,Z.id);this.projectId=V.projectId,this.userTier=Z.id,T.debug(`✅ [AntigravityChatService] User setup complete: tier=${this.userTier}, project=${this.projectId||"(managed)"}`)}catch($){T.warn("Failed to setup user:",$)}this.projectIdInitialized=!0}async callLoadCodeAssist($){let W=`${N0.production}${z0.loadCodeAssist}`,Q=p4(this.configType),Z=Z1(this.configType),V=await r(W,{method:"POST",headers:{Authorization:`Bearer ${$}`,"Content-Type":"application/json","User-Agent":Z},body:JSON.stringify({metadata:Q})});if(!V.ok){let X=await V.text();throw Error(`loadCodeAssist failed: ${V.status} - ${X}`)}return await V.json()}getDefaultTier($){for(let W of $.allowedTiers||[])if(W.isDefault)return{id:W.id};return{id:"free-tier"}}async callOnboardUser($,W){let Q=`${N0.production}${z0.onboardUser}`,Z=p4(this.configType),V=Z1(this.configType),X={tierId:W,metadata:Z};if(W!=="free-tier"){let G=process.env.GOOGLE_CLOUD_PROJECT||process.env.GOOGLE_CLOUD_PROJECT_ID;if(G)X.cloudaicompanionProject=G,X.metadata={...Z,duetProject:G}}let Y=0,J=30;while(Y<J){let G=await r(Q,{method:"POST",headers:{Authorization:`Bearer ${$}`,"Content-Type":"application/json","User-Agent":V},body:JSON.stringify(X)});if(!G.ok){let B=await G.text();throw Error(`onboardUser failed: ${G.status} - ${B}`)}let K=await G.json();if(T.debug(`[AntigravityChatService] onboardUser attempt ${Y+1}:`,JSON.stringify(K)),K.error)throw Error(`onboardUser error: ${K.error.message||K.error.code}`);if(K.done)return{projectId:K.response?.cloudaicompanionProject?.id};T.debug("[AntigravityChatService] onboardUser not done, waiting 5s..."),await new Promise((B)=>setTimeout(B,5000)),Y++}throw Error("onboardUser timeout: LRO did not complete in time")}convertToAntigravityMessages($){let W=$.find((J)=>J.role==="system"),Q=W?{parts:[{text:V1(W.content)}]}:void 0,Z=[],V=$.filter((J)=>J.role!=="system"),X=new Map;for(let J of V)if(J.role==="assistant"&&J.tool_calls){for(let G of J.tool_calls)if(G.type==="function")X.set(G.id,G.function.name)}for(let J of V)if(J.role==="user"){let G=[];if(Array.isArray(J.content)){for(let K of J.content)if(K.type==="text")G.push({text:K.text})}else G.push({text:J.content});Z.push({role:"user",parts:G})}else if(J.role==="assistant"){let G=[],K=V1(J.content);if(K)G.push({text:K});if(J.tool_calls)for(let B of J.tool_calls){if(B.type!=="function")continue;let q={};try{q=JSON.parse(B.function.arguments||"{}")}catch{T.warn(`Failed to parse tool arguments: ${B.function.arguments}`)}G.push({functionCall:{name:B.function.name,args:q,id:B.id}})}if(G.length>0)Z.push({role:"model",parts:G})}else if(J.role==="tool"){let G=X.get(J.tool_call_id||"");if(G){let K;try{K=JSON.parse(V1(J.content))}catch{K={result:V1(J.content)}}Z.push({role:"user",parts:[{functionResponse:{name:G,id:J.tool_call_id,response:K}}]})}}let Y=[];for(let J of Z){let G=Y[Y.length-1];if(G?.role===J.role)G.parts=[...G.parts,...J.parts];else Y.push(J)}if(Y.length>0&&Y[0].role!=="user")Y.unshift({role:"user",parts:[{text:"[Conversation start]"}]});return{systemInstruction:Q,contents:Y}}convertToAntigravityTools($){if(!$||$.length===0)return;return[{functionDeclarations:$.map((Q)=>({name:Q.name,description:Q.description,parameters:Y2(Q.parameters||{type:"object",properties:{}})}))}]}async makeRequest($,W,Q){let Z=await this.auth.getAccessToken(),V=`${N0.production}${$}`,X=Z1(this.configType),Y=await r(V,{method:"POST",headers:{Authorization:`Bearer ${Z}`,"Content-Type":"application/json","User-Agent":X},body:JSON.stringify(W),signal:Q});if(!Y.ok){let J=await Y.text();if(T.error(`Antigravity API error: ${Y.status} - ${J}`),Y.status===401)throw Error("Authentication expired. Please run /login again.");if(Y.status===403)throw Error("Permission denied. Please check your Google account permissions.");if(Y.status===429)throw Error("Rate limit exceeded. Please wait a moment and try again.");throw Error(`Antigravity API error: ${Y.status} - ${J}`)}return Y}async chat($,W,Q){let Z=Date.now();T.debug("\uD83D\uDE80 [AntigravityChatService] Starting chat request"),T.debug("\uD83D\uDCDD [AntigravityChatService] Messages count:",$.length),await this.ensureProjectId();let V=u4($);if(V.length<$.length)T.debug(`Filtered ${$.length-V.length} orphan tool messages`);let{systemInstruction:X,contents:Y}=this.convertToAntigravityMessages(V),J=this.convertToAntigravityTools(W),G=`prompt_${Date.now()}_${Math.random().toString(36).slice(2,9)}`,K={model:this.config.model,project:this.projectId,user_prompt_id:G,request:{contents:Y,systemInstruction:X,generationConfig:{...this.config.maxOutputTokens&&{maxOutputTokens:this.config.maxOutputTokens},temperature:this.config.temperature??0.7},tools:J,session_id:this.sessionId}};T.debug("\uD83D\uDCE4 [AntigravityChatService] Request:",{model:this.config.model,contentsCount:Y.length,hasSystemInstruction:!!X,toolsCount:J?.[0]?.functionDeclarations?.length||0});try{let q=await(await this.makeRequest(z0.generateContent,K,Q)).json(),w=Date.now()-Z;T.debug("\uD83D\uDCE5 [AntigravityChatService] Response received in",w,"ms");let O="",H=[],A=q.response?.candidates?.[0]?.content?.parts||[];for(let z of A)if(z.text)O+=z.text;else if(z.functionCall){let C=z.functionCall;H.push({id:C.id||`call_${Date.now()}_${Math.random().toString(36).slice(2,9)}`,type:"function",function:{name:C.name,arguments:JSON.stringify(C.args||{})}})}let D=q.response?.usageMetadata,b={content:O,toolCalls:H.length>0?H:void 0,usage:{promptTokens:D?.promptTokenCount||0,completionTokens:D?.candidatesTokenCount||0,totalTokens:D?.totalTokenCount||0}};return T.debug("✅ [AntigravityChatService] Chat completed:",{contentLength:b.content.length,toolCallsCount:b.toolCalls?.length||0,usage:b.usage}),b}catch(B){let q=Date.now()-Z;throw T.error("❌ [AntigravityChatService] Chat failed after",q,"ms"),T.error("❌ [AntigravityChatService] Error:",B),B}}async*streamChat($,W,Q){let Z=Date.now();T.debug("\uD83D\uDE80 [AntigravityChatService] Starting stream request"),await this.ensureProjectId();let V=u4($),{systemInstruction:X,contents:Y}=this.convertToAntigravityMessages(V),J=this.convertToAntigravityTools(W),G=`prompt_${Date.now()}_${Math.random().toString(36).slice(2,9)}`,K={model:this.config.model,project:this.projectId,user_prompt_id:G,request:{contents:Y,systemInstruction:X,generationConfig:{...this.config.maxOutputTokens&&{maxOutputTokens:this.config.maxOutputTokens},temperature:this.config.temperature??0.7},tools:J,session_id:this.sessionId}};try{let B=await this.auth.getAccessToken(),q=`${N0.production}${z0.streamGenerateContent}?alt=sse`,w=Z1(this.configType),O=await r(q,{method:"POST",headers:{Authorization:`Bearer ${B}`,"Content-Type":"application/json",Accept:"text/event-stream","User-Agent":w},body:JSON.stringify(K),signal:Q});if(!O.ok){let z=await O.text();throw Error(`Antigravity API error: ${O.status} - ${z}`)}let H=O.body?.getReader();if(!H)throw Error("No response body");let U=new TextDecoder,A="",D=0,b=Date.now()-Z;T.debug("\uD83D\uDCE5 [AntigravityChatService] Stream started in",b,"ms");while(!0){let{done:z,value:C}=await H.read();if(z)break;A+=U.decode(C,{stream:!0});let N=A.split(`
53
+ `);A=N.pop()||"";for(let y of N)if(y.startsWith("data: ")){let i=y.slice(6);if(i==="[DONE]"){yield{finishReason:"stop"};continue}try{let j=JSON.parse(i);if(D++,j.usageMetadata)yield{usage:{promptTokens:j.usageMetadata.promptTokenCount||0,completionTokens:j.usageMetadata.candidatesTokenCount||0,totalTokens:j.usageMetadata.totalTokenCount||0}};let d=j.candidates?.[0],z$=d?.content?.parts||[];for(let R of z$)if(R.text)yield{content:R.text};else if(R.functionCall){let L=R.functionCall;yield{toolCalls:[{id:L.id||`call_${Date.now()}_${Math.random().toString(36).slice(2,9)}`,type:"function",function:{name:L.name,arguments:JSON.stringify(L.args||{})}}]}}let R$=d?.finishReason;if(R$)yield{finishReason:R$==="STOP"?"stop":R$==="MAX_TOKENS"?"length":R$.toLowerCase()}}catch(j){T.debug("Failed to parse SSE data:",i)}}}T.debug("✅ [AntigravityChatService] Stream completed:",{eventCount:D,duration:Date.now()-Z+"ms"})}catch(B){let q=Date.now()-Z;throw T.error("❌ [AntigravityChatService] Stream failed after",q,"ms"),T.error("❌ [AntigravityChatService] Error:",B),B}}getConfig(){return{...this.config}}updateConfig($){T.debug("\uD83D\uDD04 [AntigravityChatService] Updating configuration"),this.config={...this.config,...$},T.debug("✅ [AntigravityChatService] Configuration updated")}}var C0=M("Service"),p7="https://blade-api-proxy.137844255.workers.dev/v1/get-zhipu-key",d4="blade-free-tier",X1=null;async function m4($){if($!==d4)return $;if(X1)return C0.debug("使用缓存的内置 API Key"),X1;try{C0.info("\uD83D\uDD11 正在从代理服务获取内置 API Key...");let W=await r(p7,{method:"GET",headers:{Authorization:`Bearer ${d4}`,"Content-Type":"application/json"},timeout:1e4});if(!W.ok){let Z=await W.text();throw Error(`获取 API Key 失败: ${W.status} - ${Z}`)}let Q=await W.json();if(!Q.apiKey)throw Error("代理服务返回的数据中没有 apiKey");if(X1=Q.apiKey,C0.info("✅ 成功获取内置 API Key"),Q.message)C0.debug(`提示: ${Q.message}`);return X1}catch(W){throw C0.error("❌ 获取内置 API Key 失败:",W),Error(`无法获取内置模型的 API Key: ${W instanceof Error?W.message:"未知错误"}
54
+ `+"请检查网络连接或使用自己的 API Key (/config)")}}import{isPlainObject as Y1}from"lodash-es";import{spawn as u7}from"child_process";import*as u$ from"fs/promises";import*as v0 from"path";var s$={deviceCodeUrl:"https://github.com/login/device/code",tokenUrl:"https://github.com/login/oauth/access_token",clientId:"01ab8ac9400c4e429b23",scope:"user:email",grantType:"urn:ietf:params:oauth:grant-type:device_code"},M0={tokenExchange:"https://api.github.com/copilot_internal/v2/token",chatCompletions:"https://api.githubcopilot.com/chat/completions",models:"https://api.githubcopilot.com/models"};var S0=M("Service"),G2="copilot-token.json";function K2(){let $=process.env.HOME||process.env.USERPROFILE||"";return v0.join($,".blade")}class o${static instance=null;cachedToken=null;constructor(){}static getInstance(){if(!o$.instance)o$.instance=new o$;return o$.instance}async isLoggedIn(){let $=await this.loadToken();if(!$)return!1;let W=300000;if($.copilotExpiresAt&&Date.now()>$.copilotExpiresAt-W)try{return await this.refreshCopilotToken(),!0}catch{return!1}return!0}async login(){S0.info("\uD83D\uDD10 Starting GitHub Copilot OAuth login..."),console.log(`
49
55
  \uD83D\uDD10 开始 GitHub Copilot 认证...`);let $=await this.requestDeviceCode();console.log(`
50
56
  \uD83D\uDCCB 请在浏览器中完成授权:`),console.log(` 1. 打开 ${$.verification_uri}`),console.log(` 2. 输入代码: ${$.user_code}`),console.log("");try{await this.openBrowser($.verification_uri),console.log("\uD83C\uDF10 已自动打开浏览器,请输入上面的代码完成授权")}catch{console.log("⚠️ 无法自动打开浏览器,请手动打开上述链接")}console.log(`
51
- ⏳ 等待授权中...`);let W=await this.pollForAccessToken($.device_code,$.interval,$.expires_in);console.log("✅ GitHub 授权成功!"),console.log("\uD83D\uDD04 正在获取 Copilot token...");let Q=await this.exchangeForCopilotToken(W),Z={githubToken:W,copilotToken:Q.token,copilotExpiresAt:Q.expires_at*1000};await this.saveToken(Z),this.cachedToken=Z,console.log("✅ GitHub Copilot 登录成功!"),S0.info("GitHub Copilot OAuth login completed")}async logout(){let $=v0.join(B2(),G2);try{await d$.unlink($),this.cachedToken=null,console.log("✅ 已登出 GitHub Copilot"),S0.info("GitHub Copilot logout completed")}catch(W){if(W.code!=="ENOENT")throw W;this.cachedToken=null}}async getCopilotToken(){if(this.cachedToken){if(this.cachedToken.copilotExpiresAt>Date.now()+300000)return this.cachedToken.copilotToken}let $=await this.loadToken();if(!$)throw Error("Not logged in to GitHub Copilot. Please run /login copilot first.");let W=300000;if($.copilotExpiresAt<=Date.now()+W)return await this.refreshCopilotToken(),this.cachedToken.copilotToken;return this.cachedToken=$,$.copilotToken}async refreshCopilotToken(){let $=await this.loadToken();if(!$||!$.githubToken)throw Error("No GitHub token available");S0.info("\uD83D\uDD04 Refreshing Copilot token...");let W=await this.exchangeForCopilotToken($.githubToken),Q={githubToken:$.githubToken,copilotToken:W.token,copilotExpiresAt:W.expires_at*1000};await this.saveToken(Q),this.cachedToken=Q,S0.info("✅ Copilot token refreshed successfully")}async requestDeviceCode(){let $=new URLSearchParams({client_id:o$.clientId,scope:o$.scope}),W=await r(o$.deviceCodeUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:$.toString()});if(!W.ok){let Q=await W.text();throw Error(`Failed to request device code: ${W.status} - ${Q}`)}return await W.json()}async pollForAccessToken($,W,Q){let Z=Date.now(),V=Q*1000;while(Date.now()-Z<V){await this.sleep(W*1000);let X=new URLSearchParams({client_id:o$.clientId,device_code:$,grant_type:o$.grantType}),J=await(await r(o$.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:X.toString()})).json();if(J.access_token)return J.access_token;if(J.error==="authorization_pending")continue;if(J.error==="slow_down"){W+=5;continue}if(J.error==="expired_token")throw Error("Device code expired. Please try again.");if(J.error==="access_denied")throw Error("Authorization denied by user.");if(J.error)throw Error(`OAuth error: ${J.error} - ${J.error_description||""}`)}throw Error("Device code expired. Please try again.")}async exchangeForCopilotToken($){let W=await r(M0.tokenExchange,{method:"GET",headers:{Authorization:`token ${$}`,Accept:"application/json","User-Agent":"GitHubCopilotChat/0.22.2024","Editor-Version":"vscode/1.95.0","Editor-Plugin-Version":"copilot-chat/0.22.2024"}});if(!W.ok){let Q=await W.text();if(W.status===401)throw Error("GitHub token is invalid or expired. Please run /login copilot again.");if(W.status===403)throw Error("No Copilot subscription found. Please ensure you have an active GitHub Copilot subscription.");throw Error(`Failed to exchange for Copilot token: ${W.status} - ${Q}`)}return await W.json()}async openBrowser($){let W,Q;if(process.platform==="darwin")W="open",Q=[$];else if(process.platform==="win32")W="cmd",Q=["/c","start","",$];else W="xdg-open",Q=[$];await new Promise((Z,V)=>{let X=f7(W,Q,{stdio:"ignore"});X.once("error",V),X.once("close",(Y)=>{if(Y===0||Y===null)Z();else V(Error(`Failed to open browser (exit code ${Y})`))})})}async saveToken($){let W=B2();await d$.mkdir(W,{recursive:!0,mode:493});let Q=v0.join(W,G2);await d$.writeFile(Q,JSON.stringify($,null,2),{mode:384})}async loadToken(){let $=v0.join(B2(),G2);try{let W=await d$.readFile($,"utf-8");return JSON.parse(W)}catch(W){if(W.code==="ENOENT")return null;throw W}}async getStatus(){let $=await this.loadToken();if(!$)return{loggedIn:!1};return{loggedIn:!0,expiresAt:$.copilotExpiresAt?new Date($.copilotExpiresAt):void 0}}sleep($){return new Promise((W)=>setTimeout(W,$))}}var B$=M("Chat");class K2{config;auth;constructor($){this.config=$,this.auth=t$.getInstance()}getConfig(){return this.config}updateConfig($){this.config={...this.config,...$}}async chat($,W,Q){let Z=Date.now();B$.debug("\uD83D\uDE80 [CopilotChatService] Starting chat request"),B$.debug(`\uD83D\uDCDD [CopilotChatService] Messages count: ${$.length}`);try{let V=await this.auth.getCopilotToken(),X=this.buildRequest($,W,!1),Y=await this.makeRequest(V,X,Q),J=Date.now()-Z;return B$.debug(`✅ [CopilotChatService] Chat completed in ${J} ms`),this.parseResponse(Y)}catch(V){let X=Date.now()-Z;throw B$.error(`❌ [CopilotChatService] Chat failed after ${X} ms`),B$.error(`❌ [CopilotChatService] Error: ${V}`),V}}async*streamChat($,W,Q){let Z=Date.now();B$.debug("\uD83D\uDE80 [CopilotChatService] Starting stream chat request"),B$.debug(`\uD83D\uDCDD [CopilotChatService] Messages count: ${$.length}`);try{let V=await this.auth.getCopilotToken(),X=this.buildRequest($,W,!0),Y=await r(M0.chatCompletions,{method:"POST",headers:{Authorization:`Bearer ${V}`,"Content-Type":"application/json",Accept:"text/event-stream","Copilot-Integration-Id":"vscode-chat","Editor-Version":"vscode/1.95.0","Editor-Plugin-Version":"copilot-chat/0.22.2024","User-Agent":"GitHubCopilotChat/0.22.2024"},body:JSON.stringify(X),signal:Q});if(!Y.ok){let w=await Y.text();throw Error(`Copilot API error: ${Y.status} - ${w}`)}if(!Y.body)throw Error("No response body");let J=Y.body.getReader(),G=new TextDecoder,B="",K=new Map;while(!0){let{done:w,value:O}=await J.read();if(w)break;B+=G.decode(O,{stream:!0});let b=B.split(`
52
- `);B=b.pop()||"";for(let U of b){if(!U.startsWith("data: "))continue;let F=U.slice(6).trim();if(F==="[DONE]"){if(K.size>0)yield{toolCalls:Array.from(K.values()),finishReason:"tool_calls"};continue}try{let D=JSON.parse(F).choices[0];if(D){let N={};if(D.delta.content)N.content=D.delta.content;if(D.delta.tool_calls)for(let C of D.delta.tool_calls){let z=K.get(C.index);if(z){if(C.function?.arguments)z.function.arguments+=C.function.arguments}else K.set(C.index,{id:C.id||"",type:"function",function:{name:C.function?.name||"",arguments:C.function?.arguments||""}})}if(D.finish_reason)N.finishReason=D.finish_reason;if(N.content||N.finishReason==="stop")yield N}}catch{}}}let q=Date.now()-Z;B$.debug(`✅ [CopilotChatService] Stream completed in ${q} ms`)}catch(V){let X=Date.now()-Z;throw B$.error(`❌ [CopilotChatService] Stream failed after ${X} ms`),B$.error(`❌ [CopilotChatService] Error: ${V}`),V}}sanitizeMessages($){let W=[],Q=new Set;for(let Z=0;Z<$.length;Z++){let V=$[Z];if(V.role==="assistant"&&V.tool_calls&&V.tool_calls.length>0){let X=[];for(let Y of V.tool_calls){let J=!1;for(let G=Z+1;G<$.length;G++){if($[G].role==="tool"&&$[G].tool_call_id===Y.id){J=!0;break}if($[G].role==="assistant"||$[G].role==="user")break}if(J)X.push(Y.id),Q.add(Y.id)}if(X.length>0)W.push({...V,tool_calls:V.tool_calls.filter((Y)=>X.includes(Y.id))});else W.push({role:V.role,content:V.content||"",reasoningContent:V.reasoningContent})}else if(V.role==="tool"){if(V.tool_call_id&&Q.has(V.tool_call_id))W.push(V)}else W.push(V)}if(W.length!==$.length)B$.debug(`[CopilotChatService] Sanitized messages: ${$.length} -> ${W.length}`);return W}buildRequest($,W,Q=!1){let V=this.sanitizeMessages($).map((Y)=>{let J;if(typeof Y.content==="string")J=Y.content;else if(Array.isArray(Y.content))J=Y.content.filter((B)=>B.type==="text").map((B)=>B.text).join(`
53
- `);else J=null;let G={role:Y.role,content:J};if(Y.tool_call_id)G.tool_call_id=Y.tool_call_id;if(Y.name)G.name=Y.name;if(Y.tool_calls&&Y.tool_calls.length>0)G.tool_calls=Y.tool_calls.filter((B)=>B.type==="function"&&("function"in B)).map((B)=>({id:B.id,type:"function",function:{name:B.function.name,arguments:B.function.arguments}}));return G}),X={model:this.config.model,messages:V,stream:Q};if(this.config.temperature!==void 0)X.temperature=this.config.temperature;if(this.config.maxOutputTokens)X.max_tokens=this.config.maxOutputTokens;if(W&&W.length>0)X.tools=W.map((Y)=>({type:"function",function:{name:Y.name,description:Y.description,parameters:this.cleanParameters(Y.parameters)}})),X.tool_choice="auto";return X}cleanParameters($){if(!J1($))return{};let W={};for(let[Q,Z]of Object.entries($)){if(["$ref","const","default"].includes(Q))continue;if(Q==="properties"&&J1(Z)){let V={};for(let[X,Y]of Object.entries(Z))V[X]=J1(Y)?this.cleanParameters(Y):Y;W[Q]=V}else if(Q==="items"&&J1(Z))W[Q]=this.cleanParameters(Z);else W[Q]=Z}return W}async makeRequest($,W,Q){let Z=await r(M0.chatCompletions,{method:"POST",headers:{Authorization:`Bearer ${$}`,"Content-Type":"application/json",Accept:"application/json","Copilot-Integration-Id":"vscode-chat","Editor-Version":"vscode/1.95.0","Editor-Plugin-Version":"copilot-chat/0.22.2024","User-Agent":"GitHubCopilotChat/0.22.2024"},body:JSON.stringify(W),signal:Q});if(!Z.ok){let V=await Z.text();if(B$.error(`Copilot API error: ${Z.status} - ${V}`),Z.status===401)throw Error("Copilot token expired or invalid. Please run /login copilot again.");if(Z.status===403)throw Error("Permission denied. Please ensure you have an active GitHub Copilot subscription.");if(Z.status===429)throw Error("Rate limit exceeded. Please wait and try again.");throw Error(`Copilot API error: ${Z.status} - ${V}`)}return await Z.json()}parseResponse($){let W=$.choices[0];if(!W)throw Error("No response from Copilot API");let Q={content:W.message.content||""};if(W.message.tool_calls&&W.message.tool_calls.length>0)Q.toolCalls=W.message.tool_calls.map((Z)=>({id:Z.id,type:"function",function:{name:Z.function.name,arguments:Z.function.arguments}}));if($.usage)Q.usage={promptTokens:$.usage.prompt_tokens,completionTokens:$.usage.completion_tokens,totalTokens:$.usage.total_tokens};return Q}}import{createAnthropic as x7}from"@ai-sdk/anthropic";import{createAzure as h7}from"@ai-sdk/azure";import{createDeepSeek as p7}from"@ai-sdk/deepseek";import{createGoogleGenerativeAI as u7}from"@ai-sdk/google";import{createOpenAICompatible as q2}from"@ai-sdk/openai-compatible";import{generateText as d7,jsonSchema as m7,streamText as g7}from"ai";var A$=M("Chat");function g4($){let W=new Set;for(let Q of $)if(Q.role==="assistant"&&Q.tool_calls)for(let Z of Q.tool_calls)W.add(Z.id);return $.filter((Q)=>{if(Q.role==="tool"){if(!Q.tool_call_id)return!1;return W.has(Q.tool_call_id)}return!0})}function G1($){if(typeof $==="string")return $;return $.filter((W)=>W.type==="text").map((W)=>W.text).join(`
54
- `)}function c7($,W={}){try{return JSON.parse($)}catch{return A$.warn("⚠️ [VercelAIChatService] Failed to parse JSON, using fallback",{str:$}),W}}class w2{model;config;constructor($){this.config=$,this.model=this.createModel($),A$.debug("\uD83D\uDE80 [VercelAIChatService] Initialized",{provider:$.provider,model:$.model,providerId:$.providerId})}createModel($){let{provider:W,apiKey:Q,baseUrl:Z,model:V,customHeaders:X,providerId:Y,apiVersion:J}=$;switch(W){case"anthropic":return x7({apiKey:Q,baseURL:Z||void 0,headers:X})(V);case"gemini":{if(Z&&!this.isGeminiOfficialUrl(Z))return q2({name:"gemini",apiKey:Q,baseURL:Z,headers:X})(V);return u7({apiKey:Q,baseURL:Z||void 0})(V)}case"azure-openai":{let G=this.extractAzureResourceName(Z);if(G)return h7({apiKey:Q,resourceName:G,apiVersion:J||"2024-08-01-preview"})(V);let B=this.buildAzureBaseUrl(Z,V);return q2({name:"azure-openai",apiKey:Q,baseURL:B,headers:{...X,"api-key":Q},queryParams:{"api-version":J||"2024-08-01-preview"}})(V)}default:{if(Y==="deepseek")return p7({apiKey:Q,baseURL:Z||void 0,headers:X})(V);return q2({name:Y||"custom",apiKey:Q,baseURL:Z,headers:X})(V)}}}extractAzureResourceName($){if(!$)return;let W=$.match(/https:\/\/([^.]+)\.openai\.azure(?:\.com|\.us|\.cn|\.de)/);return W?W[1]:void 0}buildAzureBaseUrl($,W){if(!$)return"";let Q=$.replace(/\/$/,"").replace(/\?.*$/,"");if(Q.includes("/openai/deployments/"))return Q;return`${Q}/openai/deployments/${W}`}isGeminiOfficialUrl($){return $.includes("generativelanguage.googleapis.com")||$.includes("aiplatform.googleapis.com")}convertMessages($){let W=[];for(let Q of $)if(Q.role==="system")if(Array.isArray(Q.content)){let Z=Q.content.find((X)=>X.type==="text"),V={role:"system",content:G1(Q.content)};if(Z?.providerOptions)V.providerOptions=Z.providerOptions;W.push(V)}else W.push({role:"system",content:Q.content});else if(Q.role==="user")if(Array.isArray(Q.content)){let Z=Q.content.map((V)=>{if(V.type==="text"){let X={type:"text",text:V.text};if(V.providerOptions)X.providerOptions=V.providerOptions;return X}return{type:"image",image:V.image_url.url}});W.push({role:"user",content:Z})}else W.push({role:"user",content:Q.content});else if(Q.role==="assistant")if(Q.tool_calls&&Q.tool_calls.length>0){let Z=Q.tool_calls.map((X)=>{let Y=X.function;return{type:"tool-call",toolCallId:X.id,toolName:Y?.name||"",input:c7(Y?.arguments||"{}",{})}}),V=G1(Q.content);if(V)W.push({role:"assistant",content:[{type:"text",text:V},...Z]});else W.push({role:"assistant",content:Z})}else W.push({role:"assistant",content:G1(Q.content)});else if(Q.role==="tool")W.push({role:"tool",content:[{type:"tool-result",toolCallId:Q.tool_call_id,toolName:Q.name||"unknown",output:{type:"text",value:G1(Q.content)}}]});return W}convertTools($){if(!$||$.length===0)return;let W={};for(let Q of $)W[Q.name]={description:Q.description,inputSchema:m7(Q.parameters)};return W}convertToolCalls($){return $.map((W)=>({id:W.toolCallId,type:"function",function:{name:W.toolName,arguments:JSON.stringify(W.args??W.input??{})}}))}convertUsage($,W){if(!$)return;let Q=$.promptTokens??0,Z=$.completionTokens??0,V={promptTokens:Q,completionTokens:Z,totalTokens:$.totalTokens??Q+Z};if(W?.anthropic){if(W.anthropic.cacheCreationInputTokens!==void 0)V.cacheCreationInputTokens=W.anthropic.cacheCreationInputTokens;if(W.anthropic.cacheReadInputTokens!==void 0)V.cacheReadInputTokens=W.anthropic.cacheReadInputTokens}return V}async chat($,W,Q){let Z=Date.now();A$.debug("\uD83D\uDE80 [VercelAIChatService] Starting chat request");let V=g4($),X=this.convertMessages(V),Y=this.convertTools(W);try{let J=await d7({model:this.model,messages:X,tools:Y,maxOutputTokens:this.config.maxOutputTokens,temperature:this.config.temperature??0,abortSignal:Q}),G=Date.now()-Z;A$.debug("\uD83D\uDCE5 [VercelAIChatService] Response received in",G,"ms");let B=J.toolCalls&&J.toolCalls.length>0?this.convertToolCalls(J.toolCalls):void 0,K=Array.isArray(J.reasoning)?J.reasoning.map((q)=>q.text).join(""):void 0;return{content:J.text,reasoningContent:K,toolCalls:B,usage:this.convertUsage(J.usage,J.providerMetadata)}}catch(J){let G=Date.now()-Z;throw A$.error("❌ [VercelAIChatService] Chat failed after",G,"ms"),J}}async*streamChat($,W,Q){let Z=Date.now();A$.debug("\uD83D\uDE80 [VercelAIChatService] Starting stream request");let V=g4($),X=this.convertMessages(V),Y=this.convertTools(W);try{let J=g7({model:this.model,messages:X,tools:Y,maxOutputTokens:this.config.maxOutputTokens,temperature:this.config.temperature??0,abortSignal:Q});A$.debug("\uD83D\uDCE5 [VercelAIChatService] Stream started");let G=0;for await(let K of J.fullStream)switch(K.type){case"text-delta":yield{content:K.text??K.textDelta};break;case"reasoning-delta":yield{reasoningContent:K.textDelta};break;case"tool-call":yield{toolCalls:[{index:G++,id:K.toolCallId,type:"function",function:{name:K.toolName,arguments:JSON.stringify(K.args??K.input??{})}}]};break;case"finish":yield{finishReason:K.finishReason,usage:this.convertUsage(K.totalUsage,K.providerMetadata)};break}let B=Date.now()-Z;A$.debug("✅ [VercelAIChatService] Stream completed in",B,"ms")}catch(J){let G=Date.now()-Z;throw A$.error("❌ [VercelAIChatService] Stream failed after",G,"ms"),J}}getConfig(){return{...this.config}}updateConfig($){A$.debug("\uD83D\uDD04 [VercelAIChatService] Updating configuration"),this.config={...this.config,...$},this.model=this.createModel(this.config),A$.debug("✅ [VercelAIChatService] Configuration updated")}}var c4=M("Service"),i7="blade-free-tier";function l7($){return $===i7}function n7($){return{}}async function B1($){let W=$;if(l7($.apiKey)){c4.info("\uD83D\uDD11 检测到内置 API Key,正在获取...");let Q=await m4($.apiKey);W={...$,apiKey:Q}}if(W.providerId){let Q=n7(W.providerId);if(Object.keys(Q).length>0)W={...W,customHeaders:{...Q,...W.customHeaders}},c4.debug(`\uD83D\uDD27 注入 ${W.providerId} 特定 headers:`,Object.keys(Q))}return a7(W)}function a7($){switch($.provider){case"antigravity":return new J2($);case"copilot":return new K2($);default:return new w2($)}}import{readFile as r7}from"node:fs/promises";import{basename as s7}from"node:path";class o{static MAX_FILES=5;static MAX_LINES_PER_FILE=1000;static analyzeFiles($){let W=new Map;return $.forEach((Z,V)=>{let X=typeof Z.content==="string"?Z.content:(Z.content||[]).filter((J)=>J.type==="text").map((J)=>J.text).join(`
55
- `);if(o.extractFilePathsFromContent(X).forEach((J)=>{o.updateFileReference(W,J,V,!1)}),Z.tool_calls&&Array.isArray(Z.tool_calls))Z.tool_calls.forEach((J)=>{let G=o.extractFilePathsFromToolCall(J),B=J.type==="function"&&"function"in J?J.function?.name:"",K=["Write","Edit"].includes(B||"");G.forEach((q)=>{o.updateFileReference(W,q,V,K)})})}),Array.from(W.values()).sort((Z,V)=>{if(Z.wasModified!==V.wasModified)return Z.wasModified?-1:1;if(Z.mentions!==V.mentions)return V.mentions-Z.mentions;return V.lastMentioned-Z.lastMentioned}).slice(0,o.MAX_FILES)}static async readFilesContent($){let W=[];for(let Q of $)try{let Z=await r7(Q,"utf-8"),V=Z.split(`
57
+ ⏳ 等待授权中...`);let W=await this.pollForAccessToken($.device_code,$.interval,$.expires_in);console.log("✅ GitHub 授权成功!"),console.log("\uD83D\uDD04 正在获取 Copilot token...");let Q=await this.exchangeForCopilotToken(W),Z={githubToken:W,copilotToken:Q.token,copilotExpiresAt:Q.expires_at*1000};await this.saveToken(Z),this.cachedToken=Z,console.log("✅ GitHub Copilot 登录成功!"),S0.info("GitHub Copilot OAuth login completed")}async logout(){let $=v0.join(K2(),G2);try{await u$.unlink($),this.cachedToken=null,console.log("✅ 已登出 GitHub Copilot"),S0.info("GitHub Copilot logout completed")}catch(W){if(W.code!=="ENOENT")throw W;this.cachedToken=null}}async getCopilotToken(){if(this.cachedToken){if(this.cachedToken.copilotExpiresAt>Date.now()+300000)return this.cachedToken.copilotToken}let $=await this.loadToken();if(!$)throw Error("Not logged in to GitHub Copilot. Please run /login copilot first.");let W=300000;if($.copilotExpiresAt<=Date.now()+W)return await this.refreshCopilotToken(),this.cachedToken.copilotToken;return this.cachedToken=$,$.copilotToken}async refreshCopilotToken(){let $=await this.loadToken();if(!$||!$.githubToken)throw Error("No GitHub token available");S0.info("\uD83D\uDD04 Refreshing Copilot token...");let W=await this.exchangeForCopilotToken($.githubToken),Q={githubToken:$.githubToken,copilotToken:W.token,copilotExpiresAt:W.expires_at*1000};await this.saveToken(Q),this.cachedToken=Q,S0.info("✅ Copilot token refreshed successfully")}async requestDeviceCode(){let $=new URLSearchParams({client_id:s$.clientId,scope:s$.scope}),W=await r(s$.deviceCodeUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:$.toString()});if(!W.ok){let Q=await W.text();throw Error(`Failed to request device code: ${W.status} - ${Q}`)}return await W.json()}async pollForAccessToken($,W,Q){let Z=Date.now(),V=Q*1000;while(Date.now()-Z<V){await this.sleep(W*1000);let X=new URLSearchParams({client_id:s$.clientId,device_code:$,grant_type:s$.grantType}),J=await(await r(s$.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:X.toString()})).json();if(J.access_token)return J.access_token;if(J.error==="authorization_pending")continue;if(J.error==="slow_down"){W+=5;continue}if(J.error==="expired_token")throw Error("Device code expired. Please try again.");if(J.error==="access_denied")throw Error("Authorization denied by user.");if(J.error)throw Error(`OAuth error: ${J.error} - ${J.error_description||""}`)}throw Error("Device code expired. Please try again.")}async exchangeForCopilotToken($){let W=await r(M0.tokenExchange,{method:"GET",headers:{Authorization:`token ${$}`,Accept:"application/json","User-Agent":"GitHubCopilotChat/0.22.2024","Editor-Version":"vscode/1.95.0","Editor-Plugin-Version":"copilot-chat/0.22.2024"}});if(!W.ok){let Q=await W.text();if(W.status===401)throw Error("GitHub token is invalid or expired. Please run /login copilot again.");if(W.status===403)throw Error("No Copilot subscription found. Please ensure you have an active GitHub Copilot subscription.");throw Error(`Failed to exchange for Copilot token: ${W.status} - ${Q}`)}return await W.json()}async openBrowser($){let W,Q;if(process.platform==="darwin")W="open",Q=[$];else if(process.platform==="win32")W="cmd",Q=["/c","start","",$];else W="xdg-open",Q=[$];await new Promise((Z,V)=>{let X=u7(W,Q,{stdio:"ignore"});X.once("error",V),X.once("close",(Y)=>{if(Y===0||Y===null)Z();else V(Error(`Failed to open browser (exit code ${Y})`))})})}async saveToken($){let W=K2();await u$.mkdir(W,{recursive:!0,mode:493});let Q=v0.join(W,G2);await u$.writeFile(Q,JSON.stringify($,null,2),{mode:384})}async loadToken(){let $=v0.join(K2(),G2);try{let W=await u$.readFile($,"utf-8");return JSON.parse(W)}catch(W){if(W.code==="ENOENT")return null;throw W}}async getStatus(){let $=await this.loadToken();if(!$)return{loggedIn:!1};return{loggedIn:!0,expiresAt:$.copilotExpiresAt?new Date($.copilotExpiresAt):void 0}}sleep($){return new Promise((W)=>setTimeout(W,$))}}var w$=M("Chat");class B2{config;auth;constructor($){this.config=$,this.auth=o$.getInstance()}getConfig(){return this.config}updateConfig($){this.config={...this.config,...$}}async chat($,W,Q){let Z=Date.now();w$.debug("\uD83D\uDE80 [CopilotChatService] Starting chat request"),w$.debug(`\uD83D\uDCDD [CopilotChatService] Messages count: ${$.length}`);try{let V=await this.auth.getCopilotToken(),X=this.buildRequest($,W,!1),Y=await this.makeRequest(V,X,Q),J=Date.now()-Z;return w$.debug(`✅ [CopilotChatService] Chat completed in ${J} ms`),this.parseResponse(Y)}catch(V){let X=Date.now()-Z;throw w$.error(`❌ [CopilotChatService] Chat failed after ${X} ms`),w$.error(`❌ [CopilotChatService] Error: ${V}`),V}}async*streamChat($,W,Q){let Z=Date.now();w$.debug("\uD83D\uDE80 [CopilotChatService] Starting stream chat request"),w$.debug(`\uD83D\uDCDD [CopilotChatService] Messages count: ${$.length}`);try{let V=await this.auth.getCopilotToken(),X=this.buildRequest($,W,!0),Y=await r(M0.chatCompletions,{method:"POST",headers:{Authorization:`Bearer ${V}`,"Content-Type":"application/json",Accept:"text/event-stream","Copilot-Integration-Id":"vscode-chat","Editor-Version":"vscode/1.95.0","Editor-Plugin-Version":"copilot-chat/0.22.2024","User-Agent":"GitHubCopilotChat/0.22.2024"},body:JSON.stringify(X),signal:Q});if(!Y.ok){let w=await Y.text();throw Error(`Copilot API error: ${Y.status} - ${w}`)}if(!Y.body)throw Error("No response body");let J=Y.body.getReader(),G=new TextDecoder,K="",B=new Map;while(!0){let{done:w,value:O}=await J.read();if(w)break;K+=G.decode(O,{stream:!0});let H=K.split(`
58
+ `);K=H.pop()||"";for(let U of H){if(!U.startsWith("data: "))continue;let A=U.slice(6).trim();if(A==="[DONE]"){if(B.size>0)yield{toolCalls:Array.from(B.values()),finishReason:"tool_calls"};continue}try{let b=JSON.parse(A).choices[0];if(b){let z={};if(b.delta.content)z.content=b.delta.content;if(b.delta.tool_calls)for(let C of b.delta.tool_calls){let N=B.get(C.index);if(N){if(C.function?.arguments)N.function.arguments+=C.function.arguments}else B.set(C.index,{id:C.id||"",type:"function",function:{name:C.function?.name||"",arguments:C.function?.arguments||""}})}if(b.finish_reason)z.finishReason=b.finish_reason;if(z.content||z.finishReason==="stop")yield z}}catch{}}}let q=Date.now()-Z;w$.debug(`✅ [CopilotChatService] Stream completed in ${q} ms`)}catch(V){let X=Date.now()-Z;throw w$.error(`❌ [CopilotChatService] Stream failed after ${X} ms`),w$.error(`❌ [CopilotChatService] Error: ${V}`),V}}sanitizeMessages($){let W=[],Q=new Set;for(let Z=0;Z<$.length;Z++){let V=$[Z];if(V.role==="assistant"&&V.tool_calls&&V.tool_calls.length>0){let X=[];for(let Y of V.tool_calls){let J=!1;for(let G=Z+1;G<$.length;G++){if($[G].role==="tool"&&$[G].tool_call_id===Y.id){J=!0;break}if($[G].role==="assistant"||$[G].role==="user")break}if(J)X.push(Y.id),Q.add(Y.id)}if(X.length>0)W.push({...V,tool_calls:V.tool_calls.filter((Y)=>X.includes(Y.id))});else W.push({role:V.role,content:V.content||"",reasoningContent:V.reasoningContent})}else if(V.role==="tool"){if(V.tool_call_id&&Q.has(V.tool_call_id))W.push(V)}else W.push(V)}if(W.length!==$.length)w$.debug(`[CopilotChatService] Sanitized messages: ${$.length} -> ${W.length}`);return W}buildRequest($,W,Q=!1){let V=this.sanitizeMessages($).map((Y)=>{let J;if(typeof Y.content==="string")J=Y.content;else if(Array.isArray(Y.content))J=Y.content.filter((K)=>K.type==="text").map((K)=>K.text).join(`
59
+ `);else J=null;let G={role:Y.role,content:J};if(Y.tool_call_id)G.tool_call_id=Y.tool_call_id;if(Y.name)G.name=Y.name;if(Y.tool_calls&&Y.tool_calls.length>0)G.tool_calls=Y.tool_calls.filter((K)=>K.type==="function"&&("function"in K)).map((K)=>({id:K.id,type:"function",function:{name:K.function.name,arguments:K.function.arguments}}));return G}),X={model:this.config.model,messages:V,stream:Q};if(this.config.temperature!==void 0)X.temperature=this.config.temperature;if(this.config.maxOutputTokens)X.max_tokens=this.config.maxOutputTokens;if(W&&W.length>0)X.tools=W.map((Y)=>({type:"function",function:{name:Y.name,description:Y.description,parameters:this.cleanParameters(Y.parameters)}})),X.tool_choice="auto";return X}cleanParameters($){if(!Y1($))return{};let W={};for(let[Q,Z]of Object.entries($)){if(["$ref","const","default"].includes(Q))continue;if(Q==="properties"&&Y1(Z)){let V={};for(let[X,Y]of Object.entries(Z))V[X]=Y1(Y)?this.cleanParameters(Y):Y;W[Q]=V}else if(Q==="items"&&Y1(Z))W[Q]=this.cleanParameters(Z);else W[Q]=Z}return W}async makeRequest($,W,Q){let Z=await r(M0.chatCompletions,{method:"POST",headers:{Authorization:`Bearer ${$}`,"Content-Type":"application/json",Accept:"application/json","Copilot-Integration-Id":"vscode-chat","Editor-Version":"vscode/1.95.0","Editor-Plugin-Version":"copilot-chat/0.22.2024","User-Agent":"GitHubCopilotChat/0.22.2024"},body:JSON.stringify(W),signal:Q});if(!Z.ok){let V=await Z.text();if(w$.error(`Copilot API error: ${Z.status} - ${V}`),Z.status===401)throw Error("Copilot token expired or invalid. Please run /login copilot again.");if(Z.status===403)throw Error("Permission denied. Please ensure you have an active GitHub Copilot subscription.");if(Z.status===429)throw Error("Rate limit exceeded. Please wait and try again.");throw Error(`Copilot API error: ${Z.status} - ${V}`)}return await Z.json()}parseResponse($){let W=$.choices[0];if(!W)throw Error("No response from Copilot API");let Q={content:W.message.content||""};if(W.message.tool_calls&&W.message.tool_calls.length>0)Q.toolCalls=W.message.tool_calls.map((Z)=>({id:Z.id,type:"function",function:{name:Z.function.name,arguments:Z.function.arguments}}));if($.usage)Q.usage={promptTokens:$.usage.prompt_tokens,completionTokens:$.usage.completion_tokens,totalTokens:$.usage.total_tokens};return Q}}import{createAnthropic as d7}from"@ai-sdk/anthropic";import{createAzure as m7}from"@ai-sdk/azure";import{createDeepSeek as g7}from"@ai-sdk/deepseek";import{createGoogleGenerativeAI as c7}from"@ai-sdk/google";import{createOpenAICompatible as q2}from"@ai-sdk/openai-compatible";import{generateText as i7,jsonSchema as l7,streamText as n7}from"ai";var D$=M("Chat");function g4($){let W=new Set;for(let Q of $)if(Q.role==="assistant"&&Q.tool_calls)for(let Z of Q.tool_calls)W.add(Z.id);return $.filter((Q)=>{if(Q.role==="tool"){if(!Q.tool_call_id)return!1;return W.has(Q.tool_call_id)}return!0})}function J1($){if(typeof $==="string")return $;return $.filter((W)=>W.type==="text").map((W)=>W.text).join(`
60
+ `)}function a7($,W={}){try{return JSON.parse($)}catch{return D$.warn("⚠️ [VercelAIChatService] Failed to parse JSON, using fallback",{str:$}),W}}class w2{model;config;constructor($){this.config=$,this.model=this.createModel($),D$.debug("\uD83D\uDE80 [VercelAIChatService] Initialized",{provider:$.provider,model:$.model,providerId:$.providerId})}createModel($){let{provider:W,apiKey:Q,baseUrl:Z,model:V,customHeaders:X,providerId:Y,apiVersion:J}=$;switch(W){case"anthropic":return d7({apiKey:Q,baseURL:Z||void 0,headers:X})(V);case"gemini":{if(Z&&!this.isGeminiOfficialUrl(Z))return q2({name:"gemini",apiKey:Q,baseURL:Z,headers:X})(V);return c7({apiKey:Q,baseURL:Z||void 0})(V)}case"azure-openai":{let G=this.extractAzureResourceName(Z);if(G)return m7({apiKey:Q,resourceName:G,apiVersion:J||"2024-08-01-preview"})(V);let K=this.buildAzureBaseUrl(Z,V);return q2({name:"azure-openai",apiKey:Q,baseURL:K,headers:{...X,"api-key":Q},queryParams:{"api-version":J||"2024-08-01-preview"}})(V)}default:{if(Y==="deepseek")return g7({apiKey:Q,baseURL:Z||void 0,headers:X})(V);return q2({name:Y||"custom",apiKey:Q,baseURL:Z,headers:X})(V)}}}extractAzureResourceName($){if(!$)return;let W=$.match(/https:\/\/([^.]+)\.openai\.azure(?:\.com|\.us|\.cn|\.de)/);return W?W[1]:void 0}buildAzureBaseUrl($,W){if(!$)return"";let Q=$.replace(/\/$/,"").replace(/\?.*$/,"");if(Q.includes("/openai/deployments/"))return Q;return`${Q}/openai/deployments/${W}`}isGeminiOfficialUrl($){return $.includes("generativelanguage.googleapis.com")||$.includes("aiplatform.googleapis.com")}convertMessages($){let W=[];for(let Q of $)if(Q.role==="system")if(Array.isArray(Q.content)){let Z=Q.content.find((X)=>X.type==="text"),V={role:"system",content:J1(Q.content)};if(Z?.providerOptions)V.providerOptions=Z.providerOptions;W.push(V)}else W.push({role:"system",content:Q.content});else if(Q.role==="user")if(Array.isArray(Q.content)){let Z=Q.content.map((V)=>{if(V.type==="text"){let X={type:"text",text:V.text};if(V.providerOptions)X.providerOptions=V.providerOptions;return X}return{type:"image",image:V.image_url.url}});W.push({role:"user",content:Z})}else W.push({role:"user",content:Q.content});else if(Q.role==="assistant")if(Q.tool_calls&&Q.tool_calls.length>0){let Z=Q.tool_calls.map((X)=>{let Y=X.function;return{type:"tool-call",toolCallId:X.id,toolName:Y?.name||"",input:a7(Y?.arguments||"{}",{})}}),V=J1(Q.content);if(V)W.push({role:"assistant",content:[{type:"text",text:V},...Z]});else W.push({role:"assistant",content:Z})}else W.push({role:"assistant",content:J1(Q.content)});else if(Q.role==="tool")W.push({role:"tool",content:[{type:"tool-result",toolCallId:Q.tool_call_id,toolName:Q.name||"unknown",output:{type:"text",value:J1(Q.content)}}]});return W}convertTools($){if(!$||$.length===0)return;let W={};for(let Q of $)W[Q.name]={description:Q.description,inputSchema:l7(Q.parameters)};return W}convertToolCalls($){return $.map((W)=>({id:W.toolCallId,type:"function",function:{name:W.toolName,arguments:JSON.stringify(W.args??W.input??{})}}))}convertUsage($,W){if(!$)return;let Q=$.promptTokens??0,Z=$.completionTokens??0,V={promptTokens:Q,completionTokens:Z,totalTokens:$.totalTokens??Q+Z};if(W?.anthropic){if(W.anthropic.cacheCreationInputTokens!==void 0)V.cacheCreationInputTokens=W.anthropic.cacheCreationInputTokens;if(W.anthropic.cacheReadInputTokens!==void 0)V.cacheReadInputTokens=W.anthropic.cacheReadInputTokens}return V}async chat($,W,Q){let Z=Date.now();D$.debug("\uD83D\uDE80 [VercelAIChatService] Starting chat request");let V=g4($),X=this.convertMessages(V),Y=this.convertTools(W);try{let J=await i7({model:this.model,messages:X,tools:Y,maxOutputTokens:this.config.maxOutputTokens,temperature:this.config.temperature??0,abortSignal:Q}),G=Date.now()-Z;D$.debug("\uD83D\uDCE5 [VercelAIChatService] Response received in",G,"ms");let K=J.toolCalls&&J.toolCalls.length>0?this.convertToolCalls(J.toolCalls):void 0,B=Array.isArray(J.reasoning)?J.reasoning.map((q)=>q.text).join(""):void 0;return{content:J.text,reasoningContent:B,toolCalls:K,usage:this.convertUsage(J.usage,J.providerMetadata)}}catch(J){let G=Date.now()-Z;throw D$.error("❌ [VercelAIChatService] Chat failed after",G,"ms"),J}}async*streamChat($,W,Q){let Z=Date.now();D$.debug("\uD83D\uDE80 [VercelAIChatService] Starting stream request");let V=g4($),X=this.convertMessages(V),Y=this.convertTools(W);try{let J=n7({model:this.model,messages:X,tools:Y,maxOutputTokens:this.config.maxOutputTokens,temperature:this.config.temperature??0,abortSignal:Q});D$.debug("\uD83D\uDCE5 [VercelAIChatService] Stream started");let G=0;for await(let B of J.fullStream)switch(B.type){case"text-delta":yield{content:B.text??B.textDelta};break;case"reasoning-delta":yield{reasoningContent:B.textDelta};break;case"tool-call":yield{toolCalls:[{index:G++,id:B.toolCallId,type:"function",function:{name:B.toolName,arguments:JSON.stringify(B.args??B.input??{})}}]};break;case"finish":yield{finishReason:B.finishReason,usage:this.convertUsage(B.totalUsage,B.providerMetadata)};break}let K=Date.now()-Z;D$.debug("✅ [VercelAIChatService] Stream completed in",K,"ms")}catch(J){let G=Date.now()-Z;throw D$.error("❌ [VercelAIChatService] Stream failed after",G,"ms"),J}}getConfig(){return{...this.config}}updateConfig($){D$.debug("\uD83D\uDD04 [VercelAIChatService] Updating configuration"),this.config={...this.config,...$},this.model=this.createModel(this.config),D$.debug("✅ [VercelAIChatService] Configuration updated")}}var c4=M("Service"),r7="blade-free-tier";function s7($){return $===r7}function o7($){return{}}async function G1($){let W=$;if(s7($.apiKey)){c4.info("\uD83D\uDD11 检测到内置 API Key,正在获取...");let Q=await m4($.apiKey);W={...$,apiKey:Q}}if(W.providerId){let Q=o7(W.providerId);if(Object.keys(Q).length>0)W={...W,customHeaders:{...Q,...W.customHeaders}},c4.debug(`\uD83D\uDD27 注入 ${W.providerId} 特定 headers:`,Object.keys(Q))}return t7(W)}function t7($){switch($.provider){case"antigravity":return new J2($);case"copilot":return new B2($);default:return new w2($)}}import{readFile as e7}from"node:fs/promises";import{basename as $6}from"node:path";class o{static MAX_FILES=5;static MAX_LINES_PER_FILE=1000;static analyzeFiles($){let W=new Map;return $.forEach((Z,V)=>{let X=typeof Z.content==="string"?Z.content:(Z.content||[]).filter((J)=>J.type==="text").map((J)=>J.text).join(`
61
+ `);if(o.extractFilePathsFromContent(X).forEach((J)=>{o.updateFileReference(W,J,V,!1)}),Z.tool_calls&&Array.isArray(Z.tool_calls))Z.tool_calls.forEach((J)=>{let G=o.extractFilePathsFromToolCall(J),K=J.type==="function"&&"function"in J?J.function?.name:"",B=["Write","Edit"].includes(K||"");G.forEach((q)=>{o.updateFileReference(W,q,V,B)})})}),Array.from(W.values()).sort((Z,V)=>{if(Z.wasModified!==V.wasModified)return Z.wasModified?-1:1;if(Z.mentions!==V.mentions)return V.mentions-Z.mentions;return V.lastMentioned-Z.lastMentioned}).slice(0,o.MAX_FILES)}static async readFilesContent($){let W=[];for(let Q of $)try{let Z=await e7(Q,"utf-8"),V=Z.split(`
56
62
  `),X=V.length,Y=Z,J=!1,G=X;if(X>o.MAX_LINES_PER_FILE)Y=V.slice(0,o.MAX_LINES_PER_FILE).join(`
57
63
  `),Y+=`
58
64
 
59
- ... (truncated ${X-o.MAX_LINES_PER_FILE} lines)`,J=!0,G=o.MAX_LINES_PER_FILE;W.push({path:Q,content:Y,truncated:J,lines:X,includedLines:G})}catch(Z){console.warn(`[FileAnalyzer] 无法读取文件: ${Q}`,Z)}return W}static extractFilePathsFromContent($){let W=new Set,Q=/```(?:\w+)?\s*\n?([\s\S]*?)```/g,Z=Array.from($.matchAll(Q));for(let X of Z){let Y=X[1];o.extractPathsFromText(Y).forEach((G)=>W.add(G))}return o.extractPathsFromText($).forEach((X)=>W.add(X)),Array.from(W)}static extractPathsFromText($){let W=[],Q=[/(?:src|tests?|docs?|lib|config|scripts?|bin|utils?|components?|services?|hooks?)\/[\w\-/.]+\.[\w]+/g,/(?:package|tsconfig|vite\.config|webpack\.config|next\.config|babel\.config)\.[\w]+/g,/(?:\.\.?\/|\/)[a-zA-Z0-9\-_/.]+\.[\w]+/g];for(let Z of Q){let V=Array.from($.matchAll(Z));for(let X of V){let Y=X[0];if(Y=Y.replace(/[,。;:!?""''()【】《》]$/g,""),Y=Y.replace(/[,.;:!?"'()[\]<>]$/g,""),o.isValidFilePath(Y))W.push(Y)}}return W}static extractFilePathsFromToolCall($){let W=[];if($.type!=="function"||!$.function)return W;try{let Q=$.function.name,Z=JSON.parse($.function.arguments||"{}");if(["Read","Write","Edit","Glob","Grep","NotebookEdit","mcp__github__get_file_contents","mcp__github__create_or_update_file"].includes(Q)){let X=["file_path","path","notebook_path","filePath"];for(let Y of X)if(Z[Y]&&typeof Z[Y]==="string")W.push(Z[Y])}}catch{}return W}static updateFileReference($,W,Q,Z){let V=$.get(W);if(V)V.mentions++,V.lastMentioned=Q,V.wasModified=V.wasModified||Z;else $.set(W,{path:W,mentions:1,lastMentioned:Q,wasModified:Z})}static isValidFilePath($){if(!$.includes("/"))return!1;let W=s7($);if(!W.includes("."))return!1;let Q=["ts","tsx","js","jsx","json","md","py","java","go","rs","c","cpp","h","css","scss","html","xml","yaml","yml","toml","sh","bash","sql","graphql","vue","svelte"],Z=W.split(".").pop()?.toLowerCase();if(!Z||!Q.includes(Z))return!1;return!0}}import{encodingForModel as i4}from"js-tiktoken";class Q${static encodingCache=new Map;static countTokens($,W){let Q=Q$.getEncoding(W),Z=0;for(let V of $){if(Z+=4,V.role)Z+=Q.encode(V.role).length;if(V.content)if(typeof V.content==="string")Z+=Q.encode(V.content).length;else Z+=Q.encode(JSON.stringify(V.content)).length;if(V.tool_calls&&Array.isArray(V.tool_calls))Z+=Q$.countToolCallTokens(V.tool_calls,Q);if(V.name)Z+=Q.encode(V.name).length}return Z}static getTokenLimit($){return $}static shouldCompact($,W,Q,Z=0.8){let V=Q$.countTokens($,W),X=Math.floor(Q*Z);return V>=X}static getEncoding($){if(!Q$.encodingCache.has($))try{let W=i4($);Q$.encodingCache.set($,W)}catch{try{let W=i4("gpt-4");Q$.encodingCache.set($,W)}catch{console.warn(`[TokenCounter] 无法为模型 ${$} 获取 encoding,使用粗略估算`),Q$.encodingCache.set($,{encode:(W)=>{return Array(Math.ceil(W.length/4))}})}}return Q$.encodingCache.get($)}static countToolCallTokens($,W){let Q=0;for(let Z of $){if(Q+=4,Z.type==="function"&&Z.function?.name)Q+=W.encode(Z.function.name).length;if(Z.type==="function"&&Z.function?.arguments)Q+=W.encode(Z.function.arguments).length;if(Z.id)Q+=W.encode(Z.id).length}return Q}static clearCache(){Q$.encodingCache.clear()}static estimateTokens($){let W=($.match(/[\u4e00-\u9fa5]/g)||[]).length,Q=$.length-W;return Math.ceil(W/1.5+Q/4)}}class t{static THRESHOLD_PERCENT=0.8;static RETAIN_PERCENT=0.2;static FALLBACK_RETAIN_PERCENT=0.3;static async compact($,W){let Q=W.actualPreTokens??Q$.countTokens($,W.modelName),Z=W.actualPreTokens?"actual (from LLM usage)":"estimated";console.log(`[CompactionService] preTokens source: ${Z}`);try{let X=await i.getInstance().executeCompactionHooks(W.trigger,{projectDir:process.cwd(),sessionId:W.sessionId||"unknown",permissionMode:W.permissionMode||"default",messagesBefore:$.length,tokensBefore:Q});if(X.blockCompaction)return console.log(`[CompactionService] Compaction hook 阻止压缩: ${X.blockReason||"(无原因)"}`),{success:!1,summary:"",preTokens:Q,postTokens:Q,filesIncluded:[],compactedMessages:$,boundaryMessage:{role:"system",content:""},summaryMessage:{role:"user",content:""},error:X.blockReason||"Compaction blocked by hook"};if(X.warning)console.warn(`[CompactionService] Compaction hook warning: ${X.warning}`)}catch(V){console.warn("[CompactionService] Compaction hook execution failed:",V)}try{console.log("[CompactionService] 开始压缩,消息数:",$.length),console.log("[CompactionService] 压缩前 tokens:",Q);let X=o.analyzeFiles($).map((D)=>D.path);console.log("[CompactionService] 提取重点文件:",X);let Y=await o.readFilesContent(X);console.log("[CompactionService] 成功读取文件:",Y.length);let J=await t.generateSummary($,Y,W);console.log("[CompactionService] 生成总结,长度:",J.length);let G=Math.ceil($.length*t.RETAIN_PERCENT),B=$.slice(-G),K=new Set;for(let D of B)if(D.role==="assistant"&&D.tool_calls)for(let N of D.tool_calls)K.add(N.id);let q=B.filter((D)=>{if(D.role==="tool"&&D.tool_call_id)return K.has(D.tool_call_id);return!0});console.log("[CompactionService] 保留消息数:",G),console.log("[CompactionService] 过滤后保留消息数:",q.length);let w=w0(),O=t.createBoundaryMessage(w,W.trigger,Q),b=w0(),U=t.createSummaryMessage(b,J),F=[U,...q],A=Q$.countTokens(F,W.modelName);return console.log("[CompactionService] 压缩完成!"),console.log("[CompactionService] Token 变化:",Q,"→",A,`(-${((1-A/Q)*100).toFixed(1)}%)`),{success:!0,summary:J,preTokens:Q,postTokens:A,filesIncluded:X,compactedMessages:F,boundaryMessage:O,summaryMessage:U}}catch(V){return console.error("[CompactionService] 压缩失败,使用降级策略",V),t.fallbackCompact($,W,Q,V)}}static async generateSummary($,W,Q){let Z=t.buildCompactionPrompt($,W);console.log("[CompactionService] 使用压缩模型:",Q.modelName);let Y=(await(await B1({apiKey:Q.apiKey||process.env.BLADE_API_KEY||"",baseUrl:Q.baseURL||process.env.BLADE_BASE_URL||"https://api.openai.com/v1",model:Q.modelName,temperature:0.3,maxOutputTokens:8000,timeout:60000,provider:"openai-compatible"})).chat([{role:"user",content:Z}])).content||"",J=Y.match(/<summary>([\s\S]*?)<\/summary>/);if(!J)return console.warn("[CompactionService] 总结格式不正确,使用完整响应"),Y;return J[1].trim()}static buildCompactionPrompt($,W){let Q=$.map((X,Y)=>{let J=X.role||"unknown",G=typeof X.content==="string"?X.content:JSON.stringify(X.content),B=5000,K=G.length>5000?G.substring(0,5000)+"...":G;return`[${Y+1}] ${J}: ${K}`}).join(`
65
+ ... (truncated ${X-o.MAX_LINES_PER_FILE} lines)`,J=!0,G=o.MAX_LINES_PER_FILE;W.push({path:Q,content:Y,truncated:J,lines:X,includedLines:G})}catch(Z){console.warn(`[FileAnalyzer] 无法读取文件: ${Q}`,Z)}return W}static extractFilePathsFromContent($){let W=new Set,Q=/```(?:\w+)?\s*\n?([\s\S]*?)```/g,Z=Array.from($.matchAll(Q));for(let X of Z){let Y=X[1];o.extractPathsFromText(Y).forEach((G)=>W.add(G))}return o.extractPathsFromText($).forEach((X)=>W.add(X)),Array.from(W)}static extractPathsFromText($){let W=[],Q=[/(?:src|tests?|docs?|lib|config|scripts?|bin|utils?|components?|services?|hooks?)\/[\w\-/.]+\.[\w]+/g,/(?:package|tsconfig|vite\.config|webpack\.config|next\.config|babel\.config)\.[\w]+/g,/(?:\.\.?\/|\/)[a-zA-Z0-9\-_/.]+\.[\w]+/g];for(let Z of Q){let V=Array.from($.matchAll(Z));for(let X of V){let Y=X[0];if(Y=Y.replace(/[,。;:!?""''()【】《》]$/g,""),Y=Y.replace(/[,.;:!?"'()[\]<>]$/g,""),o.isValidFilePath(Y))W.push(Y)}}return W}static extractFilePathsFromToolCall($){let W=[];if($.type!=="function"||!$.function)return W;try{let Q=$.function.name,Z=JSON.parse($.function.arguments||"{}");if(["Read","Write","Edit","Glob","Grep","NotebookEdit","mcp__github__get_file_contents","mcp__github__create_or_update_file"].includes(Q)){let X=["file_path","path","notebook_path","filePath"];for(let Y of X)if(Z[Y]&&typeof Z[Y]==="string")W.push(Z[Y])}}catch{}return W}static updateFileReference($,W,Q,Z){let V=$.get(W);if(V)V.mentions++,V.lastMentioned=Q,V.wasModified=V.wasModified||Z;else $.set(W,{path:W,mentions:1,lastMentioned:Q,wasModified:Z})}static isValidFilePath($){if(!$.includes("/"))return!1;let W=$6($);if(!W.includes("."))return!1;let Q=["ts","tsx","js","jsx","json","md","py","java","go","rs","c","cpp","h","css","scss","html","xml","yaml","yml","toml","sh","bash","sql","graphql","vue","svelte"],Z=W.split(".").pop()?.toLowerCase();if(!Z||!Q.includes(Z))return!1;return!0}}import{encodingForModel as i4}from"js-tiktoken";class Q${static encodingCache=new Map;static countTokens($,W){let Q=Q$.getEncoding(W),Z=0;for(let V of $){if(Z+=4,V.role)Z+=Q.encode(V.role).length;if(V.content)if(typeof V.content==="string")Z+=Q.encode(V.content).length;else Z+=Q.encode(JSON.stringify(V.content)).length;if(V.tool_calls&&Array.isArray(V.tool_calls))Z+=Q$.countToolCallTokens(V.tool_calls,Q);if(V.name)Z+=Q.encode(V.name).length}return Z}static getTokenLimit($){return $}static shouldCompact($,W,Q,Z=0.8){let V=Q$.countTokens($,W),X=Math.floor(Q*Z);return V>=X}static getEncoding($){if(!Q$.encodingCache.has($))try{let W=i4($);Q$.encodingCache.set($,W)}catch{try{let W=i4("gpt-4");Q$.encodingCache.set($,W)}catch{console.warn(`[TokenCounter] 无法为模型 ${$} 获取 encoding,使用粗略估算`),Q$.encodingCache.set($,{encode:(W)=>{return Array(Math.ceil(W.length/4))}})}}return Q$.encodingCache.get($)}static countToolCallTokens($,W){let Q=0;for(let Z of $){if(Q+=4,Z.type==="function"&&Z.function?.name)Q+=W.encode(Z.function.name).length;if(Z.type==="function"&&Z.function?.arguments)Q+=W.encode(Z.function.arguments).length;if(Z.id)Q+=W.encode(Z.id).length}return Q}static clearCache(){Q$.encodingCache.clear()}static estimateTokens($){let W=($.match(/[\u4e00-\u9fa5]/g)||[]).length,Q=$.length-W;return Math.ceil(W/1.5+Q/4)}}class t{static THRESHOLD_PERCENT=0.8;static RETAIN_PERCENT=0.2;static FALLBACK_RETAIN_PERCENT=0.3;static async compact($,W){let Q=W.actualPreTokens??Q$.countTokens($,W.modelName),Z=W.actualPreTokens?"actual (from LLM usage)":"estimated";console.log(`[CompactionService] preTokens source: ${Z}`);try{let X=await a.getInstance().executeCompactionHooks(W.trigger,{projectDir:process.cwd(),sessionId:W.sessionId||"unknown",permissionMode:W.permissionMode||"default",messagesBefore:$.length,tokensBefore:Q});if(X.blockCompaction)return console.log(`[CompactionService] Compaction hook 阻止压缩: ${X.blockReason||"(无原因)"}`),{success:!1,summary:"",preTokens:Q,postTokens:Q,filesIncluded:[],compactedMessages:$,boundaryMessage:{role:"system",content:""},summaryMessage:{role:"user",content:""},error:X.blockReason||"Compaction blocked by hook"};if(X.warning)console.warn(`[CompactionService] Compaction hook warning: ${X.warning}`)}catch(V){console.warn("[CompactionService] Compaction hook execution failed:",V)}try{console.log("[CompactionService] 开始压缩,消息数:",$.length),console.log("[CompactionService] 压缩前 tokens:",Q);let X=o.analyzeFiles($).map((b)=>b.path);console.log("[CompactionService] 提取重点文件:",X);let Y=await o.readFilesContent(X);console.log("[CompactionService] 成功读取文件:",Y.length);let J=await t.generateSummary($,Y,W);console.log("[CompactionService] 生成总结,长度:",J.length);let G=Math.ceil($.length*t.RETAIN_PERCENT),K=$.slice(-G),B=new Set;for(let b of K)if(b.role==="assistant"&&b.tool_calls)for(let z of b.tool_calls)B.add(z.id);let q=K.filter((b)=>{if(b.role==="tool"&&b.tool_call_id)return B.has(b.tool_call_id);return!0});console.log("[CompactionService] 保留消息数:",G),console.log("[CompactionService] 过滤后保留消息数:",q.length);let w=w0(),O=t.createBoundaryMessage(w,W.trigger,Q),H=w0(),U=t.createSummaryMessage(H,J),A=[U,...q],D=Q$.countTokens(A,W.modelName);return console.log("[CompactionService] 压缩完成!"),console.log("[CompactionService] Token 变化:",Q,"→",D,`(-${((1-D/Q)*100).toFixed(1)}%)`),{success:!0,summary:J,preTokens:Q,postTokens:D,filesIncluded:X,compactedMessages:A,boundaryMessage:O,summaryMessage:U}}catch(V){return console.error("[CompactionService] 压缩失败,使用降级策略",V),t.fallbackCompact($,W,Q,V)}}static async generateSummary($,W,Q){let Z=t.buildCompactionPrompt($,W);console.log("[CompactionService] 使用压缩模型:",Q.modelName);let Y=(await(await G1({apiKey:Q.apiKey||process.env.BLADE_API_KEY||"",baseUrl:Q.baseURL||process.env.BLADE_BASE_URL||"https://api.openai.com/v1",model:Q.modelName,temperature:0.3,maxOutputTokens:8000,timeout:60000,provider:"openai-compatible"})).chat([{role:"user",content:Z}])).content||"",J=Y.match(/<summary>([\s\S]*?)<\/summary>/);if(!J)return console.warn("[CompactionService] 总结格式不正确,使用完整响应"),Y;return J[1].trim()}static buildCompactionPrompt($,W){let Q=$.map((X,Y)=>{let J=X.role||"unknown",G=typeof X.content==="string"?X.content:JSON.stringify(X.content),K=5000,B=G.length>5000?G.substring(0,5000)+"...":G;return`[${Y+1}] ${J}: ${B}`}).join(`
60
66
 
61
67
  `),Z=W.map((X)=>{return`### ${X.path}
62
68
  \`\`\`
@@ -129,18 +135,18 @@ ${W.length>0?`## Important Files
129
135
 
130
136
  ${Z}`:""}
131
137
 
132
- Please provide your summary following the structure specified above, with both <analysis> and <summary> sections.`}static createBoundaryMessage($,W,Q){return{id:w0(),role:"system",content:"Conversation compacted",metadata:{type:"system",subtype:"compact_boundary",parentId:$,compactMetadata:{trigger:W,preTokens:Q}}}}static createSummaryMessage($,W){return{id:w0(),role:"user",content:W,metadata:{parentId:$,isCompactSummary:!0}}}static fallbackCompact($,W,Q,Z){let V=Math.ceil($.length*t.FALLBACK_RETAIN_PERCENT),X=$.slice(-V),Y=new Set;for(let U of X)if(U.role==="assistant"&&U.tool_calls)for(let F of U.tool_calls)Y.add(F.id);let J=X.filter((U)=>{if(U.role==="tool"&&U.tool_call_id)return Y.has(U.tool_call_id);return!0}),G=w0(),B=t.createBoundaryMessage(G,W.trigger,Q),K=Z instanceof Error?Z.message:String(Z),q=w0(),w=t.createSummaryMessage(q,`[Automatic compaction failed; using fallback]
138
+ Please provide your summary following the structure specified above, with both <analysis> and <summary> sections.`}static createBoundaryMessage($,W,Q){return{id:w0(),role:"system",content:"Conversation compacted",metadata:{type:"system",subtype:"compact_boundary",parentId:$,compactMetadata:{trigger:W,preTokens:Q}}}}static createSummaryMessage($,W){return{id:w0(),role:"user",content:W,metadata:{parentId:$,isCompactSummary:!0}}}static fallbackCompact($,W,Q,Z){let V=Math.ceil($.length*t.FALLBACK_RETAIN_PERCENT),X=$.slice(-V),Y=new Set;for(let U of X)if(U.role==="assistant"&&U.tool_calls)for(let A of U.tool_calls)Y.add(A.id);let J=X.filter((U)=>{if(U.role==="tool"&&U.tool_call_id)return Y.has(U.tool_call_id);return!0}),G=w0(),K=t.createBoundaryMessage(G,W.trigger,Q),B=Z instanceof Error?Z.message:String(Z),q=w0(),w=t.createSummaryMessage(q,`[Automatic compaction failed; using fallback]
133
139
 
134
140
  An error occurred during compaction. Retained the latest ${V} messages (~30%).
135
141
 
136
- Error: ${K}
142
+ Error: ${B}
137
143
 
138
- The conversation can continue, but consider retrying compaction later with /compact.`),O=[w,...J],b=Q$.countTokens(O,W.modelName);return{success:!1,summary:typeof w.content==="string"?w.content:w.content.filter((U)=>U.type==="text").map((U)=>U.text).join(`
139
- `),preTokens:Q,postTokens:b,filesIncluded:[],compactedMessages:O,boundaryMessage:B,summaryMessage:w,error:K}}}import{appendFileSync as o7,mkdirSync as t7,writeFileSync as e7}from"node:fs";import $6 from"node:os";import n4 from"node:path";var O2=n4.join($6.homedir(),".blade","logs","stream-debug.log"),l4=!1;function W6(){if(l4)return;let $=n4.dirname(O2);t7($,{recursive:!0,mode:493}),e7(O2,`=== Stream Debug Log Started: ${new Date().toISOString()} ===
140
- `),l4=!0}function k$($,W,Q){W6();let Z=new Date().toISOString(),V=Q?` | ${JSON.stringify(Q)}`:"",X=`[${Z}] [${$}] ${W}${V}
141
- `;o7(O2,X)}import{EventEmitter as U6}from"events";import{z as K$}from"zod";var f;((Z)=>{Z.ReadOnly="readonly";Z.Write="write";Z.Execute="execute"})(f||={});function VZ($){return $!==void 0&&typeof $.pattern==="string"&&typeof $.search_path==="string"}function XZ($){return $!==void 0&&$.kind==="edit"&&typeof $.matches_found==="number"}var P;((X)=>{X.VALIDATION_ERROR="validation_error";X.PERMISSION_DENIED="permission_denied";X.EXECUTION_ERROR="execution_error";X.TIMEOUT_ERROR="timeout_error";X.NETWORK_ERROR="network_error"})(P||={});function y0($){return $==="readonly"}import{isPlainObject as Q6}from"lodash-es";class U2{toolName;params;context;aborted=!1;result;_internal={};constructor($,W,Q){this.toolName=$;this.params=W;this.context=Q}shouldAbort(){return this.aborted||(this.context.signal?.aborted??!1)}abort($,W){this.aborted=!0,this.result={success:!1,llmContent:`Tool execution aborted: ${$||"Unknown reason"}`,displayContent:`执行已中止: ${$||"未知原因"}`,error:{type:"execution_error",message:$||"Execution aborted"},metadata:W?.shouldExitLoop?{shouldExitLoop:!0}:void 0}}setResult($){this.result=$}getResult(){if(!this.result)throw Error("Tool execution result not set");return this.result}}function T0($){if($===void 0)return"undefined";if(typeof $==="string")return $;try{let W=JSON.stringify($);return W===void 0?String($):W}catch{return String($)}}class a4 extends Error{issues;type;constructor($,W,Q="validation_error"){super($);this.issues=W;this.type=Q;this.name="ToolValidationError"}}function Z6($){let{code:W}=$,Q=$,Z=Q.received;switch(W){case"invalid_type":{let V=Q.expected;return`类型错误:期望 ${T0(V)},实际收到 ${T0(Z)}`}case"too_small":{let{minimum:V,inclusive:X}=Q,Y=typeof Q.type==="string"?Q.type:void 0;if(Y==="string"&&typeof V==="number")return`长度不能少于 ${V} 个字符`;if(Y==="number"&&typeof V==="number")return`不能小于${X?"等于":""} ${V}`;if(Y==="array"&&typeof V==="number")return`数组长度不能少于 ${V}`;return"值太小"}case"too_big":{let{maximum:V,inclusive:X}=Q,Y=typeof Q.type==="string"?Q.type:void 0;if(Y==="string"&&typeof V==="number")return`长度不能超过 ${V} 个字符`;if(Y==="number"&&typeof V==="number")return`不能大于${X?"等于":""} ${V}`;if(Y==="array"&&typeof V==="number")return`数组长度不能超过 ${V}`;return"值太大"}case"invalid_string":{let V=Q.validation;if(V==="email")return"必须是有效的电子邮件地址";if(V==="url")return"必须是有效的 URL";if(V==="uuid")return"必须是有效的 UUID";if(Q6(V)){let X=V;if(typeof X.includes==="string")return`必须包含 "${X.includes}"`;if(typeof X.startsWith==="string")return`必须以 "${X.startsWith}" 开头`;if(typeof X.endsWith==="string")return`必须以 "${X.endsWith}" 结尾`}return"字符串格式不正确"}case"invalid_enum_value":{let V=Q.options;if(Array.isArray(V))return`必须是以下值之一:${V.map((X)=>T0(X)).join(", ")}`;return"必须是枚举允许的值之一"}case"invalid_literal":{let V=Q.expected;return`必须是字面量值:${T0(V)}`}case"unrecognized_keys":{let V=Q.keys;if(Array.isArray(V))return`包含未知的参数:${V.map((X)=>T0(X)).join(", ")}`;return"包含未知的参数"}case"invalid_union":return"不符合任何有效的类型定义";case"invalid_date":return"必须是有效的日期";case"custom":return $.message||"自定义验证失败";default:return $.message||"验证失败"}}function V6($){let W=$.issues.map((Z)=>{let V=Z.path.join("."),X=Z6(Z),Y=Z.received;return{field:V||"root",message:X,value:Y}}),Q=W.length===1?`参数验证失败 [${W[0].field}]: ${W[0].message}`:`参数验证失败 (${W.length} 个错误):
144
+ The conversation can continue, but consider retrying compaction later with /compact.`),O=[w,...J],H=Q$.countTokens(O,W.modelName);return{success:!1,summary:typeof w.content==="string"?w.content:w.content.filter((U)=>U.type==="text").map((U)=>U.text).join(`
145
+ `),preTokens:Q,postTokens:H,filesIncluded:[],compactedMessages:O,boundaryMessage:K,summaryMessage:w,error:B}}}import{appendFileSync as W6,mkdirSync as Q6,writeFileSync as Z6}from"node:fs";import V6 from"node:os";import n4 from"node:path";var O2=n4.join(V6.homedir(),".blade","logs","stream-debug.log"),l4=!1;function X6(){if(l4)return;let $=n4.dirname(O2);Q6($,{recursive:!0,mode:493}),Z6(O2,`=== Stream Debug Log Started: ${new Date().toISOString()} ===
146
+ `),l4=!0}function P$($,W,Q){X6();let Z=new Date().toISOString(),V=Q?` | ${JSON.stringify(Q)}`:"",X=`[${Z}] [${$}] ${W}${V}
147
+ `;W6(O2,X)}import{EventEmitter as D6}from"events";import{z as O$}from"zod";var f;((Z)=>{Z.ReadOnly="readonly";Z.Write="write";Z.Execute="execute"})(f||={});function GZ($){return $!==void 0&&typeof $.pattern==="string"&&typeof $.search_path==="string"}function KZ($){return $!==void 0&&$.kind==="edit"&&typeof $.matches_found==="number"}var P;((X)=>{X.VALIDATION_ERROR="validation_error";X.PERMISSION_DENIED="permission_denied";X.EXECUTION_ERROR="execution_error";X.TIMEOUT_ERROR="timeout_error";X.NETWORK_ERROR="network_error"})(P||={});function y0($){return $==="readonly"}import{isPlainObject as Y6}from"lodash-es";class U2{toolName;params;context;aborted=!1;result;_internal={};constructor($,W,Q){this.toolName=$;this.params=W;this.context=Q}shouldAbort(){return this.aborted||(this.context.signal?.aborted??!1)}abort($,W){this.aborted=!0,this.result={success:!1,llmContent:`Tool execution aborted: ${$||"Unknown reason"}`,displayContent:`执行已中止: ${$||"未知原因"}`,error:{type:"execution_error",message:$||"Execution aborted"},metadata:W?.shouldExitLoop?{shouldExitLoop:!0}:void 0}}setResult($){this.result=$}getResult(){if(!this.result)throw Error("Tool execution result not set");return this.result}}function T0($){if($===void 0)return"undefined";if(typeof $==="string")return $;try{let W=JSON.stringify($);return W===void 0?String($):W}catch{return String($)}}class a4 extends Error{issues;type;constructor($,W,Q="validation_error"){super($);this.issues=W;this.type=Q;this.name="ToolValidationError"}}function J6($){let{code:W}=$,Q=$,Z=Q.received;switch(W){case"invalid_type":{let V=Q.expected;return`类型错误:期望 ${T0(V)},实际收到 ${T0(Z)}`}case"too_small":{let{minimum:V,inclusive:X}=Q,Y=typeof Q.type==="string"?Q.type:void 0;if(Y==="string"&&typeof V==="number")return`长度不能少于 ${V} 个字符`;if(Y==="number"&&typeof V==="number")return`不能小于${X?"等于":""} ${V}`;if(Y==="array"&&typeof V==="number")return`数组长度不能少于 ${V}`;return"值太小"}case"too_big":{let{maximum:V,inclusive:X}=Q,Y=typeof Q.type==="string"?Q.type:void 0;if(Y==="string"&&typeof V==="number")return`长度不能超过 ${V} 个字符`;if(Y==="number"&&typeof V==="number")return`不能大于${X?"等于":""} ${V}`;if(Y==="array"&&typeof V==="number")return`数组长度不能超过 ${V}`;return"值太大"}case"invalid_string":{let V=Q.validation;if(V==="email")return"必须是有效的电子邮件地址";if(V==="url")return"必须是有效的 URL";if(V==="uuid")return"必须是有效的 UUID";if(Y6(V)){let X=V;if(typeof X.includes==="string")return`必须包含 "${X.includes}"`;if(typeof X.startsWith==="string")return`必须以 "${X.startsWith}" 开头`;if(typeof X.endsWith==="string")return`必须以 "${X.endsWith}" 结尾`}return"字符串格式不正确"}case"invalid_enum_value":{let V=Q.options;if(Array.isArray(V))return`必须是以下值之一:${V.map((X)=>T0(X)).join(", ")}`;return"必须是枚举允许的值之一"}case"invalid_literal":{let V=Q.expected;return`必须是字面量值:${T0(V)}`}case"unrecognized_keys":{let V=Q.keys;if(Array.isArray(V))return`包含未知的参数:${V.map((X)=>T0(X)).join(", ")}`;return"包含未知的参数"}case"invalid_union":return"不符合任何有效的类型定义";case"invalid_date":return"必须是有效的日期";case"custom":return $.message||"自定义验证失败";default:return $.message||"验证失败"}}function G6($){let W=$.issues.map((Z)=>{let V=Z.path.join("."),X=J6(Z),Y=Z.received;return{field:V||"root",message:X,value:Y}}),Q=W.length===1?`参数验证失败 [${W[0].field}]: ${W[0].message}`:`参数验证失败 (${W.length} 个错误):
142
148
  ${W.map((Z)=>` - ${Z.field}: ${Z.message}`).join(`
143
- `)}`;return new a4(Q,W)}function r4($,W){let Q=$.safeParse(W);if(!Q.success)throw V6(Q.error);return Q.data}import{zodToJsonSchema as X6}from"zod-to-json-schema";function H2($){return X6($,{target:"jsonSchema7",$refStrategy:"none"})}class b2{toolName;params;executeFn;descriptionFn;affectedPathsFn;constructor($,W,Q,Z,V){this.toolName=$;this.params=W;this.executeFn=Q;this.descriptionFn=Z;this.affectedPathsFn=V}getDescription(){if(this.descriptionFn)return this.descriptionFn(this.params);return`执行工具: ${this.toolName}`}getAffectedPaths(){if(this.affectedPathsFn)return this.affectedPathsFn(this.params);return[]}async execute($,W,Q){let Z={signal:$,updateOutput:W,...Q};return this.executeFn(this.params,Z)}}function E($){return{name:$.name,displayName:$.displayName,kind:$.kind,isReadOnly:$.isReadOnly??y0($.kind),isConcurrencySafe:$.isConcurrencySafe??!0,strict:$.strict??!1,description:$.description,version:$.version||"1.0.0",category:$.category,tags:$.tags||[],getFunctionDeclaration(){let W=H2($.schema),Q=$.description.short;if($.description.long)Q+=`
149
+ `)}`;return new a4(Q,W)}function r4($,W){let Q=$.safeParse(W);if(!Q.success)throw G6(Q.error);return Q.data}import{zodToJsonSchema as K6}from"zod-to-json-schema";function F2($){return K6($,{target:"jsonSchema7",$refStrategy:"none"})}class H2{toolName;params;executeFn;descriptionFn;affectedPathsFn;constructor($,W,Q,Z,V){this.toolName=$;this.params=W;this.executeFn=Q;this.descriptionFn=Z;this.affectedPathsFn=V}getDescription(){if(this.descriptionFn)return this.descriptionFn(this.params);return`执行工具: ${this.toolName}`}getAffectedPaths(){if(this.affectedPathsFn)return this.affectedPathsFn(this.params);return[]}async execute($,W,Q){let Z={signal:$,updateOutput:W,...Q};return this.executeFn(this.params,Z)}}function E($){return{name:$.name,displayName:$.displayName,kind:$.kind,isReadOnly:$.isReadOnly??y0($.kind),isConcurrencySafe:$.isConcurrencySafe??!0,strict:$.strict??!1,description:$.description,version:$.version||"1.0.0",category:$.category,tags:$.tags||[],getFunctionDeclaration(){let W=F2($.schema),Q=$.description.short;if($.description.long)Q+=`
144
150
 
145
151
  ${$.description.long}`;if($.description.usageNotes&&$.description.usageNotes.length>0)Q+=`
146
152
 
@@ -150,20 +156,20 @@ ${$.description.usageNotes.map((Z)=>`- ${Z}`).join(`
150
156
 
151
157
  Important:
152
158
  ${$.description.important.map((Z)=>`⚠️ ${Z}`).join(`
153
- `)}`;return{name:$.name,description:Q,parameters:W}},getMetadata(){return{name:$.name,displayName:$.displayName,kind:$.kind,version:$.version||"1.0.0",category:$.category,tags:$.tags||[],description:$.description,schema:H2($.schema)}},build(W){let Q=r4($.schema,W);return new b2($.name,Q,$.execute)},async execute(W,Q){return this.build(W).execute(Q||new AbortController().signal)},extractSignatureContent:$.extractSignatureContent?(W)=>$.extractSignatureContent(W):void 0,abstractPermissionRule:$.abstractPermissionRule?(W)=>$.abstractPermissionRule(W):void 0}}function K1($,W,Q,Z){let V;try{V=P0(Q.inputSchema)}catch(Y){console.warn(`[createMcpTool] Schema 转换失败,使用降级 schema: ${Q.name}`,Y),V=K$.any()}let X=Z||Q.name;return E({name:X,displayName:`${W}: ${Q.name}`,kind:"execute",schema:V,description:{short:Q.description||`MCP Tool: ${Q.name}`,important:[`From MCP server: ${W}`,"Executes external tools; user confirmation required"]},category:"MCP tool",tags:["mcp","external",W],async execute(Y,J){try{let G=await $.callTool(Q.name,Y),B="",K="";if(G.content&&Array.isArray(G.content)){for(let q of G.content)if(q.type==="text"&&q.text)B+=q.text,K+=q.text;else if(q.type==="image")K+=`[图片: ${q.mimeType||"unknown"}]
154
- `,B+=`[image: ${q.mimeType||"unknown"}]
155
- `;else if(q.type==="resource")K+=`[资源: ${q.mimeType||"unknown"}]
156
- `,B+=`[resource: ${q.mimeType||"unknown"}]
157
- `}if(G.isError)return{success:!1,llmContent:B||"MCP tool execution failed",displayContent:`❌ ${K||"MCP工具执行失败"}`,error:{type:"execution_error",message:B||"MCP tool execution failed"}};return{success:!0,llmContent:B||"Execution succeeded",displayContent:`✅ MCP工具 ${Q.name} 执行成功
158
- ${K}`,metadata:{serverName:W,toolName:Q.name,mcpResult:G}}}catch(G){return{success:!1,llmContent:`MCP tool execution failed: ${G.message}`,displayContent:`❌ ${G.message}`,error:{type:"execution_error",message:G.message}}}}})}function P0($){if($.type==="object"||$.properties){let W={},Q=$.required||[];if($.properties){for(let[Z,V]of Object.entries($.properties))if(typeof V==="object"&&V!==null){let X=P0(V);if(!Q.includes(Z))X=X.optional();W[Z]=X}}return K$.object(W)}if($.type==="array"&&$.items){if(typeof $.items==="object"&&!Array.isArray($.items)&&$.items!==null)return K$.array(P0($.items));return K$.array(K$.any())}if($.type==="string"){let W=K$.string();if($.minLength!==void 0)W=W.min($.minLength);if($.maxLength!==void 0)W=W.max($.maxLength);if($.pattern)W=W.regex(new RegExp($.pattern));if($.enum)return K$.enum($.enum);return W}if($.type==="number"||$.type==="integer"){let W=K$.number();if($.minimum!==void 0)W=W.min($.minimum);if($.maximum!==void 0)W=W.max($.maximum);return W}if($.type==="boolean")return K$.boolean();if($.oneOf&&$.oneOf.length>0){let W=$.oneOf.filter((Q)=>typeof Q==="object"&&Q!==null).map((Q)=>P0(Q));if(W.length>=2)return K$.union(W)}if($.anyOf&&$.anyOf.length>0){let W=$.anyOf.filter((Q)=>typeof Q==="object"&&Q!==null).map((Q)=>P0(Q));if(W.length>=2)return K$.union(W)}return K$.any()}import{Client as K6}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as q6}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as w6}from"@modelcontextprotocol/sdk/client/stdio.js";import{EventEmitter as O6}from"events";var F2={name:"@blade-ai/agent-sdk",version:"0.1.0",private:!1,description:"Blade AI Agent SDK",type:"module",main:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js"}},files:["dist","vendor/ripgrep/**","README.md","CHANGELOG.md"],scripts:{build:"bun run scripts/build.ts",test:"bun test",lint:"biome lint src","lint:fix":"biome lint --write src","type-check":"bun x tsc --noEmit",release:"bun run scripts/release.js","release:dry":"bun run scripts/release.js --dry-run","release:major":"bun run scripts/release.js --major","release:minor":"bun run scripts/release.js --minor","release:patch":"bun run scripts/release.js --patch"},keywords:["sdk","blade","ai","assistant","agent","llm","bun"],author:"echoVic",license:"MIT",optionalDependencies:{"@vscode/ripgrep":"^1.17.0","bun-pty":"^0.4.8","node-pty":"1.0.0"},dependencies:{"@agentclientprotocol/sdk":"^0.12.0","@ai-sdk/anthropic":"^3.0.7","@ai-sdk/azure":"^3.0.5","@ai-sdk/deepseek":"^2.0.4","@ai-sdk/google":"^3.0.4","@ai-sdk/openai-compatible":"^2.0.4","@modelcontextprotocol/sdk":"^1.17.4",ai:"^6.0.39","async-mutex":"^0.5.0",axios:"^1.12.2",chalk:"^5.4.1",diff:"^8.0.2","fast-glob":"^3.3.3","fuse.js":"^7.1.0","gray-matter":"^4.0.3",hono:"^4.7.10","js-tiktoken":"^1.0.21","lodash-es":"^4.17.21","lru-cache":"^11.2.4",nanoid:"^5.1.6",open:"^10.1.2",openai:"^6.2.0",picomatch:"^4.0.3",semver:"^7.7.3",undici:"^7.16.0","write-file-atomic":"^7.0.0",ws:"^8.18.0",yaml:"^2.8.1",zod:"^3.24.2","zod-to-json-schema":"^3.24.6",zustand:"^5.0.9"},devDependencies:{"@biomejs/biome":"^2.2.4","@types/json-schema":"^7.0.15","@types/lodash-es":"^4.17.12","@types/picomatch":"^4.0.2","@types/semver":"^7.7.1","@types/write-file-atomic":"^4.0.3","@types/ws":"^8.5.12","bun-types":"latest",typescript:"^5.9.2"}};function s4(){return F2.version}function o4(){return F2.name}import{spawn as G6}from"child_process";import*as I0 from"crypto";import*as $8 from"http";import{URL as t4}from"url";import{promises as A2}from"fs";import J6 from"os";import D2 from"path";class _2{tokenFilePath;constructor(){let $=J6.homedir(),W=D2.join($,".blade");this.tokenFilePath=D2.join(W,"mcp-oauth-tokens.json")}async ensureConfigDir(){let $=D2.dirname(this.tokenFilePath);try{await A2.mkdir($,{recursive:!0,mode:493})}catch{}}async loadAllCredentials(){let $=new Map;try{let W=await A2.readFile(this.tokenFilePath,"utf-8"),Q=JSON.parse(W);for(let Z of Q)$.set(Z.serverName,Z)}catch(W){if(W.code!=="ENOENT")console.warn("[OAuthTokenStorage] 加载令牌失败:",W)}return $}async saveAllCredentials($){await this.ensureConfigDir();let W=Array.from($.values());await A2.writeFile(this.tokenFilePath,JSON.stringify(W,null,2),{mode:384})}async saveToken($,W,Q,Z){let V=await this.loadAllCredentials(),X={serverName:$,token:W,clientId:Q,tokenUrl:Z,updatedAt:Date.now()};V.set($,X),await this.saveAllCredentials(V)}async getCredentials($){return(await this.loadAllCredentials()).get($)||null}async deleteCredentials($){let W=await this.loadAllCredentials();W.delete($),await this.saveAllCredentials(W)}async listServers(){let $=await this.loadAllCredentials();return Array.from($.keys())}isTokenExpired($){if(!$.expiresAt)return!1;let W=300000;return Date.now()>=$.expiresAt-W}}var k0=7777,L2="/oauth/callback",e4=200;class q1{tokenStorage;constructor($=new _2){this.tokenStorage=$}generatePKCEParams(){let $=I0.randomBytes(32).toString("base64url"),W=I0.createHash("sha256").update($).digest("base64url"),Q=I0.randomBytes(16).toString("base64url");return{codeVerifier:$,codeChallenge:W,state:Q}}buildAuthorizationUrl($,W){let Q=$.redirectUri||`http://localhost:${k0}${L2}`,Z=new URLSearchParams({client_id:$.clientId,response_type:"code",redirect_uri:Q,state:W.state,code_challenge:W.codeChallenge,code_challenge_method:"S256"});if($.scopes&&$.scopes.length>0)Z.append("scope",$.scopes.join(" "));let V=new t4($.authorizationUrl);return Z.forEach((X,Y)=>{V.searchParams.append(Y,X)}),V.toString()}async startCallbackServer($){return new Promise((W,Q)=>{let Z=$8.createServer((V,X)=>{try{let Y=new t4(V.url,`http://localhost:${k0}`);if(Y.pathname!==L2){X.writeHead(404),X.end("Not found");return}let J=Y.searchParams.get("code"),G=Y.searchParams.get("state"),B=Y.searchParams.get("error");if(B){X.writeHead(e4,{"Content-Type":"text/html"}),X.end(`
159
+ `)}`;return{name:$.name,description:Q,parameters:W}},getMetadata(){return{name:$.name,displayName:$.displayName,kind:$.kind,version:$.version||"1.0.0",category:$.category,tags:$.tags||[],description:$.description,schema:F2($.schema)}},build(W){let Q=r4($.schema,W);return new H2($.name,Q,$.execute)},async execute(W,Q){return this.build(W).execute(Q||new AbortController().signal)},extractSignatureContent:$.extractSignatureContent?(W)=>$.extractSignatureContent(W):void 0,abstractPermissionRule:$.abstractPermissionRule?(W)=>$.abstractPermissionRule(W):void 0}}function K1($,W,Q,Z){let V;try{V=P0(Q.inputSchema)}catch(Y){console.warn(`[createMcpTool] Schema 转换失败,使用降级 schema: ${Q.name}`,Y),V=O$.any()}let X=Z||Q.name;return E({name:X,displayName:`${W}: ${Q.name}`,kind:"execute",schema:V,description:{short:Q.description||`MCP Tool: ${Q.name}`,important:[`From MCP server: ${W}`,"Executes external tools; user confirmation required"]},category:"MCP tool",tags:["mcp","external",W],async execute(Y,J){try{let G=await $.callTool(Q.name,Y),K="",B="";if(G.content&&Array.isArray(G.content)){for(let q of G.content)if(q.type==="text"&&q.text)K+=q.text,B+=q.text;else if(q.type==="image")B+=`[图片: ${q.mimeType||"unknown"}]
160
+ `,K+=`[image: ${q.mimeType||"unknown"}]
161
+ `;else if(q.type==="resource")B+=`[资源: ${q.mimeType||"unknown"}]
162
+ `,K+=`[resource: ${q.mimeType||"unknown"}]
163
+ `}if(G.isError)return{success:!1,llmContent:K||"MCP tool execution failed",displayContent:`❌ ${B||"MCP工具执行失败"}`,error:{type:"execution_error",message:K||"MCP tool execution failed"}};return{success:!0,llmContent:K||"Execution succeeded",displayContent:`✅ MCP工具 ${Q.name} 执行成功
164
+ ${B}`,metadata:{serverName:W,toolName:Q.name,mcpResult:G}}}catch(G){return{success:!1,llmContent:`MCP tool execution failed: ${G.message}`,displayContent:`❌ ${G.message}`,error:{type:"execution_error",message:G.message}}}}})}function P0($){if($.type==="object"||$.properties){let W={},Q=$.required||[];if($.properties){for(let[Z,V]of Object.entries($.properties))if(typeof V==="object"&&V!==null){let X=P0(V);if(!Q.includes(Z))X=X.optional();W[Z]=X}}return O$.object(W)}if($.type==="array"&&$.items){if(typeof $.items==="object"&&!Array.isArray($.items)&&$.items!==null)return O$.array(P0($.items));return O$.array(O$.any())}if($.type==="string"){let W=O$.string();if($.minLength!==void 0)W=W.min($.minLength);if($.maxLength!==void 0)W=W.max($.maxLength);if($.pattern)W=W.regex(new RegExp($.pattern));if($.enum)return O$.enum($.enum);return W}if($.type==="number"||$.type==="integer"){let W=O$.number();if($.minimum!==void 0)W=W.min($.minimum);if($.maximum!==void 0)W=W.max($.maximum);return W}if($.type==="boolean")return O$.boolean();if($.oneOf&&$.oneOf.length>0){let W=$.oneOf.filter((Q)=>typeof Q==="object"&&Q!==null).map((Q)=>P0(Q));if(W.length>=2)return O$.union(W)}if($.anyOf&&$.anyOf.length>0){let W=$.anyOf.filter((Q)=>typeof Q==="object"&&Q!==null).map((Q)=>P0(Q));if(W.length>=2)return O$.union(W)}return O$.any()}import{Client as U6}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as F6}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as H6}from"@modelcontextprotocol/sdk/client/stdio.js";import{EventEmitter as A6}from"events";var A2={name:"@blade-ai/agent-sdk",version:"0.1.1",private:!1,description:"Blade AI Agent SDK",type:"module",main:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js"}},files:["dist","vendor/ripgrep/**","README.md","CHANGELOG.md"],scripts:{build:"bun run scripts/build.ts",test:"bun test",lint:"biome lint src","lint:fix":"biome lint --write src","type-check":"bun x tsc --noEmit",release:"bun run scripts/release.js","release:dry":"bun run scripts/release.js --dry-run","release:major":"bun run scripts/release.js --major","release:minor":"bun run scripts/release.js --minor","release:patch":"bun run scripts/release.js --patch"},keywords:["sdk","blade","ai","assistant","agent","llm","bun"],author:"echoVic",license:"MIT",optionalDependencies:{"@vscode/ripgrep":"^1.17.0","bun-pty":"^0.4.8","node-pty":"1.0.0"},dependencies:{"@agentclientprotocol/sdk":"^0.12.0","@ai-sdk/anthropic":"^3.0.7","@ai-sdk/azure":"^3.0.5","@ai-sdk/deepseek":"^2.0.4","@ai-sdk/google":"^3.0.4","@ai-sdk/openai-compatible":"^2.0.4","@modelcontextprotocol/sdk":"^1.17.4",ai:"^6.0.39","async-mutex":"^0.5.0",axios:"^1.12.2",chalk:"^5.4.1",diff:"^8.0.2","fast-glob":"^3.3.3","fuse.js":"^7.1.0","gray-matter":"^4.0.3",hono:"^4.7.10","js-tiktoken":"^1.0.21","lodash-es":"^4.17.21","lru-cache":"^11.2.4",nanoid:"^5.1.6",open:"^10.1.2",openai:"^6.2.0",picomatch:"^4.0.3",semver:"^7.7.3",undici:"^7.16.0","write-file-atomic":"^7.0.0",ws:"^8.18.0",yaml:"^2.8.1",zod:"^3.24.2","zod-to-json-schema":"^3.24.6",zustand:"^5.0.9"},devDependencies:{"@biomejs/biome":"^2.2.4","@types/json-schema":"^7.0.15","@types/lodash-es":"^4.17.12","@types/picomatch":"^4.0.2","@types/semver":"^7.7.1","@types/write-file-atomic":"^4.0.3","@types/ws":"^8.5.12","bun-types":"latest",typescript:"^5.9.2"}};function s4(){return A2.version}function o4(){return A2.name}import{spawn as w6}from"child_process";import*as I0 from"crypto";import*as $8 from"http";import{URL as t4}from"url";import{promises as D2}from"fs";import q6 from"os";import b2 from"path";class _2{tokenFilePath;constructor(){let $=q6.homedir(),W=b2.join($,".blade");this.tokenFilePath=b2.join(W,"mcp-oauth-tokens.json")}async ensureConfigDir(){let $=b2.dirname(this.tokenFilePath);try{await D2.mkdir($,{recursive:!0,mode:493})}catch{}}async loadAllCredentials(){let $=new Map;try{let W=await D2.readFile(this.tokenFilePath,"utf-8"),Q=JSON.parse(W);for(let Z of Q)$.set(Z.serverName,Z)}catch(W){if(W.code!=="ENOENT")console.warn("[OAuthTokenStorage] 加载令牌失败:",W)}return $}async saveAllCredentials($){await this.ensureConfigDir();let W=Array.from($.values());await D2.writeFile(this.tokenFilePath,JSON.stringify(W,null,2),{mode:384})}async saveToken($,W,Q,Z){let V=await this.loadAllCredentials(),X={serverName:$,token:W,clientId:Q,tokenUrl:Z,updatedAt:Date.now()};V.set($,X),await this.saveAllCredentials(V)}async getCredentials($){return(await this.loadAllCredentials()).get($)||null}async deleteCredentials($){let W=await this.loadAllCredentials();W.delete($),await this.saveAllCredentials(W)}async listServers(){let $=await this.loadAllCredentials();return Array.from($.keys())}isTokenExpired($){if(!$.expiresAt)return!1;let W=300000;return Date.now()>=$.expiresAt-W}}var k0=7777,L2="/oauth/callback",e4=200;class B1{tokenStorage;constructor($=new _2){this.tokenStorage=$}generatePKCEParams(){let $=I0.randomBytes(32).toString("base64url"),W=I0.createHash("sha256").update($).digest("base64url"),Q=I0.randomBytes(16).toString("base64url");return{codeVerifier:$,codeChallenge:W,state:Q}}buildAuthorizationUrl($,W){let Q=$.redirectUri||`http://localhost:${k0}${L2}`,Z=new URLSearchParams({client_id:$.clientId,response_type:"code",redirect_uri:Q,state:W.state,code_challenge:W.codeChallenge,code_challenge_method:"S256"});if($.scopes&&$.scopes.length>0)Z.append("scope",$.scopes.join(" "));let V=new t4($.authorizationUrl);return Z.forEach((X,Y)=>{V.searchParams.append(Y,X)}),V.toString()}async startCallbackServer($){return new Promise((W,Q)=>{let Z=$8.createServer((V,X)=>{try{let Y=new t4(V.url,`http://localhost:${k0}`);if(Y.pathname!==L2){X.writeHead(404),X.end("Not found");return}let J=Y.searchParams.get("code"),G=Y.searchParams.get("state"),K=Y.searchParams.get("error");if(K){X.writeHead(e4,{"Content-Type":"text/html"}),X.end(`
159
165
  <html>
160
166
  <body>
161
167
  <h1>Authentication Failed</h1>
162
- <p>Error: ${B}</p>
168
+ <p>Error: ${K}</p>
163
169
  <p>You can close this window.</p>
164
170
  </body>
165
171
  </html>
166
- `),Z.close(),Q(Error(`OAuth error: ${B}`));return}if(!J||!G){X.writeHead(400),X.end("Missing code or state parameter");return}if(G!==$){X.writeHead(400),X.end("Invalid state parameter"),Z.close(),Q(Error("State mismatch - possible CSRF attack"));return}X.writeHead(e4,{"Content-Type":"text/html"}),X.end(`
172
+ `),Z.close(),Q(Error(`OAuth error: ${K}`));return}if(!J||!G){X.writeHead(400),X.end("Missing code or state parameter");return}if(G!==$){X.writeHead(400),X.end("Invalid state parameter"),Z.close(),Q(Error("State mismatch - possible CSRF attack"));return}X.writeHead(e4,{"Content-Type":"text/html"}),X.end(`
167
173
  <html>
168
174
  <body>
169
175
  <h1>Authentication Successful!</h1>
@@ -173,7 +179,7 @@ ${K}`,metadata:{serverName:W,toolName:Q.name,mcpResult:G}}}catch(G){return{succe
173
179
  </html>
174
180
  `),Z.close(),W(J)}catch(Y){Z.close(),Q(Y)}});Z.on("error",Q),Z.listen(k0,()=>{console.log(`[OAuth] Callback server listening on port ${k0}`)}),setTimeout(()=>{Z.close(),Q(Error("OAuth callback timeout"))},300000)})}async exchangeCodeForToken($,W,Q){let Z=$.redirectUri||`http://localhost:${k0}${L2}`,V=new URLSearchParams({grant_type:"authorization_code",code:W,redirect_uri:Z,code_verifier:Q,client_id:$.clientId});if($.clientSecret)V.append("client_secret",$.clientSecret);let X=await fetch($.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:V.toString()});if(!X.ok){let Y=await X.text();throw Error(`Token exchange failed: ${X.status} - ${Y}`)}return await X.json()}async refreshAccessToken($,W){let Q=new URLSearchParams({grant_type:"refresh_token",refresh_token:W,client_id:$.clientId});if($.clientSecret)Q.append("client_secret",$.clientSecret);if($.scopes&&$.scopes.length>0)Q.append("scope",$.scopes.join(" "));let Z=await fetch($.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:Q.toString()});if(!Z.ok){let V=await Z.text();throw Error(`Token refresh failed: ${Z.status} - ${V}`)}return await Z.json()}async authenticate($,W){if(!W.clientId||!W.authorizationUrl||!W.tokenUrl)throw Error("Missing required OAuth configuration");let Q=this.generatePKCEParams(),Z=this.buildAuthorizationUrl(W,Q);console.log(`
175
181
  [OAuth] Opening browser for authentication...`),console.log(`
176
- If the browser does not open automatically, copy and paste this URL:`),console.log(Z),console.log("");let V=this.startCallbackServer(Q.state);try{await this.openAuthorizationUrl(Z)}catch(G){console.warn("[OAuth] Failed to open browser automatically:",G)}let X=await V;console.log("[OAuth] Authorization code received, exchanging for tokens...");let Y=await this.exchangeCodeForToken(W,X,Q.codeVerifier),J={accessToken:Y.access_token,tokenType:Y.token_type||"Bearer",refreshToken:Y.refresh_token,scope:Y.scope};if(Y.expires_in)J.expiresAt=Date.now()+Y.expires_in*1000;return await this.tokenStorage.saveToken($,J,W.clientId,W.tokenUrl),console.log("[OAuth] Authentication successful! Token saved."),J}async openAuthorizationUrl($){let{command:W,args:Q}=this.getBrowserCommand($);await new Promise((Z,V)=>{let X=G6(W,Q,{stdio:"ignore"});X.once("error",V),X.once("close",(Y)=>{if(Y===0||Y===null)Z();else V(Error(`Failed to open browser (exit code ${Y})`))})})}getBrowserCommand($){if(process.platform==="darwin")return{command:"open",args:[$]};if(process.platform==="win32")return{command:"cmd",args:["/c","start","",$]};return{command:"xdg-open",args:[$]}}async getValidToken($,W){let Q=await this.tokenStorage.getCredentials($);if(!Q)return null;let{token:Z}=Q;if(!this.tokenStorage.isTokenExpired(Z))return Z.accessToken;if(Z.refreshToken&&W.clientId&&Q.tokenUrl)try{console.log(`[OAuth] Refreshing expired token for server: ${$}`);let V=await this.refreshAccessToken(W,Z.refreshToken),X={accessToken:V.access_token,tokenType:V.token_type,refreshToken:V.refresh_token||Z.refreshToken,scope:V.scope||Z.scope};if(V.expires_in)X.expiresAt=Date.now()+V.expires_in*1000;return await this.tokenStorage.saveToken($,X,W.clientId,Q.tokenUrl),X.accessToken}catch(V){console.error("[OAuth] Failed to refresh token:",V),await this.tokenStorage.deleteCredentials($)}return null}}import{EventEmitter as B6}from"events";var w1;((V)=>{V.DISCONNECTED="disconnected";V.CONNECTING="connecting";V.CONNECTED="connected";V.ERROR="error"})(w1||={});class j2 extends B6{client;config;checkTimer=null;isChecking=!1;consecutiveFailures=0;lastCheckTime=0;currentStatus="healthy";constructor($,W={}){super();this.client=$,this.config={interval:W.interval??30000,timeout:W.timeout??1e4,enabled:W.enabled??!1,failureThreshold:W.failureThreshold??3}}start(){if(this.checkTimer){console.warn("[HealthMonitor] 健康监控已在运行");return}if(!this.config.enabled){console.log("[HealthMonitor] 健康监控未启用");return}console.log(`[HealthMonitor] 启动健康监控(间隔: ${this.config.interval}ms)`),this.scheduleNextCheck()}stop(){if(this.checkTimer)clearTimeout(this.checkTimer),this.checkTimer=null,console.log("[HealthMonitor] 停止健康监控")}scheduleNextCheck(){this.checkTimer=setTimeout(async()=>{await this.performHealthCheck(),this.scheduleNextCheck()},this.config.interval)}async performHealthCheck(){if(this.isChecking)return console.warn("[HealthMonitor] 上一次检查仍在进行中"),this.getLastResult();this.isChecking=!0,this.lastCheckTime=Date.now(),this.setStatus("checking");try{let $=this.client.connectionStatus;if($==="connected"){await this.pingServer(),this.consecutiveFailures=0,this.setStatus("healthy");let W={status:"healthy",timestamp:Date.now(),consecutiveFailures:0};return this.emit("healthCheck",W),W}else throw Error(`连接状态异常: ${$}`)}catch($){this.consecutiveFailures++;let W=$;console.warn(`[HealthMonitor] 健康检查失败(${this.consecutiveFailures}/${this.config.failureThreshold}):`,W.message);let Q;if(this.consecutiveFailures>=this.config.failureThreshold)Q="unhealthy",this.emit("unhealthy",this.consecutiveFailures,W),console.log("[HealthMonitor] 达到失败阈值,触发重连..."),this.triggerReconnection().catch((V)=>{console.error("[HealthMonitor] 重连失败:",V)});else Q="degraded";this.setStatus(Q);let Z={status:Q,timestamp:Date.now(),consecutiveFailures:this.consecutiveFailures,lastError:W};return this.emit("healthCheck",Z),Z}finally{this.isChecking=!1}}async pingServer(){let $=new Promise((Q,Z)=>{setTimeout(()=>Z(Error("Health check timeout")),this.config.timeout)}),W=(async()=>{if(this.client.availableTools.length===0){if(!this.client.server)throw Error("Server info not available")}})();await Promise.race([W,$])}async triggerReconnection(){try{await this.client.disconnect(),await new Promise(($)=>setTimeout($,1000)),await this.client.connect(),console.log("[HealthMonitor] 重连成功"),this.consecutiveFailures=0,this.setStatus("healthy"),this.emit("reconnected")}catch($){throw console.error("[HealthMonitor] 重连失败:",$),$}}setStatus($){if(this.currentStatus!==$){let W=this.currentStatus;this.currentStatus=$,this.emit("statusChanged",$,W)}}getStatus(){return this.currentStatus}getLastResult(){return{status:this.currentStatus,timestamp:this.lastCheckTime,consecutiveFailures:this.consecutiveFailures}}getStatistics(){return{status:this.currentStatus,consecutiveFailures:this.consecutiveFailures,lastCheckTime:this.lastCheckTime,isChecking:this.isChecking,config:this.config}}async checkNow(){return this.performHealthCheck()}resetFailureCount(){if(this.consecutiveFailures=0,this.currentStatus!=="checking")this.setStatus("healthy")}}function W8($){if(!($ instanceof Error))return{type:"unknown",isRetryable:!1,originalError:Error(String($))};let W=$.message.toLowerCase();if(["command not found","no such file","permission denied","invalid configuration","malformed","syntax error"].some((V)=>W.includes(V)))return{type:"config_error",isRetryable:!1,originalError:$};if(W.includes("unauthorized")||W.includes("401")||W.includes("authentication failed"))return{type:"auth_error",isRetryable:!1,originalError:$};if(["timeout","connection refused","network error","temporary","try again","rate limit","too many requests","service unavailable","socket hang up","econnreset","enotfound","econnrefused","etimedout","503","429"].some((V)=>W.includes(V)))return{type:"network_temporary",isRetryable:!0,originalError:$};return{type:"unknown",isRetryable:!0,originalError:$}}class z2 extends O6{config;status="disconnected";sdkClient=null;tools=new Map;serverInfo=null;reconnectAttempts=0;MAX_RECONNECT_ATTEMPTS=5;reconnectTimer=null;isManualDisconnect=!1;oauthProvider=null;serverName;healthMonitor=null;constructor($,W,Q){super();this.config=$;if(this.serverName=W||"default",$.oauth?.enabled)this.oauthProvider=new q1;if(Q?.enabled)this.healthMonitor=new j2(this,Q),this.healthMonitor.on("unhealthy",(Z,V)=>{this.emit("unhealthy",Z,V)}),this.healthMonitor.on("reconnected",()=>{this.emit("healthMonitorReconnected")})}get connectionStatus(){return this.status}get availableTools(){return Array.from(this.tools.values())}get server(){return this.serverInfo}get healthCheck(){return this.healthMonitor}async connect(){return this.connectWithRetry(3,1000)}async connectWithRetry($=3,W=1000){if(this.status!=="disconnected"&&this.status!=="error")throw Error("客户端已连接或正在连接中");if(this.status==="error"){if(this.sdkClient){try{await this.sdkClient.close()}catch{}this.sdkClient=null}this.setStatus("disconnected")}let Q=null;for(let Z=1;Z<=$;Z++)try{await this.doConnect(),this.reconnectAttempts=0;return}catch(V){Q=V;let X=W8(V);if(!X.isRetryable)throw console.error("[McpClient] 检测到永久性错误,放弃重试:",X.type),V;if(Z<$){let Y=W*2**(Z-1);console.warn(`[McpClient] 连接失败(${Z}/${$}),${Y}ms 后重试...`),await new Promise((J)=>setTimeout(J,Y))}}throw Q||Error("连接失败")}async doConnect(){try{this.setStatus("connecting"),this.sdkClient=new K6({name:o4(),version:s4()},{capabilities:{roots:{listChanged:!0},sampling:{}}}),this.sdkClient.onclose=()=>{this.handleUnexpectedClose()};let $=await this.createTransport();await this.sdkClient.connect($);let W=this.sdkClient.getServerVersion();if(this.serverInfo={name:W?.name||"Unknown",version:W?.version||"0.0.0"},await this.loadTools(),this.setStatus("connected"),this.emit("connected",this.serverInfo),this.healthMonitor)this.healthMonitor.start()}catch($){throw this.setStatus("error"),this.emit("error",$),$}}handleUnexpectedClose(){if(this.isManualDisconnect)return;if(this.status==="connected")console.warn("[McpClient] 检测到意外断连,准备重连..."),this.setStatus("error"),this.emit("error",Error("MCP服务器连接意外关闭")),this.scheduleReconnect()}scheduleReconnect(){if(this.reconnectTimer)clearTimeout(this.reconnectTimer),this.reconnectTimer=null;if(this.reconnectAttempts>=this.MAX_RECONNECT_ATTEMPTS){console.error("[McpClient] 达到最大重连次数,放弃重连"),this.emit("reconnectFailed");return}let $=Math.min(1000*2**this.reconnectAttempts,30000);this.reconnectAttempts++,console.log(`[McpClient] 将在 ${$}ms 后进行第 ${this.reconnectAttempts} 次重连...`),this.reconnectTimer=setTimeout(async()=>{try{if(this.sdkClient){try{await this.sdkClient.close()}catch{}this.sdkClient=null}this.setStatus("disconnected"),await this.doConnect(),console.log("[McpClient] 重连成功"),this.reconnectAttempts=0,this.emit("reconnected")}catch(W){if(console.error("[McpClient] 重连失败:",W),W8(W).isRetryable)this.scheduleReconnect();else console.error("[McpClient] 检测到永久性错误,停止重连"),this.emit("reconnectFailed")}},$)}async disconnect(){if(this.isManualDisconnect=!0,this.healthMonitor)this.healthMonitor.stop();if(this.reconnectTimer)clearTimeout(this.reconnectTimer),this.reconnectTimer=null;if(this.sdkClient){try{await this.sdkClient.close()}catch($){console.warn("[McpClient] 断开连接时出错:",$)}this.sdkClient=null}this.tools.clear(),this.serverInfo=null,this.reconnectAttempts=0,this.setStatus("disconnected"),this.emit("disconnected"),this.isManualDisconnect=!1}async callTool($,W={}){if(!this.sdkClient)throw Error("客户端未连接到服务器");if(!this.tools.has($))throw Error(`工具 "${$}" 不存在`);try{return await this.sdkClient.callTool({name:$,arguments:W})}catch(Q){throw console.error(`[McpClient] 调用工具 "${$}" 失败:`,Q),Q}}async createTransport(){let{type:$,command:W,args:Q,env:Z,url:V,headers:X,oauth:Y}=this.config,J={...X};if(Y?.enabled&&this.oauthProvider&&($==="sse"||$==="http"))try{let G=await this.oauthProvider.getValidToken(this.serverName,Y);if(!G){console.log(`[McpClient] 服务器 "${this.serverName}" 需要 OAuth 认证`);let B=await this.oauthProvider.authenticate(this.serverName,Y);J.Authorization=`Bearer ${B.accessToken}`}else J.Authorization=`Bearer ${G}`}catch(G){throw console.error("[McpClient] OAuth 认证失败:",G),Error(`OAuth 认证失败: ${G instanceof Error?G.message:String(G)}`)}if($==="stdio"){if(!W)throw Error("stdio 传输需要 command 参数");let G={};for(let[B,K]of Object.entries(process.env))if(K!==void 0)G[B]=K;return new w6({command:W,args:Q||[],env:{...G,...Z},stderr:"ignore"})}else if($==="sse"){if(!V)throw Error("sse 传输需要 url 参数");return new q6(new URL(V),{requestInit:{headers:J}})}else if($==="http"){if(!V)throw Error("http 传输需要 url 参数");let{StreamableHTTPClientTransport:G}=await import("@modelcontextprotocol/sdk/client/streamableHttp.js");return new G(new URL(V),{requestInit:{headers:J}})}throw Error(`不支持的传输类型: ${$}`)}async loadTools(){if(!this.sdkClient)return;try{let $=await this.sdkClient.listTools();if(this.tools.clear(),$.tools)for(let W of $.tools)this.tools.set(W.name,W);this.emit("toolsUpdated",this.availableTools)}catch($){throw console.error("[McpClient] 加载工具失败:",$),$}}setStatus($){let W=this.status;this.status=$,this.emit("statusChanged",$,W)}async initialize(){return this.connect()}async destroy(){return this.disconnect()}async connectToServer($){return this.connect()}async disconnectFromServer($){return this.disconnect()}async listResources($){if(!this.sdkClient)return[];try{return(await this.sdkClient.listResources()).resources||[]}catch{return[]}}async listTools($){return this.availableTools}async readResource($,W){if(!this.sdkClient)throw Error("客户端未连接");return(await this.sdkClient.readResource({uri:$})).contents?.[0]||{uri:$,text:""}}}class E$ extends U6{static instance=null;servers=new Map;isDiscovering=!1;constructor(){super()}static getInstance(){if(!E$.instance)E$.instance=new E$;return E$.instance}async registerServer($,W){if(this.servers.has($))throw Error(`MCP服务器 "${$}" 已经注册`);let Q=new z2(W,$,W.healthCheck),Z={config:W,client:Q,status:"disconnected",tools:[]};this.setupClientEventHandlers(Q,Z,$),this.servers.set($,Z),this.emit("serverRegistered",$,Z);try{await this.connectServer($)}catch(V){console.warn(`MCP服务器 "${$}" 连接失败:`,V)}}async unregisterServer($){let W=this.servers.get($);if(!W)return;try{await W.client.disconnect()}catch(Q){console.warn(`断开MCP服务器 "${$}" 时出错:`,Q)}this.servers.delete($),this.emit("serverUnregistered",$)}async connectServer($){let W=this.servers.get($);if(!W)throw Error(`MCP服务器 "${$}" 未注册`);if(W.status==="connected")return;try{W.status="connecting",await W.client.connect(),W.connectedAt=new Date,W.lastError=void 0,W.tools=W.client.availableTools}catch(Q){throw W.lastError=Q,W.status="error",Q}}async disconnectServer($){let W=this.servers.get($);if(!W)return;await W.client.disconnect(),W.connectedAt=void 0}async reconnectServer($){let W=this.servers.get($);if(!W)throw Error(`MCP服务器 "${$}" 未注册`);if(W.status==="connected")await W.client.disconnect();try{W.status="connecting",await W.client.connect(),W.connectedAt=new Date,W.lastError=void 0,W.tools=W.client.availableTools}catch(Q){throw W.lastError=Q,W.status="error",Q}}async getAvailableTools(){let $=[],W=new Map;for(let[Q,Z]of this.servers)if(Z.status==="connected")for(let V of Z.tools){let X=W.get(V.name)||0;W.set(V.name,X+1)}for(let[Q,Z]of this.servers)if(Z.status==="connected")for(let V of Z.tools){let Y=(W.get(V.name)||0)>1?`${Q}__${V.name}`:V.name,J=K1(Z.client,Q,V,Y);$.push(J)}return $}async findTool($){for(let[W,Q]of this.servers)if(Q.status==="connected"){let Z=Q.tools.find((V)=>V.name===$);if(Z)return K1(Q.client,W,Z)}return null}getToolsByServer($){let W=this.servers.get($);if(!W||W.status!=="connected")return[];return W.tools.map((Q)=>K1(W.client,$,Q))}getServerStatus($){return this.servers.get($)||null}getAllServers(){return new Map(this.servers)}async refreshAllTools(){let $=[];for(let[W,Q]of this.servers)if(Q.status==="connected")$.push(this.refreshServerTools(W));await Promise.allSettled($)}async refreshServerTools($){let W=this.servers.get($);if(!W||W.status!=="connected")return;try{let Q=W.client.availableTools,Z=W.tools.length;W.tools=Q,this.emit("toolsUpdated",$,Q,Z)}catch(Q){console.warn(`刷新服务器 "${$}" 工具列表失败:`,Q)}}setupClientEventHandlers($,W,Q){$.on("connected",(Z)=>{W.status="connected",W.connectedAt=new Date,W.tools=$.availableTools,this.emit("serverConnected",Q,Z)}),$.on("disconnected",()=>{W.status="disconnected",W.connectedAt=void 0,W.tools=[],this.emit("serverDisconnected",Q)}),$.on("error",(Z)=>{W.status="error",W.lastError=Z,this.emit("serverError",Q,Z)}),$.on("toolsUpdated",(Z)=>{let V=W.tools.length;W.tools=Z,this.emit("toolsUpdated",Q,Z,V)}),$.on("statusChanged",(Z,V)=>{W.status=Z,this.emit("serverStatusChanged",Q,Z,V)})}async discoverServers(){if(this.isDiscovering)return Array.from(this.servers.values());this.isDiscovering=!0,this.emit("discoveryStarted");try{return Array.from(this.servers.values())}finally{this.isDiscovering=!1,this.emit("discoveryCompleted")}}async registerServers($){let W=Object.entries($).map(([Q,Z])=>this.registerServer(Q,Z).catch((V)=>{return console.warn(`注册MCP服务器 "${Q}" 失败:`,V),V}));await Promise.allSettled(W)}getStatistics(){let $=0,W=0,Q=0;for(let Z of this.servers.values())if(Z.status==="connected")$++,W+=Z.tools.length;else if(Z.status==="error")Q++;return{totalServers:this.servers.size,connectedServers:$,errorServers:Q,totalTools:W,isDiscovering:this.isDiscovering}}async disconnectAll(){let $=[];for(let[W,Q]of this.servers)if(Q.status==="connected")$.push(Q.client.disconnect().catch((Z)=>{console.warn(`断开 MCP 服务器 "${W}" 时出错:`,Z)}));await Promise.allSettled($),this.servers.clear()}}import{promises as H8}from"fs";import S6 from"path";import*as F1 from"node:fs/promises";import{homedir as q8}from"node:os";import*as C$ from"node:path";var O1={name:"skill-creator",description:"Create new Skills interactively. Use when the user wants to create a new Skill, define a custom workflow, or add a specialized capability to Blade.",allowedTools:["Read","Write","Glob","Bash","AskUserQuestion"],version:"1.0.0",argumentHint:void 0,userInvocable:!0,disableModelInvocation:!1,model:void 0,whenToUse:"User wants to create a new skill, define a custom workflow, or add a specialized capability.",path:"builtin://skill-creator",basePath:"",source:"builtin"};function Q8(){return{metadata:O1,instructions:`# Skill Creator
182
+ If the browser does not open automatically, copy and paste this URL:`),console.log(Z),console.log("");let V=this.startCallbackServer(Q.state);try{await this.openAuthorizationUrl(Z)}catch(G){console.warn("[OAuth] Failed to open browser automatically:",G)}let X=await V;console.log("[OAuth] Authorization code received, exchanging for tokens...");let Y=await this.exchangeCodeForToken(W,X,Q.codeVerifier),J={accessToken:Y.access_token,tokenType:Y.token_type||"Bearer",refreshToken:Y.refresh_token,scope:Y.scope};if(Y.expires_in)J.expiresAt=Date.now()+Y.expires_in*1000;return await this.tokenStorage.saveToken($,J,W.clientId,W.tokenUrl),console.log("[OAuth] Authentication successful! Token saved."),J}async openAuthorizationUrl($){let{command:W,args:Q}=this.getBrowserCommand($);await new Promise((Z,V)=>{let X=w6(W,Q,{stdio:"ignore"});X.once("error",V),X.once("close",(Y)=>{if(Y===0||Y===null)Z();else V(Error(`Failed to open browser (exit code ${Y})`))})})}getBrowserCommand($){if(process.platform==="darwin")return{command:"open",args:[$]};if(process.platform==="win32")return{command:"cmd",args:["/c","start","",$]};return{command:"xdg-open",args:[$]}}async getValidToken($,W){let Q=await this.tokenStorage.getCredentials($);if(!Q)return null;let{token:Z}=Q;if(!this.tokenStorage.isTokenExpired(Z))return Z.accessToken;if(Z.refreshToken&&W.clientId&&Q.tokenUrl)try{console.log(`[OAuth] Refreshing expired token for server: ${$}`);let V=await this.refreshAccessToken(W,Z.refreshToken),X={accessToken:V.access_token,tokenType:V.token_type,refreshToken:V.refresh_token||Z.refreshToken,scope:V.scope||Z.scope};if(V.expires_in)X.expiresAt=Date.now()+V.expires_in*1000;return await this.tokenStorage.saveToken($,X,W.clientId,Q.tokenUrl),X.accessToken}catch(V){console.error("[OAuth] Failed to refresh token:",V),await this.tokenStorage.deleteCredentials($)}return null}}import{EventEmitter as O6}from"events";var q1;((V)=>{V.DISCONNECTED="disconnected";V.CONNECTING="connecting";V.CONNECTED="connected";V.ERROR="error"})(q1||={});class j2 extends O6{client;config;checkTimer=null;isChecking=!1;consecutiveFailures=0;lastCheckTime=0;currentStatus="healthy";constructor($,W={}){super();this.client=$,this.config={interval:W.interval??30000,timeout:W.timeout??1e4,enabled:W.enabled??!1,failureThreshold:W.failureThreshold??3}}start(){if(this.checkTimer){console.warn("[HealthMonitor] 健康监控已在运行");return}if(!this.config.enabled){console.log("[HealthMonitor] 健康监控未启用");return}console.log(`[HealthMonitor] 启动健康监控(间隔: ${this.config.interval}ms)`),this.scheduleNextCheck()}stop(){if(this.checkTimer)clearTimeout(this.checkTimer),this.checkTimer=null,console.log("[HealthMonitor] 停止健康监控")}scheduleNextCheck(){this.checkTimer=setTimeout(async()=>{await this.performHealthCheck(),this.scheduleNextCheck()},this.config.interval)}async performHealthCheck(){if(this.isChecking)return console.warn("[HealthMonitor] 上一次检查仍在进行中"),this.getLastResult();this.isChecking=!0,this.lastCheckTime=Date.now(),this.setStatus("checking");try{let $=this.client.connectionStatus;if($==="connected"){await this.pingServer(),this.consecutiveFailures=0,this.setStatus("healthy");let W={status:"healthy",timestamp:Date.now(),consecutiveFailures:0};return this.emit("healthCheck",W),W}else throw Error(`连接状态异常: ${$}`)}catch($){this.consecutiveFailures++;let W=$;console.warn(`[HealthMonitor] 健康检查失败(${this.consecutiveFailures}/${this.config.failureThreshold}):`,W.message);let Q;if(this.consecutiveFailures>=this.config.failureThreshold)Q="unhealthy",this.emit("unhealthy",this.consecutiveFailures,W),console.log("[HealthMonitor] 达到失败阈值,触发重连..."),this.triggerReconnection().catch((V)=>{console.error("[HealthMonitor] 重连失败:",V)});else Q="degraded";this.setStatus(Q);let Z={status:Q,timestamp:Date.now(),consecutiveFailures:this.consecutiveFailures,lastError:W};return this.emit("healthCheck",Z),Z}finally{this.isChecking=!1}}async pingServer(){let $=new Promise((Q,Z)=>{setTimeout(()=>Z(Error("Health check timeout")),this.config.timeout)}),W=(async()=>{if(this.client.availableTools.length===0){if(!this.client.server)throw Error("Server info not available")}})();await Promise.race([W,$])}async triggerReconnection(){try{await this.client.disconnect(),await new Promise(($)=>setTimeout($,1000)),await this.client.connect(),console.log("[HealthMonitor] 重连成功"),this.consecutiveFailures=0,this.setStatus("healthy"),this.emit("reconnected")}catch($){throw console.error("[HealthMonitor] 重连失败:",$),$}}setStatus($){if(this.currentStatus!==$){let W=this.currentStatus;this.currentStatus=$,this.emit("statusChanged",$,W)}}getStatus(){return this.currentStatus}getLastResult(){return{status:this.currentStatus,timestamp:this.lastCheckTime,consecutiveFailures:this.consecutiveFailures}}getStatistics(){return{status:this.currentStatus,consecutiveFailures:this.consecutiveFailures,lastCheckTime:this.lastCheckTime,isChecking:this.isChecking,config:this.config}}async checkNow(){return this.performHealthCheck()}resetFailureCount(){if(this.consecutiveFailures=0,this.currentStatus!=="checking")this.setStatus("healthy")}}function W8($){if(!($ instanceof Error))return{type:"unknown",isRetryable:!1,originalError:Error(String($))};let W=$.message.toLowerCase();if(["command not found","no such file","permission denied","invalid configuration","malformed","syntax error"].some((V)=>W.includes(V)))return{type:"config_error",isRetryable:!1,originalError:$};if(W.includes("unauthorized")||W.includes("401")||W.includes("authentication failed"))return{type:"auth_error",isRetryable:!1,originalError:$};if(["timeout","connection refused","network error","temporary","try again","rate limit","too many requests","service unavailable","socket hang up","econnreset","enotfound","econnrefused","etimedout","503","429"].some((V)=>W.includes(V)))return{type:"network_temporary",isRetryable:!0,originalError:$};return{type:"unknown",isRetryable:!0,originalError:$}}class N2 extends A6{config;status="disconnected";sdkClient=null;tools=new Map;serverInfo=null;reconnectAttempts=0;MAX_RECONNECT_ATTEMPTS=5;reconnectTimer=null;isManualDisconnect=!1;oauthProvider=null;serverName;healthMonitor=null;constructor($,W,Q){super();this.config=$;if(this.serverName=W||"default",$.oauth?.enabled)this.oauthProvider=new B1;if(Q?.enabled)this.healthMonitor=new j2(this,Q),this.healthMonitor.on("unhealthy",(Z,V)=>{this.emit("unhealthy",Z,V)}),this.healthMonitor.on("reconnected",()=>{this.emit("healthMonitorReconnected")})}get connectionStatus(){return this.status}get availableTools(){return Array.from(this.tools.values())}get server(){return this.serverInfo}get healthCheck(){return this.healthMonitor}async connect(){return this.connectWithRetry(3,1000)}async connectWithRetry($=3,W=1000){if(this.status!=="disconnected"&&this.status!=="error")throw Error("客户端已连接或正在连接中");if(this.status==="error"){if(this.sdkClient){try{await this.sdkClient.close()}catch{}this.sdkClient=null}this.setStatus("disconnected")}let Q=null;for(let Z=1;Z<=$;Z++)try{await this.doConnect(),this.reconnectAttempts=0;return}catch(V){Q=V;let X=W8(V);if(!X.isRetryable)throw console.error("[McpClient] 检测到永久性错误,放弃重试:",X.type),V;if(Z<$){let Y=W*2**(Z-1);console.warn(`[McpClient] 连接失败(${Z}/${$}),${Y}ms 后重试...`),await new Promise((J)=>setTimeout(J,Y))}}throw Q||Error("连接失败")}async doConnect(){try{this.setStatus("connecting"),this.sdkClient=new U6({name:o4(),version:s4()},{capabilities:{roots:{listChanged:!0},sampling:{}}}),this.sdkClient.onclose=()=>{this.handleUnexpectedClose()};let $=await this.createTransport();await this.sdkClient.connect($);let W=this.sdkClient.getServerVersion();if(this.serverInfo={name:W?.name||"Unknown",version:W?.version||"0.0.0"},await this.loadTools(),this.setStatus("connected"),this.emit("connected",this.serverInfo),this.healthMonitor)this.healthMonitor.start()}catch($){throw this.setStatus("error"),this.emit("error",$),$}}handleUnexpectedClose(){if(this.isManualDisconnect)return;if(this.status==="connected")console.warn("[McpClient] 检测到意外断连,准备重连..."),this.setStatus("error"),this.emit("error",Error("MCP服务器连接意外关闭")),this.scheduleReconnect()}scheduleReconnect(){if(this.reconnectTimer)clearTimeout(this.reconnectTimer),this.reconnectTimer=null;if(this.reconnectAttempts>=this.MAX_RECONNECT_ATTEMPTS){console.error("[McpClient] 达到最大重连次数,放弃重连"),this.emit("reconnectFailed");return}let $=Math.min(1000*2**this.reconnectAttempts,30000);this.reconnectAttempts++,console.log(`[McpClient] 将在 ${$}ms 后进行第 ${this.reconnectAttempts} 次重连...`),this.reconnectTimer=setTimeout(async()=>{try{if(this.sdkClient){try{await this.sdkClient.close()}catch{}this.sdkClient=null}this.setStatus("disconnected"),await this.doConnect(),console.log("[McpClient] 重连成功"),this.reconnectAttempts=0,this.emit("reconnected")}catch(W){if(console.error("[McpClient] 重连失败:",W),W8(W).isRetryable)this.scheduleReconnect();else console.error("[McpClient] 检测到永久性错误,停止重连"),this.emit("reconnectFailed")}},$)}async disconnect(){if(this.isManualDisconnect=!0,this.healthMonitor)this.healthMonitor.stop();if(this.reconnectTimer)clearTimeout(this.reconnectTimer),this.reconnectTimer=null;if(this.sdkClient){try{await this.sdkClient.close()}catch($){console.warn("[McpClient] 断开连接时出错:",$)}this.sdkClient=null}this.tools.clear(),this.serverInfo=null,this.reconnectAttempts=0,this.setStatus("disconnected"),this.emit("disconnected"),this.isManualDisconnect=!1}async callTool($,W={}){if(!this.sdkClient)throw Error("客户端未连接到服务器");if(!this.tools.has($))throw Error(`工具 "${$}" 不存在`);try{return await this.sdkClient.callTool({name:$,arguments:W})}catch(Q){throw console.error(`[McpClient] 调用工具 "${$}" 失败:`,Q),Q}}async createTransport(){let{type:$,command:W,args:Q,env:Z,url:V,headers:X,oauth:Y}=this.config,J={...X};if(Y?.enabled&&this.oauthProvider&&($==="sse"||$==="http"))try{let G=await this.oauthProvider.getValidToken(this.serverName,Y);if(!G){console.log(`[McpClient] 服务器 "${this.serverName}" 需要 OAuth 认证`);let K=await this.oauthProvider.authenticate(this.serverName,Y);J.Authorization=`Bearer ${K.accessToken}`}else J.Authorization=`Bearer ${G}`}catch(G){throw console.error("[McpClient] OAuth 认证失败:",G),Error(`OAuth 认证失败: ${G instanceof Error?G.message:String(G)}`)}if($==="stdio"){if(!W)throw Error("stdio 传输需要 command 参数");let G={};for(let[K,B]of Object.entries(process.env))if(B!==void 0)G[K]=B;return new H6({command:W,args:Q||[],env:{...G,...Z},stderr:"ignore"})}else if($==="sse"){if(!V)throw Error("sse 传输需要 url 参数");return new F6(new URL(V),{requestInit:{headers:J}})}else if($==="http"){if(!V)throw Error("http 传输需要 url 参数");let{StreamableHTTPClientTransport:G}=await import("@modelcontextprotocol/sdk/client/streamableHttp.js");return new G(new URL(V),{requestInit:{headers:J}})}throw Error(`不支持的传输类型: ${$}`)}async loadTools(){if(!this.sdkClient)return;try{let $=await this.sdkClient.listTools();if(this.tools.clear(),$.tools)for(let W of $.tools)this.tools.set(W.name,W);this.emit("toolsUpdated",this.availableTools)}catch($){throw console.error("[McpClient] 加载工具失败:",$),$}}setStatus($){let W=this.status;this.status=$,this.emit("statusChanged",$,W)}async initialize(){return this.connect()}async destroy(){return this.disconnect()}async connectToServer($){return this.connect()}async disconnectFromServer($){return this.disconnect()}async listResources($){if(!this.sdkClient)return[];try{return(await this.sdkClient.listResources()).resources||[]}catch{return[]}}async listTools($){return this.availableTools}async readResource($,W){if(!this.sdkClient)throw Error("客户端未连接");return(await this.sdkClient.readResource({uri:$})).contents?.[0]||{uri:$,text:""}}}class E$ extends D6{static instance=null;servers=new Map;isDiscovering=!1;constructor(){super()}static getInstance(){if(!E$.instance)E$.instance=new E$;return E$.instance}async registerServer($,W){if(this.servers.has($))throw Error(`MCP服务器 "${$}" 已经注册`);let Q=new N2(W,$,W.healthCheck),Z={config:W,client:Q,status:"disconnected",tools:[]};this.setupClientEventHandlers(Q,Z,$),this.servers.set($,Z),this.emit("serverRegistered",$,Z);try{await this.connectServer($)}catch(V){console.warn(`MCP服务器 "${$}" 连接失败:`,V)}}async unregisterServer($){let W=this.servers.get($);if(!W)return;try{await W.client.disconnect()}catch(Q){console.warn(`断开MCP服务器 "${$}" 时出错:`,Q)}this.servers.delete($),this.emit("serverUnregistered",$)}async connectServer($){let W=this.servers.get($);if(!W)throw Error(`MCP服务器 "${$}" 未注册`);if(W.status==="connected")return;try{W.status="connecting",await W.client.connect(),W.connectedAt=new Date,W.lastError=void 0,W.tools=W.client.availableTools}catch(Q){throw W.lastError=Q,W.status="error",Q}}async disconnectServer($){let W=this.servers.get($);if(!W)return;await W.client.disconnect(),W.connectedAt=void 0}async reconnectServer($){let W=this.servers.get($);if(!W)throw Error(`MCP服务器 "${$}" 未注册`);if(W.status==="connected")await W.client.disconnect();try{W.status="connecting",await W.client.connect(),W.connectedAt=new Date,W.lastError=void 0,W.tools=W.client.availableTools}catch(Q){throw W.lastError=Q,W.status="error",Q}}async getAvailableTools(){let $=[],W=new Map;for(let[Q,Z]of this.servers)if(Z.status==="connected")for(let V of Z.tools){let X=W.get(V.name)||0;W.set(V.name,X+1)}for(let[Q,Z]of this.servers)if(Z.status==="connected")for(let V of Z.tools){let Y=(W.get(V.name)||0)>1?`${Q}__${V.name}`:V.name,J=K1(Z.client,Q,V,Y);$.push(J)}return $}async findTool($){for(let[W,Q]of this.servers)if(Q.status==="connected"){let Z=Q.tools.find((V)=>V.name===$);if(Z)return K1(Q.client,W,Z)}return null}getToolsByServer($){let W=this.servers.get($);if(!W||W.status!=="connected")return[];return W.tools.map((Q)=>K1(W.client,$,Q))}getServerStatus($){return this.servers.get($)||null}getAllServers(){return new Map(this.servers)}async refreshAllTools(){let $=[];for(let[W,Q]of this.servers)if(Q.status==="connected")$.push(this.refreshServerTools(W));await Promise.allSettled($)}async refreshServerTools($){let W=this.servers.get($);if(!W||W.status!=="connected")return;try{let Q=W.client.availableTools,Z=W.tools.length;W.tools=Q,this.emit("toolsUpdated",$,Q,Z)}catch(Q){console.warn(`刷新服务器 "${$}" 工具列表失败:`,Q)}}setupClientEventHandlers($,W,Q){$.on("connected",(Z)=>{W.status="connected",W.connectedAt=new Date,W.tools=$.availableTools,this.emit("serverConnected",Q,Z)}),$.on("disconnected",()=>{W.status="disconnected",W.connectedAt=void 0,W.tools=[],this.emit("serverDisconnected",Q)}),$.on("error",(Z)=>{W.status="error",W.lastError=Z,this.emit("serverError",Q,Z)}),$.on("toolsUpdated",(Z)=>{let V=W.tools.length;W.tools=Z,this.emit("toolsUpdated",Q,Z,V)}),$.on("statusChanged",(Z,V)=>{W.status=Z,this.emit("serverStatusChanged",Q,Z,V)})}async discoverServers(){if(this.isDiscovering)return Array.from(this.servers.values());this.isDiscovering=!0,this.emit("discoveryStarted");try{return Array.from(this.servers.values())}finally{this.isDiscovering=!1,this.emit("discoveryCompleted")}}async registerServers($){let W=Object.entries($).map(([Q,Z])=>this.registerServer(Q,Z).catch((V)=>{return console.warn(`注册MCP服务器 "${Q}" 失败:`,V),V}));await Promise.allSettled(W)}getStatistics(){let $=0,W=0,Q=0;for(let Z of this.servers.values())if(Z.status==="connected")$++,W+=Z.tools.length;else if(Z.status==="error")Q++;return{totalServers:this.servers.size,connectedServers:$,errorServers:Q,totalTools:W,isDiscovering:this.isDiscovering}}async disconnectAll(){let $=[];for(let[W,Q]of this.servers)if(Q.status==="connected")$.push(Q.client.disconnect().catch((Z)=>{console.warn(`断开 MCP 服务器 "${W}" 时出错:`,Z)}));await Promise.allSettled($),this.servers.clear()}}import{promises as F8}from"fs";import P6 from"path";import*as H1 from"node:fs/promises";import{homedir as q8}from"node:os";import*as C$ from"node:path";var w1={name:"skill-creator",description:"Create new Skills interactively. Use when the user wants to create a new Skill, define a custom workflow, or add a specialized capability to Blade.",allowedTools:["Read","Write","Glob","Bash","AskUserQuestion"],version:"1.0.0",argumentHint:void 0,userInvocable:!0,disableModelInvocation:!1,model:void 0,whenToUse:"User wants to create a new skill, define a custom workflow, or add a specialized capability.",path:"builtin://skill-creator",basePath:"",source:"builtin"};function Q8(){return{metadata:w1,instructions:`# Skill Creator
177
183
 
178
184
  帮助用户创建新的 Blade Skills。
179
185
 
@@ -356,10 +362,10 @@ user-invocable: true
356
362
  <footer>
357
363
  \`\`\`
358
364
  \`\`\`
359
- `}}import{exec as H6}from"node:child_process";import*as S from"node:fs/promises";import{homedir as b6}from"node:os";import*as c from"node:path";import{promisify as F6}from"node:util";var U1=F6(H6),g=M("General"),N2={url:"https://github.com/anthropics/skills.git",branch:"main",defaultSkills:["skill-creator"]};class Z8{skillsDir;constructor($){this.skillsDir=$||c.join(b6(),".blade","skills")}async isInstalled($){let W=c.join(this.skillsDir,$,"SKILL.md");try{return await S.access(W),!0}catch{return!1}}async isGitAvailable(){try{return await U1("git --version"),!0}catch{return!1}}async installOfficialSkill($){let{url:W,branch:Q}=N2,Z=c.join(this.skillsDir,$),V=c.join(this.skillsDir,`.tmp-${$}-${Date.now()}`);try{if(!await this.isGitAvailable())return g.warn("Git not available, skipping skill installation"),!1;g.info(`Installing official skill: ${$}...`),await S.mkdir(this.skillsDir,{recursive:!0,mode:493}),await U1(`git clone --depth 1 --branch ${Q} --single-branch ${W} "${V}"`,{timeout:30000});let X=c.join(V,"skills",$);try{await S.access(X)}catch{return g.warn(`Skill ${$} not found in official repository`),await S.rm(V,{recursive:!0,force:!0}),!1}try{await S.rm(Z,{recursive:!0,force:!0})}catch{}return await S.cp(X,Z,{recursive:!0}),await S.rm(V,{recursive:!0,force:!0}),g.info(`Successfully installed: ${$}`),!0}catch(X){try{await S.rm(V,{recursive:!0,force:!0})}catch{}return g.warn(`Failed to install ${$}: ${X instanceof Error?X.message:"Unknown error"}`),!1}}async ensureDefaultSkillsInstalled(){await S.mkdir(this.skillsDir,{recursive:!0,mode:493});for(let $ of N2.defaultSkills)if(!await this.isInstalled($))await this.installOfficialSkill($)}async installFromRepo($,W){let Q=W||this.extractRepoName($),Z=c.join(this.skillsDir,Q),V=c.join(this.skillsDir,`.tmp-repo-${Q}-${Date.now()}`);try{if(!await this.isGitAvailable())return g.warn("Git not available, cannot install from repo"),!1;g.info(`Installing skill from repo: ${$}...`),await S.mkdir(this.skillsDir,{recursive:!0,mode:493}),await U1(`git clone --depth 1 "${$}" "${V}"`,{timeout:60000});let X=c.join(V,"SKILL.md");try{await S.access(X)}catch{return g.warn(`No SKILL.md found in repository ${$}`),await S.rm(V,{recursive:!0,force:!0}),!1}await S.rm(Z,{recursive:!0,force:!0}),await S.rename(V,Z);try{await S.rm(c.join(Z,".git"),{recursive:!0,force:!0})}catch{}return g.info(`Successfully installed skill from repo: ${Q}`),!0}catch(X){try{await S.rm(V,{recursive:!0,force:!0})}catch{}return g.warn(`Failed to install from repo ${$}: ${X instanceof Error?X.message:"Unknown error"}`),!1}}async installFromLocal($,W,Q=!0){let Z=W||c.basename($),V=c.join(this.skillsDir,Z);try{let X=c.resolve($);try{await S.access(X)}catch{return g.warn(`Local path does not exist: ${X}`),!1}let Y=c.join(X,"SKILL.md");try{await S.access(Y)}catch{return g.warn(`No SKILL.md found in local path: ${X}`),!1}if(g.info(`Installing skill from local path: ${X}...`),await S.mkdir(this.skillsDir,{recursive:!0,mode:493}),await S.rm(V,{recursive:!0,force:!0}),Q)await S.symlink(X,V,"dir"),g.info(`Created symlink for skill: ${Z}`);else await S.cp(X,V,{recursive:!0}),g.info(`Copied skill to: ${Z}`);return!0}catch(X){return g.warn(`Failed to install from local path ${$}: ${X instanceof Error?X.message:"Unknown error"}`),!1}}extractRepoName($){return $.match(/\/([^/]+?)(\.git)?$/)?.[1]||"unknown-skill"}async installAllOfficialSkills(){let{url:$,branch:W}=N2,Q=c.join(this.skillsDir,`.tmp-all-${Date.now()}`),Z=[],V=[];try{if(!await this.isGitAvailable())return g.warn("Git not available, skipping skill installation"),{installed:Z,failed:V};await S.mkdir(this.skillsDir,{recursive:!0,mode:493}),g.info("Cloning official skills repository..."),await U1(`git clone --depth 1 --branch ${W} --single-branch ${$} "${Q}"`,{timeout:60000});let X=c.join(Q,"skills"),Y=await S.readdir(X,{withFileTypes:!0});for(let J of Y){if(!J.isDirectory())continue;let G=J.name,B=c.join(X,G),K=c.join(this.skillsDir,G);try{await S.access(c.join(B,"SKILL.md")),await S.rm(K,{recursive:!0,force:!0}),await S.cp(B,K,{recursive:!0}),g.info(`Installed: ${G}`),Z.push(G)}catch(q){g.warn(`Failed to install ${G}`),V.push(G)}}await S.rm(Q,{recursive:!0,force:!0})}catch(X){try{await S.rm(Q,{recursive:!0,force:!0})}catch{}g.warn(`Failed to install skills: ${X instanceof Error?X.message:"Unknown error"}`)}return{installed:Z,failed:V}}}var R2=null;function V8($){if(!R2)R2=new Z8($);return R2}import*as f0 from"node:fs/promises";import*as H1 from"node:path";import{parse as A6}from"yaml";var D6=/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/,_6=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]?$/,X8=1024;function L6($){if(!$)return;if(typeof $==="string")return $.split(",").map((W)=>W.trim()).filter(Boolean);if(Array.isArray($))return $.map((W)=>String(W).trim()).filter(Boolean);return}function Y8($){if($===void 0)return;if(typeof $==="boolean")return $;if(typeof $==="string"){let W=$.toLowerCase().trim();if(W==="true"||W==="yes"||W==="1")return!0;if(W==="false"||W==="no"||W==="0")return!1}return}function j6($,W){if(!$.name)return{valid:!1,error:"Missing required field: name"};if(!_6.test($.name))return{valid:!1,error:`Invalid name "${$.name}": must be lowercase letters, numbers, and hyphens only, 1-64 characters`};if(!$.description)return{valid:!1,error:"Missing required field: description"};if($.description.length>X8)return{valid:!1,error:`Description too long: ${$.description.length} characters (max ${X8})`};let Q;if($.model)Q=$.model==="inherit"?"inherit":$.model;return{valid:!0,metadata:{name:$.name,description:$.description.trim(),allowedTools:L6($["allowed-tools"]),version:$.version,argumentHint:$["argument-hint"]?.trim(),userInvocable:Y8($["user-invocable"]),disableModelInvocation:Y8($["disable-model-invocation"]),model:Q,whenToUse:$.when_to_use?.trim()}}}function J8($,W,Q){let Z=$.match(D6);if(!Z)return{success:!1,error:"Invalid SKILL.md format: missing YAML frontmatter (must start with ---)"};let[,V,X]=Z,Y;try{Y=A6(V)}catch(B){return{success:!1,error:`Failed to parse YAML frontmatter: ${B instanceof Error?B.message:String(B)}`}}let J=j6(Y,W);if(!J.valid)return{success:!1,error:J.error};let G=H1.dirname(W);return{success:!0,content:{metadata:{...J.metadata,path:W,basePath:G,source:Q},instructions:X.trim()}}}async function G8($,W){try{let Q=await f0.readFile($,"utf-8");return J8(Q,$,W)}catch(Q){if(Q.code==="ENOENT")return{success:!1,error:`File not found: ${$}`};return{success:!1,error:`Failed to read file: ${Q instanceof Error?Q.message:String(Q)}`}}}async function B8($){try{let W=await f0.readFile($.path,"utf-8"),Q=J8(W,$.path,$.source);return Q.success?Q.content:null}catch{return null}}async function K8($){try{return await f0.access(H1.join($,"SKILL.md")),!0}catch{return!1}}var z6={userSkillsDir:C$.join(q8(),".blade","skills"),projectSkillsDir:".blade/skills",claudeUserSkillsDir:C$.join(q8(),".claude","skills"),claudeProjectSkillsDir:".claude/skills",cwd:process.cwd()},b1=null;class E2{skills=new Map;pluginSkills=new Map;config;initialized=!1;constructor($){this.config={...z6,...$}}static getInstance($){if(!b1)b1=new E2($);return b1}static resetInstance(){b1=null}async initialize(){if(this.initialized)return{skills:Array.from(this.skills.values()),errors:[]};let $=[],W=[];try{await V8(this.config.userSkillsDir).ensureDefaultSkillsInstalled()}catch(G){$.push({path:"SkillInstaller",error:`Failed to install default skills: ${G instanceof Error?G.message:"Unknown error"}`})}this.loadBuiltinSkills();let Q=await this.scanDirectory(this.config.claudeUserSkillsDir,"user");W.push(...Q.skills),$.push(...Q.errors);let Z=await this.scanDirectory(this.config.userSkillsDir,"user");W.push(...Z.skills),$.push(...Z.errors);let V=C$.isAbsolute(this.config.claudeProjectSkillsDir)?this.config.claudeProjectSkillsDir:C$.join(this.config.cwd,this.config.claudeProjectSkillsDir),X=await this.scanDirectory(V,"project");W.push(...X.skills),$.push(...X.errors);let Y=C$.isAbsolute(this.config.projectSkillsDir)?this.config.projectSkillsDir:C$.join(this.config.cwd,this.config.projectSkillsDir),J=await this.scanDirectory(Y,"project");W.push(...J.skills),$.push(...J.errors);for(let G of W)this.skills.set(G.name,G);return this.initialized=!0,{skills:Array.from(this.skills.values()),errors:$}}loadBuiltinSkills(){this.skills.set(O1.name,O1)}async scanDirectory($,W){let Q=[],Z=[];try{await F1.access($)}catch{return{skills:Q,errors:Z}}try{let V=await F1.readdir($,{withFileTypes:!0});for(let X of V){if(!X.isDirectory())continue;let Y=C$.join($,X.name),J=C$.join(Y,"SKILL.md");if(!await K8(Y))continue;let G=await G8(J,W);if(G.success&&G.content)Q.push(G.content.metadata);else Z.push({path:J,error:G.error||"Unknown error"})}}catch(V){Z.push({path:$,error:`Failed to scan directory: ${V instanceof Error?V.message:String(V)}`})}return{skills:Q,errors:Z}}getAll(){return Array.from(this.skills.values())}get($){return this.skills.get($)}has($){return this.skills.has($)}async loadContent($){let W=this.skills.get($);if(!W)return null;if(W.source==="builtin")return this.loadBuiltinContent($);return B8(W)}loadBuiltinContent($){switch($){case"skill-creator":return Q8();default:return null}}getModelInvocableSkills(){return Array.from(this.skills.values()).filter(($)=>!$.disableModelInvocation)}getUserInvocableSkills(){return Array.from(this.skills.values()).filter(($)=>$.userInvocable===!0)}generateAvailableSkillsList(){let $=this.getModelInvocableSkills();if($.length===0)return"";let W=[];for(let Q of $){let Z=Q.description.length>100?`${Q.description.substring(0,97)}...`:Q.description,V=Q.argumentHint?`${Q.name} ${Q.argumentHint}`:Q.name;W.push(`- ${V}: ${Z}`)}return W.join(`
360
- `)}get size(){return this.skills.size}async refresh(){return this.skills.clear(),this.pluginSkills.clear(),this.initialized=!1,this.initialize()}registerPluginSkill($){this.pluginSkills.set($.namespacedName,$),this.skills.set($.namespacedName,$.metadata)}findPluginSkill($){let W=this.pluginSkills.get($);if(W)return W;let Q=[];for(let Z of this.pluginSkills.values())if(Z.originalName===$)Q.push(Z);if(Q.length===1)return Q[0];return}getAllPluginSkills(){return Array.from(this.pluginSkills.values())}clearPluginSkills(){for(let $ of this.pluginSkills.values())this.skills.delete($.namespacedName);this.pluginSkills.clear()}getPluginSkillCount(){return this.pluginSkills.size}}function m$($){return E2.getInstance($)}async function A1($){return m$($).initialize()}var N6="Skill",R6=/<available_skills>\s*<\/available_skills>/;function D1($){let Q=m$().generateAvailableSkillsList();if(!Q)return $;return $.map((Z)=>{if(Z.name!==N6)return Z;let V=Z.description.replace(R6,`<available_skills>
365
+ `}}import{exec as b6}from"node:child_process";import*as S from"node:fs/promises";import{homedir as _6}from"node:os";import*as c from"node:path";import{promisify as L6}from"node:util";var O1=L6(b6),g=M("General"),z2={url:"https://github.com/anthropics/skills.git",branch:"main",defaultSkills:["skill-creator"]};class Z8{skillsDir;constructor($){this.skillsDir=$||c.join(_6(),".blade","skills")}async isInstalled($){let W=c.join(this.skillsDir,$,"SKILL.md");try{return await S.access(W),!0}catch{return!1}}async isGitAvailable(){try{return await O1("git --version"),!0}catch{return!1}}async installOfficialSkill($){let{url:W,branch:Q}=z2,Z=c.join(this.skillsDir,$),V=c.join(this.skillsDir,`.tmp-${$}-${Date.now()}`);try{if(!await this.isGitAvailable())return g.warn("Git not available, skipping skill installation"),!1;g.info(`Installing official skill: ${$}...`),await S.mkdir(this.skillsDir,{recursive:!0,mode:493}),await O1(`git clone --depth 1 --branch ${Q} --single-branch ${W} "${V}"`,{timeout:30000});let X=c.join(V,"skills",$);try{await S.access(X)}catch{return g.warn(`Skill ${$} not found in official repository`),await S.rm(V,{recursive:!0,force:!0}),!1}try{await S.rm(Z,{recursive:!0,force:!0})}catch{}return await S.cp(X,Z,{recursive:!0}),await S.rm(V,{recursive:!0,force:!0}),g.info(`Successfully installed: ${$}`),!0}catch(X){try{await S.rm(V,{recursive:!0,force:!0})}catch{}return g.warn(`Failed to install ${$}: ${X instanceof Error?X.message:"Unknown error"}`),!1}}async ensureDefaultSkillsInstalled(){await S.mkdir(this.skillsDir,{recursive:!0,mode:493});for(let $ of z2.defaultSkills)if(!await this.isInstalled($))await this.installOfficialSkill($)}async installFromRepo($,W){let Q=W||this.extractRepoName($),Z=c.join(this.skillsDir,Q),V=c.join(this.skillsDir,`.tmp-repo-${Q}-${Date.now()}`);try{if(!await this.isGitAvailable())return g.warn("Git not available, cannot install from repo"),!1;g.info(`Installing skill from repo: ${$}...`),await S.mkdir(this.skillsDir,{recursive:!0,mode:493}),await O1(`git clone --depth 1 "${$}" "${V}"`,{timeout:60000});let X=c.join(V,"SKILL.md");try{await S.access(X)}catch{return g.warn(`No SKILL.md found in repository ${$}`),await S.rm(V,{recursive:!0,force:!0}),!1}await S.rm(Z,{recursive:!0,force:!0}),await S.rename(V,Z);try{await S.rm(c.join(Z,".git"),{recursive:!0,force:!0})}catch{}return g.info(`Successfully installed skill from repo: ${Q}`),!0}catch(X){try{await S.rm(V,{recursive:!0,force:!0})}catch{}return g.warn(`Failed to install from repo ${$}: ${X instanceof Error?X.message:"Unknown error"}`),!1}}async installFromLocal($,W,Q=!0){let Z=W||c.basename($),V=c.join(this.skillsDir,Z);try{let X=c.resolve($);try{await S.access(X)}catch{return g.warn(`Local path does not exist: ${X}`),!1}let Y=c.join(X,"SKILL.md");try{await S.access(Y)}catch{return g.warn(`No SKILL.md found in local path: ${X}`),!1}if(g.info(`Installing skill from local path: ${X}...`),await S.mkdir(this.skillsDir,{recursive:!0,mode:493}),await S.rm(V,{recursive:!0,force:!0}),Q)await S.symlink(X,V,"dir"),g.info(`Created symlink for skill: ${Z}`);else await S.cp(X,V,{recursive:!0}),g.info(`Copied skill to: ${Z}`);return!0}catch(X){return g.warn(`Failed to install from local path ${$}: ${X instanceof Error?X.message:"Unknown error"}`),!1}}extractRepoName($){return $.match(/\/([^/]+?)(\.git)?$/)?.[1]||"unknown-skill"}async installAllOfficialSkills(){let{url:$,branch:W}=z2,Q=c.join(this.skillsDir,`.tmp-all-${Date.now()}`),Z=[],V=[];try{if(!await this.isGitAvailable())return g.warn("Git not available, skipping skill installation"),{installed:Z,failed:V};await S.mkdir(this.skillsDir,{recursive:!0,mode:493}),g.info("Cloning official skills repository..."),await O1(`git clone --depth 1 --branch ${W} --single-branch ${$} "${Q}"`,{timeout:60000});let X=c.join(Q,"skills"),Y=await S.readdir(X,{withFileTypes:!0});for(let J of Y){if(!J.isDirectory())continue;let G=J.name,K=c.join(X,G),B=c.join(this.skillsDir,G);try{await S.access(c.join(K,"SKILL.md")),await S.rm(B,{recursive:!0,force:!0}),await S.cp(K,B,{recursive:!0}),g.info(`Installed: ${G}`),Z.push(G)}catch(q){g.warn(`Failed to install ${G}`),V.push(G)}}await S.rm(Q,{recursive:!0,force:!0})}catch(X){try{await S.rm(Q,{recursive:!0,force:!0})}catch{}g.warn(`Failed to install skills: ${X instanceof Error?X.message:"Unknown error"}`)}return{installed:Z,failed:V}}}var R2=null;function V8($){if(!R2)R2=new Z8($);return R2}import*as f0 from"node:fs/promises";import*as U1 from"node:path";import{parse as j6}from"yaml";var N6=/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/,z6=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]?$/,X8=1024;function R6($){if(!$)return;if(typeof $==="string")return $.split(",").map((W)=>W.trim()).filter(Boolean);if(Array.isArray($))return $.map((W)=>String(W).trim()).filter(Boolean);return}function Y8($){if($===void 0)return;if(typeof $==="boolean")return $;if(typeof $==="string"){let W=$.toLowerCase().trim();if(W==="true"||W==="yes"||W==="1")return!0;if(W==="false"||W==="no"||W==="0")return!1}return}function E6($,W){if(!$.name)return{valid:!1,error:"Missing required field: name"};if(!z6.test($.name))return{valid:!1,error:`Invalid name "${$.name}": must be lowercase letters, numbers, and hyphens only, 1-64 characters`};if(!$.description)return{valid:!1,error:"Missing required field: description"};if($.description.length>X8)return{valid:!1,error:`Description too long: ${$.description.length} characters (max ${X8})`};let Q;if($.model)Q=$.model==="inherit"?"inherit":$.model;return{valid:!0,metadata:{name:$.name,description:$.description.trim(),allowedTools:R6($["allowed-tools"]),version:$.version,argumentHint:$["argument-hint"]?.trim(),userInvocable:Y8($["user-invocable"]),disableModelInvocation:Y8($["disable-model-invocation"]),model:Q,whenToUse:$.when_to_use?.trim()}}}function J8($,W,Q){let Z=$.match(N6);if(!Z)return{success:!1,error:"Invalid SKILL.md format: missing YAML frontmatter (must start with ---)"};let[,V,X]=Z,Y;try{Y=j6(V)}catch(K){return{success:!1,error:`Failed to parse YAML frontmatter: ${K instanceof Error?K.message:String(K)}`}}let J=E6(Y,W);if(!J.valid)return{success:!1,error:J.error};let G=U1.dirname(W);return{success:!0,content:{metadata:{...J.metadata,path:W,basePath:G,source:Q},instructions:X.trim()}}}async function G8($,W){try{let Q=await f0.readFile($,"utf-8");return J8(Q,$,W)}catch(Q){if(Q.code==="ENOENT")return{success:!1,error:`File not found: ${$}`};return{success:!1,error:`Failed to read file: ${Q instanceof Error?Q.message:String(Q)}`}}}async function K8($){try{let W=await f0.readFile($.path,"utf-8"),Q=J8(W,$.path,$.source);return Q.success?Q.content:null}catch{return null}}async function B8($){try{return await f0.access(U1.join($,"SKILL.md")),!0}catch{return!1}}var C6={userSkillsDir:C$.join(q8(),".blade","skills"),projectSkillsDir:".blade/skills",claudeUserSkillsDir:C$.join(q8(),".claude","skills"),claudeProjectSkillsDir:".claude/skills",cwd:process.cwd()},F1=null;class E2{skills=new Map;pluginSkills=new Map;config;initialized=!1;constructor($){this.config={...C6,...$}}static getInstance($){if(!F1)F1=new E2($);return F1}static resetInstance(){F1=null}async initialize(){if(this.initialized)return{skills:Array.from(this.skills.values()),errors:[]};let $=[],W=[];try{await V8(this.config.userSkillsDir).ensureDefaultSkillsInstalled()}catch(G){$.push({path:"SkillInstaller",error:`Failed to install default skills: ${G instanceof Error?G.message:"Unknown error"}`})}this.loadBuiltinSkills();let Q=await this.scanDirectory(this.config.claudeUserSkillsDir,"user");W.push(...Q.skills),$.push(...Q.errors);let Z=await this.scanDirectory(this.config.userSkillsDir,"user");W.push(...Z.skills),$.push(...Z.errors);let V=C$.isAbsolute(this.config.claudeProjectSkillsDir)?this.config.claudeProjectSkillsDir:C$.join(this.config.cwd,this.config.claudeProjectSkillsDir),X=await this.scanDirectory(V,"project");W.push(...X.skills),$.push(...X.errors);let Y=C$.isAbsolute(this.config.projectSkillsDir)?this.config.projectSkillsDir:C$.join(this.config.cwd,this.config.projectSkillsDir),J=await this.scanDirectory(Y,"project");W.push(...J.skills),$.push(...J.errors);for(let G of W)this.skills.set(G.name,G);return this.initialized=!0,{skills:Array.from(this.skills.values()),errors:$}}loadBuiltinSkills(){this.skills.set(w1.name,w1)}async scanDirectory($,W){let Q=[],Z=[];try{await H1.access($)}catch{return{skills:Q,errors:Z}}try{let V=await H1.readdir($,{withFileTypes:!0});for(let X of V){if(!X.isDirectory())continue;let Y=C$.join($,X.name),J=C$.join(Y,"SKILL.md");if(!await B8(Y))continue;let G=await G8(J,W);if(G.success&&G.content)Q.push(G.content.metadata);else Z.push({path:J,error:G.error||"Unknown error"})}}catch(V){Z.push({path:$,error:`Failed to scan directory: ${V instanceof Error?V.message:String(V)}`})}return{skills:Q,errors:Z}}getAll(){return Array.from(this.skills.values())}get($){return this.skills.get($)}has($){return this.skills.has($)}async loadContent($){let W=this.skills.get($);if(!W)return null;if(W.source==="builtin")return this.loadBuiltinContent($);return K8(W)}loadBuiltinContent($){switch($){case"skill-creator":return Q8();default:return null}}getModelInvocableSkills(){return Array.from(this.skills.values()).filter(($)=>!$.disableModelInvocation)}getUserInvocableSkills(){return Array.from(this.skills.values()).filter(($)=>$.userInvocable===!0)}generateAvailableSkillsList(){let $=this.getModelInvocableSkills();if($.length===0)return"";let W=[];for(let Q of $){let Z=Q.description.length>100?`${Q.description.substring(0,97)}...`:Q.description,V=Q.argumentHint?`${Q.name} ${Q.argumentHint}`:Q.name;W.push(`- ${V}: ${Z}`)}return W.join(`
366
+ `)}get size(){return this.skills.size}async refresh(){return this.skills.clear(),this.pluginSkills.clear(),this.initialized=!1,this.initialize()}registerPluginSkill($){this.pluginSkills.set($.namespacedName,$),this.skills.set($.namespacedName,$.metadata)}findPluginSkill($){let W=this.pluginSkills.get($);if(W)return W;let Q=[];for(let Z of this.pluginSkills.values())if(Z.originalName===$)Q.push(Z);if(Q.length===1)return Q[0];return}getAllPluginSkills(){return Array.from(this.pluginSkills.values())}clearPluginSkills(){for(let $ of this.pluginSkills.values())this.skills.delete($.namespacedName);this.pluginSkills.clear()}getPluginSkillCount(){return this.pluginSkills.size}}function d$($){return E2.getInstance($)}async function A1($){return d$($).initialize()}var M6="Skill",S6=/<available_skills>\s*<\/available_skills>/;function D1($){let Q=d$().generateAvailableSkillsList();if(!Q)return $;return $.map((Z)=>{if(Z.name!==M6)return Z;let V=Z.description.replace(S6,`<available_skills>
361
367
  ${Q}
362
- </available_skills>`);if(V===Z.description)return Z;return{...Z,description:V}})}import{execSync as E6}from"child_process";import*as U0 from"os";import*as O0 from"path";function C6(){let $=process.cwd(),W=M6($);return{workingDirectory:$,projectRoot:W,platform:`${U0.platform()} (${U0.arch()})`,nodeVersion:process.version,currentDate:new Date().toISOString().split("T")[0],homeDirectory:U0.homedir()}}function _1(){let $=C6();return`# Environment Context
368
+ </available_skills>`);if(V===Z.description)return Z;return{...Z,description:V}})}import{execSync as v6}from"child_process";import*as U0 from"os";import*as O0 from"path";function y6(){let $=process.cwd(),W=T6($);return{workingDirectory:$,projectRoot:W,platform:`${U0.platform()} (${U0.arch()})`,nodeVersion:process.version,currentDate:new Date().toISOString().split("T")[0],homeDirectory:U0.homedir()}}function b1(){let $=y6();return`# Environment Context
363
369
 
364
370
  ## Working Directory
365
371
  **Current**: \`${$.workingDirectory}\`
@@ -377,7 +383,7 @@ When using file tools (read, write, edit), provide **absolute paths**:
377
383
  - ❌ Incorrect: \`/package.json\` (root directory)
378
384
  - ❌ Incorrect: \`package.json\` (relative path without context)
379
385
 
380
- **Always use** \`${$.workingDirectory}/\` as the base for file paths.`}function M6($){let W=$;while(W!==O0.dirname(W)){if(w8(O0.join(W,".git")))return W;if(w8(O0.join(W,"package.json")))return W;W=O0.dirname(W)}return $}function w8($){try{return E6(`test -e "${$}"`,{stdio:"ignore"}),!0}catch{return!1}}var O8=`You are Blade Code, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
386
+ **Always use** \`${$.workingDirectory}/\` as the base for file paths.`}function T6($){let W=$;while(W!==O0.dirname(W)){if(w8(O0.join(W,".git")))return W;if(w8(O0.join(W,"package.json")))return W;W=O0.dirname(W)}return $}function w8($){try{return v6(`test -e "${$}"`,{stdio:"ignore"}),!0}catch{return!1}}var O8=`You are Blade Code, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
381
387
 
382
388
  IMPORTANT: Assist with authorized security testing, defensive security, CTF challenges, and educational contexts. Refuse requests for destructive techniques, DoS attacks, mass targeting, supply chain compromise, or detection evasion for malicious purposes. Dual-use security tools (C2 frameworks, credential testing, exploit development) require clear authorization context: pentesting engagements, CTF competitions, security research, or defensive use cases.
383
389
  IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files.
@@ -577,69 +583,69 @@ Your plan should include:
577
583
  5. **Risks** - Potential issues and mitigations
578
584
  `;function x0($){return`<system-reminder>Plan mode is active. You MUST NOT make any file changes or run non-readonly tools. Research only, then call ExitPlanMode with your plan.</system-reminder>
579
585
 
580
- `+$}var v6=/<available_skills>\s*<\/available_skills>/;async function h0($={}){let{projectPath:W,replaceDefault:Q,append:Z,mode:V,includeEnvironment:X=!0,language:Y}=$,J=[],G=[];if(X){let O=_1();if(O)J.push(O),G.push({name:"environment",loaded:!0,length:O.length})}let B=V==="plan",K,q;if(B)K=U8,q="plan_mode_prompt";else K=Q??O8,q=Q?"replace_default":"default";if(J.push(K),G.push({name:q,loaded:!0,length:K.length}),W){let O=await k6(W);if(O)J.push(O),G.push({name:"blade_md",loaded:!0,length:O.length});else G.push({name:"blade_md",loaded:!1})}if(Z?.trim())J.push(Z.trim()),G.push({name:"append",loaded:!0,length:Z.trim().length});let w=J.join(`
586
+ `+$}var k6=/<available_skills>\s*<\/available_skills>/;async function h0($={}){let{projectPath:W,replaceDefault:Q,append:Z,mode:V,includeEnvironment:X=!0,language:Y}=$,J=[],G=[];if(X){let O=b1();if(O)J.push(O),G.push({name:"environment",loaded:!0,length:O.length})}let K=V==="plan",B,q;if(K)B=U8,q="plan_mode_prompt";else B=Q??O8,q=Q?"replace_default":"default";if(J.push(B),G.push({name:q,loaded:!0,length:B.length}),W){let O=await h6(W);if(O)J.push(O),G.push({name:"blade_md",loaded:!0,length:O.length});else G.push({name:"blade_md",loaded:!1})}if(Z?.trim())J.push(Z.trim()),G.push({name:"append",loaded:!0,length:Z.trim().length});let w=J.join(`
581
587
 
582
588
  ---
583
589
 
584
- `);return w=y6(w),w=P6(w,Y),{prompt:w,sources:G}}function y6($){let Q=m$().generateAvailableSkillsList();if(!Q)return $;return $.replace(v6,`<available_skills>
590
+ `);return w=I6(w),w=x6(w,Y),{prompt:w,sources:G}}function I6($){let Q=d$().generateAvailableSkillsList();if(!Q)return $;return $.replace(k6,`<available_skills>
585
591
  ${Q}
586
- </available_skills>`)}var T6={"zh-CN":"Chinese (Simplified Chinese)","zh-TW":"Chinese (Traditional Chinese)","en-US":"English","en-GB":"English (British)","ja-JP":"Japanese","ko-KR":"Korean","es-ES":"Spanish","fr-FR":"French","de-DE":"German","pt-BR":"Portuguese (Brazilian)","ru-RU":"Russian"};function P6($,W){let Q=W||"zh-CN",Z=T6[Q]||Q,V=`IMPORTANT: Always respond in ${Z}. All your responses must be in ${Z}.`;return $.replace("{{LANGUAGE_INSTRUCTION}}",V)}async function k6($){let W=S6.join($,"BLADE.md");try{return(await H8.readFile(W,"utf-8")).trim()||null}catch{return null}}import*as j5 from"os";import*as z5 from"path";import{basename as h6,extname as p6}from"path";import{z as j1}from"zod";function g$(){return!1}function b8(){throw Error("ACP mode is not available")}import*as D$ from"fs/promises";class F8{async readTextFile($){return D$.readFile($,"utf-8")}async writeTextFile($,W){await D$.writeFile($,W,"utf-8")}async exists($){try{return await D$.access($),!0}catch{return!1}}async readBinaryFile($){return D$.readFile($)}async stat($){try{let W=await D$.stat($);return{size:W.size,isDirectory:W.isDirectory(),isFile:W.isFile(),mtime:W.mtime}}catch{return null}}async mkdir($,W){await D$.mkdir($,{recursive:W?.recursive??!1,mode:W?.mode??493})}}var I6=new F8;function H0(){return I6}import{isAbsolute as A8}from"path";import{z as n}from"zod";var p={filePath:($)=>n.string().min(1,"File path is required").refine((W)=>A8(W),{message:"Path must be absolute"}).describe($?.description||"Absolute file path"),encoding:()=>n.enum(["utf8","base64","binary"]).default("utf8").describe("File encoding"),timeout:($=1000,W=300000,Q=30000)=>n.number().int("Must be an integer").min($,`Cannot be less than ${$}ms`).max(W,`Cannot exceed ${W}ms`).default(Q).describe(`Timeout in milliseconds (default ${Q}ms)`),pattern:($)=>n.string().min(1,"Pattern is required").describe($?.description||"Regex or glob pattern"),glob:($)=>n.string().min(1,"Glob pattern is required").describe($?.description||'Glob pattern (e.g., "*.js", "**/*.ts")'),lineNumber:($)=>n.number().int("Line number must be an integer").min($?.min??0,`Line number cannot be less than ${$?.min??0}`).describe($?.description||"Line number"),lineLimit:($)=>n.number().int("Line count must be an integer").min($?.min??1,`Line count cannot be less than ${$?.min??1}`).max($?.max??1e4,`Line count cannot exceed ${$?.max??1e4}`).describe($?.description||"Limit on lines to read"),workingDirectory:()=>n.string().min(1,"Working directory is required").refine(($)=>A8($),{message:"Path must be absolute"}).describe("Absolute working directory"),environment:()=>n.record(n.string(),n.string()).describe("Environment variables (key-value)").optional(),outputMode:($,W)=>{let Q=n.enum($);return W?Q.default(W):Q},flag:($)=>n.boolean().default($?.defaultValue??!1).describe($?.description||"Boolean flag"),url:($)=>n.string().url("Must be a valid URL").describe($?.description||"URL"),port:()=>n.number().int("Port must be an integer").min(1,"Port cannot be less than 1").max(65535,"Port cannot exceed 65535").describe("Port number"),command:($)=>n.string().min(1,"Command is required").describe($?.description||"Command to execute"),sessionId:()=>n.string().min(1,"Session ID is required").uuid("Must be a valid UUID").optional().describe("Session identifier (UUID)"),nonNegativeInt:($)=>n.number().int("Must be an integer").min(0,"Cannot be negative").describe($?.description||"Non-negative integer"),positiveInt:($)=>n.number().int("Must be an integer").min(1,"Must be greater than 0").describe($?.description||"Positive integer")};import*as C2 from"diff";function D8($,W,Q=4){if($===W)return null;let Z=C2.createPatch("file",$,W,"","",{context:Q}),V=Z.split(`
592
+ </available_skills>`)}var f6={"zh-CN":"Chinese (Simplified Chinese)","zh-TW":"Chinese (Traditional Chinese)","en-US":"English","en-GB":"English (British)","ja-JP":"Japanese","ko-KR":"Korean","es-ES":"Spanish","fr-FR":"French","de-DE":"German","pt-BR":"Portuguese (Brazilian)","ru-RU":"Russian"};function x6($,W){let Q=W||"zh-CN",Z=f6[Q]||Q,V=`IMPORTANT: Always respond in ${Z}. All your responses must be in ${Z}.`;return $.replace("{{LANGUAGE_INSTRUCTION}}",V)}async function h6($){let W=P6.join($,"BLADE.md");try{return(await F8.readFile(W,"utf-8")).trim()||null}catch{return null}}import*as j5 from"os";import*as N5 from"path";import{basename as m6,extname as g6}from"path";import{z as L1}from"zod";function m$(){return!1}function H8(){throw Error("ACP mode is not available")}import*as b$ from"fs/promises";class A8{async readTextFile($){return b$.readFile($,"utf-8")}async writeTextFile($,W){await b$.writeFile($,W,"utf-8")}async exists($){try{return await b$.access($),!0}catch{return!1}}async readBinaryFile($){return b$.readFile($)}async stat($){try{let W=await b$.stat($);return{size:W.size,isDirectory:W.isDirectory(),isFile:W.isFile(),mtime:W.mtime}}catch{return null}}async mkdir($,W){await b$.mkdir($,{recursive:W?.recursive??!1,mode:W?.mode??493})}}var p6=new A8;function F0(){return p6}import{isAbsolute as D8}from"path";import{z as l}from"zod";var p={filePath:($)=>l.string().min(1,"File path is required").refine((W)=>D8(W),{message:"Path must be absolute"}).describe($?.description||"Absolute file path"),encoding:()=>l.enum(["utf8","base64","binary"]).default("utf8").describe("File encoding"),timeout:($=1000,W=300000,Q=30000)=>l.number().int("Must be an integer").min($,`Cannot be less than ${$}ms`).max(W,`Cannot exceed ${W}ms`).default(Q).describe(`Timeout in milliseconds (default ${Q}ms)`),pattern:($)=>l.string().min(1,"Pattern is required").describe($?.description||"Regex or glob pattern"),glob:($)=>l.string().min(1,"Glob pattern is required").describe($?.description||'Glob pattern (e.g., "*.js", "**/*.ts")'),lineNumber:($)=>l.number().int("Line number must be an integer").min($?.min??0,`Line number cannot be less than ${$?.min??0}`).describe($?.description||"Line number"),lineLimit:($)=>l.number().int("Line count must be an integer").min($?.min??1,`Line count cannot be less than ${$?.min??1}`).max($?.max??1e4,`Line count cannot exceed ${$?.max??1e4}`).describe($?.description||"Limit on lines to read"),workingDirectory:()=>l.string().min(1,"Working directory is required").refine(($)=>D8($),{message:"Path must be absolute"}).describe("Absolute working directory"),environment:()=>l.record(l.string(),l.string()).describe("Environment variables (key-value)").optional(),outputMode:($,W)=>{let Q=l.enum($);return W?Q.default(W):Q},flag:($)=>l.boolean().default($?.defaultValue??!1).describe($?.description||"Boolean flag"),url:($)=>l.string().url("Must be a valid URL").describe($?.description||"URL"),port:()=>l.number().int("Port must be an integer").min(1,"Port cannot be less than 1").max(65535,"Port cannot exceed 65535").describe("Port number"),command:($)=>l.string().min(1,"Command is required").describe($?.description||"Command to execute"),sessionId:()=>l.string().min(1,"Session ID is required").uuid("Must be a valid UUID").optional().describe("Session identifier (UUID)"),nonNegativeInt:($)=>l.number().int("Must be an integer").min(0,"Cannot be negative").describe($?.description||"Non-negative integer"),positiveInt:($)=>l.number().int("Must be an integer").min(1,"Must be greater than 0").describe($?.description||"Positive integer")};import*as C2 from"diff";function b8($,W,Q=4){if($===W)return null;let Z=C2.createPatch("file",$,W,"","",{context:Q}),V=Z.split(`
587
593
  `),X=1;for(let Y of V){let J=Y.match(/@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/);if(J){X=parseInt(J[1],10);break}}return`
588
594
  <<<DIFF>>>
589
595
  ${JSON.stringify({patch:Z,startLine:Math.max(1,X-Q),matchLine:X})}
590
596
  <<</DIFF>>>
591
597
  `}function _8($,W,Q,Z,V=4){let X=$.indexOf(Q);if(X===-1)return null;let J=$.substring(0,X).split(`
592
598
  `).length-1,G=$.split(`
593
- `),B=W.split(`
594
- `),K=Q.split(`
599
+ `),K=W.split(`
600
+ `),B=Q.split(`
595
601
  `),q=Z.split(`
596
- `),w=Math.max(0,J-V),O=Math.min(G.length,J+K.length+V),b=Math.min(B.length,J+q.length+V),U=G.slice(w,O).join(`
597
- `),F=B.slice(w,b).join(`
598
- `),A=C2.createPatch("file",U,F,"","",{context:V});return`
602
+ `),w=Math.max(0,J-V),O=Math.min(G.length,J+B.length+V),H=Math.min(K.length,J+q.length+V),U=G.slice(w,O).join(`
603
+ `),A=K.slice(w,H).join(`
604
+ `),D=C2.createPatch("file",U,A,"","",{context:V});return`
599
605
  <<<DIFF>>>
600
- ${JSON.stringify({patch:A,startLine:w+1,matchLine:J+1})}
606
+ ${JSON.stringify({patch:D,startLine:w+1,matchLine:J+1})}
601
607
  <<</DIFF>>>
602
608
  `}function L8($){return $.replace(/\\+(n|t|r|'|"|`|\\|\n)/g,(W,Q)=>{switch(Q){case"n":return`
603
609
  `;case"t":return"\t";case"r":return"\r";case"'":return"'";case'"':return'"';case"`":return"`";case"\\":return"\\";case`
604
610
  `:return`
605
611
  `;default:return W}})}function j8($,W){let Q=W.split(`
606
- `);if(Q.length===1)return null;let V=Q[0].match(/^(\s+)/);if(!V)return null;let X=V[1],J=Q.map((B)=>{if(B.startsWith(X))return B.slice(X.length);return B}).join(`
612
+ `);if(Q.length===1)return null;let V=Q[0].match(/^(\s+)/);if(!V)return null;let X=V[1],J=Q.map((K)=>{if(K.startsWith(X))return K.slice(X.length);return K}).join(`
607
613
  `),G=$.split(`
608
- `);for(let B=0;B<=G.length-Q.length;B++){let K=G[B].match(/^(\s+)/),q=K?K[1]:"",w=G.slice(B,B+Q.length);if(w.map((U)=>{if(U.startsWith(q))return U.slice(q.length);return U}).join(`
614
+ `);for(let K=0;K<=G.length-Q.length;K++){let B=G[K].match(/^(\s+)/),q=B?B[1]:"",w=G.slice(K,K+Q.length);if(w.map((U)=>{if(U.startsWith(q))return U.slice(q.length);return U}).join(`
609
615
  `)===J)return w.join(`
610
- `)}return null}import{promises as L1}from"node:fs";var p0=M("Tool");class Z${static instance=null;accessedFiles=new Map;constructor(){}static getInstance(){if(!Z$.instance)Z$.instance=new Z$;return Z$.instance}async recordFileRead($,W){try{let Q=await L1.stat($),Z={filePath:$,accessTime:Date.now(),mtime:Q.mtimeMs,sessionId:W,lastOperation:"read"};this.accessedFiles.set($,Z),p0.debug(`记录文件读取: ${$}`)}catch(Q){p0.warn(`记录文件读取失败: ${$}`,Q)}}async recordFileEdit($,W,Q="edit"){try{let Z=await L1.stat($),V={filePath:$,accessTime:Date.now(),mtime:Z.mtimeMs,sessionId:W,lastOperation:Q};this.accessedFiles.set($,V),p0.debug(`记录文件${Q==="edit"?"编辑":"写入"}: ${$}`)}catch(Z){p0.warn(`记录文件${Q==="edit"?"编辑":"写入"}失败: ${$}`,Z)}}hasFileBeenRead($,W){let Q=this.accessedFiles.get($);if(!Q)return!1;if(W&&Q.sessionId!==W)return!1;return!0}async checkFileModification($){let W=this.accessedFiles.get($);if(!W)return{modified:!1,message:"文件未被跟踪"};try{let Q=await L1.stat($);if(Math.abs(Q.mtimeMs-W.mtime)>1)return{modified:!0,message:`文件在访问后被修改(访问时间: ${new Date(W.accessTime).toISOString()}, 当前修改时间: ${Q.mtime.toISOString()})`};return{modified:!1}}catch(Q){let Z=Q;if(Z.code==="ENOENT")return{modified:!0,message:"文件已被删除"};return{modified:!1,message:`无法检查文件状态: ${Z.message}`}}}async checkExternalModification($){let W=this.accessedFiles.get($);if(!W)return{isExternal:!1,message:"文件未被跟踪"};try{let Q=await L1.stat($);if(Q.mtimeMs-W.mtime>2000)return{isExternal:!0,message:`文件在 ${new Date(W.accessTime).toISOString()} (${W.lastOperation}) 之后被外部程序修改(当前修改时间: ${Q.mtime.toISOString()})`};return{isExternal:!1}}catch(Q){let Z=Q;if(Z.code==="ENOENT")return{isExternal:!0,message:"文件已被删除"};return p0.warn(`检查文件外部修改失败: ${$}`,Q),{isExternal:!1,message:`无法检查文件状态: ${Z.message}`}}}getFileRecord($){return this.accessedFiles.get($)}clearFileRecord($){this.accessedFiles.delete($)}clearAll(){this.accessedFiles.clear()}clearSession($){for(let[W,Q]of this.accessedFiles.entries())if(Q.sessionId===$)this.accessedFiles.delete(W)}getTrackedFiles(){return Array.from(this.accessedFiles.keys())}getTrackedFileCount(){return this.accessedFiles.size}static resetInstance(){Z$.instance=null}}import*as R8 from"node:crypto";import{promises as M$}from"node:fs";import*as $0 from"node:path";import{execSync as f6}from"node:child_process";import*as M2 from"node:os";import*as e$ from"node:path";function x6($){return e$.resolve($).replace(/[/\\]/g,"-").replace(/:/g,"_")}function u0($){let W=M2.homedir(),Q=x6($);return e$.join(W,".blade","projects",Q)}function Y$($,W){return e$.join(u0($),`${W}.jsonl`)}function z8($){try{return f6("git rev-parse --abbrev-ref HEAD",{cwd:$,encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()||void 0}catch{return}}function d0(){return e$.join(M2.homedir(),".blade")}async function N8(){let{readdir:$}=await import("node:fs/promises");try{let W=e$.join(d0(),"projects");return(await $(W,{withFileTypes:!0})).filter((Z)=>Z.isDirectory()).map((Z)=>Z.name)}catch{return[]}}class m0{sessionId;enableCheckpoints;maxSnapshots;snapshotDir;trackedFileBackups=new Map;snapshots=[];constructor($){this.sessionId=$.sessionId,this.enableCheckpoints=$.enableCheckpoints??!0,this.maxSnapshots=$.maxSnapshots??10;let W=d0();this.snapshotDir=$0.join(W,"file-history",this.sessionId)}async initialize(){if(!this.enableCheckpoints)return;try{await M$.mkdir(this.snapshotDir,{recursive:!0,mode:493}),console.log(`[SnapshotManager] 初始化快照目录: ${this.snapshotDir}`)}catch($){throw console.warn("[SnapshotManager] 创建快照目录失败:",$),$}}async createSnapshot($,W){if(!this.enableCheckpoints)return console.log("[SnapshotManager] 检查点已禁用,跳过快照创建"),{backupFileName:"",version:0,backupTime:new Date};try{await M$.access($)}catch{return console.warn(`[SnapshotManager] 文件不存在,跳过快照: ${$}`),{backupFileName:"",version:0,backupTime:new Date}}let Q=this.trackedFileBackups.get($),Z=Q?Q.version+1:1,V=this.generateFileHash($,Z),X=$0.join(this.snapshotDir,`${V}@v${Z}`);try{let Y=await M$.readFile($,{encoding:"utf-8"});await M$.writeFile(X,Y,{encoding:"utf-8"});let J={backupFileName:V,version:Z,backupTime:new Date};return this.trackedFileBackups.set($,J),this.snapshots.push({messageId:W,backupFileName:V,timestamp:new Date,filePath:$}),console.log(`[SnapshotManager] 创建快照: ${$} -> ${V}@v${Z}`),await this.cleanupOldSnapshots($),J}catch(Y){throw console.error(`[SnapshotManager] 创建快照失败: ${$}`,Y),Y}}async restoreSnapshot($,W){let Q=this.snapshots.slice().reverse().find((X)=>X.messageId===W&&X.filePath===$);if(!Q)throw Error(`未找到快照: messageId=${W}, filePath=${$}`);let Z=this.trackedFileBackups.get($);if(!Z)throw Error(`未找到文件追踪信息: ${$}`);let V=$0.join(this.snapshotDir,`${Q.backupFileName}@v${Z.version}`);try{let X=await M$.readFile(V,{encoding:"utf-8"});await M$.writeFile($,X,{encoding:"utf-8"}),console.log(`[SnapshotManager] 恢复快照: ${$} <- ${Q.backupFileName}@v${Z.version}`)}catch(X){throw console.error(`[SnapshotManager] 恢复快照失败: ${$}`,X),X}}async listSnapshots($){return this.snapshots.filter((W)=>W.filePath===$)}async cleanupOldSnapshots($){let W=this.snapshots.filter((V)=>V.filePath===$);if(W.length<=this.maxSnapshots)return;let Z=W.sort((V,X)=>V.timestamp.getTime()-X.timestamp.getTime()).slice(0,W.length-this.maxSnapshots);for(let V of Z){let X=this.trackedFileBackups.get(V.filePath);if(!X)continue;let Y=$0.join(this.snapshotDir,`${V.backupFileName}@v${X.version}`);try{await M$.unlink(Y),console.log(`[SnapshotManager] 删除旧快照: ${Y}`)}catch(G){console.warn(`[SnapshotManager] 删除快照失败: ${Y}`,G)}let J=this.snapshots.indexOf(V);if(J>-1)this.snapshots.splice(J,1)}}async cleanup($=0){try{let W=await M$.readdir(this.snapshotDir);if(W.length<=$)return;let Q=await Promise.all(W.map(async(V)=>{let X=$0.join(this.snapshotDir,V),Y=await M$.stat(X);return{file:V,mtime:Y.mtime.getTime()}}));Q.sort((V,X)=>X.mtime-V.mtime);let Z=Q.slice($);for(let{file:V}of Z){let X=$0.join(this.snapshotDir,V);await M$.unlink(X),console.log(`[SnapshotManager] 清理快照: ${X}`)}}catch(W){console.warn("[SnapshotManager] 清理快照失败:",W)}}generateFileHash($,W){let Q=R8.createHash("md5");return Q.update(`${$}:${W}`),Q.digest("hex").substring(0,16)}getSnapshotDir(){return this.snapshotDir}getSessionId(){return this.sessionId}getTrackedFileCount(){return this.trackedFileBackups.size}getSnapshotCount(){return this.snapshots.length}}var S2=E({name:"Edit",displayName:"File Edit",kind:"write",strict:!0,isConcurrencySafe:!1,schema:j1.object({file_path:p.filePath({description:"Absolute path of the file to edit"}),old_string:j1.string().min(1,"old_string cannot be empty").describe("String to replace"),new_string:j1.string().describe("Replacement string (can be empty)"),replace_all:j1.boolean().default(!1).describe("Replace all matches (default: first only)")}),description:{short:"Performs exact string replacements in files",long:"Performs exact string replacements in files.",usageNotes:["You must use your Read tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.","When editing text from Read tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + tab. Everything after that tab is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.","ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.","Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.","The edit will FAIL if old_string is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use replace_all to change every instance of old_string.","Use replace_all for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance."]},async execute($,W){let{file_path:Q,old_string:Z,new_string:V,replace_all:X}=$,{updateOutput:Y,sessionId:J,messageId:G}=W,B=W.signal??new AbortController().signal;try{Y?.("Starting to read file...");let K=H0(),q=g$(),w;try{if(q)Y?.("通过 IDE 读取文件...");w=await K.readTextFile(Q)}catch(j){let d=j;if(d.code==="ENOENT"||d.message?.includes("not found"))return{success:!1,llmContent:`File not found: ${Q}`,displayContent:`❌ 文件不存在: ${Q}`,error:{type:"execution_error",message:"文件不存在"}};throw j}if(typeof B.throwIfAborted==="function")B.throwIfAborted();if(J){let j=Z$.getInstance();if(!j.hasFileBeenRead(Q,J))return{success:!1,llmContent:"You must use your Read tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.",displayContent:"\uD83D\uDCD6 我需要先读取文件内容,然后再进行编辑。",error:{type:"validation_error",message:"File not read before edit"},metadata:{requiresRead:!0}};let d=await j.checkExternalModification(Q);if(d.isExternal)return{success:!1,llmContent:`The file has been modified by an external program since you last read it. You must use the Read tool again to see the current content before editing.
616
+ `)}return null}import{promises as _1}from"node:fs";var p0=M("Tool");class Z${static instance=null;accessedFiles=new Map;constructor(){}static getInstance(){if(!Z$.instance)Z$.instance=new Z$;return Z$.instance}async recordFileRead($,W){try{let Q=await _1.stat($),Z={filePath:$,accessTime:Date.now(),mtime:Q.mtimeMs,sessionId:W,lastOperation:"read"};this.accessedFiles.set($,Z),p0.debug(`记录文件读取: ${$}`)}catch(Q){p0.warn(`记录文件读取失败: ${$}`,Q)}}async recordFileEdit($,W,Q="edit"){try{let Z=await _1.stat($),V={filePath:$,accessTime:Date.now(),mtime:Z.mtimeMs,sessionId:W,lastOperation:Q};this.accessedFiles.set($,V),p0.debug(`记录文件${Q==="edit"?"编辑":"写入"}: ${$}`)}catch(Z){p0.warn(`记录文件${Q==="edit"?"编辑":"写入"}失败: ${$}`,Z)}}hasFileBeenRead($,W){let Q=this.accessedFiles.get($);if(!Q)return!1;if(W&&Q.sessionId!==W)return!1;return!0}async checkFileModification($){let W=this.accessedFiles.get($);if(!W)return{modified:!1,message:"文件未被跟踪"};try{let Q=await _1.stat($);if(Math.abs(Q.mtimeMs-W.mtime)>1)return{modified:!0,message:`文件在访问后被修改(访问时间: ${new Date(W.accessTime).toISOString()}, 当前修改时间: ${Q.mtime.toISOString()})`};return{modified:!1}}catch(Q){let Z=Q;if(Z.code==="ENOENT")return{modified:!0,message:"文件已被删除"};return{modified:!1,message:`无法检查文件状态: ${Z.message}`}}}async checkExternalModification($){let W=this.accessedFiles.get($);if(!W)return{isExternal:!1,message:"文件未被跟踪"};try{let Q=await _1.stat($);if(Q.mtimeMs-W.mtime>2000)return{isExternal:!0,message:`文件在 ${new Date(W.accessTime).toISOString()} (${W.lastOperation}) 之后被外部程序修改(当前修改时间: ${Q.mtime.toISOString()})`};return{isExternal:!1}}catch(Q){let Z=Q;if(Z.code==="ENOENT")return{isExternal:!0,message:"文件已被删除"};return p0.warn(`检查文件外部修改失败: ${$}`,Q),{isExternal:!1,message:`无法检查文件状态: ${Z.message}`}}}getFileRecord($){return this.accessedFiles.get($)}clearFileRecord($){this.accessedFiles.delete($)}clearAll(){this.accessedFiles.clear()}clearSession($){for(let[W,Q]of this.accessedFiles.entries())if(Q.sessionId===$)this.accessedFiles.delete(W)}getTrackedFiles(){return Array.from(this.accessedFiles.keys())}getTrackedFileCount(){return this.accessedFiles.size}static resetInstance(){Z$.instance=null}}import*as R8 from"node:crypto";import{promises as M$}from"node:fs";import*as e$ from"node:path";import{execSync as u6}from"node:child_process";import*as M2 from"node:os";import*as t$ from"node:path";function d6($){return t$.resolve($).replace(/[/\\]/g,"-").replace(/:/g,"_")}function u0($){let W=M2.homedir(),Q=d6($);return t$.join(W,".blade","projects",Q)}function K$($,W){return t$.join(u0($),`${W}.jsonl`)}function N8($){try{return u6("git rev-parse --abbrev-ref HEAD",{cwd:$,encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()||void 0}catch{return}}function d0(){return t$.join(M2.homedir(),".blade")}async function z8(){let{readdir:$}=await import("node:fs/promises");try{let W=t$.join(d0(),"projects");return(await $(W,{withFileTypes:!0})).filter((Z)=>Z.isDirectory()).map((Z)=>Z.name)}catch{return[]}}class m0{sessionId;enableCheckpoints;maxSnapshots;snapshotDir;trackedFileBackups=new Map;snapshots=[];constructor($){this.sessionId=$.sessionId,this.enableCheckpoints=$.enableCheckpoints??!0,this.maxSnapshots=$.maxSnapshots??10;let W=d0();this.snapshotDir=e$.join(W,"file-history",this.sessionId)}async initialize(){if(!this.enableCheckpoints)return;try{await M$.mkdir(this.snapshotDir,{recursive:!0,mode:493}),console.log(`[SnapshotManager] 初始化快照目录: ${this.snapshotDir}`)}catch($){throw console.warn("[SnapshotManager] 创建快照目录失败:",$),$}}async createSnapshot($,W){if(!this.enableCheckpoints)return console.log("[SnapshotManager] 检查点已禁用,跳过快照创建"),{backupFileName:"",version:0,backupTime:new Date};try{await M$.access($)}catch{return console.warn(`[SnapshotManager] 文件不存在,跳过快照: ${$}`),{backupFileName:"",version:0,backupTime:new Date}}let Q=this.trackedFileBackups.get($),Z=Q?Q.version+1:1,V=this.generateFileHash($,Z),X=e$.join(this.snapshotDir,`${V}@v${Z}`);try{let Y=await M$.readFile($,{encoding:"utf-8"});await M$.writeFile(X,Y,{encoding:"utf-8"});let J={backupFileName:V,version:Z,backupTime:new Date};return this.trackedFileBackups.set($,J),this.snapshots.push({messageId:W,backupFileName:V,timestamp:new Date,filePath:$}),console.log(`[SnapshotManager] 创建快照: ${$} -> ${V}@v${Z}`),await this.cleanupOldSnapshots($),J}catch(Y){throw console.error(`[SnapshotManager] 创建快照失败: ${$}`,Y),Y}}async restoreSnapshot($,W){let Q=this.snapshots.slice().reverse().find((X)=>X.messageId===W&&X.filePath===$);if(!Q)throw Error(`未找到快照: messageId=${W}, filePath=${$}`);let Z=this.trackedFileBackups.get($);if(!Z)throw Error(`未找到文件追踪信息: ${$}`);let V=e$.join(this.snapshotDir,`${Q.backupFileName}@v${Z.version}`);try{let X=await M$.readFile(V,{encoding:"utf-8"});await M$.writeFile($,X,{encoding:"utf-8"}),console.log(`[SnapshotManager] 恢复快照: ${$} <- ${Q.backupFileName}@v${Z.version}`)}catch(X){throw console.error(`[SnapshotManager] 恢复快照失败: ${$}`,X),X}}async listSnapshots($){return this.snapshots.filter((W)=>W.filePath===$)}async cleanupOldSnapshots($){let W=this.snapshots.filter((V)=>V.filePath===$);if(W.length<=this.maxSnapshots)return;let Z=W.sort((V,X)=>V.timestamp.getTime()-X.timestamp.getTime()).slice(0,W.length-this.maxSnapshots);for(let V of Z){let X=this.trackedFileBackups.get(V.filePath);if(!X)continue;let Y=e$.join(this.snapshotDir,`${V.backupFileName}@v${X.version}`);try{await M$.unlink(Y),console.log(`[SnapshotManager] 删除旧快照: ${Y}`)}catch(G){console.warn(`[SnapshotManager] 删除快照失败: ${Y}`,G)}let J=this.snapshots.indexOf(V);if(J>-1)this.snapshots.splice(J,1)}}async cleanup($=0){try{let W=await M$.readdir(this.snapshotDir);if(W.length<=$)return;let Q=await Promise.all(W.map(async(V)=>{let X=e$.join(this.snapshotDir,V),Y=await M$.stat(X);return{file:V,mtime:Y.mtime.getTime()}}));Q.sort((V,X)=>X.mtime-V.mtime);let Z=Q.slice($);for(let{file:V}of Z){let X=e$.join(this.snapshotDir,V);await M$.unlink(X),console.log(`[SnapshotManager] 清理快照: ${X}`)}}catch(W){console.warn("[SnapshotManager] 清理快照失败:",W)}}generateFileHash($,W){let Q=R8.createHash("md5");return Q.update(`${$}:${W}`),Q.digest("hex").substring(0,16)}getSnapshotDir(){return this.snapshotDir}getSessionId(){return this.sessionId}getTrackedFileCount(){return this.trackedFileBackups.size}getSnapshotCount(){return this.snapshots.length}}var S2=E({name:"Edit",displayName:"File Edit",kind:"write",strict:!0,isConcurrencySafe:!1,schema:L1.object({file_path:p.filePath({description:"Absolute path of the file to edit"}),old_string:L1.string().min(1,"old_string cannot be empty").describe("String to replace"),new_string:L1.string().describe("Replacement string (can be empty)"),replace_all:L1.boolean().default(!1).describe("Replace all matches (default: first only)")}),description:{short:"Performs exact string replacements in files",long:"Performs exact string replacements in files.",usageNotes:["You must use your Read tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.","When editing text from Read tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + tab. Everything after that tab is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.","ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.","Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.","The edit will FAIL if old_string is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use replace_all to change every instance of old_string.","Use replace_all for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance."]},async execute($,W){let{file_path:Q,old_string:Z,new_string:V,replace_all:X}=$,{updateOutput:Y,sessionId:J,messageId:G}=W,K=W.signal??new AbortController().signal;try{Y?.("Starting to read file...");let B=F0(),q=m$(),w;try{if(q)Y?.("通过 IDE 读取文件...");w=await B.readTextFile(Q)}catch(j){let d=j;if(d.code==="ENOENT"||d.message?.includes("not found"))return{success:!1,llmContent:`File not found: ${Q}`,displayContent:`❌ 文件不存在: ${Q}`,error:{type:"execution_error",message:"文件不存在"}};throw j}if(typeof K.throwIfAborted==="function")K.throwIfAborted();if(J){let j=Z$.getInstance();if(!j.hasFileBeenRead(Q,J))return{success:!1,llmContent:"You must use your Read tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.",displayContent:"\uD83D\uDCD6 我需要先读取文件内容,然后再进行编辑。",error:{type:"validation_error",message:"File not read before edit"},metadata:{requiresRead:!0}};let d=await j.checkExternalModification(Q);if(d.isExternal)return{success:!1,llmContent:`The file has been modified by an external program since you last read it. You must use the Read tool again to see the current content before editing.
611
617
 
612
618
  Details: ${d.message}`,displayContent:`❌ 编辑失败:文件已被外部程序修改
613
619
 
614
620
  ${d.message}
615
621
 
616
- \uD83D\uDCA1 我需要重新读取文件内容后再编辑`,error:{type:"validation_error",message:"File modified externally",details:{externalModification:d.message}}}}if(J&&G)try{let j=new m0({sessionId:J});await j.initialize(),await j.createSnapshot(Q,G)}catch(j){console.warn("[EditTool] 创建快照失败:",j)}if(Z===V)return{success:!1,llmContent:"New string is identical; no replacement needed",displayContent:"⚠️ 新字符串与旧字符串相同,无需进行替换",error:{type:"validation_error",message:"新旧字符串相同"}};let O=u6(w,Z);if(!O.matched){let j=g6(w,Z,Q);return{success:!1,llmContent:j.llmContent,displayContent:j.displayContent,error:{type:"execution_error",message:"未找到匹配内容",details:j.metadata}}}let b=O.matched;if(O.strategy!=="exact")console.log(`[SmartEdit] 使用策略: ${O.strategy}`);let U=d6(w,b);if(U.length>1&&!X){let j=w.split(`
617
- `),d=0,N$=[];for(let L=0;L<j.length;L++){let v=j[L],a=d,I=d+v.length;for(let k of U)if(k>=a&&k<I){let h=Math.max(0,L-1),W$=Math.min(j.length-1,L+1),d1=j.slice(h,W$+1).map((m1)=>m1.trim()).join(" ").slice(0,80);N$.push({line:L+1,column:k-a+1,context:d1})}d=I+1}let R$=[`⚠️ EDIT PAUSED: old_string matches ${U.length} locations (must be unique).`,"","**Matches found at:**",...N$.map((L,v)=>` ${v+1}. Line ${L.line}`),"","**Action Required:** Add 3-5 lines of surrounding context to make old_string unique.","","**Tips for quick success:**","• Include the function/class name that wraps the target code","• Add 2-3 lines before and after the target","• Include unique comments or variable names nearby",`• Or use replace_all=true to change all ${U.length} occurrences`,"","\uD83E\uDD16 **Auto-retry expected** - This usually resolves in 1-2 attempts."].join(`
618
- `),R=["⚠️ 编辑暂停:需要更精确的定位","",`在文件中找到 ${U.length} 处相似代码:`,...N$.map((L,v)=>` • 第 ${L.line} 行 (匹配 ${v+1}/${U.length})`),"","AI 正在自动调整,添加更多上下文以精确定位...","通常需要 1-2 次尝试即可成功","","\uD83D\uDCA1 如果多次失败,可能需要:"," • 包含函数/类名等独特标识符"," • 添加目标代码前后 3-5 行完整上下文",` • 或使用 replace_all=true 同时替换所有 ${U.length} 处匹配`].join(`
619
- `);return{success:!1,llmContent:R$,displayContent:R,error:{type:"validation_error",message:"old_string is not unique",details:{matches:N$.map((L)=>({line:L.line,column:L.column})),count:U.length}}}}else Y?.(`找到 ${U.length} 个匹配项,开始替换...`);let F,A;if(X)F=w.split(b).join(V),A=U.length;else{let j=w.indexOf(b);F=w.substring(0,j)+V+w.substring(j+b.length),A=1}if(typeof B.throwIfAborted==="function")B.throwIfAborted();if(q)Y?.("通过 IDE 写入文件...");if(await K.writeTextFile(Q,F),J)await Z$.getInstance().recordFileEdit(Q,J,"edit");let D=await K.stat(Q),N=_8(w,F,b,V,4),C=h6(Q),z=A===1?`替换 1 处匹配到 ${C}`:`替换 ${A} 处匹配到 ${C}`,y={file_path:Q,matches_found:U.length,replacements_made:A,replace_all:X,old_string_length:Z.length,new_string_length:V.length,original_size:w.length,new_size:F.length,size_diff:F.length-w.length,last_modified:D?.mtime instanceof Date?D.mtime.toISOString():void 0,snapshot_created:!!(J&&G),session_id:J,message_id:G,diff_snippet:N,summary:z,kind:"edit",oldContent:w,newContent:F},l=m6(y,N);return{success:!0,llmContent:{file_path:Q,replacements:A,total_matches:U.length},displayContent:l,metadata:y}}catch(K){let q=K;if(q.name==="AbortError")return{success:!1,llmContent:"File edit aborted",displayContent:"⚠️ 文件编辑被用户中止",error:{type:"execution_error",message:"操作被中止"}};return{success:!1,llmContent:`File edit failed: ${q.message}`,displayContent:`❌ 编辑文件失败: ${q.message}`,error:{type:"execution_error",message:q.message,details:q}}}},version:"2.0.0",category:"文件操作",tags:["file","edit","replace","modify"],extractSignatureContent:($)=>$.file_path,abstractPermissionRule:($)=>{let W=p6($.file_path);return W?`**/*${W}`:"**/*"}});function E8($){return $.replaceAll("‘","'").replaceAll("’","'").replaceAll("“",'"').replaceAll("”",'"')}function u6($,W){if($.includes(W))return{matched:W,strategy:"exact"};let Q=E8(W),V=E8($).indexOf(Q);if(V!==-1)return{matched:$.substring(V,V+W.length),strategy:"normalize_quotes"};let X=L8(W);if(X!==W&&$.includes(X))return{matched:X,strategy:"unescape"};let Y=j8($,W);if(Y)return{matched:Y,strategy:"flexible"};return{matched:null,strategy:"failed"}}function d6($,W){if(W.length===0)return[];let Q=[],Z=$.indexOf(W);while(Z!==-1)Q.push(Z),Z=$.indexOf(W,Z+W.length);return Q}function m6($,W){let{file_path:Q,matches_found:Z,replacements_made:V,replace_all:X,size_diff:Y}=$,J=`✅ 成功编辑文件: ${Q}`;if(J+=`
622
+ \uD83D\uDCA1 我需要重新读取文件内容后再编辑`,error:{type:"validation_error",message:"File modified externally",details:{externalModification:d.message}}}}if(J&&G)try{let j=new m0({sessionId:J});await j.initialize(),await j.createSnapshot(Q,G)}catch(j){console.warn("[EditTool] 创建快照失败:",j)}if(Z===V)return{success:!1,llmContent:"New string is identical; no replacement needed",displayContent:"⚠️ 新字符串与旧字符串相同,无需进行替换",error:{type:"validation_error",message:"新旧字符串相同"}};let O=c6(w,Z);if(!O.matched){let j=n6(w,Z,Q);return{success:!1,llmContent:j.llmContent,displayContent:j.displayContent,error:{type:"execution_error",message:"未找到匹配内容",details:j.metadata}}}let H=O.matched;if(O.strategy!=="exact")console.log(`[SmartEdit] 使用策略: ${O.strategy}`);let U=i6(w,H);if(U.length>1&&!X){let j=w.split(`
623
+ `),d=0,z$=[];for(let L=0;L<j.length;L++){let v=j[L],n=d,I=d+v.length;for(let k of U)if(k>=n&&k<I){let h=Math.max(0,L-1),W$=Math.min(j.length-1,L+1),d1=j.slice(h,W$+1).map((m1)=>m1.trim()).join(" ").slice(0,80);z$.push({line:L+1,column:k-n+1,context:d1})}d=I+1}let R$=[`⚠️ EDIT PAUSED: old_string matches ${U.length} locations (must be unique).`,"","**Matches found at:**",...z$.map((L,v)=>` ${v+1}. Line ${L.line}`),"","**Action Required:** Add 3-5 lines of surrounding context to make old_string unique.","","**Tips for quick success:**","• Include the function/class name that wraps the target code","• Add 2-3 lines before and after the target","• Include unique comments or variable names nearby",`• Or use replace_all=true to change all ${U.length} occurrences`,"","\uD83E\uDD16 **Auto-retry expected** - This usually resolves in 1-2 attempts."].join(`
624
+ `),R=["⚠️ 编辑暂停:需要更精确的定位","",`在文件中找到 ${U.length} 处相似代码:`,...z$.map((L,v)=>` • 第 ${L.line} 行 (匹配 ${v+1}/${U.length})`),"","AI 正在自动调整,添加更多上下文以精确定位...","通常需要 1-2 次尝试即可成功","","\uD83D\uDCA1 如果多次失败,可能需要:"," • 包含函数/类名等独特标识符"," • 添加目标代码前后 3-5 行完整上下文",` • 或使用 replace_all=true 同时替换所有 ${U.length} 处匹配`].join(`
625
+ `);return{success:!1,llmContent:R$,displayContent:R,error:{type:"validation_error",message:"old_string is not unique",details:{matches:z$.map((L)=>({line:L.line,column:L.column})),count:U.length}}}}else Y?.(`找到 ${U.length} 个匹配项,开始替换...`);let A,D;if(X)A=w.split(H).join(V),D=U.length;else{let j=w.indexOf(H);A=w.substring(0,j)+V+w.substring(j+H.length),D=1}if(typeof K.throwIfAborted==="function")K.throwIfAborted();if(q)Y?.("通过 IDE 写入文件...");if(await B.writeTextFile(Q,A),J)await Z$.getInstance().recordFileEdit(Q,J,"edit");let b=await B.stat(Q),z=_8(w,A,H,V,4),C=m6(Q),N=D===1?`替换 1 处匹配到 ${C}`:`替换 ${D} 处匹配到 ${C}`,y={file_path:Q,matches_found:U.length,replacements_made:D,replace_all:X,old_string_length:Z.length,new_string_length:V.length,original_size:w.length,new_size:A.length,size_diff:A.length-w.length,last_modified:b?.mtime instanceof Date?b.mtime.toISOString():void 0,snapshot_created:!!(J&&G),session_id:J,message_id:G,diff_snippet:z,summary:N,kind:"edit",oldContent:w,newContent:A},i=l6(y,z);return{success:!0,llmContent:{file_path:Q,replacements:D,total_matches:U.length},displayContent:i,metadata:y}}catch(B){let q=B;if(q.name==="AbortError")return{success:!1,llmContent:"File edit aborted",displayContent:"⚠️ 文件编辑被用户中止",error:{type:"execution_error",message:"操作被中止"}};return{success:!1,llmContent:`File edit failed: ${q.message}`,displayContent:`❌ 编辑文件失败: ${q.message}`,error:{type:"execution_error",message:q.message,details:q}}}},version:"2.0.0",category:"文件操作",tags:["file","edit","replace","modify"],extractSignatureContent:($)=>$.file_path,abstractPermissionRule:($)=>{let W=g6($.file_path);return W?`**/*${W}`:"**/*"}});function E8($){return $.replaceAll("‘","'").replaceAll("’","'").replaceAll("“",'"').replaceAll("”",'"')}function c6($,W){if($.includes(W))return{matched:W,strategy:"exact"};let Q=E8(W),V=E8($).indexOf(Q);if(V!==-1)return{matched:$.substring(V,V+W.length),strategy:"normalize_quotes"};let X=L8(W);if(X!==W&&$.includes(X))return{matched:X,strategy:"unescape"};let Y=j8($,W);if(Y)return{matched:Y,strategy:"flexible"};return{matched:null,strategy:"failed"}}function i6($,W){if(W.length===0)return[];let Q=[],Z=$.indexOf(W);while(Z!==-1)Q.push(Z),Z=$.indexOf(W,Z+W.length);return Q}function l6($,W){let{file_path:Q,matches_found:Z,replacements_made:V,replace_all:X,size_diff:Y}=$,J=`✅ 成功编辑文件: ${Q}`;if(J+=`
620
626
  \uD83D\uDCDD 替换了 ${V} 个匹配项`,!X&&Z>1)J+=` (共找到 ${Z} 个匹配项)`;if(Y!==0){let G=Y>0?`增加${Y}`:`减少${Math.abs(Y)}`;J+=`
621
- \uD83D\uDCCA 文件大小${G}个字符`}if(W)J+=W;return J}function g6($,W,Q){let Z=$.split(`
622
- `),V=Z.length,X=c6($,W,3),Y=0,J=Math.min(20,V);if(X.length>0){let O=X[0];Y=Math.max(0,O.lineNumber-10),J=Math.min(V,O.lineNumber+10)}let B=Z.slice(Y,J).map((O,b)=>{return` ${(Y+b+1).toString().padStart(4)}: ${O}`}).join(`
623
- `),K=`String not found in file.
627
+ \uD83D\uDCCA 文件大小${G}个字符`}if(W)J+=W;return J}function n6($,W,Q){let Z=$.split(`
628
+ `),V=Z.length,X=a6($,W,3),Y=0,J=Math.min(20,V);if(X.length>0){let O=X[0];Y=Math.max(0,O.lineNumber-10),J=Math.min(V,O.lineNumber+10)}let K=Z.slice(Y,J).map((O,H)=>{return` ${(Y+H+1).toString().padStart(4)}: ${O}`}).join(`
629
+ `),B=`String not found in file.
624
630
 
625
631
  File: ${Q}
626
632
  Total lines: ${V}
627
633
 
628
634
  `,q=W.length>300?W.substring(0,300)+`
629
- ... (truncated)`:W;if(K+=`You tried to match:
635
+ ... (truncated)`:W;if(B+=`You tried to match:
630
636
  ${q}
631
637
 
632
- `,X.length>0)K+=`File content around possible matches (lines ${Y+1}-${J}):
633
- ${B}
638
+ `,X.length>0)B+=`File content around possible matches (lines ${Y+1}-${J}):
639
+ ${K}
634
640
 
635
- `;else K+=`File content preview (lines ${Y+1}-${J}):
636
- ${B}
641
+ `;else B+=`File content preview (lines ${Y+1}-${J}):
642
+ ${K}
637
643
 
638
- `;if(X.length>0)K+=`Possible similar matches found:
639
- `,X.forEach((O,b)=>{let U=O.text.length>100?O.text.substring(0,100)+"...":O.text;K+=` ${b+1}. Line ${O.lineNumber} (similarity: ${Math.round(O.similarity*100)}%)
644
+ `;if(X.length>0)B+=`Possible similar matches found:
645
+ `,X.forEach((O,H)=>{let U=O.text.length>100?O.text.substring(0,100)+"...":O.text;B+=` ${H+1}. Line ${O.lineNumber} (similarity: ${Math.round(O.similarity*100)}%)
640
646
  ${U.replace(/\n/g,"\\n")}
641
- `}),K+=`
642
- `;K+=`Recovery suggestions:
647
+ `}),B+=`
648
+ `;B+=`Recovery suggestions:
643
649
  1. Use the Read tool to verify the current file content
644
650
  2. Check for typos, whitespace differences, or quote mismatches
645
651
  3. Provide more surrounding context to make the match unique
@@ -655,52 +661,52 @@ Common issues:
655
661
  搜索字符串长度: ${W.length} 字符
656
662
  `;if(X.length>0)w+=`
657
663
  \uD83D\uDCA1 找到 ${X.length} 个相似匹配项:
658
- `,X.forEach((O,b)=>{w+=` ${b+1}. 第 ${O.lineNumber} 行 (相似度: ${Math.round(O.similarity*100)}%)
664
+ `,X.forEach((O,H)=>{w+=` ${H+1}. 第 ${O.lineNumber} 行 (相似度: ${Math.round(O.similarity*100)}%)
659
665
  `});else w+=`
660
666
  ⚠️ 未找到相似的匹配项
661
667
  `;return w+=`
662
668
  \uD83D\uDCC4 文件内容摘录 (${Y+1}-${J} 行):
663
- ${B}
669
+ ${K}
664
670
  `,w+=`
665
671
  \uD83D\uDD27 接下来我会:
666
672
  `,w+=` 1. 重新读取文件内容
667
673
  `,w+=` 2. 仔细核对空格、换行符、引号
668
- `,w+=" 3. 使用更多上下文代码确保唯一性",{llmContent:K,displayContent:w,metadata:{searchStringLength:W.length,fuzzyMatches:X.map((O)=>({line:O.lineNumber,similarity:O.similarity,preview:O.text.substring(0,100)})),excerptRange:[Y+1,J],totalLines:V}}}function c6($,W,Q=3){let Z=$.split(`
674
+ `,w+=" 3. 使用更多上下文代码确保唯一性",{llmContent:B,displayContent:w,metadata:{searchStringLength:W.length,fuzzyMatches:X.map((O)=>({line:O.lineNumber,similarity:O.similarity,preview:O.text.substring(0,100)})),excerptRange:[Y+1,J],totalLines:V}}}function a6($,W,Q=3){let Z=$.split(`
669
675
  `),V=W.split(`
670
- `);if(V.length===1)return Z.map((G,B)=>({text:G,lineNumber:B+1,similarity:C8(W.trim(),G.trim())})).filter((G)=>G.similarity>0.5).sort((G,B)=>B.similarity-G.similarity).slice(0,Q);let X=V.length,Y=[];for(let J=0;J<=Z.length-X;J++){let G=Z.slice(J,J+X).join(`
671
- `),B=C8(W,G);if(B>0.5)Y.push({text:G,lineNumber:J+1,similarity:B})}return Y.sort((J,G)=>G.similarity-J.similarity).slice(0,Q)}function C8($,W){let Q=(w)=>w.trim().replace(/\s+/g," ").replace(/[\u201c\u201d"]/g,'"').replace(/[\u2018\u2019']/g,"'"),Z=Q($),V=Q(W);if(Z===V)return 1;let X=Z.length,Y=V.length;if(X===0)return Y===0?1:0;if(Y===0)return 0;let J=200,G=Z.substring(0,J),B=V.substring(0,J),K=i6(G,B),q=Math.max(G.length,B.length);return 1-K/q}function i6($,W){let Q=$.length,Z=W.length,V=Array(Q+1).fill(null).map(()=>Array(Z+1).fill(0));for(let X=0;X<=Q;X++)V[X][0]=X;for(let X=0;X<=Z;X++)V[0][X]=X;for(let X=1;X<=Q;X++)for(let Y=1;Y<=Z;Y++){let J=$[X-1]===W[Y-1]?0:1;V[X][Y]=Math.min(V[X-1][Y]+1,V[X][Y-1]+1,V[X-1][Y-1]+J)}return V[Q][Z]}import{basename as l6,extname as M8}from"path";import{z as n6}from"zod";var v2=E({name:"Read",displayName:"File Read",kind:"readonly",schema:n6.object({file_path:p.filePath({description:"File path to read (must be absolute)"}),offset:p.lineNumber({description:"Starting line number (0-based, text files only)"}).optional(),limit:p.lineLimit({description:"Number of lines to read (text files only)"}).optional(),encoding:p.encoding()}),description:{short:"Read files from the local filesystem",long:"Reads a file from the local filesystem. You can access any file directly by using this tool. Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.",usageNotes:["The file_path parameter must be an absolute path, not a relative path","By default, it reads up to 2000 lines starting from the beginning of the file","You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters","Any lines longer than 2000 characters will be truncated","Results are returned using cat -n format, with line numbers starting at 1","This tool allows reading images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as this is a multimodal LLM.","This tool can read PDF files (.pdf). PDFs are processed page by page, extracting both text and visual content for analysis.","This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.","This tool can only read files, not directories. To read a directory, use an ls command via the Bash tool.","You can call multiple tools in a single response. It is always better to speculatively read multiple potentially useful files in parallel.","You will regularly be asked to read screenshots. If the user provides a path to a screenshot, ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths.","If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents."],examples:[{description:"Read the entire file (recommended)",params:{file_path:"/path/to/file.ts"}},{description:"Read the first 100 lines",params:{file_path:"/path/to/file.txt",limit:100}},{description:"Read 100 lines starting at line 50 (large file)",params:{file_path:"/path/to/large-file.log",offset:50,limit:100}}],important:["file_path must be absolute","Prefer reading the entire file (omit offset and limit)","Use offset/limit only for very large files","Line numbers start at 1 (cat -n format)"]},async execute($,W){let{file_path:Q,offset:Z,limit:V,encoding:X="utf8"}=$,{updateOutput:Y,sessionId:J}=W,G=W.signal??new AbortController().signal;try{Y?.("Starting file read...");let B=H0(),K=g$();try{if(!await B.exists(Q))throw Error("File not found")}catch(z){return{success:!1,llmContent:`File not found: ${Q}`,displayContent:`❌ 文件不存在: ${Q}`,error:{type:"execution_error",message:`File not found: ${Q}`}}}if(typeof G.throwIfAborted==="function")G.throwIfAborted();if(J)await Z$.getInstance().recordFileRead(Q,J);let q=await B.stat(Q);if(q?.isDirectory)return{success:!1,llmContent:`Cannot read a directory: ${Q}`,displayContent:`❌ 无法读取目录: ${Q}`,error:{type:"execution_error",message:"Target is a directory, not a file"}};let w=M8(Q).toLowerCase(),O=a6(w),b=r6(w),U,F={file_path:Q,file_size:q?.size,file_type:w,last_modified:q?.mtime instanceof Date?q.mtime.toISOString():void 0,encoding:X,acp_mode:K};if(b&&X==="utf8"){if(K)Y?.("⚠️ 二进制文件通过本地读取(ACP 不支持)..."),F.acp_fallback=!0;else Y?.("检测到二进制文件,使用 base64 编码...");U=(await B.readBinaryFile(Q)).toString("base64"),F.encoding="base64",F.is_binary=!0}else if(O){if(K)Y?.("通过 IDE 读取文件...");U=await B.readTextFile(Q)}else{if(K)F.acp_fallback=!0;let z=await B.readBinaryFile(Q);if(X==="base64")U=z.toString("base64");else if(X==="binary")U=z.toString("binary");else U=z.toString("utf8")}if(typeof G.throwIfAborted==="function")G.throwIfAborted();if((Z!==void 0||V!==void 0)&&X==="utf8"&&O){let z=U.split(`
672
- `),y=Z||0,l=V!==void 0?y+V:z.length,j=z.slice(y,l);U=j.map((d,N$)=>{let R$=y+N$+1,R=d.length>2000?`${d.substring(0,2000)}...`:d;return`${R$.toString().padStart(6)}→${R}`}).join(`
673
- `),F.lines_read=j.length,F.total_lines=z.length,F.start_line=y+1,F.end_line=Math.min(l,z.length)}let A=l6(Q),D=F.lines_read||F.total_lines,N=D?`读取 ${D} 行从 ${A}`:`读取 ${A}`;F.summary=N;let C=s6(Q,F);return{success:!0,llmContent:U,displayContent:C,metadata:F}}catch(B){let K=B;if(K.name==="AbortError")return{success:!1,llmContent:"File read aborted",displayContent:"⚠️ 文件读取被用户中止",error:{type:"execution_error",message:"Operation aborted"}};return{success:!1,llmContent:`File read failed: ${K.message}`,displayContent:`❌ 读取文件失败: ${K.message}`,error:{type:"execution_error",message:K.message,details:K}}}},version:"2.0.0",category:"文件操作",tags:["file","io","read"],extractSignatureContent:($)=>$.file_path,abstractPermissionRule:($)=>{let W=M8($.file_path);return W?`**/*${W}`:"**/*"}});function a6($){return[".txt",".md",".js",".ts",".jsx",".tsx",".json",".xml",".html",".htm",".css",".scss",".sass",".less",".yml",".yaml",".toml",".ini",".cfg",".py",".rb",".php",".java",".cpp",".c",".h",".hpp",".rs",".go",".sh",".bash",".zsh",".fish",".ps1",".bat",".cmd",".sql",".graphql",".vue",".svelte",".astro",".dockerfile",".gitignore",".env"].includes($)||$===""}function r6($){return[".jpg",".jpeg",".png",".gif",".bmp",".svg",".ico",".webp",".mp3",".wav",".mp4",".avi",".mov",".wmv",".flv",".webm",".pdf",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".zip",".tar",".gz",".rar",".7z",".exe",".dll",".so",".ttf",".otf",".woff",".woff2",".eot"].includes($)}function s6($,W){let Q=`✅ 成功读取文件: ${$}`;if(W.file_size!==void 0&&typeof W.file_size==="number")Q+=` (${o6(W.file_size)})`;if(W.lines_read!==void 0)Q+=`
676
+ `);if(V.length===1)return Z.map((G,K)=>({text:G,lineNumber:K+1,similarity:C8(W.trim(),G.trim())})).filter((G)=>G.similarity>0.5).sort((G,K)=>K.similarity-G.similarity).slice(0,Q);let X=V.length,Y=[];for(let J=0;J<=Z.length-X;J++){let G=Z.slice(J,J+X).join(`
677
+ `),K=C8(W,G);if(K>0.5)Y.push({text:G,lineNumber:J+1,similarity:K})}return Y.sort((J,G)=>G.similarity-J.similarity).slice(0,Q)}function C8($,W){let Q=(w)=>w.trim().replace(/\s+/g," ").replace(/[\u201c\u201d"]/g,'"').replace(/[\u2018\u2019']/g,"'"),Z=Q($),V=Q(W);if(Z===V)return 1;let X=Z.length,Y=V.length;if(X===0)return Y===0?1:0;if(Y===0)return 0;let J=200,G=Z.substring(0,J),K=V.substring(0,J),B=r6(G,K),q=Math.max(G.length,K.length);return 1-B/q}function r6($,W){let Q=$.length,Z=W.length,V=Array(Q+1).fill(null).map(()=>Array(Z+1).fill(0));for(let X=0;X<=Q;X++)V[X][0]=X;for(let X=0;X<=Z;X++)V[0][X]=X;for(let X=1;X<=Q;X++)for(let Y=1;Y<=Z;Y++){let J=$[X-1]===W[Y-1]?0:1;V[X][Y]=Math.min(V[X-1][Y]+1,V[X][Y-1]+1,V[X-1][Y-1]+J)}return V[Q][Z]}import{basename as s6,extname as M8}from"path";import{z as o6}from"zod";var v2=E({name:"Read",displayName:"File Read",kind:"readonly",schema:o6.object({file_path:p.filePath({description:"File path to read (must be absolute)"}),offset:p.lineNumber({description:"Starting line number (0-based, text files only)"}).optional(),limit:p.lineLimit({description:"Number of lines to read (text files only)"}).optional(),encoding:p.encoding()}),description:{short:"Read files from the local filesystem",long:"Reads a file from the local filesystem. You can access any file directly by using this tool. Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.",usageNotes:["The file_path parameter must be an absolute path, not a relative path","By default, it reads up to 2000 lines starting from the beginning of the file","You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters","Any lines longer than 2000 characters will be truncated","Results are returned using cat -n format, with line numbers starting at 1","This tool allows reading images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as this is a multimodal LLM.","This tool can read PDF files (.pdf). PDFs are processed page by page, extracting both text and visual content for analysis.","This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.","This tool can only read files, not directories. To read a directory, use an ls command via the Bash tool.","You can call multiple tools in a single response. It is always better to speculatively read multiple potentially useful files in parallel.","You will regularly be asked to read screenshots. If the user provides a path to a screenshot, ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths.","If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents."],examples:[{description:"Read the entire file (recommended)",params:{file_path:"/path/to/file.ts"}},{description:"Read the first 100 lines",params:{file_path:"/path/to/file.txt",limit:100}},{description:"Read 100 lines starting at line 50 (large file)",params:{file_path:"/path/to/large-file.log",offset:50,limit:100}}],important:["file_path must be absolute","Prefer reading the entire file (omit offset and limit)","Use offset/limit only for very large files","Line numbers start at 1 (cat -n format)"]},async execute($,W){let{file_path:Q,offset:Z,limit:V,encoding:X="utf8"}=$,{updateOutput:Y,sessionId:J}=W,G=W.signal??new AbortController().signal;try{Y?.("Starting file read...");let K=F0(),B=m$();try{if(!await K.exists(Q))throw Error("File not found")}catch(N){return{success:!1,llmContent:`File not found: ${Q}`,displayContent:`❌ 文件不存在: ${Q}`,error:{type:"execution_error",message:`File not found: ${Q}`}}}if(typeof G.throwIfAborted==="function")G.throwIfAborted();if(J)await Z$.getInstance().recordFileRead(Q,J);let q=await K.stat(Q);if(q?.isDirectory)return{success:!1,llmContent:`Cannot read a directory: ${Q}`,displayContent:`❌ 无法读取目录: ${Q}`,error:{type:"execution_error",message:"Target is a directory, not a file"}};let w=M8(Q).toLowerCase(),O=t6(w),H=e6(w),U,A={file_path:Q,file_size:q?.size,file_type:w,last_modified:q?.mtime instanceof Date?q.mtime.toISOString():void 0,encoding:X,acp_mode:B};if(H&&X==="utf8"){if(B)Y?.("⚠️ 二进制文件通过本地读取(ACP 不支持)..."),A.acp_fallback=!0;else Y?.("检测到二进制文件,使用 base64 编码...");U=(await K.readBinaryFile(Q)).toString("base64"),A.encoding="base64",A.is_binary=!0}else if(O){if(B)Y?.("通过 IDE 读取文件...");U=await K.readTextFile(Q)}else{if(B)A.acp_fallback=!0;let N=await K.readBinaryFile(Q);if(X==="base64")U=N.toString("base64");else if(X==="binary")U=N.toString("binary");else U=N.toString("utf8")}if(typeof G.throwIfAborted==="function")G.throwIfAborted();if((Z!==void 0||V!==void 0)&&X==="utf8"&&O){let N=U.split(`
678
+ `),y=Z||0,i=V!==void 0?y+V:N.length,j=N.slice(y,i);U=j.map((d,z$)=>{let R$=y+z$+1,R=d.length>2000?`${d.substring(0,2000)}...`:d;return`${R$.toString().padStart(6)}→${R}`}).join(`
679
+ `),A.lines_read=j.length,A.total_lines=N.length,A.start_line=y+1,A.end_line=Math.min(i,N.length)}let D=s6(Q),b=A.lines_read||A.total_lines,z=b?`读取 ${b} 行从 ${D}`:`读取 ${D}`;A.summary=z;let C=$9(Q,A);return{success:!0,llmContent:U,displayContent:C,metadata:A}}catch(K){let B=K;if(B.name==="AbortError")return{success:!1,llmContent:"File read aborted",displayContent:"⚠️ 文件读取被用户中止",error:{type:"execution_error",message:"Operation aborted"}};return{success:!1,llmContent:`File read failed: ${B.message}`,displayContent:`❌ 读取文件失败: ${B.message}`,error:{type:"execution_error",message:B.message,details:B}}}},version:"2.0.0",category:"文件操作",tags:["file","io","read"],extractSignatureContent:($)=>$.file_path,abstractPermissionRule:($)=>{let W=M8($.file_path);return W?`**/*${W}`:"**/*"}});function t6($){return[".txt",".md",".js",".ts",".jsx",".tsx",".json",".xml",".html",".htm",".css",".scss",".sass",".less",".yml",".yaml",".toml",".ini",".cfg",".py",".rb",".php",".java",".cpp",".c",".h",".hpp",".rs",".go",".sh",".bash",".zsh",".fish",".ps1",".bat",".cmd",".sql",".graphql",".vue",".svelte",".astro",".dockerfile",".gitignore",".env"].includes($)||$===""}function e6($){return[".jpg",".jpeg",".png",".gif",".bmp",".svg",".ico",".webp",".mp3",".wav",".mp4",".avi",".mov",".wmv",".flv",".webm",".pdf",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".zip",".tar",".gz",".rar",".7z",".exe",".dll",".so",".ttf",".otf",".woff",".woff2",".eot"].includes($)}function $9($,W){let Q=`✅ 成功读取文件: ${$}`;if(W.file_size!==void 0&&typeof W.file_size==="number")Q+=` (${W9(W.file_size)})`;if(W.lines_read!==void 0)Q+=`
674
680
  \uD83D\uDCC4 读取了 ${W.lines_read} 行 (第${W.start_line}-${W.end_line}行,共${W.total_lines}行)`;if(W.is_binary)Q+=`
675
- \uD83D\uDD10 文件以 base64 编码显示`;return Q}function o6($){let W=["B","KB","MB","GB"],Q=$,Z=0;while(Q>=1024&&Z<W.length-1)Q/=1024,Z++;return`${Q.toFixed(1)}${W[Z]}`}import{promises as t6}from"fs";import{basename as e6,dirname as $9,extname as S8}from"path";import{z as y2}from"zod";var T2=E({name:"Write",displayName:"File Write",kind:"write",strict:!0,isConcurrencySafe:!1,schema:y2.object({file_path:p.filePath({description:"Absolute file path to write"}),content:y2.string().describe("Content to write"),encoding:p.encoding(),create_directories:y2.boolean().default(!0).describe("Automatically create missing parent directories")}),description:{short:"Writes a file to the local filesystem",long:"Writes a file to the local filesystem.",usageNotes:["This tool will overwrite the existing file if there is one at the provided path.","If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.","ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.","NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.","Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked."]},async execute($,W){let{file_path:Q,content:Z,encoding:V,create_directories:X}=$,{updateOutput:Y,sessionId:J,messageId:G}=W,B=W.signal??new AbortController().signal;try{Y?.("开始写入文件...");let K=H0(),q=g$();if(X){let z=$9(Q);try{await K.mkdir(z,{recursive:!0,mode:493})}catch(y){if(y.code!=="EEXIST")throw y}}if(typeof B.throwIfAborted==="function")B.throwIfAborted();let w=!1,O=null;try{if(w=await K.exists(Q),w&&V==="utf8")try{O=await K.readTextFile(Q)}catch(z){console.warn("[WriteTool] 读取旧文件内容失败:",z)}}catch{}if(w&&J){let z=Z$.getInstance();if(!z.hasFileBeenRead(Q,J))return{success:!1,llmContent:"If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.",displayContent:"\uD83D\uDCD6 我需要先读取文件内容,然后再进行写入。",error:{type:"validation_error",message:"File not read before write"},metadata:{requiresRead:!0}};let y=await z.checkExternalModification(Q);if(y.isExternal)return{success:!1,llmContent:`The file has been modified by an external program since you last read it. You must use the Read tool again to see the current content before writing.
681
+ \uD83D\uDD10 文件以 base64 编码显示`;return Q}function W9($){let W=["B","KB","MB","GB"],Q=$,Z=0;while(Q>=1024&&Z<W.length-1)Q/=1024,Z++;return`${Q.toFixed(1)}${W[Z]}`}import{promises as Q9}from"fs";import{basename as Z9,dirname as V9,extname as S8}from"path";import{z as y2}from"zod";var T2=E({name:"Write",displayName:"File Write",kind:"write",strict:!0,isConcurrencySafe:!1,schema:y2.object({file_path:p.filePath({description:"Absolute file path to write"}),content:y2.string().describe("Content to write"),encoding:p.encoding(),create_directories:y2.boolean().default(!0).describe("Automatically create missing parent directories")}),description:{short:"Writes a file to the local filesystem",long:"Writes a file to the local filesystem.",usageNotes:["This tool will overwrite the existing file if there is one at the provided path.","If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.","ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.","NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.","Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked."]},async execute($,W){let{file_path:Q,content:Z,encoding:V,create_directories:X}=$,{updateOutput:Y,sessionId:J,messageId:G}=W,K=W.signal??new AbortController().signal;try{Y?.("开始写入文件...");let B=F0(),q=m$();if(X){let N=V9(Q);try{await B.mkdir(N,{recursive:!0,mode:493})}catch(y){if(y.code!=="EEXIST")throw y}}if(typeof K.throwIfAborted==="function")K.throwIfAborted();let w=!1,O=null;try{if(w=await B.exists(Q),w&&V==="utf8")try{O=await B.readTextFile(Q)}catch(N){console.warn("[WriteTool] 读取旧文件内容失败:",N)}}catch{}if(w&&J){let N=Z$.getInstance();if(!N.hasFileBeenRead(Q,J))return{success:!1,llmContent:"If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.",displayContent:"\uD83D\uDCD6 我需要先读取文件内容,然后再进行写入。",error:{type:"validation_error",message:"File not read before write"},metadata:{requiresRead:!0}};let y=await N.checkExternalModification(Q);if(y.isExternal)return{success:!1,llmContent:`The file has been modified by an external program since you last read it. You must use the Read tool again to see the current content before writing.
676
682
 
677
683
  Details: ${y.message}`,displayContent:`❌ 写入失败:文件已被外部程序修改
678
684
 
679
685
  ${y.message}
680
686
 
681
- \uD83D\uDCA1 我需要重新读取文件内容后再写入`,error:{type:"validation_error",message:"File modified externally",details:{externalModification:y.message}}}}let b=!1;if(w&&J&&G)try{let z=new m0({sessionId:J});await z.initialize(),await z.createSnapshot(Q,G),b=!0}catch(z){console.warn("[WriteTool] 创建快照失败:",z)}if(typeof B.throwIfAborted==="function")B.throwIfAborted();if(V==="utf8"){if(q)Y?.("通过 IDE 写入文件...");await K.writeTextFile(Q,Z)}else{if(q)return{success:!1,llmContent:"Binary file writes are not supported in ACP mode. The IDE only supports text file operations. Please use encoding='utf8' for text files, or ask the user to write the file manually.",displayContent:`❌ ACP 模式不支持二进制文件写入
687
+ \uD83D\uDCA1 我需要重新读取文件内容后再写入`,error:{type:"validation_error",message:"File modified externally",details:{externalModification:y.message}}}}let H=!1;if(w&&J&&G)try{let N=new m0({sessionId:J});await N.initialize(),await N.createSnapshot(Q,G),H=!0}catch(N){console.warn("[WriteTool] 创建快照失败:",N)}if(typeof K.throwIfAborted==="function")K.throwIfAborted();if(V==="utf8"){if(q)Y?.("通过 IDE 写入文件...");await B.writeTextFile(Q,Z)}else{if(q)return{success:!1,llmContent:"Binary file writes are not supported in ACP mode. The IDE only supports text file operations. Please use encoding='utf8' for text files, or ask the user to write the file manually.",displayContent:`❌ ACP 模式不支持二进制文件写入
682
688
 
683
689
  当前通过 IDE 执行文件操作,但 IDE 仅支持文本文件。
684
690
 
685
- \uD83D\uDCA1 如果是文本文件,我会使用 encoding='utf8' 重试;如果必须写入二进制文件,需要在本地终端执行`,error:{type:"validation_error",message:"Binary writes not supported in ACP mode"}};let z;if(V==="base64")z=Buffer.from(Z,"base64");else if(V==="binary")z=Buffer.from(Z,"binary");else z=Buffer.from(Z,"utf8");await t6.writeFile(Q,z)}if(J)await Z$.getInstance().recordFileEdit(Q,J,"write");if(typeof B.throwIfAborted==="function")B.throwIfAborted();let U=await K.stat(Q),F=V==="utf8"?Z.split(`
686
- `).length:0,A=e6(Q),D=null;if(O&&V==="utf8"&&O!==Z){if(O.length<1048576&&Z.length<1048576)D=D8(O,Z,4)}let N={file_path:Q,content_size:Z.length,file_size:U?.size,encoding:V,created_directories:X,snapshot_created:b,session_id:J,message_id:G,last_modified:U?.mtime instanceof Date?U.mtime.toISOString():void 0,has_diff:!!D,summary:V==="utf8"?`写入 ${F} 行到 ${A}`:`写入 ${U?.size?v8(U.size):"unknown"} 到 ${A}`,kind:"edit",oldContent:O||"",newContent:V==="utf8"?Z:void 0},C=W9(Q,N,Z,D);return{success:!0,llmContent:{file_path:Q,size:U?.size,modified:U?.mtime instanceof Date?U.mtime.toISOString():void 0},displayContent:C,metadata:N}}catch(K){let q=K;if(q.name==="AbortError")return{success:!1,llmContent:"File write aborted",displayContent:"⚠️ 文件写入被用户中止",error:{type:"execution_error",message:"操作被中止"}};return{success:!1,llmContent:`File write failed: ${q.message}`,displayContent:`❌ 写入文件失败: ${q.message}`,error:{type:"execution_error",message:q.message,details:q}}}},version:"2.0.0",category:"文件操作",tags:["file","io","write","create"],extractSignatureContent:($)=>$.file_path,abstractPermissionRule:($)=>{let W=S8($.file_path);return W?`**/*${W}`:"**/*"}});function W9($,W,Q,Z){let V=`✅ 成功写入文件: ${$}`;if(W.file_size!==void 0)V+=` (${v8(W.file_size)})`;if(W.snapshot_created)V+=`
691
+ \uD83D\uDCA1 如果是文本文件,我会使用 encoding='utf8' 重试;如果必须写入二进制文件,需要在本地终端执行`,error:{type:"validation_error",message:"Binary writes not supported in ACP mode"}};let N;if(V==="base64")N=Buffer.from(Z,"base64");else if(V==="binary")N=Buffer.from(Z,"binary");else N=Buffer.from(Z,"utf8");await Q9.writeFile(Q,N)}if(J)await Z$.getInstance().recordFileEdit(Q,J,"write");if(typeof K.throwIfAborted==="function")K.throwIfAborted();let U=await B.stat(Q),A=V==="utf8"?Z.split(`
692
+ `).length:0,D=Z9(Q),b=null;if(O&&V==="utf8"&&O!==Z){if(O.length<1048576&&Z.length<1048576)b=b8(O,Z,4)}let z={file_path:Q,content_size:Z.length,file_size:U?.size,encoding:V,created_directories:X,snapshot_created:H,session_id:J,message_id:G,last_modified:U?.mtime instanceof Date?U.mtime.toISOString():void 0,has_diff:!!b,summary:V==="utf8"?`写入 ${A} 行到 ${D}`:`写入 ${U?.size?v8(U.size):"unknown"} 到 ${D}`,kind:"edit",oldContent:O||"",newContent:V==="utf8"?Z:void 0},C=X9(Q,z,Z,b);return{success:!0,llmContent:{file_path:Q,size:U?.size,modified:U?.mtime instanceof Date?U.mtime.toISOString():void 0},displayContent:C,metadata:z}}catch(B){let q=B;if(q.name==="AbortError")return{success:!1,llmContent:"File write aborted",displayContent:"⚠️ 文件写入被用户中止",error:{type:"execution_error",message:"操作被中止"}};return{success:!1,llmContent:`File write failed: ${q.message}`,displayContent:`❌ 写入文件失败: ${q.message}`,error:{type:"execution_error",message:q.message,details:q}}}},version:"2.0.0",category:"文件操作",tags:["file","io","write","create"],extractSignatureContent:($)=>$.file_path,abstractPermissionRule:($)=>{let W=S8($.file_path);return W?`**/*${W}`:"**/*"}});function X9($,W,Q,Z){let V=`✅ 成功写入文件: ${$}`;if(W.file_size!==void 0)V+=` (${v8(W.file_size)})`;if(W.snapshot_created)V+=`
687
693
  \uD83D\uDCF8 已创建快照 (可回滚)`;if(W.encoding!=="utf8")V+=`
688
- \uD83D\uDD10 使用编码: ${W.encoding}`;if(Z)V+=Z;if(Q&&W.encoding==="utf8"&&!Z){let X=Q9($,Q);if(X)V+=`
694
+ \uD83D\uDD10 使用编码: ${W.encoding}`;if(Z)V+=Z;if(Q&&W.encoding==="utf8"&&!Z){let X=Y9($,Q);if(X)V+=`
689
695
 
690
- `+X}return V}function Q9($,W){let Q=S8($).toLowerCase(),V={".ts":"typescript",".tsx":"tsx",".js":"javascript",".jsx":"jsx",".py":"python",".go":"go",".rs":"rust",".java":"java",".c":"c",".cpp":"cpp",".h":"c",".hpp":"cpp",".cs":"csharp",".rb":"ruby",".php":"php",".swift":"swift",".kt":"kotlin",".scala":"scala",".sh":"bash",".bash":"bash",".zsh":"zsh",".json":"json",".yaml":"yaml",".yml":"yaml",".toml":"toml",".xml":"xml",".html":"html",".css":"css",".scss":"scss",".sass":"sass",".less":"less",".md":"markdown",".sql":"sql",".graphql":"graphql",".proto":"protobuf"}[Q]||"",X=100,Y=5000,J=W,G=!1,B=W.split(`
691
- `);if(B.length>100)J=B.slice(0,100).join(`
692
- `),G=!0;if(J.length>5000)J=J.substring(0,5000),G=!0;let K=`\uD83D\uDCC4 文件内容:
696
+ `+X}return V}function Y9($,W){let Q=S8($).toLowerCase(),V={".ts":"typescript",".tsx":"tsx",".js":"javascript",".jsx":"jsx",".py":"python",".go":"go",".rs":"rust",".java":"java",".c":"c",".cpp":"cpp",".h":"c",".hpp":"cpp",".cs":"csharp",".rb":"ruby",".php":"php",".swift":"swift",".kt":"kotlin",".scala":"scala",".sh":"bash",".bash":"bash",".zsh":"zsh",".json":"json",".yaml":"yaml",".yml":"yaml",".toml":"toml",".xml":"xml",".html":"html",".css":"css",".scss":"scss",".sass":"sass",".less":"less",".md":"markdown",".sql":"sql",".graphql":"graphql",".proto":"protobuf"}[Q]||"",X=100,Y=5000,J=W,G=!1,K=W.split(`
697
+ `);if(K.length>100)J=K.slice(0,100).join(`
698
+ `),G=!0;if(J.length>5000)J=J.substring(0,5000),G=!0;let B=`\uD83D\uDCC4 文件内容:
693
699
 
694
- `;if(K+="```"+V+`
695
- `,K+=J,!J.endsWith(`
696
- `))K+=`
697
- `;if(K+="```",G)K+=`
700
+ `;if(B+="```"+V+`
701
+ `,B+=J,!J.endsWith(`
702
+ `))B+=`
703
+ `;if(B+="```",G)B+=`
698
704
 
699
- ⚠️ 内容已截断(完整文件共 ${B.length} 行,${W.length} 字符)`;return K}function v8($){let W=["B","KB","MB","GB"],Q=$,Z=0;while(Q>=1024&&Z<W.length-1)Q/=1024,Z++;return`${Q.toFixed(1)}${W[Z]}`}import*as z1 from"fs/promises";import{z as b0}from"zod";var P2=E({name:"NotebookEdit",displayName:"Notebook Edit",kind:"write",schema:b0.object({notebook_path:b0.string().describe("The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)"),cell_id:b0.string().optional().describe("The ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified."),new_source:b0.string().describe("The new source for the cell"),cell_type:b0.enum(["code","markdown"]).optional().describe("The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required."),edit_mode:b0.enum(["replace","insert","delete"]).optional().default("replace").describe("The type of edit to make (replace, insert, delete). Defaults to replace.")}),description:{short:"Completely replaces the contents of a specific cell in a Jupyter notebook",long:"Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The cell_number is 0-indexed. Use edit_mode=insert to add a new cell at the index specified by cell_number. Use edit_mode=delete to delete the cell at the index specified by cell_number."},async execute($,W){let{notebook_path:Q,cell_id:Z,new_source:V,cell_type:X,edit_mode:Y="replace"}=$;try{let J=await z1.readFile(Q,"utf-8"),G=JSON.parse(J);if(!G.cells||!Array.isArray(G.cells))return{success:!1,llmContent:"Invalid notebook format: no cells array found",displayContent:"Invalid notebook format",error:{type:"validation_error",message:"Invalid notebook format"}};let B=-1;if(Z){if(B=G.cells.findIndex((q)=>q.id===Z),B===-1&&Y!=="insert")return{success:!1,llmContent:`Cell with ID "${Z}" not found`,displayContent:"Cell not found",error:{type:"validation_error",message:`Cell ID "${Z}" not found`}}}switch(Y){case"replace":{if(B===-1)return{success:!1,llmContent:"Cell ID required for replace operation",displayContent:"Cell ID required",error:{type:"validation_error",message:"Cell ID required for replace"}};let q=G.cells[B];if(q.source=V.split(`
700
- `).map((w,O,b)=>O<b.length-1?w+`
705
+ ⚠️ 内容已截断(完整文件共 ${K.length} 行,${W.length} 字符)`;return B}function v8($){let W=["B","KB","MB","GB"],Q=$,Z=0;while(Q>=1024&&Z<W.length-1)Q/=1024,Z++;return`${Q.toFixed(1)}${W[Z]}`}import*as j1 from"fs/promises";import{z as H0}from"zod";var P2=E({name:"NotebookEdit",displayName:"Notebook Edit",kind:"write",schema:H0.object({notebook_path:H0.string().describe("The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)"),cell_id:H0.string().optional().describe("The ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified."),new_source:H0.string().describe("The new source for the cell"),cell_type:H0.enum(["code","markdown"]).optional().describe("The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required."),edit_mode:H0.enum(["replace","insert","delete"]).optional().default("replace").describe("The type of edit to make (replace, insert, delete). Defaults to replace.")}),description:{short:"Completely replaces the contents of a specific cell in a Jupyter notebook",long:"Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The cell_number is 0-indexed. Use edit_mode=insert to add a new cell at the index specified by cell_number. Use edit_mode=delete to delete the cell at the index specified by cell_number."},async execute($,W){let{notebook_path:Q,cell_id:Z,new_source:V,cell_type:X,edit_mode:Y="replace"}=$;try{let J=await j1.readFile(Q,"utf-8"),G=JSON.parse(J);if(!G.cells||!Array.isArray(G.cells))return{success:!1,llmContent:"Invalid notebook format: no cells array found",displayContent:"Invalid notebook format",error:{type:"validation_error",message:"Invalid notebook format"}};let K=-1;if(Z){if(K=G.cells.findIndex((q)=>q.id===Z),K===-1&&Y!=="insert")return{success:!1,llmContent:`Cell with ID "${Z}" not found`,displayContent:"Cell not found",error:{type:"validation_error",message:`Cell ID "${Z}" not found`}}}switch(Y){case"replace":{if(K===-1)return{success:!1,llmContent:"Cell ID required for replace operation",displayContent:"Cell ID required",error:{type:"validation_error",message:"Cell ID required for replace"}};let q=G.cells[K];if(q.source=V.split(`
706
+ `).map((w,O,H)=>O<H.length-1?w+`
701
707
  `:w),X)q.cell_type=X;break}case"insert":{if(!X)return{success:!1,llmContent:"cell_type is required for insert operation",displayContent:"cell_type required",error:{type:"validation_error",message:"cell_type required for insert"}};let q={cell_type:X,source:V.split(`
702
- `).map((O,b,U)=>b<U.length-1?O+`
703
- `:O),metadata:{},...X==="code"?{execution_count:null,outputs:[]}:{}},w=B===-1?0:B+1;G.cells.splice(w,0,q);break}case"delete":{if(B===-1)return{success:!1,llmContent:"Cell ID required for delete operation",displayContent:"Cell ID required",error:{type:"validation_error",message:"Cell ID required for delete"}};G.cells.splice(B,1);break}}await z1.writeFile(Q,JSON.stringify(G,null,2));let K=Y==="replace"?"replaced":Y==="insert"?"inserted":"deleted";return{success:!0,llmContent:`Successfully ${K} cell in ${Q}`,displayContent:`Cell ${K} in notebook`,metadata:{notebook_path:Q,edit_mode:Y,cell_id:Z}}}catch(J){let G=J instanceof Error?J.message:"Unknown error";return{success:!1,llmContent:`Failed to edit notebook: ${G}`,displayContent:"Notebook edit failed",error:{type:"execution_error",message:G}}}}});import{z as Z9}from"zod";var k2=E({name:"EnterPlanMode",displayName:"Enter Plan Mode",kind:"readonly",schema:Z9.object({}),description:{short:"Use this tool to enter plan mode for complex tasks requiring careful planning",long:`Use this tool when you encounter a complex task that requires careful planning and exploration before implementation. This tool transitions you into plan mode where you can thoroughly explore the codebase and design an implementation approach.
708
+ `).map((O,H,U)=>H<U.length-1?O+`
709
+ `:O),metadata:{},...X==="code"?{execution_count:null,outputs:[]}:{}},w=K===-1?0:K+1;G.cells.splice(w,0,q);break}case"delete":{if(K===-1)return{success:!1,llmContent:"Cell ID required for delete operation",displayContent:"Cell ID required",error:{type:"validation_error",message:"Cell ID required for delete"}};G.cells.splice(K,1);break}}await j1.writeFile(Q,JSON.stringify(G,null,2));let B=Y==="replace"?"replaced":Y==="insert"?"inserted":"deleted";return{success:!0,llmContent:`Successfully ${B} cell in ${Q}`,displayContent:`Cell ${B} in notebook`,metadata:{notebook_path:Q,edit_mode:Y,cell_id:Z}}}catch(J){let G=J instanceof Error?J.message:"Unknown error";return{success:!1,llmContent:`Failed to edit notebook: ${G}`,displayContent:"Notebook edit failed",error:{type:"execution_error",message:G}}}}});import{z as J9}from"zod";var k2=E({name:"EnterPlanMode",displayName:"Enter Plan Mode",kind:"readonly",schema:J9.object({}),description:{short:"Use this tool to enter plan mode for complex tasks requiring careful planning",long:`Use this tool when you encounter a complex task that requires careful planning and exploration before implementation. This tool transitions you into plan mode where you can thoroughly explore the codebase and design an implementation approach.
704
710
 
705
711
  ## When to Use This Tool
706
712
 
@@ -792,7 +798,7 @@ Begin your research now.`,displayContent:"✅ Entering Plan mode",metadata:{appr
792
798
 
793
799
  `+"Proceed with the task directly without planning phase. You can still use search tools to understand the codebase as needed, but implement the solution directly.",displayContent:"⚠️ Plan mode declined, proceeding directly",metadata:{approved:!1,enterPlanMode:!1}}}catch(Q){return{success:!1,llmContent:`Confirmation flow error: ${Q instanceof Error?Q.message:"Unknown error"}`,displayContent:"❌ Failed to request confirmation",error:{type:"execution_error",message:"Confirmation flow error"}}}return{success:!0,llmContent:`Plan mode requested but no interactive confirmation available.
794
800
 
795
- Proceeding with research phase. Use read-only tools to explore the codebase, then call ExitPlanMode with your implementation plan when ready.`,displayContent:"Plan mode (non-interactive)",metadata:{approved:null,enterPlanMode:!0}}}});import{promises as y8}from"node:fs";import{homedir as V9}from"node:os";import*as I2 from"node:path";import{z as T8}from"zod";var f2=E({name:"ExitPlanMode",displayName:"Exit Plan Mode",kind:"readonly",schema:T8.object({plan:T8.string().describe("The complete implementation plan in markdown format")}),description:{short:"Use this tool when you are in plan mode and have finished creating your plan and are ready for user approval",long:`Use this tool when you are in plan mode and have finished creating your implementation plan and are ready for user approval.
801
+ Proceeding with research phase. Use read-only tools to explore the codebase, then call ExitPlanMode with your implementation plan when ready.`,displayContent:"Plan mode (non-interactive)",metadata:{approved:null,enterPlanMode:!0}}}});import{promises as y8}from"node:fs";import{homedir as G9}from"node:os";import*as I2 from"node:path";import{z as T8}from"zod";var f2=E({name:"ExitPlanMode",displayName:"Exit Plan Mode",kind:"readonly",schema:T8.object({plan:T8.string().describe("The complete implementation plan in markdown format")}),description:{short:"Use this tool when you are in plan mode and have finished creating your plan and are ready for user approval",long:`Use this tool when you are in plan mode and have finished creating your implementation plan and are ready for user approval.
796
802
 
797
803
  ## \uD83D\uDEA8 PREREQUISITES (MUST be satisfied before calling)
798
804
 
@@ -827,7 +833,7 @@ Before using this tool, ensure your plan is clear and unambiguous. If there are
827
833
  1. Initial task: "Search for and understand the implementation of vim mode in the codebase" - Do not use the exit plan mode tool because you are not planning the implementation steps of a task.
828
834
  2. Initial task: "Help me implement yank mode for vim" - Use the exit plan mode tool after you have finished planning the implementation steps of the task.
829
835
  3. Initial task: "Add a new feature to handle user authentication" - If unsure about auth method (OAuth, JWT, etc.), use AskUserQuestion first, then use exit plan mode tool after clarifying the approach.
830
- `},async execute($,W){let Q=$.plan||"";if(Q&&W.sessionId)try{let Z=I2.join(V9(),".blade","plans");await y8.mkdir(Z,{recursive:!0,mode:493});let V=I2.join(Z,`plan_${W.sessionId}.md`);await y8.writeFile(V,Q,"utf-8")}catch(Z){console.warn("Failed to save plan file:",Z)}if(W.confirmationHandler)try{let Z=await W.confirmationHandler.requestConfirmation({type:"exitPlanMode",message:`The assistant has finished planning and is ready for your review.
836
+ `},async execute($,W){let Q=$.plan||"";if(Q&&W.sessionId)try{let Z=I2.join(G9(),".blade","plans");await y8.mkdir(Z,{recursive:!0,mode:493});let V=I2.join(Z,`plan_${W.sessionId}.md`);await y8.writeFile(V,Q,"utf-8")}catch(Z){console.warn("Failed to save plan file:",Z)}if(W.confirmationHandler)try{let Z=await W.confirmationHandler.requestConfirmation({type:"exitPlanMode",message:`The assistant has finished planning and is ready for your review.
831
837
 
832
838
  `+`⚠️ Before approving, please verify:
833
839
  `+`1. The assistant has written a detailed plan to the plan file
@@ -840,35 +846,35 @@ please reject and ask for a proper plan.`,details:"After approval, the assistant
840
846
  `+(Z.feedback||"No specific feedback provided.")+`
841
847
 
842
848
  The agent has stopped and control is returned to the user. The user can now provide additional information or clarification.`,displayContent:"⚠️ 方案被拒绝,等待用户补充信息",metadata:{approved:!1,shouldExitLoop:!0,feedback:Z.feedback,awaitingUserInput:!0}}}catch(Z){return{success:!1,llmContent:`Confirmation flow error: ${Z instanceof Error?Z.message:"Unknown error"}`,displayContent:"❌ Confirmation failed",error:{type:"execution_error",message:"Confirmation flow error"}}}return{success:!0,llmContent:`✅ Plan mode exit requested. No interactive confirmation available.
843
- `+"Proceeding with implementation.",displayContent:"Plan mode exit (non-interactive)",metadata:{approved:null}}}});import U9 from"fast-glob";import{stat as H9}from"node:fs/promises";import{join as b9,resolve as F9}from"path";import{z as R1}from"zod";import{existsSync as X9,readFileSync as Y9}from"node:fs";import{readFile as J9}from"node:fs/promises";import{dirname as G9,join as k8}from"node:path";import B9 from"fast-glob";import{LRUCache as K9}from"lru-cache";import c0 from"picomatch";function g0($){return $.replace(/\\/g,"/").split("/").filter(Boolean)}var W0=["node_modules",".git","dist","build","out",".next",".nuxt",".cache",".parcel-cache","coverage",".nyc_output",".idea",".vscode",".vs","bower_components","jspm_packages"],q9=["*.log","npm-debug.log*","yarn-debug.log*","pnpm-debug.log*","*.lock","package-lock.json","yarn.lock","pnpm-lock.yaml","*.tmp","*.temp","*.swp","*.bak","*~",".DS_Store","Thumbs.db","*.pid","*.seed"];function w9($){if(!X9($))return{patterns:[],negatePatterns:[]};try{let W=Y9($,"utf-8"),Q=[],Z=[];for(let V of W.split(`
844
- `)){let X=V.trim();if(!X||X.startsWith("#"))continue;if(X.startsWith("!"))Z.push(X.slice(1));else Q.push(X)}return{patterns:Q,negatePatterns:Z}}catch(W){return console.warn(`Failed to read .gitignore: ${W}`),{patterns:[],negatePatterns:[]}}}var P8=new K9({max:100,ttl:30000,updateAgeOnGet:!0});async function O9($,W){let Q=[...W0.map((G)=>`${G}/**`),...W?.scanIgnore??[]],Z=`${$}|${Q.join(",")}`,V=P8.get(Z);if(V)return V;let X=await B9("**/.gitignore",{cwd:$,dot:!0,onlyFiles:!0,followSymbolicLinks:!1,unique:!0,ignore:Q});X.sort((G,B)=>g0(G).length-g0(B).length);let Y=[];for(let G of X){let B=G9(G).replace(/\\/g,"/"),K=B==="."?"":B,w=(await J9(k8($,G),"utf-8")).split(`
845
- `);for(let O of w){let b=O.trim();if(!b||b.startsWith("#"))continue;let U=b.startsWith("!"),A=(U?b.slice(1):b).trim();if(!A)continue;let D="";if(A.startsWith("/")){let N=A.slice(1).replace(/\\/g,"/");if(D=(K?K+"/":"")+N,Y.push({type:U?"negate":"ignore",pattern:D}),A.endsWith("/")){let C=D+"**";Y.push({type:U?"negate":"ignore",pattern:C});let z=D.replace(/\/$/,"");if(z!==D)Y.push({type:U?"negate":"ignore",pattern:z})}}else{let N=A.replace(/\\/g,"/");if(N.includes("/")){if(D=(K?K+"/":"")+N,Y.push({type:U?"negate":"ignore",pattern:D}),N.endsWith("/")){let C=D+"**";Y.push({type:U?"negate":"ignore",pattern:C});let z=D.replace(/\/$/,"");if(z!==D)Y.push({type:U?"negate":"ignore",pattern:z})}}else D=(K?K+"/**/":"**/")+N,Y.push({type:U?"negate":"ignore",pattern:D})}}}let J=W?.cacheTTL??30000;return P8.set(Z,Y,{ttl:J}),Y}class N1{orderedRules=[];ignorePatterns=[];negatePatterns=[];constructor($={}){this.initialize($)}static async create($={}){let W=new N1({...$,useGitignore:!1}),{cwd:Q=process.cwd(),useGitignore:Z=!0,gitignoreScanMode:V="root",customScanIgnore:X=[],cacheTTL:Y}=$;if(Z&&V==="recursive"){let J=await O9(Q,{scanIgnore:X,cacheTTL:Y});for(let G of J)if(W.orderedRules.push({type:G.type,matcher:c0(G.pattern,{dot:!0})}),G.type==="ignore")W.ignorePatterns.push(G.pattern);else W.negatePatterns.push(G.pattern)}return W}initialize($){let{cwd:W=process.cwd(),useGitignore:Q=!0,useDefaults:Z=!0,customPatterns:V=[]}=$,X=[],Y=[];if(Z){let J=[...W0.map((G)=>`${G}/**`),...W0,...q9];X.push(...J);for(let G of J)this.orderedRules.push({type:"ignore",matcher:c0(G,{dot:!0})})}if(Q){let J=k8(W,".gitignore"),{patterns:G,negatePatterns:B}=w9(J);for(let K of G)this.orderedRules.push({type:"ignore",matcher:c0(K,{dot:!0})}),X.push(K);for(let K of B)this.orderedRules.push({type:"negate",matcher:c0(K,{dot:!0})}),Y.push(K)}X.push(...V);for(let J of V)this.orderedRules.push({type:"ignore",matcher:c0(J,{dot:!0})});this.ignorePatterns=X,this.negatePatterns=Y}shouldIgnore($){let W=$.replace(/\\/g,"/"),Q;for(let Z of this.orderedRules)if(Z.matcher(W))Q=Z.type==="ignore";return Q===!0}shouldIgnoreDirectory($){let W=$.replace(/\\/g,"/");return this.shouldIgnore(W)||this.shouldIgnore(`${W}/`)}filter($){return $.filter((W)=>!this.shouldIgnore(W))}getIgnorePatterns(){return this.ignorePatterns}getNegatePatterns(){return this.negatePatterns}}function x2($){let W=Error($);return W.name="AbortError",W}var h2=E({name:"Glob",displayName:"File Pattern Match",kind:"readonly",schema:R1.object({pattern:p.glob({description:"Glob pattern string (supports *, ?, ** wildcards)"}),path:R1.string().optional().describe("Search path (optional, defaults to cwd)"),max_results:p.positiveInt({description:"Maximum number of results"}).max(1000,"At most 1000 results can be returned").default(100),include_directories:R1.boolean().default(!1).describe("Include directories in results"),case_sensitive:R1.boolean().default(!1).describe("Case sensitive matching")}),description:{short:"Fast file pattern matching tool that works with any codebase size",long:'Fast file pattern matching tool that works with any codebase size. Supports glob patterns like "**/*.js" or "src/**/*.ts". Returns matching file paths sorted by modification time.',usageNotes:["Use this tool when you need to find files by name patterns","When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead","You can call multiple tools in a single response. It is always better to speculatively perform multiple searches in parallel if they are potentially useful."]},async execute($,W){let{pattern:Q,path:Z=process.cwd(),max_results:V,include_directories:X,case_sensitive:Y}=$,{updateOutput:J}=W,G=W.signal??new AbortController().signal;try{J?.(`Searching in ${Z} for pattern "${Q}"...`);let B=F9(Z);try{if(!(await H9(B)).isDirectory())return{success:!1,llmContent:`Search path must be a directory: ${B}`,displayContent:`❌ 搜索路径必须是目录: ${B}`,error:{type:"validation_error",message:"搜索路径必须是目录"}}}catch(A){if(A.code==="ENOENT")return{success:!1,llmContent:`Search path does not exist: ${B}`,displayContent:`❌ 搜索路径不存在: ${B}`,error:{type:"execution_error",message:"搜索路径不存在"}};throw A}G.throwIfAborted();let K=await N1.create({cwd:B,useGitignore:!0,useDefaults:!0,gitignoreScanMode:"recursive",customScanIgnore:[],cacheTTL:30000}),{matches:q,wasTruncated:w}=await A9(B,Q,{maxResults:V,includeDirectories:X,caseSensitive:Y,signal:G},K),O=D9(q),b={search_path:B,pattern:Q,total_matches:q.length,returned_matches:q.length,max_results:V,include_directories:X,case_sensitive:Y,truncated:w},U=_9(b),F;if(O.length>0)F=`${w?`Found at least ${O.length} file(s) matching "${Q}" (truncated)`:`Found ${O.length} file(s) matching "${Q}"`}:
849
+ `+"Proceeding with implementation.",displayContent:"Plan mode exit (non-interactive)",metadata:{approved:null}}}});import D9 from"fast-glob";import{stat as b9}from"node:fs/promises";import{join as _9,resolve as L9}from"path";import{z as z1}from"zod";import{existsSync as K9,readFileSync as B9}from"node:fs";import{readFile as q9}from"node:fs/promises";import{dirname as w9,join as k8}from"node:path";import O9 from"fast-glob";import{LRUCache as U9}from"lru-cache";import c0 from"picomatch";function g0($){return $.replace(/\\/g,"/").split("/").filter(Boolean)}var $0=["node_modules",".git","dist","build","out",".next",".nuxt",".cache",".parcel-cache","coverage",".nyc_output",".idea",".vscode",".vs","bower_components","jspm_packages"],F9=["*.log","npm-debug.log*","yarn-debug.log*","pnpm-debug.log*","*.lock","package-lock.json","yarn.lock","pnpm-lock.yaml","*.tmp","*.temp","*.swp","*.bak","*~",".DS_Store","Thumbs.db","*.pid","*.seed"];function H9($){if(!K9($))return{patterns:[],negatePatterns:[]};try{let W=B9($,"utf-8"),Q=[],Z=[];for(let V of W.split(`
850
+ `)){let X=V.trim();if(!X||X.startsWith("#"))continue;if(X.startsWith("!"))Z.push(X.slice(1));else Q.push(X)}return{patterns:Q,negatePatterns:Z}}catch(W){return console.warn(`Failed to read .gitignore: ${W}`),{patterns:[],negatePatterns:[]}}}var P8=new U9({max:100,ttl:30000,updateAgeOnGet:!0});async function A9($,W){let Q=[...$0.map((G)=>`${G}/**`),...W?.scanIgnore??[]],Z=`${$}|${Q.join(",")}`,V=P8.get(Z);if(V)return V;let X=await O9("**/.gitignore",{cwd:$,dot:!0,onlyFiles:!0,followSymbolicLinks:!1,unique:!0,ignore:Q});X.sort((G,K)=>g0(G).length-g0(K).length);let Y=[];for(let G of X){let K=w9(G).replace(/\\/g,"/"),B=K==="."?"":K,w=(await q9(k8($,G),"utf-8")).split(`
851
+ `);for(let O of w){let H=O.trim();if(!H||H.startsWith("#"))continue;let U=H.startsWith("!"),D=(U?H.slice(1):H).trim();if(!D)continue;let b="";if(D.startsWith("/")){let z=D.slice(1).replace(/\\/g,"/");if(b=(B?B+"/":"")+z,Y.push({type:U?"negate":"ignore",pattern:b}),D.endsWith("/")){let C=b+"**";Y.push({type:U?"negate":"ignore",pattern:C});let N=b.replace(/\/$/,"");if(N!==b)Y.push({type:U?"negate":"ignore",pattern:N})}}else{let z=D.replace(/\\/g,"/");if(z.includes("/")){if(b=(B?B+"/":"")+z,Y.push({type:U?"negate":"ignore",pattern:b}),z.endsWith("/")){let C=b+"**";Y.push({type:U?"negate":"ignore",pattern:C});let N=b.replace(/\/$/,"");if(N!==b)Y.push({type:U?"negate":"ignore",pattern:N})}}else b=(B?B+"/**/":"**/")+z,Y.push({type:U?"negate":"ignore",pattern:b})}}}let J=W?.cacheTTL??30000;return P8.set(Z,Y,{ttl:J}),Y}class N1{orderedRules=[];ignorePatterns=[];negatePatterns=[];constructor($={}){this.initialize($)}static async create($={}){let W=new N1({...$,useGitignore:!1}),{cwd:Q=process.cwd(),useGitignore:Z=!0,gitignoreScanMode:V="root",customScanIgnore:X=[],cacheTTL:Y}=$;if(Z&&V==="recursive"){let J=await A9(Q,{scanIgnore:X,cacheTTL:Y});for(let G of J)if(W.orderedRules.push({type:G.type,matcher:c0(G.pattern,{dot:!0})}),G.type==="ignore")W.ignorePatterns.push(G.pattern);else W.negatePatterns.push(G.pattern)}return W}initialize($){let{cwd:W=process.cwd(),useGitignore:Q=!0,useDefaults:Z=!0,customPatterns:V=[]}=$,X=[],Y=[];if(Z){let J=[...$0.map((G)=>`${G}/**`),...$0,...F9];X.push(...J);for(let G of J)this.orderedRules.push({type:"ignore",matcher:c0(G,{dot:!0})})}if(Q){let J=k8(W,".gitignore"),{patterns:G,negatePatterns:K}=H9(J);for(let B of G)this.orderedRules.push({type:"ignore",matcher:c0(B,{dot:!0})}),X.push(B);for(let B of K)this.orderedRules.push({type:"negate",matcher:c0(B,{dot:!0})}),Y.push(B)}X.push(...V);for(let J of V)this.orderedRules.push({type:"ignore",matcher:c0(J,{dot:!0})});this.ignorePatterns=X,this.negatePatterns=Y}shouldIgnore($){let W=$.replace(/\\/g,"/"),Q;for(let Z of this.orderedRules)if(Z.matcher(W))Q=Z.type==="ignore";return Q===!0}shouldIgnoreDirectory($){let W=$.replace(/\\/g,"/");return this.shouldIgnore(W)||this.shouldIgnore(`${W}/`)}filter($){return $.filter((W)=>!this.shouldIgnore(W))}getIgnorePatterns(){return this.ignorePatterns}getNegatePatterns(){return this.negatePatterns}}function x2($){let W=Error($);return W.name="AbortError",W}var h2=E({name:"Glob",displayName:"File Pattern Match",kind:"readonly",schema:z1.object({pattern:p.glob({description:"Glob pattern string (supports *, ?, ** wildcards)"}),path:z1.string().optional().describe("Search path (optional, defaults to cwd)"),max_results:p.positiveInt({description:"Maximum number of results"}).max(1000,"At most 1000 results can be returned").default(100),include_directories:z1.boolean().default(!1).describe("Include directories in results"),case_sensitive:z1.boolean().default(!1).describe("Case sensitive matching")}),description:{short:"Fast file pattern matching tool that works with any codebase size",long:'Fast file pattern matching tool that works with any codebase size. Supports glob patterns like "**/*.js" or "src/**/*.ts". Returns matching file paths sorted by modification time.',usageNotes:["Use this tool when you need to find files by name patterns","When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead","You can call multiple tools in a single response. It is always better to speculatively perform multiple searches in parallel if they are potentially useful."]},async execute($,W){let{pattern:Q,path:Z=process.cwd(),max_results:V,include_directories:X,case_sensitive:Y}=$,{updateOutput:J}=W,G=W.signal??new AbortController().signal;try{J?.(`Searching in ${Z} for pattern "${Q}"...`);let K=L9(Z);try{if(!(await b9(K)).isDirectory())return{success:!1,llmContent:`Search path must be a directory: ${K}`,displayContent:`❌ 搜索路径必须是目录: ${K}`,error:{type:"validation_error",message:"搜索路径必须是目录"}}}catch(D){if(D.code==="ENOENT")return{success:!1,llmContent:`Search path does not exist: ${K}`,displayContent:`❌ 搜索路径不存在: ${K}`,error:{type:"execution_error",message:"搜索路径不存在"}};throw D}G.throwIfAborted();let B=await N1.create({cwd:K,useGitignore:!0,useDefaults:!0,gitignoreScanMode:"recursive",customScanIgnore:[],cacheTTL:30000}),{matches:q,wasTruncated:w}=await j9(K,Q,{maxResults:V,includeDirectories:X,caseSensitive:Y,signal:G},B),O=N9(q),H={search_path:K,pattern:Q,total_matches:q.length,returned_matches:q.length,max_results:V,include_directories:X,case_sensitive:Y,truncated:w},U=z9(H),A;if(O.length>0)A=`${w?`Found at least ${O.length} file(s) matching "${Q}" (truncated)`:`Found ${O.length} file(s) matching "${Q}"`}:
846
852
 
847
- `+O.map((D)=>`- ${D.relative_path}`).join(`
853
+ `+O.map((b)=>`- ${b.relative_path}`).join(`
848
854
  `)+`
849
855
 
850
- Use the relative_path values above for Read/Edit operations.`;else F=`No files found matching "${Q}"`;return{success:!0,llmContent:F,displayContent:U,metadata:{...b,matches:O}}}catch(B){let K=B;if(K.name==="AbortError")return{success:!1,llmContent:"File search aborted",displayContent:"⚠️ 文件搜索被用户中止",error:{type:"execution_error",message:"操作被中止"}};return{success:!1,llmContent:`Search failed: ${K.message}`,displayContent:`❌ 搜索失败: ${K.message}`,error:{type:"execution_error",message:K.message,details:K}}}},version:"2.0.0",category:"搜索工具",tags:["file","search","glob","pattern","wildcard"],extractSignatureContent:($)=>$.pattern,abstractPermissionRule:()=>"*"});async function A9($,W,Q,Z){let V=Z.getIgnorePatterns(),X=[],Y=!1;return await new Promise((J,G)=>{if(Q.signal.aborted){G(x2("文件搜索被用户中止"));return}let B=U9.stream(W,{cwd:$,dot:!0,followSymbolicLinks:!1,unique:!0,caseSensitiveMatch:Q.caseSensitive,objectMode:!0,stats:!0,onlyFiles:!Q.includeDirectories,ignore:V}),K=!1,q=null,w=()=>{if(q){if(Q.signal.removeEventListener)Q.signal.removeEventListener("abort",q);else if("onabort"in Q.signal)Q.signal.onabort=null;q=null}},O=()=>{if(!K)K=!0,Y=!0,B.destroy(),w(),J({matches:X,wasTruncated:Y})},b=(U)=>{if(Q.signal.aborted){if(!K)K=!0,B.destroy(x2("文件搜索被用户中止"));return}if(X.length>=Q.maxResults){O();return}let F=U.path.replace(/\\/g,"/"),A=b9($,F);if(Z.shouldIgnore(F))return;let D=U.stats?U.stats.isDirectory():!1;if(D&&Z.shouldIgnoreDirectory(F))return;let N=U.stats&&U.stats.isFile()?U.stats.size:void 0,C=U.stats?U.stats.mtime.toISOString():void 0;if(X.push({path:A,relative_path:F,is_directory:D,size:N,modified:C}),X.length>=Q.maxResults)O()};if(B.on("data",b),q=()=>{if(!K)K=!0,w(),B.destroy(x2("文件搜索被用户中止"))},Q.signal.addEventListener)Q.signal.addEventListener("abort",q);else if("onabort"in Q.signal)Q.signal.onabort=q;B.once("error",(U)=>{if(!K)K=!0,w(),G(U)}),B.once("end",()=>{if(!K)K=!0,w(),J({matches:X,wasTruncated:Y})})})}function D9($){return $.sort((W,Q)=>{if(W.is_directory!==Q.is_directory)return W.is_directory?1:-1;if(W.modified&&Q.modified)return new Date(Q.modified).getTime()-new Date(W.modified).getTime();return W.relative_path.localeCompare(Q.relative_path)})}function _9($){let{search_path:W,pattern:Q,total_matches:Z,returned_matches:V,truncated:X}=$,Y;if(X)Y=`✅ 在 ${W} 中找到至少 ${Z} 个匹配 "${Q}" 的文件(已截断)`,Y+=`
851
- \uD83D\uDCCB 显示前 ${V} 个结果`;else Y=`✅ 在 ${W} 中找到 ${Z} 个匹配 "${Q}" 的文件`;return Y}import{execSync as p2,spawn as u2}from"child_process";import{existsSync as E1}from"fs";import{readdir as L9,readFile as j9}from"fs/promises";import{join as I8,relative as z9}from"path";import N9 from"picomatch";import{z as c$}from"zod";function R9(){let{platform:$,arch:W}=process,Q={"darwin-arm64":"darwin-arm64/rg","darwin-x64":"darwin-x64/rg","linux-arm64":"linux-arm64/rg","linux-x64":"linux-x64/rg","win32-x64":"win32-x64/rg.exe"},Z=`${$}-${W}`,V=Q[Z];if(!V)return null;let X=I8(process.cwd(),"vendor","ripgrep",V);if(E1(X))return X;try{let Y=new URL("../../../../vendor/ripgrep/"+V,import.meta.url).pathname;if(E1(Y))return Y}catch{}return null}function f8(){try{let W=process.platform==="win32"?"where rg":"command -v rg 2>/dev/null || which rg 2>/dev/null",Q=p2(W,{encoding:"utf8",stdio:["pipe","pipe","ignore"]}).split(/\r?\n/)[0].trim();if(Q)return Q}catch{}let $=R9();if($&&E1($))return $;try{let W=j0("@vscode/ripgrep");if(W?.rgPath&&E1(W.rgPath))return W.rgPath}catch{}return null}async function E9($){try{return p2("git rev-parse --git-dir",{cwd:$,stdio:"ignore"}),!0}catch{return!1}}function C9(){try{return p2("grep --version",{stdio:"ignore"}),!0}catch{return!1}}async function M9($,W,Q,Z){let V=f8();if(!V)throw Error("ripgrep not available");return new Promise((X,Y)=>{let J=u2(V,$,{stdio:["pipe","pipe","pipe"]}),G="",B="";J.stdout.on("data",(q)=>{G+=q.toString()}),J.stderr.on("data",(q)=>{B+=q.toString()}),J.on("close",(q)=>{X({stdout:G,stderr:B,exitCode:q||0})}),J.on("error",(q)=>{Y(q)});let K=()=>{J.kill("SIGTERM"),Y(Error("搜索被用户中止"))};Q.addEventListener("abort",K),J.on("close",()=>{Q.removeEventListener("abort",K)})})}async function S9($,W,Q,Z){let V=["grep","-n"];if(Q.caseInsensitive)V.push("-i");if(Q.contextLines!==void 0)V.push(`-C${Q.contextLines}`);if(V.push("-e",$),Q.glob)V.push("--",Q.glob);return new Promise((X,Y)=>{let J=u2("git",V,{cwd:W,stdio:["pipe","pipe","pipe"]}),G="",B="";J.stdout.on("data",(q)=>{G+=q.toString()}),J.stderr.on("data",(q)=>{B+=q.toString()}),J.on("close",(q)=>{X({stdout:G,stderr:B,exitCode:q||0})}),J.on("error",(q)=>{Y(q)});let K=()=>{J.kill("SIGTERM"),Y(Error("搜索被用户中止"))};Z.addEventListener("abort",K),J.on("close",()=>{Z.removeEventListener("abort",K)})})}async function v9($,W,Q,Z){let V=["-rn"];if(Q.caseInsensitive)V.push("-i");if(Q.contextLines!==void 0)V.push(`-C${Q.contextLines}`);for(let X of W0)V.push("--exclude-dir="+X.replace(/^\./,""));return V.push("-e",$,W),new Promise((X,Y)=>{let J=u2("grep",V,{stdio:["pipe","pipe","pipe"]}),G="",B="";J.stdout.on("data",(q)=>{G+=q.toString()}),J.stderr.on("data",(q)=>{B+=q.toString()}),J.on("close",(q)=>{X({stdout:G,stderr:B,exitCode:q||0})}),J.on("error",(q)=>{Y(q)});let K=()=>{J.kill("SIGTERM"),Y(Error("搜索被用户中止"))};Z.addEventListener("abort",K),J.on("close",()=>{Z.removeEventListener("abort",K)})})}async function y9($,W,Q,Z){let V=[],X=new RegExp($,Q.caseInsensitive?"gi":"g"),Y=await T9(W,Z),J=0;for(let G of Y){if(Z.throwIfAborted(),x8(G))continue;if(Q.glob&&!P9(G,Q.glob))continue;try{(await j9(G,"utf-8")).split(`
852
- `).forEach((q,w)=>{if(X.test(q))V.push({file_path:z9(W,G),line_number:w+1,content:q})}),J++}catch(B){}}return{matches:V,totalFiles:J}}async function T9($,W){let Q=[];async function Z(V){W.throwIfAborted();try{let X=await L9(V,{withFileTypes:!0});for(let Y of X){W.throwIfAborted();let J=I8(V,Y.name);if(Y.isDirectory()){if(!x8(J))await Z(J)}else if(Y.isFile())Q.push(J)}}catch(X){}}return await Z($),Q}function x8($){for(let W of W0)if($.includes(W))return!0;return!1}function P9($,W){return N9(W)($)}function k9($){let W=[];if($.case_insensitive)W.push("-i");if($.multiline)W.push("-U","--multiline-dotall");switch($.output_mode){case"files_with_matches":W.push("-l");break;case"count":W.push("-c");break;case"content":if($.line_numbers)W.push("-n");break}if($.context!==void 0&&$.output_mode==="content")W.push("-C",$.context.toString());else{if($.context_before!==void 0&&$.output_mode==="content")W.push("-B",$.context_before.toString());if($.context_after!==void 0&&$.output_mode==="content")W.push("-A",$.context_after.toString())}if($.type)W.push("--type",$.type);for(let Q of W0)W.push("--glob",`!${Q}/**`);if($.glob)W.push("--glob",$.glob);if($.head_limit!==void 0){let Q=($.offset??0)+$.head_limit;W.push("-m",Q.toString())}return W.push($.pattern),W.push($.path),W}function I9($,W){if(!$.trim())return[];let Q=$.trim().split(`
853
- `),Z=[];switch(W){case"files_with_matches":return Q.map((V)=>({file_path:V.trim()}));case"count":return Q.map((V)=>{let[X,Y]=V.split(":");return{file_path:X,count:parseInt(Y,10)}});case"content":for(let V of Q){let X=f9(V);if(X)Z.push(X)}return Z;default:return[]}}function f9($){let W=$.indexOf(":");if(W===-1)return null;let Q=$.substring(0,W),Z=$.substring(W+1),V=Z.indexOf(":");if(V!==-1&&/^\d+$/.test(Z.substring(0,V))){let X=parseInt(Z.substring(0,V),10),Y=Z.substring(V+1);return{file_path:Q,line_number:X,content:Y}}else return{file_path:Q,content:Z}}function x9($){let{search_pattern:W,search_path:Q,output_mode:Z,total_matches:V,strategy:X}=$,Y=`✅ 在 ${Q} 中搜索 "${W}"`;if(X)Y+=`
856
+ Use the relative_path values above for Read/Edit operations.`;else A=`No files found matching "${Q}"`;return{success:!0,llmContent:A,displayContent:U,metadata:{...H,matches:O}}}catch(K){let B=K;if(B.name==="AbortError")return{success:!1,llmContent:"File search aborted",displayContent:"⚠️ 文件搜索被用户中止",error:{type:"execution_error",message:"操作被中止"}};return{success:!1,llmContent:`Search failed: ${B.message}`,displayContent:`❌ 搜索失败: ${B.message}`,error:{type:"execution_error",message:B.message,details:B}}}},version:"2.0.0",category:"搜索工具",tags:["file","search","glob","pattern","wildcard"],extractSignatureContent:($)=>$.pattern,abstractPermissionRule:()=>"*"});async function j9($,W,Q,Z){let V=Z.getIgnorePatterns(),X=[],Y=!1;return await new Promise((J,G)=>{if(Q.signal.aborted){G(x2("文件搜索被用户中止"));return}let K=D9.stream(W,{cwd:$,dot:!0,followSymbolicLinks:!1,unique:!0,caseSensitiveMatch:Q.caseSensitive,objectMode:!0,stats:!0,onlyFiles:!Q.includeDirectories,ignore:V}),B=!1,q=null,w=()=>{if(q){if(Q.signal.removeEventListener)Q.signal.removeEventListener("abort",q);else if("onabort"in Q.signal)Q.signal.onabort=null;q=null}},O=()=>{if(!B)B=!0,Y=!0,K.destroy(),w(),J({matches:X,wasTruncated:Y})},H=(U)=>{if(Q.signal.aborted){if(!B)B=!0,K.destroy(x2("文件搜索被用户中止"));return}if(X.length>=Q.maxResults){O();return}let A=U.path.replace(/\\/g,"/"),D=_9($,A);if(Z.shouldIgnore(A))return;let b=U.stats?U.stats.isDirectory():!1;if(b&&Z.shouldIgnoreDirectory(A))return;let z=U.stats&&U.stats.isFile()?U.stats.size:void 0,C=U.stats?U.stats.mtime.toISOString():void 0;if(X.push({path:D,relative_path:A,is_directory:b,size:z,modified:C}),X.length>=Q.maxResults)O()};if(K.on("data",H),q=()=>{if(!B)B=!0,w(),K.destroy(x2("文件搜索被用户中止"))},Q.signal.addEventListener)Q.signal.addEventListener("abort",q);else if("onabort"in Q.signal)Q.signal.onabort=q;K.once("error",(U)=>{if(!B)B=!0,w(),G(U)}),K.once("end",()=>{if(!B)B=!0,w(),J({matches:X,wasTruncated:Y})})})}function N9($){return $.sort((W,Q)=>{if(W.is_directory!==Q.is_directory)return W.is_directory?1:-1;if(W.modified&&Q.modified)return new Date(Q.modified).getTime()-new Date(W.modified).getTime();return W.relative_path.localeCompare(Q.relative_path)})}function z9($){let{search_path:W,pattern:Q,total_matches:Z,returned_matches:V,truncated:X}=$,Y;if(X)Y=`✅ 在 ${W} 中找到至少 ${Z} 个匹配 "${Q}" 的文件(已截断)`,Y+=`
857
+ \uD83D\uDCCB 显示前 ${V} 个结果`;else Y=`✅ 在 ${W} 中找到 ${Z} 个匹配 "${Q}" 的文件`;return Y}import{execSync as p2,spawn as u2}from"child_process";import{existsSync as R1}from"fs";import{readdir as R9,readFile as E9}from"fs/promises";import{join as I8,relative as C9}from"path";import M9 from"picomatch";import{z as g$}from"zod";function S9(){let{platform:$,arch:W}=process,Q={"darwin-arm64":"darwin-arm64/rg","darwin-x64":"darwin-x64/rg","linux-arm64":"linux-arm64/rg","linux-x64":"linux-x64/rg","win32-x64":"win32-x64/rg.exe"},Z=`${$}-${W}`,V=Q[Z];if(!V)return null;let X=I8(process.cwd(),"vendor","ripgrep",V);if(R1(X))return X;try{let Y=new URL("../../../../vendor/ripgrep/"+V,import.meta.url).pathname;if(R1(Y))return Y}catch{}return null}function f8(){try{let W=process.platform==="win32"?"where rg":"command -v rg 2>/dev/null || which rg 2>/dev/null",Q=p2(W,{encoding:"utf8",stdio:["pipe","pipe","ignore"]}).split(/\r?\n/)[0].trim();if(Q)return Q}catch{}let $=S9();if($&&R1($))return $;try{let W=j0("@vscode/ripgrep");if(W?.rgPath&&R1(W.rgPath))return W.rgPath}catch{}return null}async function v9($){try{return p2("git rev-parse --git-dir",{cwd:$,stdio:"ignore"}),!0}catch{return!1}}function y9(){try{return p2("grep --version",{stdio:"ignore"}),!0}catch{return!1}}async function T9($,W,Q,Z){let V=f8();if(!V)throw Error("ripgrep not available");return new Promise((X,Y)=>{let J=u2(V,$,{stdio:["pipe","pipe","pipe"]}),G="",K="";J.stdout.on("data",(q)=>{G+=q.toString()}),J.stderr.on("data",(q)=>{K+=q.toString()}),J.on("close",(q)=>{X({stdout:G,stderr:K,exitCode:q||0})}),J.on("error",(q)=>{Y(q)});let B=()=>{J.kill("SIGTERM"),Y(Error("搜索被用户中止"))};Q.addEventListener("abort",B),J.on("close",()=>{Q.removeEventListener("abort",B)})})}async function P9($,W,Q,Z){let V=["grep","-n"];if(Q.caseInsensitive)V.push("-i");if(Q.contextLines!==void 0)V.push(`-C${Q.contextLines}`);if(V.push("-e",$),Q.glob)V.push("--",Q.glob);return new Promise((X,Y)=>{let J=u2("git",V,{cwd:W,stdio:["pipe","pipe","pipe"]}),G="",K="";J.stdout.on("data",(q)=>{G+=q.toString()}),J.stderr.on("data",(q)=>{K+=q.toString()}),J.on("close",(q)=>{X({stdout:G,stderr:K,exitCode:q||0})}),J.on("error",(q)=>{Y(q)});let B=()=>{J.kill("SIGTERM"),Y(Error("搜索被用户中止"))};Z.addEventListener("abort",B),J.on("close",()=>{Z.removeEventListener("abort",B)})})}async function k9($,W,Q,Z){let V=["-rn"];if(Q.caseInsensitive)V.push("-i");if(Q.contextLines!==void 0)V.push(`-C${Q.contextLines}`);for(let X of $0)V.push("--exclude-dir="+X.replace(/^\./,""));return V.push("-e",$,W),new Promise((X,Y)=>{let J=u2("grep",V,{stdio:["pipe","pipe","pipe"]}),G="",K="";J.stdout.on("data",(q)=>{G+=q.toString()}),J.stderr.on("data",(q)=>{K+=q.toString()}),J.on("close",(q)=>{X({stdout:G,stderr:K,exitCode:q||0})}),J.on("error",(q)=>{Y(q)});let B=()=>{J.kill("SIGTERM"),Y(Error("搜索被用户中止"))};Z.addEventListener("abort",B),J.on("close",()=>{Z.removeEventListener("abort",B)})})}async function I9($,W,Q,Z){let V=[],X=new RegExp($,Q.caseInsensitive?"gi":"g"),Y=await f9(W,Z),J=0;for(let G of Y){if(Z.throwIfAborted(),x8(G))continue;if(Q.glob&&!x9(G,Q.glob))continue;try{(await E9(G,"utf-8")).split(`
858
+ `).forEach((q,w)=>{if(X.test(q))V.push({file_path:C9(W,G),line_number:w+1,content:q})}),J++}catch(K){}}return{matches:V,totalFiles:J}}async function f9($,W){let Q=[];async function Z(V){W.throwIfAborted();try{let X=await R9(V,{withFileTypes:!0});for(let Y of X){W.throwIfAborted();let J=I8(V,Y.name);if(Y.isDirectory()){if(!x8(J))await Z(J)}else if(Y.isFile())Q.push(J)}}catch(X){}}return await Z($),Q}function x8($){for(let W of $0)if($.includes(W))return!0;return!1}function x9($,W){return M9(W)($)}function h9($){let W=[];if($.case_insensitive)W.push("-i");if($.multiline)W.push("-U","--multiline-dotall");switch($.output_mode){case"files_with_matches":W.push("-l");break;case"count":W.push("-c");break;case"content":if($.line_numbers)W.push("-n");break}if($.context!==void 0&&$.output_mode==="content")W.push("-C",$.context.toString());else{if($.context_before!==void 0&&$.output_mode==="content")W.push("-B",$.context_before.toString());if($.context_after!==void 0&&$.output_mode==="content")W.push("-A",$.context_after.toString())}if($.type)W.push("--type",$.type);for(let Q of $0)W.push("--glob",`!${Q}/**`);if($.glob)W.push("--glob",$.glob);if($.head_limit!==void 0){let Q=($.offset??0)+$.head_limit;W.push("-m",Q.toString())}return W.push($.pattern),W.push($.path),W}function p9($,W){if(!$.trim())return[];let Q=$.trim().split(`
859
+ `),Z=[];switch(W){case"files_with_matches":return Q.map((V)=>({file_path:V.trim()}));case"count":return Q.map((V)=>{let[X,Y]=V.split(":");return{file_path:X,count:parseInt(Y,10)}});case"content":for(let V of Q){let X=u9(V);if(X)Z.push(X)}return Z;default:return[]}}function u9($){let W=$.indexOf(":");if(W===-1)return null;let Q=$.substring(0,W),Z=$.substring(W+1),V=Z.indexOf(":");if(V!==-1&&/^\d+$/.test(Z.substring(0,V))){let X=parseInt(Z.substring(0,V),10),Y=Z.substring(V+1);return{file_path:Q,line_number:X,content:Y}}else return{file_path:Q,content:Z}}function d9($){let{search_pattern:W,search_path:Q,output_mode:Z,total_matches:V,strategy:X}=$,Y=`✅ 在 ${Q} 中搜索 "${W}"`;if(X)Y+=`
854
860
  \uD83D\uDD27 使用策略: ${X}`;switch(Z){case"files_with_matches":Y+=`
855
861
  \uD83D\uDCC1 找到 ${V} 个包含匹配内容的文件`;break;case"count":Y+=`
856
862
  \uD83D\uDD22 统计了 ${V} 个文件的匹配数量`;break;case"content":Y+=`
857
- \uD83D\uDCDD 找到 ${V} 个匹配行`;break}return Y}var d2=E({name:"Grep",displayName:"内容搜索",kind:"readonly",schema:c$.object({pattern:p.pattern({description:"The regular expression pattern to search for in file contents"}),path:c$.string().optional().describe("File or directory to search in (rg PATH). Defaults to current working directory"),glob:c$.string().optional().describe('Glob pattern to filter files (e.g. "*.js", "*.{ts,tsx}") - maps to rg --glob'),type:c$.string().optional().describe("File type to search (rg --type). Common types: js, py, rust, go, java, etc. More efficient than include for standard file types"),output_mode:c$.enum(["content","files_with_matches","count"]).default("files_with_matches").describe('Output mode: "content" shows matching lines (supports -A/-B/-C context, -n line numbers, head_limit), "files_with_matches" shows file paths (supports head_limit), "count" shows match counts (supports head_limit). Defaults to "files_with_matches"'),"-i":c$.boolean().optional().describe("Case insensitive search (rg -i)"),"-n":c$.boolean().default(!0).describe('Show line numbers in output (rg -n). Requires output_mode: "content", ignored otherwise. Defaults to true'),"-B":p.nonNegativeInt().optional().describe('Number of lines to show before each match (rg -B). Requires output_mode: "content", ignored otherwise'),"-A":p.nonNegativeInt().optional().describe('Number of lines to show after each match (rg -A). Requires output_mode: "content", ignored otherwise'),"-C":p.nonNegativeInt().optional().describe('Number of lines to show before and after each match (rg -C). Requires output_mode: "content", ignored otherwise'),head_limit:p.positiveInt().optional().describe('Limit output to first N lines/entries, equivalent to "| head -N". Works across all output modes: content (limits output lines), files_with_matches (limits file paths), count (limits count entries). Defaults based on "cap" experiment value: 0 (unlimited), 20, or 100'),offset:p.nonNegativeInt().optional().describe('Skip first N lines/entries before applying head_limit, equivalent to "| tail -n +N | head -N". Works across all output modes. Defaults to 0'),multiline:c$.boolean().default(!1).describe("Enable multiline mode where . matches newlines and patterns can span lines (rg -U --multiline-dotall). Default: false")}),description:{short:"A powerful search tool built on ripgrep",long:'A powerful search tool built on ripgrep\n\n Usage:\n - ALWAYS use Grep for search tasks. NEVER invoke `grep` or `rg` as a Bash command. The Grep tool has been optimized for correct permissions and access.\n - Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")\n - Filter files with glob parameter (e.g., "*.js", "**/*.tsx") or type parameter (e.g., "js", "py", "rust")\n - Output modes: "content" shows matching lines, "files_with_matches" shows only file paths (default), "count" shows match counts\n - Use Task tool for open-ended searches requiring multiple rounds\n - Pattern syntax: Uses ripgrep (not grep) - literal braces need escaping (use `interface\\{\\}` to find `interface{}` in Go code)\n - Multiline matching: By default patterns match within single lines only. For cross-line patterns like `struct \\{[\\s\\S]*?field`, use `multiline: true`\n'},async execute($,W){let{pattern:Q,path:Z=process.cwd(),glob:V,type:X,output_mode:Y,"-i":J,"-n":G=!0,"-B":B,"-A":K,"-C":q,head_limit:w,offset:O,multiline:b}=$,{updateOutput:U}=W,F=W.signal??new AbortController().signal;try{U?.(`使用智能搜索策略查找模式 "${Q}"...`);let A=null,D="ripgrep",N=[],C=f8();if(C)try{U?.(`\uD83D\uDE80 使用 ripgrep (${C})`);let j=k9({pattern:Q,path:Z,glob:V,type:X,output_mode:Y,case_insensitive:J??!1,line_numbers:G,context_before:B,context_after:K,context:q,head_limit:w,offset:O,multiline:b??!1});A=await M9(j,Y,F,U),D="ripgrep"}catch{U?.("⚠️ ripgrep 失败,尝试降级策略..."),A=null}if(!A&&await E9(Z))try{U?.("\uD83D\uDCE6 使用 git grep"),A=await S9(Q,Z,{caseInsensitive:J??!1,glob:V,contextLines:q},F),D="git-grep"}catch{U?.("⚠️ git grep 失败,继续尝试其他策略..."),A=null}if(!A&&C9())try{U?.("\uD83D\uDD27 使用系统 grep"),A=await v9(Q,Z,{caseInsensitive:J??!1,contextLines:q},F),D="system-grep"}catch{U?.("⚠️ 系统 grep 失败,使用纯 JavaScript 实现..."),A=null}if(!A)U?.("\uD83D\uDCA1 使用纯 JavaScript 搜索实现"),N=(await y9(Q,Z,{caseInsensitive:J??!1,glob:V,multiline:b??!1},F)).matches,D="fallback",A={stdout:"",stderr:"",exitCode:0};else N=I9(A.stdout,Y);let z=N.length;if(O!==void 0&&O>0)N=N.slice(O);if(w!==void 0&&N.length>w)N=N.slice(0,w);let y={search_pattern:Q,search_path:Z,output_mode:Y,case_insensitive:J??!1,total_matches:N.length,original_total:z,offset:O,head_limit:w,strategy:D,exit_code:A?.exitCode};if(A&&A.exitCode!==0&&A.stderr)return{success:!1,llmContent:`Search execution failed: ${A.stderr}`,displayContent:`❌ 搜索执行失败: ${A.stderr}`,error:{type:"execution_error",message:A.stderr}};let l=x9(y);return{success:!0,llmContent:N,displayContent:l,metadata:y}}catch(A){let D=A;if(D.name==="AbortError")return{success:!1,llmContent:"Search aborted",displayContent:"⚠️ 搜索被用户中止",error:{type:"execution_error",message:"操作被中止"}};return{success:!1,llmContent:`Search failed: ${D.message}`,displayContent:`❌ 搜索失败: ${D.message}`,error:{type:"execution_error",message:D.message,details:D}}}},version:"3.0.0",category:"搜索工具",tags:["search","grep","ripgrep","regex","text","fallback"],extractSignatureContent:($)=>$.pattern,abstractPermissionRule:()=>"*"});import{spawn as m9}from"child_process";import{randomUUID as g9}from"crypto";import{z as m2}from"zod";import{spawn as h9}from"child_process";import{randomUUID as p9}from"crypto";class J${static instance=null;processes=new Map;static getInstance(){if(!J$.instance)J$.instance=new J$;return J$.instance}startBackgroundProcess($){let W=`bash_${p9()}`,Q={};for(let[X,Y]of Object.entries({...process.env,...$.env,BLADE_CLI:"1"}))if(Y!==void 0)Q[X]=Y;let Z=h9("bash",["-c",$.command],{cwd:$.cwd||process.cwd(),env:Q,stdio:["ignore","pipe","pipe"]}),V={id:W,command:$.command,sessionId:$.sessionId,cwd:$.cwd,env:$.env,process:Z,pid:Z.pid,status:"running",startTime:Date.now(),pendingStdout:"",pendingStderr:""};return Z.stdout?.setEncoding("utf8"),Z.stderr?.setEncoding("utf8"),Z.stdout?.on("data",(X)=>{V.pendingStdout+=X.toString()}),Z.stderr?.on("data",(X)=>{V.pendingStderr+=X.toString()}),Z.on("close",(X,Y)=>{V.status=V.status==="killed"?"killed":"exited",V.exitCode=X,V.signal=Y,V.endTime=Date.now(),V.process=void 0}),Z.on("error",(X)=>{V.status="error",V.errorMessage=X.message,V.endTime=Date.now(),V.process=void 0,V.pendingStderr+=`
858
- [error] ${X.message}`}),this.processes.set(W,V),V}consumeOutput($){let W=this.processes.get($);if(!W)return;let Q={id:W.id,command:W.command,status:W.status,stdout:W.pendingStdout,stderr:W.pendingStderr,exitCode:W.exitCode,signal:W.signal,pid:W.pid,startedAt:W.startTime,endedAt:W.endTime,errorMessage:W.errorMessage};return W.pendingStdout="",W.pendingStderr="",Q}getProcess($){return this.processes.get($)}kill($){let W=this.processes.get($);if(!W)return;if(W.status!=="running"||!W.process)return{success:!1,alreadyExited:!0,status:W.status,pid:W.pid,exitCode:W.exitCode,signal:W.signal};if(!W.process.kill("SIGTERM"))return{success:!1,alreadyExited:!1,status:W.status,pid:W.pid,exitCode:W.exitCode,signal:W.signal};return W.status="killed",W.endTime=Date.now(),W.process=void 0,{success:!0,alreadyExited:!1,status:W.status,pid:W.pid,exitCode:W.exitCode,signal:W.signal}}killAll(){for(let[$,W]of this.processes)if(W.status==="running"&&W.process)try{W.process.kill("SIGTERM"),W.status="killed",W.endTime=Date.now(),W.process=void 0}catch{}this.processes.clear()}}var C1={maxLines:30,maxChars:3000,keepHead:10,keepTail:10,summarize:!0},Q0={maxLines:100,maxChars:1e4,keepHead:40,keepTail:40,summarize:!0},h8={maxLines:200,maxChars:20000,keepHead:80,keepTail:80,summarize:!1},u9={maxLines:150,maxChars:15000,keepHead:50,keepTail:50,summarize:!0},d9=[{pattern:/^git\s+(rm|add)\s+(-r|--cached|-rf|-f)?\s*/i,config:C1,summaryTemplate:($)=>`Successfully processed ${$} files`},{pattern:/^(npm|pnpm|yarn|bun)\s+(install|i|add|remove|uninstall)/i,config:C1,summaryTemplate:($)=>`Package operation completed (${$} lines of output)`},{pattern:/^(npm|pnpm|yarn|bun)\s+(run|exec)\s+(build|compile|bundle)/i,config:Q0,summaryTemplate:($)=>`Build completed (${$} lines of output)`},{pattern:/^(npm|pnpm|yarn|bun)\s+(run|exec)\s+(test|lint|check)/i,config:h8},{pattern:/^git\s+(status|branch|remote)/i,config:Q0},{pattern:/^git\s+(log|diff|show)/i,config:h8},{pattern:/^(ls|dir|tree)\s+/i,config:Q0,summaryTemplate:($)=>`Listed ${$} items`},{pattern:/^find\s+/i,config:Q0,summaryTemplate:($)=>`Found ${$} matches`},{pattern:/^(grep|rg|ag)\s+/i,config:Q0,summaryTemplate:($)=>`Found ${$} matching lines`},{pattern:/^(docker|podman)\s+(build|pull|push)/i,config:C1,summaryTemplate:($)=>`Docker operation completed (${$} lines)`},{pattern:/^(pip|pip3|poetry|pipenv)\s+(install|uninstall)/i,config:C1,summaryTemplate:($)=>`Python package operation completed (${$} lines)`},{pattern:/^(cargo|rustup)\s+(build|install|update)/i,config:Q0,summaryTemplate:($)=>`Rust operation completed (${$} lines)`},{pattern:/^(go)\s+(build|get|mod)/i,config:Q0,summaryTemplate:($)=>`Go operation completed (${$} lines)`}];class S${static getConfigForCommand($){for(let{pattern:W,config:Q,summaryTemplate:Z}of d9)if(W.test($))return{config:Q,summaryTemplate:Z};return{config:u9}}static truncate($,W){let{config:Q,summaryTemplate:Z}=S$.getConfigForCommand(W);return S$.truncateWithConfig($,Q,Z)}static truncateWithConfig($,W,Q){let Z=$.length,V=$.split(`
859
- `),X=V.length;if(X<=W.maxLines&&Z<=W.maxChars)return{content:$,truncated:!1,originalLines:X,originalChars:Z};let Y=V.slice(0,W.keepHead),J=V.slice(-W.keepTail),G=X-W.keepHead-W.keepTail,B=Y.join(`
860
- `);if(B+=`
863
+ \uD83D\uDCDD 找到 ${V} 个匹配行`;break}return Y}var d2=E({name:"Grep",displayName:"内容搜索",kind:"readonly",schema:g$.object({pattern:p.pattern({description:"The regular expression pattern to search for in file contents"}),path:g$.string().optional().describe("File or directory to search in (rg PATH). Defaults to current working directory"),glob:g$.string().optional().describe('Glob pattern to filter files (e.g. "*.js", "*.{ts,tsx}") - maps to rg --glob'),type:g$.string().optional().describe("File type to search (rg --type). Common types: js, py, rust, go, java, etc. More efficient than include for standard file types"),output_mode:g$.enum(["content","files_with_matches","count"]).default("files_with_matches").describe('Output mode: "content" shows matching lines (supports -A/-B/-C context, -n line numbers, head_limit), "files_with_matches" shows file paths (supports head_limit), "count" shows match counts (supports head_limit). Defaults to "files_with_matches"'),"-i":g$.boolean().optional().describe("Case insensitive search (rg -i)"),"-n":g$.boolean().default(!0).describe('Show line numbers in output (rg -n). Requires output_mode: "content", ignored otherwise. Defaults to true'),"-B":p.nonNegativeInt().optional().describe('Number of lines to show before each match (rg -B). Requires output_mode: "content", ignored otherwise'),"-A":p.nonNegativeInt().optional().describe('Number of lines to show after each match (rg -A). Requires output_mode: "content", ignored otherwise'),"-C":p.nonNegativeInt().optional().describe('Number of lines to show before and after each match (rg -C). Requires output_mode: "content", ignored otherwise'),head_limit:p.positiveInt().optional().describe('Limit output to first N lines/entries, equivalent to "| head -N". Works across all output modes: content (limits output lines), files_with_matches (limits file paths), count (limits count entries). Defaults based on "cap" experiment value: 0 (unlimited), 20, or 100'),offset:p.nonNegativeInt().optional().describe('Skip first N lines/entries before applying head_limit, equivalent to "| tail -n +N | head -N". Works across all output modes. Defaults to 0'),multiline:g$.boolean().default(!1).describe("Enable multiline mode where . matches newlines and patterns can span lines (rg -U --multiline-dotall). Default: false")}),description:{short:"A powerful search tool built on ripgrep",long:'A powerful search tool built on ripgrep\n\n Usage:\n - ALWAYS use Grep for search tasks. NEVER invoke `grep` or `rg` as a Bash command. The Grep tool has been optimized for correct permissions and access.\n - Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")\n - Filter files with glob parameter (e.g., "*.js", "**/*.tsx") or type parameter (e.g., "js", "py", "rust")\n - Output modes: "content" shows matching lines, "files_with_matches" shows only file paths (default), "count" shows match counts\n - Use Task tool for open-ended searches requiring multiple rounds\n - Pattern syntax: Uses ripgrep (not grep) - literal braces need escaping (use `interface\\{\\}` to find `interface{}` in Go code)\n - Multiline matching: By default patterns match within single lines only. For cross-line patterns like `struct \\{[\\s\\S]*?field`, use `multiline: true`\n'},async execute($,W){let{pattern:Q,path:Z=process.cwd(),glob:V,type:X,output_mode:Y,"-i":J,"-n":G=!0,"-B":K,"-A":B,"-C":q,head_limit:w,offset:O,multiline:H}=$,{updateOutput:U}=W,A=W.signal??new AbortController().signal;try{U?.(`使用智能搜索策略查找模式 "${Q}"...`);let D=null,b="ripgrep",z=[],C=f8();if(C)try{U?.(`\uD83D\uDE80 使用 ripgrep (${C})`);let j=h9({pattern:Q,path:Z,glob:V,type:X,output_mode:Y,case_insensitive:J??!1,line_numbers:G,context_before:K,context_after:B,context:q,head_limit:w,offset:O,multiline:H??!1});D=await T9(j,Y,A,U),b="ripgrep"}catch{U?.("⚠️ ripgrep 失败,尝试降级策略..."),D=null}if(!D&&await v9(Z))try{U?.("\uD83D\uDCE6 使用 git grep"),D=await P9(Q,Z,{caseInsensitive:J??!1,glob:V,contextLines:q},A),b="git-grep"}catch{U?.("⚠️ git grep 失败,继续尝试其他策略..."),D=null}if(!D&&y9())try{U?.("\uD83D\uDD27 使用系统 grep"),D=await k9(Q,Z,{caseInsensitive:J??!1,contextLines:q},A),b="system-grep"}catch{U?.("⚠️ 系统 grep 失败,使用纯 JavaScript 实现..."),D=null}if(!D)U?.("\uD83D\uDCA1 使用纯 JavaScript 搜索实现"),z=(await I9(Q,Z,{caseInsensitive:J??!1,glob:V,multiline:H??!1},A)).matches,b="fallback",D={stdout:"",stderr:"",exitCode:0};else z=p9(D.stdout,Y);let N=z.length;if(O!==void 0&&O>0)z=z.slice(O);if(w!==void 0&&z.length>w)z=z.slice(0,w);let y={search_pattern:Q,search_path:Z,output_mode:Y,case_insensitive:J??!1,total_matches:z.length,original_total:N,offset:O,head_limit:w,strategy:b,exit_code:D?.exitCode};if(D&&D.exitCode!==0&&D.stderr)return{success:!1,llmContent:`Search execution failed: ${D.stderr}`,displayContent:`❌ 搜索执行失败: ${D.stderr}`,error:{type:"execution_error",message:D.stderr}};let i=d9(y);return{success:!0,llmContent:z,displayContent:i,metadata:y}}catch(D){let b=D;if(b.name==="AbortError")return{success:!1,llmContent:"Search aborted",displayContent:"⚠️ 搜索被用户中止",error:{type:"execution_error",message:"操作被中止"}};return{success:!1,llmContent:`Search failed: ${b.message}`,displayContent:`❌ 搜索失败: ${b.message}`,error:{type:"execution_error",message:b.message,details:b}}}},version:"3.0.0",category:"搜索工具",tags:["search","grep","ripgrep","regex","text","fallback"],extractSignatureContent:($)=>$.pattern,abstractPermissionRule:()=>"*"});import{spawn as l9}from"child_process";import{randomUUID as n9}from"crypto";import{z as m2}from"zod";import{spawn as m9}from"child_process";import{randomUUID as g9}from"crypto";class B${static instance=null;processes=new Map;static getInstance(){if(!B$.instance)B$.instance=new B$;return B$.instance}startBackgroundProcess($){let W=`bash_${g9()}`,Q={};for(let[X,Y]of Object.entries({...process.env,...$.env,BLADE_CLI:"1"}))if(Y!==void 0)Q[X]=Y;let Z=m9("bash",["-c",$.command],{cwd:$.cwd||process.cwd(),env:Q,stdio:["ignore","pipe","pipe"]}),V={id:W,command:$.command,sessionId:$.sessionId,cwd:$.cwd,env:$.env,process:Z,pid:Z.pid,status:"running",startTime:Date.now(),pendingStdout:"",pendingStderr:""};return Z.stdout?.setEncoding("utf8"),Z.stderr?.setEncoding("utf8"),Z.stdout?.on("data",(X)=>{V.pendingStdout+=X.toString()}),Z.stderr?.on("data",(X)=>{V.pendingStderr+=X.toString()}),Z.on("close",(X,Y)=>{V.status=V.status==="killed"?"killed":"exited",V.exitCode=X,V.signal=Y,V.endTime=Date.now(),V.process=void 0}),Z.on("error",(X)=>{V.status="error",V.errorMessage=X.message,V.endTime=Date.now(),V.process=void 0,V.pendingStderr+=`
864
+ [error] ${X.message}`}),this.processes.set(W,V),V}consumeOutput($){let W=this.processes.get($);if(!W)return;let Q={id:W.id,command:W.command,status:W.status,stdout:W.pendingStdout,stderr:W.pendingStderr,exitCode:W.exitCode,signal:W.signal,pid:W.pid,startedAt:W.startTime,endedAt:W.endTime,errorMessage:W.errorMessage};return W.pendingStdout="",W.pendingStderr="",Q}getProcess($){return this.processes.get($)}kill($){let W=this.processes.get($);if(!W)return;if(W.status!=="running"||!W.process)return{success:!1,alreadyExited:!0,status:W.status,pid:W.pid,exitCode:W.exitCode,signal:W.signal};if(!W.process.kill("SIGTERM"))return{success:!1,alreadyExited:!1,status:W.status,pid:W.pid,exitCode:W.exitCode,signal:W.signal};return W.status="killed",W.endTime=Date.now(),W.process=void 0,{success:!0,alreadyExited:!1,status:W.status,pid:W.pid,exitCode:W.exitCode,signal:W.signal}}killAll(){for(let[$,W]of this.processes)if(W.status==="running"&&W.process)try{W.process.kill("SIGTERM"),W.status="killed",W.endTime=Date.now(),W.process=void 0}catch{}this.processes.clear()}}var E1={maxLines:30,maxChars:3000,keepHead:10,keepTail:10,summarize:!0},W0={maxLines:100,maxChars:1e4,keepHead:40,keepTail:40,summarize:!0},h8={maxLines:200,maxChars:20000,keepHead:80,keepTail:80,summarize:!1},c9={maxLines:150,maxChars:15000,keepHead:50,keepTail:50,summarize:!0},i9=[{pattern:/^git\s+(rm|add)\s+(-r|--cached|-rf|-f)?\s*/i,config:E1,summaryTemplate:($)=>`Successfully processed ${$} files`},{pattern:/^(npm|pnpm|yarn|bun)\s+(install|i|add|remove|uninstall)/i,config:E1,summaryTemplate:($)=>`Package operation completed (${$} lines of output)`},{pattern:/^(npm|pnpm|yarn|bun)\s+(run|exec)\s+(build|compile|bundle)/i,config:W0,summaryTemplate:($)=>`Build completed (${$} lines of output)`},{pattern:/^(npm|pnpm|yarn|bun)\s+(run|exec)\s+(test|lint|check)/i,config:h8},{pattern:/^git\s+(status|branch|remote)/i,config:W0},{pattern:/^git\s+(log|diff|show)/i,config:h8},{pattern:/^(ls|dir|tree)\s+/i,config:W0,summaryTemplate:($)=>`Listed ${$} items`},{pattern:/^find\s+/i,config:W0,summaryTemplate:($)=>`Found ${$} matches`},{pattern:/^(grep|rg|ag)\s+/i,config:W0,summaryTemplate:($)=>`Found ${$} matching lines`},{pattern:/^(docker|podman)\s+(build|pull|push)/i,config:E1,summaryTemplate:($)=>`Docker operation completed (${$} lines)`},{pattern:/^(pip|pip3|poetry|pipenv)\s+(install|uninstall)/i,config:E1,summaryTemplate:($)=>`Python package operation completed (${$} lines)`},{pattern:/^(cargo|rustup)\s+(build|install|update)/i,config:W0,summaryTemplate:($)=>`Rust operation completed (${$} lines)`},{pattern:/^(go)\s+(build|get|mod)/i,config:W0,summaryTemplate:($)=>`Go operation completed (${$} lines)`}];class S${static getConfigForCommand($){for(let{pattern:W,config:Q,summaryTemplate:Z}of i9)if(W.test($))return{config:Q,summaryTemplate:Z};return{config:c9}}static truncate($,W){let{config:Q,summaryTemplate:Z}=S$.getConfigForCommand(W);return S$.truncateWithConfig($,Q,Z)}static truncateWithConfig($,W,Q){let Z=$.length,V=$.split(`
865
+ `),X=V.length;if(X<=W.maxLines&&Z<=W.maxChars)return{content:$,truncated:!1,originalLines:X,originalChars:Z};let Y=V.slice(0,W.keepHead),J=V.slice(-W.keepTail),G=X-W.keepHead-W.keepTail,K=Y.join(`
866
+ `);if(K+=`
861
867
 
862
868
  ... (${G} lines truncated, showing first ${W.keepHead} and last ${W.keepTail} of ${X} total) ...
863
869
 
864
- `,B+=J.join(`
865
- `),B.length>W.maxChars){let q=Math.floor(W.maxChars/2)-50,w=B.slice(0,q),O=B.slice(-q);B=`${w}
870
+ `,K+=J.join(`
871
+ `),K.length>W.maxChars){let q=Math.floor(W.maxChars/2)-50,w=K.slice(0,q),O=K.slice(-q);K=`${w}
866
872
 
867
873
  ... (content truncated to ${W.maxChars} chars) ...
868
874
 
869
- ${O}`}let K=W.summarize&&Q?Q(X,Z):void 0;if(K)B+=`
875
+ ${O}`}let B=W.summarize&&Q?Q(X,Z):void 0;if(B)K+=`
870
876
 
871
- [Summary: ${K}]`;return{content:B,truncated:!0,originalLines:X,originalChars:Z,summary:K}}static truncateForLLM($,W,Q){let Z=S$.truncate($,Q),V=S$.truncate(W,Q),X;if(Z.truncated||V.truncated){let Y=[];if(Z.truncated)Y.push(`stdout: ${Z.originalLines} lines → ${Z.content.split(`
877
+ [Summary: ${B}]`;return{content:K,truncated:!0,originalLines:X,originalChars:Z,summary:B}}static truncateForLLM($,W,Q){let Z=S$.truncate($,Q),V=S$.truncate(W,Q),X;if(Z.truncated||V.truncated){let Y=[];if(Z.truncated)Y.push(`stdout: ${Z.originalLines} lines → ${Z.content.split(`
872
878
  `).length} lines`);if(V.truncated)Y.push(`stderr: ${V.originalLines} lines → ${V.content.split(`
873
879
  `).length} lines`);X=`Output truncated: ${Y.join(", ")}`}return{stdout:Z.content,stderr:V.content,truncationInfo:X}}static shouldTruncate($,W){let{config:Q}=S$.getConfigForCommand(W);return $.split(`
874
880
  `).length>Q.maxLines||$.length>Q.maxChars}static getStats($){return{lines:$.split(`
@@ -888,18 +894,18 @@ Before executing commands:
888
894
  * cd "/Users/name/My Documents" (correct)
889
895
  * cd /Users/name/My Documents (incorrect - will fail)
890
896
  * python "/path/with spaces/script.py" (correct)
891
- * python /path/with spaces/script.py (incorrect - will fail)`,usageNotes:["The command argument is required","You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands will timeout after 30000ms (30 seconds)","It is very helpful if you write a clear, concise description of what this command does in 5-10 words","If the output exceeds 30000 characters, output will be truncated before being returned to you",'You can use the run_in_background parameter to run the command in the background, which allows you to continue working while the command runs. You can monitor the output using the TaskOutput tool. You do not need to use "&" at the end of the command when using this parameter',"Avoid using Bash with the find, grep, cat, head, tail, sed, awk, or echo commands, unless explicitly instructed or when these commands are truly necessary for the task. Instead, always prefer using the dedicated tools for these commands:"," - File search: Use Glob (NOT find or ls)"," - Content search: Use Grep (NOT grep or rg)"," - Read files: Use Read (NOT cat/head/tail)"," - Edit files: Use Edit (NOT sed/awk)"," - Write files: Use Write (NOT echo >/cat <<EOF)"," - Communication: Output text directly (NOT echo/printf)","When issuing multiple commands:",' - If the commands are independent and can run in parallel, make multiple Bash tool calls in a single message. For example, if you need to run "git status" and "git diff", send a single message with two Bash tool calls in parallel',' - If the commands depend on each other and must run sequentially, use a single Bash call with "&&" to chain them together (e.g., git add . && git commit -m "message" && git push). For instance, if one operation must complete before another starts (like mkdir before cp, Write before Bash for git operations, or git add before git commit), run these operations sequentially instead',` - Use ";" only when you need to run commands sequentially but don't care if earlier commands fail`," - DO NOT use newlines to separate commands (newlines are ok in quoted strings)","Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of cd. You may use cd if the User explicitly requests it"," Good example: pytest /foo/bar/tests"," Bad example: cd /foo/bar && pytest tests"],examples:[{description:"Run a simple command",params:{command:"ls -la",description:"List files in current directory"}},{description:"Temporarily change working directory (this command only)",params:{command:"npm install",cwd:"/path/to/project",description:"Install package dependencies"}},{description:"Persistently change working directory",params:{command:"cd /path/to/project && npm install",description:"Change directory and install dependencies"}},{description:"Run a long-running command in background",params:{command:"npm run dev",run_in_background:!0,description:"Start development server in background"}},{description:"Run multiple independent commands in parallel",params:{command:"git status",description:"Show working tree status"}}],important:["Committing changes with git:"," - Only create commits when requested by the user. If unclear, ask first"," - Git Safety Protocol:"," * NEVER update the git config"," * NEVER run destructive/irreversible git commands (like push --force, hard reset, etc) unless the user explicitly requests them"," * NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it"," * NEVER run force push to main/master, warn the user if they request it"," * Avoid git commit --amend. ONLY use --amend when either (1) user explicitly requested amend OR (2) adding edits from pre-commit hook",' * Before amending: ALWAYS check authorship (git log -1 --format="%an %ae")'," * NEVER commit changes unless the user explicitly asks you to"," - When creating commits:"," 1. Run git status, git diff, and git log in parallel to understand changes",' 2. Analyze staged changes and draft a concise commit message (1-2 sentences) focusing on "why" rather than "what"'," 3. Add relevant untracked files, create the commit, and run git status to verify"," 4. Always pass commit message via HEREDOC format"," - DO NOT push to remote repository unless explicitly requested"," - NEVER use git commands with the -i flag (no interactive input supported)"," - If no changes to commit, do not create an empty commit","Creating pull requests:"," - Use the gh command for ALL GitHub-related tasks"," - When creating a PR:"," 1. Run git status, git diff, and git log in parallel to understand branch changes"," 2. Analyze all commits (not just the latest) and draft a PR summary"," 3. Create new branch if needed, push with -u flag, and create PR using gh pr create with HEREDOC body format"," - Return the PR URL when done","Other important notes:"," - Dangerous commands (rm -rf, sudo, etc.) require user confirmation"," - Background commands require manual termination using KillShell"," - NEVER use find, grep, cat, sed, etc. — use dedicated tools instead"]},async execute($,W){let{command:Q,timeout:Z=30000,cwd:V,env:X,run_in_background:Y=!1}=$,{updateOutput:J}=W,G=W.signal??new AbortController().signal;try{if(J?.(`Executing Bash command: ${Q}`),Y)return c9(Q,V,X);if(g$())return J?.("通过 IDE 终端执行命令..."),i9(Q,V,X,Z,G,J);else return l9(Q,V,X,Z,G,J)}catch(B){let K=B;if(K.name==="AbortError")return{success:!1,llmContent:"Command execution aborted",displayContent:"⚠️ 命令执行被用户中止",error:{type:"execution_error",message:"Operation aborted"}};return{success:!1,llmContent:`Command execution failed: ${K.message}`,displayContent:`❌ 命令执行失败: ${K.message}`,error:{type:"execution_error",message:K.message,details:K}}}},version:"2.0.0",category:"命令工具",tags:["bash","shell","non-interactive","event-driven"],extractSignatureContent:($)=>{return $.command.trim()},abstractPermissionRule:($)=>{let Q=$.command.trim().split(/\s+/);if(Q.length===1)return Q[0];if(["run","exec","test","start","build","dev"].includes(Q[1])){if(Q.length===2)return`${Q[0]} ${Q[1]}`;return`${Q[0]} ${Q[1]} *`}if(Q.length===2)return`${Q[0]} ${Q[1]}`;return`${Q[0]} ${Q[1]} *`}});function c9($,W,Q){let V=J$.getInstance().startBackgroundProcess({command:$,sessionId:g9(),cwd:W||process.cwd(),env:Q}),Y=`后台启动命令: ${$.length>30?`${$.substring(0,30)}...`:$}`,J={command:$,background:!0,pid:V.pid??0,bash_id:V.id,shell_id:V.id,message:"命令已在后台启动",summary:Y},G=`✅ 命令已在后台启动
897
+ * python /path/with spaces/script.py (incorrect - will fail)`,usageNotes:["The command argument is required","You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands will timeout after 30000ms (30 seconds)","It is very helpful if you write a clear, concise description of what this command does in 5-10 words","If the output exceeds 30000 characters, output will be truncated before being returned to you",'You can use the run_in_background parameter to run the command in the background, which allows you to continue working while the command runs. You can monitor the output using the TaskOutput tool. You do not need to use "&" at the end of the command when using this parameter',"Avoid using Bash with the find, grep, cat, head, tail, sed, awk, or echo commands, unless explicitly instructed or when these commands are truly necessary for the task. Instead, always prefer using the dedicated tools for these commands:"," - File search: Use Glob (NOT find or ls)"," - Content search: Use Grep (NOT grep or rg)"," - Read files: Use Read (NOT cat/head/tail)"," - Edit files: Use Edit (NOT sed/awk)"," - Write files: Use Write (NOT echo >/cat <<EOF)"," - Communication: Output text directly (NOT echo/printf)","When issuing multiple commands:",' - If the commands are independent and can run in parallel, make multiple Bash tool calls in a single message. For example, if you need to run "git status" and "git diff", send a single message with two Bash tool calls in parallel',' - If the commands depend on each other and must run sequentially, use a single Bash call with "&&" to chain them together (e.g., git add . && git commit -m "message" && git push). For instance, if one operation must complete before another starts (like mkdir before cp, Write before Bash for git operations, or git add before git commit), run these operations sequentially instead',` - Use ";" only when you need to run commands sequentially but don't care if earlier commands fail`," - DO NOT use newlines to separate commands (newlines are ok in quoted strings)","Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of cd. You may use cd if the User explicitly requests it"," Good example: pytest /foo/bar/tests"," Bad example: cd /foo/bar && pytest tests"],examples:[{description:"Run a simple command",params:{command:"ls -la",description:"List files in current directory"}},{description:"Temporarily change working directory (this command only)",params:{command:"npm install",cwd:"/path/to/project",description:"Install package dependencies"}},{description:"Persistently change working directory",params:{command:"cd /path/to/project && npm install",description:"Change directory and install dependencies"}},{description:"Run a long-running command in background",params:{command:"npm run dev",run_in_background:!0,description:"Start development server in background"}},{description:"Run multiple independent commands in parallel",params:{command:"git status",description:"Show working tree status"}}],important:["Committing changes with git:"," - Only create commits when requested by the user. If unclear, ask first"," - Git Safety Protocol:"," * NEVER update the git config"," * NEVER run destructive/irreversible git commands (like push --force, hard reset, etc) unless the user explicitly requests them"," * NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it"," * NEVER run force push to main/master, warn the user if they request it"," * Avoid git commit --amend. ONLY use --amend when either (1) user explicitly requested amend OR (2) adding edits from pre-commit hook",' * Before amending: ALWAYS check authorship (git log -1 --format="%an %ae")'," * NEVER commit changes unless the user explicitly asks you to"," - When creating commits:"," 1. Run git status, git diff, and git log in parallel to understand changes",' 2. Analyze staged changes and draft a concise commit message (1-2 sentences) focusing on "why" rather than "what"'," 3. Add relevant untracked files, create the commit, and run git status to verify"," 4. Always pass commit message via HEREDOC format"," - DO NOT push to remote repository unless explicitly requested"," - NEVER use git commands with the -i flag (no interactive input supported)"," - If no changes to commit, do not create an empty commit","Creating pull requests:"," - Use the gh command for ALL GitHub-related tasks"," - When creating a PR:"," 1. Run git status, git diff, and git log in parallel to understand branch changes"," 2. Analyze all commits (not just the latest) and draft a PR summary"," 3. Create new branch if needed, push with -u flag, and create PR using gh pr create with HEREDOC body format"," - Return the PR URL when done","Other important notes:"," - Dangerous commands (rm -rf, sudo, etc.) require user confirmation"," - Background commands require manual termination using KillShell"," - NEVER use find, grep, cat, sed, etc. — use dedicated tools instead"]},async execute($,W){let{command:Q,timeout:Z=30000,cwd:V,env:X,run_in_background:Y=!1}=$,{updateOutput:J}=W,G=W.signal??new AbortController().signal;try{if(J?.(`Executing Bash command: ${Q}`),Y)return a9(Q,V,X);if(m$())return J?.("通过 IDE 终端执行命令..."),r9(Q,V,X,Z,G,J);else return s9(Q,V,X,Z,G,J)}catch(K){let B=K;if(B.name==="AbortError")return{success:!1,llmContent:"Command execution aborted",displayContent:"⚠️ 命令执行被用户中止",error:{type:"execution_error",message:"Operation aborted"}};return{success:!1,llmContent:`Command execution failed: ${B.message}`,displayContent:`❌ 命令执行失败: ${B.message}`,error:{type:"execution_error",message:B.message,details:B}}}},version:"2.0.0",category:"命令工具",tags:["bash","shell","non-interactive","event-driven"],extractSignatureContent:($)=>{return $.command.trim()},abstractPermissionRule:($)=>{let Q=$.command.trim().split(/\s+/);if(Q.length===1)return Q[0];if(["run","exec","test","start","build","dev"].includes(Q[1])){if(Q.length===2)return`${Q[0]} ${Q[1]}`;return`${Q[0]} ${Q[1]} *`}if(Q.length===2)return`${Q[0]} ${Q[1]}`;return`${Q[0]} ${Q[1]} *`}});function a9($,W,Q){let V=B$.getInstance().startBackgroundProcess({command:$,sessionId:n9(),cwd:W||process.cwd(),env:Q}),Y=`后台启动命令: ${$.length>30?`${$.substring(0,30)}...`:$}`,J={command:$,background:!0,pid:V.pid??0,bash_id:V.id,shell_id:V.id,message:"命令已在后台启动",summary:Y},G=`✅ 命令已在后台启动
892
898
  `+`\uD83C\uDD94 进程 ID: ${V.pid}
893
899
  `+`\uD83D\uDCA1 Bash ID: ${V.id}
894
- `+"⚠️ 使用 TaskOutput/KillShell 管理后台进程";return{success:!0,llmContent:{command:$,background:!0,pid:V.pid,bash_id:V.id,shell_id:V.id},displayContent:G,metadata:J}}async function i9($,W,Q,Z,V,X){let Y=Date.now();try{let G=await b8().execute($,{cwd:W||process.cwd(),env:Q,timeout:Z,signal:V,onOutput:(U)=>{X?.(U)}}),B=Date.now()-Y;if(V.aborted||G.error==="Command was aborted"||G.error==="Command was terminated")return{success:!1,llmContent:"Command execution aborted by user",displayContent:`⚠️ 命令执行被用户中止
900
+ `+"⚠️ 使用 TaskOutput/KillShell 管理后台进程";return{success:!0,llmContent:{command:$,background:!0,pid:V.pid,bash_id:V.id,shell_id:V.id},displayContent:G,metadata:J}}async function r9($,W,Q,Z,V,X){let Y=Date.now();try{let G=await H8().execute($,{cwd:W||process.cwd(),env:Q,timeout:Z,signal:V,onOutput:(U)=>{X?.(U)}}),K=Date.now()-Y;if(V.aborted||G.error==="Command was aborted"||G.error==="Command was terminated")return{success:!1,llmContent:"Command execution aborted by user",displayContent:`⚠️ 命令执行被用户中止
895
901
  输出: ${G.stdout}
896
- 错误: ${G.stderr}`,error:{type:"execution_error",message:"操作被中止"},metadata:{command:$,aborted:!0,stdout:G.stdout,stderr:G.stderr,execution_time:B}};if(G.error==="Command timed out")return{success:!1,llmContent:`Command execution timed out (${Z}ms)`,displayContent:`⏱️ 命令执行超时 (${Z}ms)
902
+ 错误: ${G.stderr}`,error:{type:"execution_error",message:"操作被中止"},metadata:{command:$,aborted:!0,stdout:G.stdout,stderr:G.stderr,execution_time:K}};if(G.error==="Command timed out")return{success:!1,llmContent:`Command execution timed out (${Z}ms)`,displayContent:`⏱️ 命令执行超时 (${Z}ms)
897
903
  输出: ${G.stdout}
898
- 错误: ${G.stderr}`,error:{type:"timeout_error",message:"命令执行超时"},metadata:{command:$,timeout:!0,stdout:G.stdout,stderr:G.stderr,execution_time:B}};let K=$.length>30?`${$.substring(0,30)}...`:$,q=G.exitCode===0?`执行命令成功 (${B}ms): ${K}`:`执行命令完成 (退出码 ${G.exitCode}, ${B}ms): ${K}`,w={command:$,execution_time:B,exit_code:G.exitCode,stdout_length:G.stdout.length,stderr_length:G.stderr.length,has_stderr:G.stderr.length>0,acp_mode:!0,summary:q},O=p8({stdout:G.stdout,stderr:G.stderr,command:$,execution_time:B,exit_code:G.exitCode,signal:null}),b=S$.truncateForLLM(G.stdout.trim(),G.stderr.trim(),$);return{success:G.success,llmContent:{stdout:b.stdout,stderr:b.stderr,execution_time:B,exit_code:G.exitCode,...b.truncationInfo&&{truncation_info:b.truncationInfo}},displayContent:O,metadata:w}}catch(J){let G=J,B=Date.now()-Y;return{success:!1,llmContent:`Command execution failed: ${G.message}`,displayContent:`❌ 命令执行失败: ${G.message}`,error:{type:"execution_error",message:G.message,details:G},metadata:{command:$,execution_time:B,error:G.message}}}}async function l9($,W,Q,Z,V,X){return new Promise((Y)=>{let J=Date.now(),G="",B="",K=!1,q=m9("bash",["-c",$],{cwd:W||process.cwd(),env:{...process.env,...Q,BLADE_CLI:"1"},stdio:["pipe","pipe","pipe"]});q.stdout.on("data",(b)=>{G+=b.toString()}),q.stderr.on("data",(b)=>{B+=b.toString()});let w=setTimeout(()=>{K=!0,q.kill("SIGTERM"),setTimeout(()=>{if(!q.killed)q.kill("SIGKILL")},1000)},Z),O=()=>{q.kill("SIGTERM"),clearTimeout(w)};if(V.addEventListener)V.addEventListener("abort",O);else if("onabort"in V)V.onabort=O;q.on("close",(b,U)=>{if(clearTimeout(w),V.removeEventListener)V.removeEventListener("abort",O);else if("onabort"in V)V.onabort=null;let F=Date.now()-J;if(K){Y({success:!1,llmContent:`Command execution timed out (${Z}ms)`,displayContent:`⏱️ 命令执行超时 (${Z}ms)
904
+ 错误: ${G.stderr}`,error:{type:"timeout_error",message:"命令执行超时"},metadata:{command:$,timeout:!0,stdout:G.stdout,stderr:G.stderr,execution_time:K}};let B=$.length>30?`${$.substring(0,30)}...`:$,q=G.exitCode===0?`执行命令成功 (${K}ms): ${B}`:`执行命令完成 (退出码 ${G.exitCode}, ${K}ms): ${B}`,w={command:$,execution_time:K,exit_code:G.exitCode,stdout_length:G.stdout.length,stderr_length:G.stderr.length,has_stderr:G.stderr.length>0,acp_mode:!0,summary:q},O=p8({stdout:G.stdout,stderr:G.stderr,command:$,execution_time:K,exit_code:G.exitCode,signal:null}),H=S$.truncateForLLM(G.stdout.trim(),G.stderr.trim(),$);return{success:G.success,llmContent:{stdout:H.stdout,stderr:H.stderr,execution_time:K,exit_code:G.exitCode,...H.truncationInfo&&{truncation_info:H.truncationInfo}},displayContent:O,metadata:w}}catch(J){let G=J,K=Date.now()-Y;return{success:!1,llmContent:`Command execution failed: ${G.message}`,displayContent:`❌ 命令执行失败: ${G.message}`,error:{type:"execution_error",message:G.message,details:G},metadata:{command:$,execution_time:K,error:G.message}}}}async function s9($,W,Q,Z,V,X){return new Promise((Y)=>{let J=Date.now(),G="",K="",B=!1,q=l9("bash",["-c",$],{cwd:W||process.cwd(),env:{...process.env,...Q,BLADE_CLI:"1"},stdio:["pipe","pipe","pipe"]});q.stdout.on("data",(H)=>{G+=H.toString()}),q.stderr.on("data",(H)=>{K+=H.toString()});let w=setTimeout(()=>{B=!0,q.kill("SIGTERM"),setTimeout(()=>{if(!q.killed)q.kill("SIGKILL")},1000)},Z),O=()=>{q.kill("SIGTERM"),clearTimeout(w)};if(V.addEventListener)V.addEventListener("abort",O);else if("onabort"in V)V.onabort=O;q.on("close",(H,U)=>{if(clearTimeout(w),V.removeEventListener)V.removeEventListener("abort",O);else if("onabort"in V)V.onabort=null;let A=Date.now()-J;if(B){Y({success:!1,llmContent:`Command execution timed out (${Z}ms)`,displayContent:`⏱️ 命令执行超时 (${Z}ms)
899
905
  输出: ${G}
900
- 错误: ${B}`,error:{type:"timeout_error",message:"命令执行超时"},metadata:{command:$,timeout:!0,stdout:G,stderr:B,execution_time:F}});return}if(V.aborted){Y({success:!1,llmContent:"Command execution aborted by user",displayContent:`⚠️ 命令执行被用户中止
906
+ 错误: ${K}`,error:{type:"timeout_error",message:"命令执行超时"},metadata:{command:$,timeout:!0,stdout:G,stderr:K,execution_time:A}});return}if(V.aborted){Y({success:!1,llmContent:"Command execution aborted by user",displayContent:`⚠️ 命令执行被用户中止
901
907
  输出: ${G}
902
- 错误: ${B}`,error:{type:"execution_error",message:"操作被中止"},metadata:{command:$,aborted:!0,stdout:G,stderr:B,execution_time:F}});return}let A=$.length>30?`${$.substring(0,30)}...`:$,D=b===0?`执行命令成功 (${F}ms): ${A}`:`执行命令完成 (退出码 ${b}, ${F}ms): ${A}`,N={command:$,execution_time:F,exit_code:b,signal:U,stdout_length:G.length,stderr_length:B.length,has_stderr:B.length>0,summary:D},C=p8({stdout:G,stderr:B,command:$,execution_time:F,exit_code:b,signal:U}),z=S$.truncateForLLM(G.trim(),B.trim(),$);Y({success:!0,llmContent:{stdout:z.stdout,stderr:z.stderr,execution_time:F,exit_code:b,signal:U,...z.truncationInfo&&{truncation_info:z.truncationInfo}},displayContent:C,metadata:N})}),q.on("error",(b)=>{if(clearTimeout(w),V.removeEventListener)V.removeEventListener("abort",O);else if("onabort"in V)V.onabort=null;Y({success:!1,llmContent:`Command execution failed: ${b.message}`,displayContent:`❌ 命令执行失败: ${b.message}`,error:{type:"execution_error",message:b.message,details:b}})})})}function p8($){let{stdout:W,stderr:Q,command:Z,execution_time:V,exit_code:X,signal:Y}=$,J=`✅ Bash 命令执行完成: ${Z}`;if(J+=`
908
+ 错误: ${K}`,error:{type:"execution_error",message:"操作被中止"},metadata:{command:$,aborted:!0,stdout:G,stderr:K,execution_time:A}});return}let D=$.length>30?`${$.substring(0,30)}...`:$,b=H===0?`执行命令成功 (${A}ms): ${D}`:`执行命令完成 (退出码 ${H}, ${A}ms): ${D}`,z={command:$,execution_time:A,exit_code:H,signal:U,stdout_length:G.length,stderr_length:K.length,has_stderr:K.length>0,summary:b},C=p8({stdout:G,stderr:K,command:$,execution_time:A,exit_code:H,signal:U}),N=S$.truncateForLLM(G.trim(),K.trim(),$);Y({success:!0,llmContent:{stdout:N.stdout,stderr:N.stderr,execution_time:A,exit_code:H,signal:U,...N.truncationInfo&&{truncation_info:N.truncationInfo}},displayContent:C,metadata:z})}),q.on("error",(H)=>{if(clearTimeout(w),V.removeEventListener)V.removeEventListener("abort",O);else if("onabort"in V)V.onabort=null;Y({success:!1,llmContent:`Command execution failed: ${H.message}`,displayContent:`❌ 命令执行失败: ${H.message}`,error:{type:"execution_error",message:H.message,details:H}})})})}function p8($){let{stdout:W,stderr:Q,command:Z,execution_time:V,exit_code:X,signal:Y}=$,J=`✅ Bash 命令执行完成: ${Z}`;if(J+=`
903
909
  ⏱️ 执行时间: ${V}ms`,J+=`
904
910
  \uD83D\uDCCA 退出码: ${X??"N/A"}`,Y)J+=`
905
911
  ⚡ 信号: ${Y}`;if(W&&W.trim())J+=`
@@ -912,13 +918,13 @@ ${Q.trim()}`;return J}import{z as u8}from"zod";var c2=E({name:"KillShell",displa
912
918
  - Returns a success or failure status
913
919
  - Use this tool when you need to terminate a long-running shell
914
920
  - Shell IDs can be found using the /tasks command
915
- `},async execute($,W){let Z=J$.getInstance().kill($.shell_id);if(!Z)return{success:!1,llmContent:`Shell not found: ${$.shell_id}`,displayContent:`❌ 未找到 Shell: ${$.shell_id}`,error:{type:"execution_error",message:"Shell ID 不存在或已清理"}};if(!Z.success&&!Z.alreadyExited)return{success:!1,llmContent:`Failed to terminate Shell: ${$.shell_id}`,displayContent:`❌ 无法终止 Shell (${$.shell_id})`,error:{type:"execution_error",message:"发送终止信号失败"},metadata:{...Z}};let V=Z.alreadyExited?`Shell ${$.shell_id} 已经处于 ${Z.status} 状态`:`已向 Shell ${$.shell_id} 发送终止信号`;return{success:!0,llmContent:{shell_id:$.shell_id,status:Z.status,already_exited:Z.alreadyExited,pid:Z.pid,exit_code:Z.exitCode,signal:Z.signal},displayContent:Z.alreadyExited?`ℹ️ ${V}`:`✂️ ${V}`,metadata:{...Z}}},version:"1.0.0",category:"命令工具",tags:["bash","shell","terminate"],extractSignatureContent:($)=>$.shell_id,abstractPermissionRule:()=>"*"});import{z as i$}from"zod";import{nanoid as o9}from"nanoid";import{promises as s}from"node:fs";import*as x from"node:path";import{fileURLToPath as n9}from"node:url";import{nanoid as a9}from"nanoid";var d8={proposal:"proposal.md",spec:"spec.md",requirements:"requirements.md",design:"design.md",tasks:"tasks.md",meta:".meta.json"},Z0={SPECS:"specs",CHANGES:"changes",ARCHIVE:"archive",STEERING:"steering",SPEC_DELTA:"specs"},V0={CONSTITUTION:"constitution.md",PRODUCT:"product.md",TECH:"tech.md",STRUCTURE:"structure.md"},$J=["init","requirements","design","tasks","implementation","done"],i0={init:["requirements"],requirements:["design","tasks"],design:["tasks"],tasks:["implementation"],implementation:["done","tasks"],done:[]},q$={init:"初始化",requirements:"需求定义",design:"架构设计",tasks:"任务分解",implementation:"实现中",done:"已完成"},m8={init:"proposal",requirements:"requirements",design:"design",tasks:"tasks",implementation:"tasks",done:null};var r9=n9(import.meta.url),s9=x.dirname(r9),g8=x.join(s9,"templates");class l0{workspaceRoot;bladeDir;constructor($){this.workspaceRoot=$,this.bladeDir=x.join($,".blade")}getSpecsDir(){return x.join(this.bladeDir,Z0.SPECS)}getChangesDir(){return x.join(this.bladeDir,Z0.CHANGES)}getArchiveDir(){return x.join(this.bladeDir,Z0.ARCHIVE)}getSteeringDir(){return x.join(this.bladeDir,Z0.STEERING)}getChangePath($){return x.join(this.getChangesDir(),$)}getChangeFilePath($,W){return x.join(this.getChangePath($),d8[W])}async initializeDirectories(){await s.mkdir(this.getChangesDir(),{recursive:!0,mode:493})}async createChangeDir($){let W=this.getChangePath($);return await s.mkdir(W,{recursive:!0,mode:493}),await s.mkdir(x.join(W,Z0.SPEC_DELTA),{recursive:!0,mode:493}),W}async readFile($){try{return await s.readFile($,"utf-8")}catch(W){if(W.code==="ENOENT")return null;throw W}}async writeFile($,W){let Q=x.dirname($);await s.mkdir(Q,{recursive:!0,mode:493}),await s.writeFile($,W,"utf-8")}async fileExists($){try{return await s.access($),!0}catch{return!1}}async dirExists($){try{return(await s.stat($)).isDirectory()}catch{return!1}}createMetadata($,W){let Q=new Date().toISOString();return{id:a9(),name:$,description:W,phase:"init",createdAt:Q,updatedAt:Q,tasks:[]}}async readMetadata($){let W=this.getChangeFilePath($,"meta"),Q=await this.readFile(W);if(!Q)return null;try{return JSON.parse(Q)}catch{return null}}async writeMetadata($,W){let Q=this.getChangeFilePath($,"meta");W.updatedAt=new Date().toISOString(),await this.writeFile(Q,JSON.stringify(W,null,2))}async updatePhase($,W){let Q=await this.readMetadata($);if(!Q)return null;return Q.phase=W,await this.writeMetadata($,Q),Q}async readSpecFile($,W){let Q=this.getChangeFilePath($,W);return this.readFile(Q)}async writeSpecFile($,W,Q){let Z=this.getChangeFilePath($,W);await this.writeFile(Z,Q);let V=await this.readMetadata($);if(V)await this.writeMetadata($,V)}async getPhaseContent($,W){let Q=m8[W];if(!Q)return null;return this.readSpecFile($,Q)}async readSteeringContext(){let $=this.getSteeringDir(),[W,Q,Z,V]=await Promise.all([this.readFile(x.join($,V0.CONSTITUTION)),this.readFile(x.join($,V0.PRODUCT)),this.readFile(x.join($,V0.TECH)),this.readFile(x.join($,V0.STRUCTURE))]);return{constitution:W||void 0,product:Q||void 0,tech:Z||void 0,structure:V||void 0}}async writeSteeringFile($,W){let Q=x.join(this.getSteeringDir(),V0[$]);await this.writeFile(Q,W)}async hasSteeringDocs(){let $=this.getSteeringDir();if(!await this.dirExists($))return!1;return(await s.readdir($)).length>0}async listActiveChanges(){let $=this.getChangesDir();if(!await this.dirExists($))return[];return(await s.readdir($,{withFileTypes:!0})).filter((Q)=>Q.isDirectory()).map((Q)=>Q.name)}async listArchivedChanges(){let $=this.getArchiveDir();if(!await this.dirExists($))return[];return(await s.readdir($,{withFileTypes:!0})).filter((Q)=>Q.isDirectory()).map((Q)=>Q.name)}async changeExists($){return this.dirExists(this.getChangePath($))}async archiveChange($){let W=this.getChangePath($),Q=x.join(this.getArchiveDir(),$);await s.mkdir(x.dirname(Q),{recursive:!0,mode:493}),await s.rename(W,Q)}async restoreChange($){let W=x.join(this.getArchiveDir(),$),Q=this.getChangePath($);await s.rename(W,Q)}async listSpecDomains(){let $=this.getSpecsDir();if(!await this.dirExists($))return[];return(await s.readdir($,{withFileTypes:!0})).filter((Q)=>Q.isDirectory()).map((Q)=>Q.name)}async readAuthorativeSpec($){let W=x.join(this.getSpecsDir(),$,"spec.md");return this.readFile(W)}async writeAuthorativeSpec($,W){let Q=x.join(this.getSpecsDir(),$,"spec.md");await this.writeFile(Q,W)}async mergeSpecDeltas($){let W=x.join(this.getChangePath($),Z0.SPEC_DELTA);if(!await this.dirExists(W))return[];let Q=[],Z=await s.readdir(W,{withFileTypes:!0});for(let V of Z){if(!V.isDirectory())continue;let X=x.join(W,V.name,"spec.md"),Y=await this.readFile(X);if(Y){let J=await this.readAuthorativeSpec(V.name),G=J?`${J}
921
+ `},async execute($,W){let Z=B$.getInstance().kill($.shell_id);if(!Z)return{success:!1,llmContent:`Shell not found: ${$.shell_id}`,displayContent:`❌ 未找到 Shell: ${$.shell_id}`,error:{type:"execution_error",message:"Shell ID 不存在或已清理"}};if(!Z.success&&!Z.alreadyExited)return{success:!1,llmContent:`Failed to terminate Shell: ${$.shell_id}`,displayContent:`❌ 无法终止 Shell (${$.shell_id})`,error:{type:"execution_error",message:"发送终止信号失败"},metadata:{...Z}};let V=Z.alreadyExited?`Shell ${$.shell_id} 已经处于 ${Z.status} 状态`:`已向 Shell ${$.shell_id} 发送终止信号`;return{success:!0,llmContent:{shell_id:$.shell_id,status:Z.status,already_exited:Z.alreadyExited,pid:Z.pid,exit_code:Z.exitCode,signal:Z.signal},displayContent:Z.alreadyExited?`ℹ️ ${V}`:`✂️ ${V}`,metadata:{...Z}}},version:"1.0.0",category:"命令工具",tags:["bash","shell","terminate"],extractSignatureContent:($)=>$.shell_id,abstractPermissionRule:()=>"*"});import{z as c$}from"zod";import{nanoid as W3}from"nanoid";import{promises as s}from"node:fs";import*as x from"node:path";import{fileURLToPath as o9}from"node:url";import{nanoid as t9}from"nanoid";var d8={proposal:"proposal.md",spec:"spec.md",requirements:"requirements.md",design:"design.md",tasks:"tasks.md",meta:".meta.json"},Q0={SPECS:"specs",CHANGES:"changes",ARCHIVE:"archive",STEERING:"steering",SPEC_DELTA:"specs"},Z0={CONSTITUTION:"constitution.md",PRODUCT:"product.md",TECH:"tech.md",STRUCTURE:"structure.md"},VJ=["init","requirements","design","tasks","implementation","done"],i0={init:["requirements"],requirements:["design","tasks"],design:["tasks"],tasks:["implementation"],implementation:["done","tasks"],done:[]},U$={init:"初始化",requirements:"需求定义",design:"架构设计",tasks:"任务分解",implementation:"实现中",done:"已完成"},m8={init:"proposal",requirements:"requirements",design:"design",tasks:"tasks",implementation:"tasks",done:null};var e9=o9(import.meta.url),$3=x.dirname(e9),g8=x.join($3,"templates");class l0{workspaceRoot;bladeDir;constructor($){this.workspaceRoot=$,this.bladeDir=x.join($,".blade")}getSpecsDir(){return x.join(this.bladeDir,Q0.SPECS)}getChangesDir(){return x.join(this.bladeDir,Q0.CHANGES)}getArchiveDir(){return x.join(this.bladeDir,Q0.ARCHIVE)}getSteeringDir(){return x.join(this.bladeDir,Q0.STEERING)}getChangePath($){return x.join(this.getChangesDir(),$)}getChangeFilePath($,W){return x.join(this.getChangePath($),d8[W])}async initializeDirectories(){await s.mkdir(this.getChangesDir(),{recursive:!0,mode:493})}async createChangeDir($){let W=this.getChangePath($);return await s.mkdir(W,{recursive:!0,mode:493}),await s.mkdir(x.join(W,Q0.SPEC_DELTA),{recursive:!0,mode:493}),W}async readFile($){try{return await s.readFile($,"utf-8")}catch(W){if(W.code==="ENOENT")return null;throw W}}async writeFile($,W){let Q=x.dirname($);await s.mkdir(Q,{recursive:!0,mode:493}),await s.writeFile($,W,"utf-8")}async fileExists($){try{return await s.access($),!0}catch{return!1}}async dirExists($){try{return(await s.stat($)).isDirectory()}catch{return!1}}createMetadata($,W){let Q=new Date().toISOString();return{id:t9(),name:$,description:W,phase:"init",createdAt:Q,updatedAt:Q,tasks:[]}}async readMetadata($){let W=this.getChangeFilePath($,"meta"),Q=await this.readFile(W);if(!Q)return null;try{return JSON.parse(Q)}catch{return null}}async writeMetadata($,W){let Q=this.getChangeFilePath($,"meta");W.updatedAt=new Date().toISOString(),await this.writeFile(Q,JSON.stringify(W,null,2))}async updatePhase($,W){let Q=await this.readMetadata($);if(!Q)return null;return Q.phase=W,await this.writeMetadata($,Q),Q}async readSpecFile($,W){let Q=this.getChangeFilePath($,W);return this.readFile(Q)}async writeSpecFile($,W,Q){let Z=this.getChangeFilePath($,W);await this.writeFile(Z,Q);let V=await this.readMetadata($);if(V)await this.writeMetadata($,V)}async getPhaseContent($,W){let Q=m8[W];if(!Q)return null;return this.readSpecFile($,Q)}async readSteeringContext(){let $=this.getSteeringDir(),[W,Q,Z,V]=await Promise.all([this.readFile(x.join($,Z0.CONSTITUTION)),this.readFile(x.join($,Z0.PRODUCT)),this.readFile(x.join($,Z0.TECH)),this.readFile(x.join($,Z0.STRUCTURE))]);return{constitution:W||void 0,product:Q||void 0,tech:Z||void 0,structure:V||void 0}}async writeSteeringFile($,W){let Q=x.join(this.getSteeringDir(),Z0[$]);await this.writeFile(Q,W)}async hasSteeringDocs(){let $=this.getSteeringDir();if(!await this.dirExists($))return!1;return(await s.readdir($)).length>0}async listActiveChanges(){let $=this.getChangesDir();if(!await this.dirExists($))return[];return(await s.readdir($,{withFileTypes:!0})).filter((Q)=>Q.isDirectory()).map((Q)=>Q.name)}async listArchivedChanges(){let $=this.getArchiveDir();if(!await this.dirExists($))return[];return(await s.readdir($,{withFileTypes:!0})).filter((Q)=>Q.isDirectory()).map((Q)=>Q.name)}async changeExists($){return this.dirExists(this.getChangePath($))}async archiveChange($){let W=this.getChangePath($),Q=x.join(this.getArchiveDir(),$);await s.mkdir(x.dirname(Q),{recursive:!0,mode:493}),await s.rename(W,Q)}async restoreChange($){let W=x.join(this.getArchiveDir(),$),Q=this.getChangePath($);await s.rename(W,Q)}async listSpecDomains(){let $=this.getSpecsDir();if(!await this.dirExists($))return[];return(await s.readdir($,{withFileTypes:!0})).filter((Q)=>Q.isDirectory()).map((Q)=>Q.name)}async readAuthorativeSpec($){let W=x.join(this.getSpecsDir(),$,"spec.md");return this.readFile(W)}async writeAuthorativeSpec($,W){let Q=x.join(this.getSpecsDir(),$,"spec.md");await this.writeFile(Q,W)}async mergeSpecDeltas($){let W=x.join(this.getChangePath($),Q0.SPEC_DELTA);if(!await this.dirExists(W))return[];let Q=[],Z=await s.readdir(W,{withFileTypes:!0});for(let V of Z){if(!V.isDirectory())continue;let X=x.join(W,V.name,"spec.md"),Y=await this.readFile(X);if(Y){let J=await this.readAuthorativeSpec(V.name),G=J?`${J}
916
922
 
917
923
  ---
918
924
 
919
925
  <!-- Merged from ${$} -->
920
926
 
921
- ${Y}`:Y;await this.writeAuthorativeSpec(V.name,G),Q.push(V.name)}}return Q}static TEMPLATE_NAMES={proposal:"proposal.md.template",spec:"spec.md.template",requirements:"requirements.md.template",design:"design.md.template",tasks:"tasks.md.template",meta:""};static STEERING_TEMPLATE_NAMES={CONSTITUTION:"steering/constitution.md.template",PRODUCT:"steering/product.md.template",TECH:"steering/tech.md.template",STRUCTURE:"steering/structure.md.template"};async readTemplate($){let W=l0.TEMPLATE_NAMES[$];if(!W)return null;let Q=x.join(g8,W);return this.readFile(Q)}async readSteeringTemplate($){let W=l0.STEERING_TEMPLATE_NAMES[$],Q=x.join(g8,W);return this.readFile(Q)}fillTemplate($,W){let Q=$;for(let[Z,V]of Object.entries(W))Q=Q.replace(new RegExp(`\\{\\{${Z}\\}\\}`,"g"),V);return Q}async createFromTemplate($,W,Q){let Z=await this.readTemplate(W);if(!Z)return null;let V=this.fillTemplate(Z,{name:$,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString(),...Q});return await this.writeSpecFile($,W,V),V}async createSteeringFromTemplate($,W={}){let Q=await this.readSteeringTemplate($);if(!Q)return null;let Z=this.fillTemplate(Q,{createdAt:new Date().toISOString(),...W});return await this.writeSteeringFile($,Z),Z}async initializeSteeringDocs(){let $=[],W=this.getSteeringDir();for(let[Q,Z]of Object.entries(V0)){let V=x.join(W,Z);if(!await this.fileExists(V))await this.createSteeringFromTemplate(Q),$.push(Z)}return $}}var i2=M("Spec");class u{static instance=null;fileManager=null;state={currentSpec:null,specPath:null,isActive:!1,recentSpecs:[],steeringContext:null};stateChangeCallbacks=[];constructor(){}static getInstance(){if(!u.instance)u.instance=new u;return u.instance}static resetInstance(){u.instance=null}onStateChange($){return this.stateChangeCallbacks.push($),()=>{let W=this.stateChangeCallbacks.indexOf($);if(W>-1)this.stateChangeCallbacks.splice(W,1)}}notifyStateChange(){for(let $ of this.stateChangeCallbacks)$(this.state)}updateState($){this.state={...this.state,...$},this.notifyStateChange()}async initialize($){if(this.fileManager){i2.debug("SpecManager already initialized, skipping...");return}this.fileManager=new l0($),await this.fileManager.initializeDirectories();let W=await this.fileManager.readSteeringContext();this.updateState({steeringContext:W}),i2.debug("SpecManager initialized successfully")}getFileManager(){if(!this.fileManager)throw Error("SpecManager not initialized. Call initialize() first.");return this.fileManager}getState(){return{...this.state}}getCurrentSpec(){return this.state.currentSpec}isActive(){return this.state.isActive}getSteeringContext(){return this.state.steeringContext}async getSteeringContextString(){let $=this.state.steeringContext;if(!$)return null;let W=[];if($.constitution)W.push(`## Constitution (Project Governance)
927
+ ${Y}`:Y;await this.writeAuthorativeSpec(V.name,G),Q.push(V.name)}}return Q}static TEMPLATE_NAMES={proposal:"proposal.md.template",spec:"spec.md.template",requirements:"requirements.md.template",design:"design.md.template",tasks:"tasks.md.template",meta:""};static STEERING_TEMPLATE_NAMES={CONSTITUTION:"steering/constitution.md.template",PRODUCT:"steering/product.md.template",TECH:"steering/tech.md.template",STRUCTURE:"steering/structure.md.template"};async readTemplate($){let W=l0.TEMPLATE_NAMES[$];if(!W)return null;let Q=x.join(g8,W);return this.readFile(Q)}async readSteeringTemplate($){let W=l0.STEERING_TEMPLATE_NAMES[$],Q=x.join(g8,W);return this.readFile(Q)}fillTemplate($,W){let Q=$;for(let[Z,V]of Object.entries(W))Q=Q.replace(new RegExp(`\\{\\{${Z}\\}\\}`,"g"),V);return Q}async createFromTemplate($,W,Q){let Z=await this.readTemplate(W);if(!Z)return null;let V=this.fillTemplate(Z,{name:$,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString(),...Q});return await this.writeSpecFile($,W,V),V}async createSteeringFromTemplate($,W={}){let Q=await this.readSteeringTemplate($);if(!Q)return null;let Z=this.fillTemplate(Q,{createdAt:new Date().toISOString(),...W});return await this.writeSteeringFile($,Z),Z}async initializeSteeringDocs(){let $=[],W=this.getSteeringDir();for(let[Q,Z]of Object.entries(Z0)){let V=x.join(W,Z);if(!await this.fileExists(V))await this.createSteeringFromTemplate(Q),$.push(Z)}return $}}var i2=M("Spec");class u{static instance=null;fileManager=null;state={currentSpec:null,specPath:null,isActive:!1,recentSpecs:[],steeringContext:null};stateChangeCallbacks=[];constructor(){}static getInstance(){if(!u.instance)u.instance=new u;return u.instance}static resetInstance(){u.instance=null}onStateChange($){return this.stateChangeCallbacks.push($),()=>{let W=this.stateChangeCallbacks.indexOf($);if(W>-1)this.stateChangeCallbacks.splice(W,1)}}notifyStateChange(){for(let $ of this.stateChangeCallbacks)$(this.state)}updateState($){this.state={...this.state,...$},this.notifyStateChange()}async initialize($){if(this.fileManager){i2.debug("SpecManager already initialized, skipping...");return}this.fileManager=new l0($),await this.fileManager.initializeDirectories();let W=await this.fileManager.readSteeringContext();this.updateState({steeringContext:W}),i2.debug("SpecManager initialized successfully")}getFileManager(){if(!this.fileManager)throw Error("SpecManager not initialized. Call initialize() first.");return this.fileManager}getState(){return{...this.state}}getCurrentSpec(){return this.state.currentSpec}isActive(){return this.state.isActive}getSteeringContext(){return this.state.steeringContext}async getSteeringContextString(){let $=this.state.steeringContext;if(!$)return null;let W=[];if($.constitution)W.push(`## Constitution (Project Governance)
922
928
 
923
929
  ${$.constitution}`);if($.product)W.push(`## Product Vision
924
930
 
@@ -930,7 +936,7 @@ ${$.structure}`);return W.length>0?W.join(`
930
936
 
931
937
  ---
932
938
 
933
- `):null}async createSpec($,W){let Q=this.getFileManager();if(await Q.changeExists($))return{success:!1,message:`Spec "${$}" already exists`,error:"SPEC_EXISTS"};let Z=await Q.createChangeDir($),V=Q.createMetadata($,W);await Q.writeMetadata($,V);let X=this.generateProposalTemplate($,W);await Q.writeSpecFile($,"proposal",X);let Y=this.state.recentSpecs.filter((J)=>J!==$);return Y.unshift($),this.updateState({currentSpec:V,specPath:Z,isActive:!0,recentSpecs:Y.slice(0,10)}),{success:!0,message:`Spec "${$}" created successfully`,data:{spec:V,path:Z}}}async loadSpec($){let W=this.getFileManager(),Q=await W.readMetadata($);if(!Q)return{success:!1,message:`Spec "${$}" not found`,error:"SPEC_NOT_FOUND"};let Z=W.getChangePath($),V=this.state.recentSpecs.filter((X)=>X!==$);return V.unshift($),this.updateState({currentSpec:Q,specPath:Z,isActive:!0,recentSpecs:V.slice(0,10)}),{success:!0,message:`Spec "${$}" loaded successfully`,data:{spec:Q,path:Z}}}closeSpec(){this.updateState({currentSpec:null,specPath:null,isActive:!1})}exitSpecMode(){this.closeSpec()}async transitionPhase($){let W=this.getCurrentSpec();if(!W)return{success:!1,message:"No active spec",error:"NO_ACTIVE_SPEC"};if(!i0[W.phase].includes($))return{success:!1,message:`Cannot transition from "${W.phase}" to "${$}"`,error:"INVALID_TRANSITION"};let V=await this.getFileManager().updatePhase(W.name,$);if(!V)return{success:!1,message:"Failed to update phase",error:"UPDATE_FAILED"};if(this.updateState({currentSpec:V}),$==="done")i2.info("Spec completed");return{success:!0,message:`Transitioned to "${$}" phase`,data:{spec:V,phase:$}}}getAllowedTransitions(){let $=this.getCurrentSpec();if(!$)return[];return i0[$.phase]}async addTask($,W,Q){let Z=this.getCurrentSpec();if(!Z)return{success:!1,message:"No active spec",error:"NO_ACTIVE_SPEC"};let V={id:o9(8),title:$,description:W,status:"pending",dependencies:Q?.dependencies||[],affectedFiles:Q?.affectedFiles||[],complexity:Q?.complexity||"medium"},X={...Z,tasks:[...Z.tasks,V],updatedAt:new Date().toISOString()};return await this.getFileManager().writeMetadata(Z.name,X),this.updateState({currentSpec:X}),{success:!0,message:`Task "${$}" added`,data:{task:V}}}async updateTaskStatus($,W){let Q=this.getCurrentSpec();if(!Q)return{success:!1,message:"No active spec",error:"NO_ACTIVE_SPEC"};let Z=Q.tasks.find((J)=>J.id===$);if(!Z)return{success:!1,message:`Task "${$}" not found`,error:"TASK_NOT_FOUND"};let V={...Z,status:W,completedAt:W==="completed"?new Date().toISOString():Z.completedAt},X=Q.tasks.map((J)=>J.id===$?V:J),Y={...Q,tasks:X,currentTaskId:W==="in_progress"?$:Q.currentTaskId===$?void 0:Q.currentTaskId,updatedAt:new Date().toISOString()};return await this.getFileManager().writeMetadata(Q.name,Y),this.updateState({currentSpec:Y}),{success:!0,message:`Task status updated to "${W}"`,data:{task:V}}}getNextTask(){let $=this.getCurrentSpec();if(!$)return null;return $.tasks.find((W)=>{if(W.status!=="pending")return!1;return W.dependencies.every((Q)=>{return $.tasks.find((V)=>V.id===Q)?.status==="completed"})})||null}getTaskProgress(){let $=this.getCurrentSpec();if(!$||$.tasks.length===0)return{total:0,completed:0,percentage:0};let W=$.tasks.length,Q=$.tasks.filter((V)=>V.status==="completed").length,Z=Math.round(Q/W*100);return{total:W,completed:Q,percentage:Z}}async listSpecs($){let W=this.getFileManager(),Q=[],Z=await W.listActiveChanges();for(let V of Z){let X=await W.readMetadata(V);if(!X)continue;if($?.phase&&X.phase!==$.phase)continue;if($?.tags&&!$.tags.some((J)=>X.tags?.includes(J)))continue;if($?.query&&!X.name.toLowerCase().includes($.query.toLowerCase())&&!X.description.toLowerCase().includes($.query.toLowerCase()))continue;let Y=this.calculateTaskProgress(X.tasks);Q.push({name:X.name,description:X.description,phase:X.phase,updatedAt:X.updatedAt,path:W.getChangePath(V),isArchived:!1,taskProgress:Y})}if($?.includeArchived){let V=await W.listArchivedChanges();for(let X of V)Q.push({name:X,description:"(archived)",phase:"done",updatedAt:"",path:`${W.getArchiveDir()}/${X}`,isArchived:!0,taskProgress:{total:0,completed:0}})}return Q.sort((V,X)=>{if(V.isArchived!==X.isArchived)return V.isArchived?1:-1;return new Date(X.updatedAt).getTime()-new Date(V.updatedAt).getTime()}),Q}async archiveCurrentSpec(){let $=this.getCurrentSpec();if(!$)return{success:!1,message:"No active spec",error:"NO_ACTIVE_SPEC"};let W=this.getFileManager();return await W.mergeSpecDeltas($.name),await W.updatePhase($.name,"done"),await W.archiveChange($.name),this.closeSpec(),{success:!0,message:`Spec "${$.name}" archived successfully`,data:{spec:{...$,phase:"done"}}}}async validateCurrentSpec(){let $=this.getCurrentSpec();if(!$)return{valid:!1,phase:"init",completeness:{proposal:!1,spec:!1,requirements:!1,design:!1,tasks:!1},issues:[{severity:"error",file:"meta",message:"No active spec"}],suggestions:["Create a new spec with /spec proposal <name>"]};let W=this.getFileManager(),Q=[],Z=[],[V,X,Y,J,G]=await Promise.all([W.readSpecFile($.name,"proposal"),W.readSpecFile($.name,"spec"),W.readSpecFile($.name,"requirements"),W.readSpecFile($.name,"design"),W.readSpecFile($.name,"tasks")]),B={proposal:!!V,spec:!!X,requirements:!!Y,design:!!J,tasks:!!G};if($.phase==="requirements"&&!B.requirements)Q.push({severity:"warning",file:"requirements",message:"Requirements document is missing"}),Z.push("Generate requirements using EARS format");if($.phase==="design"&&!B.design)Q.push({severity:"warning",file:"design",message:"Design document is missing"}),Z.push("Create architecture diagrams and API contracts");if($.phase==="tasks"&&$.tasks.length===0)Q.push({severity:"warning",file:"tasks",message:"No tasks defined"}),Z.push("Break down the spec into atomic tasks");if($.phase==="implementation"){let K=this.getTaskProgress();if(K.completed<K.total)Q.push({severity:"info",file:"tasks",message:`${K.total-K.completed} tasks remaining`})}return{valid:Q.filter((K)=>K.severity==="error").length===0,phase:$.phase,completeness:B,issues:Q,suggestions:Z}}generateProposalTemplate($,W){return`# ${$}
939
+ `):null}async createSpec($,W){let Q=this.getFileManager();if(await Q.changeExists($))return{success:!1,message:`Spec "${$}" already exists`,error:"SPEC_EXISTS"};let Z=await Q.createChangeDir($),V=Q.createMetadata($,W);await Q.writeMetadata($,V);let X=this.generateProposalTemplate($,W);await Q.writeSpecFile($,"proposal",X);let Y=this.state.recentSpecs.filter((J)=>J!==$);return Y.unshift($),this.updateState({currentSpec:V,specPath:Z,isActive:!0,recentSpecs:Y.slice(0,10)}),{success:!0,message:`Spec "${$}" created successfully`,data:{spec:V,path:Z}}}async loadSpec($){let W=this.getFileManager(),Q=await W.readMetadata($);if(!Q)return{success:!1,message:`Spec "${$}" not found`,error:"SPEC_NOT_FOUND"};let Z=W.getChangePath($),V=this.state.recentSpecs.filter((X)=>X!==$);return V.unshift($),this.updateState({currentSpec:Q,specPath:Z,isActive:!0,recentSpecs:V.slice(0,10)}),{success:!0,message:`Spec "${$}" loaded successfully`,data:{spec:Q,path:Z}}}closeSpec(){this.updateState({currentSpec:null,specPath:null,isActive:!1})}exitSpecMode(){this.closeSpec()}async transitionPhase($){let W=this.getCurrentSpec();if(!W)return{success:!1,message:"No active spec",error:"NO_ACTIVE_SPEC"};if(!i0[W.phase].includes($))return{success:!1,message:`Cannot transition from "${W.phase}" to "${$}"`,error:"INVALID_TRANSITION"};let V=await this.getFileManager().updatePhase(W.name,$);if(!V)return{success:!1,message:"Failed to update phase",error:"UPDATE_FAILED"};if(this.updateState({currentSpec:V}),$==="done")i2.info("Spec completed");return{success:!0,message:`Transitioned to "${$}" phase`,data:{spec:V,phase:$}}}getAllowedTransitions(){let $=this.getCurrentSpec();if(!$)return[];return i0[$.phase]}async addTask($,W,Q){let Z=this.getCurrentSpec();if(!Z)return{success:!1,message:"No active spec",error:"NO_ACTIVE_SPEC"};let V={id:W3(8),title:$,description:W,status:"pending",dependencies:Q?.dependencies||[],affectedFiles:Q?.affectedFiles||[],complexity:Q?.complexity||"medium"},X={...Z,tasks:[...Z.tasks,V],updatedAt:new Date().toISOString()};return await this.getFileManager().writeMetadata(Z.name,X),this.updateState({currentSpec:X}),{success:!0,message:`Task "${$}" added`,data:{task:V}}}async updateTaskStatus($,W){let Q=this.getCurrentSpec();if(!Q)return{success:!1,message:"No active spec",error:"NO_ACTIVE_SPEC"};let Z=Q.tasks.find((J)=>J.id===$);if(!Z)return{success:!1,message:`Task "${$}" not found`,error:"TASK_NOT_FOUND"};let V={...Z,status:W,completedAt:W==="completed"?new Date().toISOString():Z.completedAt},X=Q.tasks.map((J)=>J.id===$?V:J),Y={...Q,tasks:X,currentTaskId:W==="in_progress"?$:Q.currentTaskId===$?void 0:Q.currentTaskId,updatedAt:new Date().toISOString()};return await this.getFileManager().writeMetadata(Q.name,Y),this.updateState({currentSpec:Y}),{success:!0,message:`Task status updated to "${W}"`,data:{task:V}}}getNextTask(){let $=this.getCurrentSpec();if(!$)return null;return $.tasks.find((W)=>{if(W.status!=="pending")return!1;return W.dependencies.every((Q)=>{return $.tasks.find((V)=>V.id===Q)?.status==="completed"})})||null}getTaskProgress(){let $=this.getCurrentSpec();if(!$||$.tasks.length===0)return{total:0,completed:0,percentage:0};let W=$.tasks.length,Q=$.tasks.filter((V)=>V.status==="completed").length,Z=Math.round(Q/W*100);return{total:W,completed:Q,percentage:Z}}async listSpecs($){let W=this.getFileManager(),Q=[],Z=await W.listActiveChanges();for(let V of Z){let X=await W.readMetadata(V);if(!X)continue;if($?.phase&&X.phase!==$.phase)continue;if($?.tags&&!$.tags.some((J)=>X.tags?.includes(J)))continue;if($?.query&&!X.name.toLowerCase().includes($.query.toLowerCase())&&!X.description.toLowerCase().includes($.query.toLowerCase()))continue;let Y=this.calculateTaskProgress(X.tasks);Q.push({name:X.name,description:X.description,phase:X.phase,updatedAt:X.updatedAt,path:W.getChangePath(V),isArchived:!1,taskProgress:Y})}if($?.includeArchived){let V=await W.listArchivedChanges();for(let X of V)Q.push({name:X,description:"(archived)",phase:"done",updatedAt:"",path:`${W.getArchiveDir()}/${X}`,isArchived:!0,taskProgress:{total:0,completed:0}})}return Q.sort((V,X)=>{if(V.isArchived!==X.isArchived)return V.isArchived?1:-1;return new Date(X.updatedAt).getTime()-new Date(V.updatedAt).getTime()}),Q}async archiveCurrentSpec(){let $=this.getCurrentSpec();if(!$)return{success:!1,message:"No active spec",error:"NO_ACTIVE_SPEC"};let W=this.getFileManager();return await W.mergeSpecDeltas($.name),await W.updatePhase($.name,"done"),await W.archiveChange($.name),this.closeSpec(),{success:!0,message:`Spec "${$.name}" archived successfully`,data:{spec:{...$,phase:"done"}}}}async validateCurrentSpec(){let $=this.getCurrentSpec();if(!$)return{valid:!1,phase:"init",completeness:{proposal:!1,spec:!1,requirements:!1,design:!1,tasks:!1},issues:[{severity:"error",file:"meta",message:"No active spec"}],suggestions:["Create a new spec with /spec proposal <name>"]};let W=this.getFileManager(),Q=[],Z=[],[V,X,Y,J,G]=await Promise.all([W.readSpecFile($.name,"proposal"),W.readSpecFile($.name,"spec"),W.readSpecFile($.name,"requirements"),W.readSpecFile($.name,"design"),W.readSpecFile($.name,"tasks")]),K={proposal:!!V,spec:!!X,requirements:!!Y,design:!!J,tasks:!!G};if($.phase==="requirements"&&!K.requirements)Q.push({severity:"warning",file:"requirements",message:"Requirements document is missing"}),Z.push("Generate requirements using EARS format");if($.phase==="design"&&!K.design)Q.push({severity:"warning",file:"design",message:"Design document is missing"}),Z.push("Create architecture diagrams and API contracts");if($.phase==="tasks"&&$.tasks.length===0)Q.push({severity:"warning",file:"tasks",message:"No tasks defined"}),Z.push("Break down the spec into atomic tasks");if($.phase==="implementation"){let B=this.getTaskProgress();if(B.completed<B.total)Q.push({severity:"info",file:"tasks",message:`${B.total-B.completed} tasks remaining`})}return{valid:Q.filter((B)=>B.severity==="error").length===0,phase:$.phase,completeness:K,issues:Q,suggestions:Z}}generateProposalTemplate($,W){return`# ${$}
934
940
 
935
941
  ## Summary
936
942
 
@@ -964,7 +970,7 @@ ${W}
964
970
  <!-- What needs to be clarified before proceeding? -->
965
971
 
966
972
  1.
967
- `}calculateTaskProgress($){let W=$.length,Q=$.filter((Z)=>Z.status==="completed").length;return{total:W,completed:Q}}}var c8=E({name:"AddTask",displayName:"Add Task",kind:"write",schema:i$.object({title:i$.string().min(1).describe("Brief title of the task"),description:i$.string().min(1).describe("Detailed description of what needs to be done"),complexity:i$.enum(["low","medium","high"]).optional().default("medium").describe("Estimated complexity of the task"),affectedFiles:i$.array(i$.string()).optional().default([]).describe("List of files that will be modified by this task"),dependencies:i$.array(i$.string()).optional().default([]).describe("IDs of tasks that must be completed before this one")}),description:{short:"Add a task to the current Spec project",long:`Use this tool to add tasks to the current Spec-Driven Development project.
973
+ `}calculateTaskProgress($){let W=$.length,Q=$.filter((Z)=>Z.status==="completed").length;return{total:W,completed:Q}}}var c8=E({name:"AddTask",displayName:"Add Task",kind:"write",schema:c$.object({title:c$.string().min(1).describe("Brief title of the task"),description:c$.string().min(1).describe("Detailed description of what needs to be done"),complexity:c$.enum(["low","medium","high"]).optional().default("medium").describe("Estimated complexity of the task"),affectedFiles:c$.array(c$.string()).optional().default([]).describe("List of files that will be modified by this task"),dependencies:c$.array(c$.string()).optional().default([]).describe("IDs of tasks that must be completed before this one")}),description:{short:"Add a task to the current Spec project",long:`Use this tool to add tasks to the current Spec-Driven Development project.
968
974
 
969
975
  ## Task Structure
970
976
 
@@ -999,16 +1005,16 @@ AddTask({
999
1005
  - Tasks are tracked in .meta.json, not tasks.md
1000
1006
  - Use UpdateTaskStatus to mark tasks as completed
1001
1007
  - Use GetSpecContext to see current tasks and progress
1002
- `},async execute($,W){let{title:Q,description:Z,complexity:V,affectedFiles:X,dependencies:Y}=$,J=u.getInstance();if(!J.getCurrentSpec())return{success:!1,llmContent:"No active spec. Use EnterSpecMode to start a new spec project, or use the /spec command to load an existing one.",displayContent:"❌ No active spec",error:{type:"validation_error",message:"No active spec project"}};let B=await J.addTask(Q,Z,{complexity:V,affectedFiles:X,dependencies:Y});if(!B.success)return{success:!1,llmContent:`Failed to add task: ${B.message}`,displayContent:`❌ Failed to add task: ${B.message}`,error:{type:"execution_error",message:B.message}};let K=B.data?.task,q=J.getTaskProgress();return{success:!0,llmContent:`✅ Task added: "${Q}"
1008
+ `},async execute($,W){let{title:Q,description:Z,complexity:V,affectedFiles:X,dependencies:Y}=$,J=u.getInstance();if(!J.getCurrentSpec())return{success:!1,llmContent:"No active spec. Use EnterSpecMode to start a new spec project, or use the /spec command to load an existing one.",displayContent:"❌ No active spec",error:{type:"validation_error",message:"No active spec project"}};let K=await J.addTask(Q,Z,{complexity:V,affectedFiles:X,dependencies:Y});if(!K.success)return{success:!1,llmContent:`Failed to add task: ${K.message}`,displayContent:`❌ Failed to add task: ${K.message}`,error:{type:"execution_error",message:K.message}};let B=K.data?.task,q=J.getTaskProgress();return{success:!0,llmContent:`✅ Task added: "${Q}"
1003
1009
 
1004
- `+`\uD83D\uDCCB Task ID: ${K?.id}
1010
+ `+`\uD83D\uDCCB Task ID: ${B?.id}
1005
1011
  `+`\uD83D\uDCCA Complexity: ${V}
1006
1012
  `+`\uD83D\uDCC1 Affected files: ${X?.length?X.join(", "):"None specified"}
1007
1013
  `+`\uD83D\uDD17 Dependencies: ${Y?.length?Y.join(", "):"None"}
1008
1014
 
1009
1015
  `+`\uD83D\uDCC8 Progress: ${q.completed}/${q.total} tasks (${q.percentage}%)
1010
1016
 
1011
- `+"\uD83D\uDCA1 Use AddTask to add more tasks, or use /spec apply to start implementation.",displayContent:`✅ Added task: ${Q} (ID: ${K?.id})`,metadata:{taskId:K?.id,title:Q,complexity:V,affectedFiles:X,dependencies:Y,totalTasks:q.total}}}});import{z as l2}from"zod";var i8=E({name:"EnterSpecMode",displayName:"Enter Spec Mode",kind:"readonly",schema:l2.object({featureName:l2.string().min(1).describe("The name of the feature/change (used as directory name)"),description:l2.string().min(1).describe("Brief description of what this feature/change does")}),description:{short:"Enter Spec-Driven Development mode for complex features",long:`Use this tool to enter Spec mode when you need to implement a complex feature that benefits from structured planning.
1017
+ `+"\uD83D\uDCA1 Use AddTask to add more tasks, or use /spec apply to start implementation.",displayContent:`✅ Added task: ${Q} (ID: ${B?.id})`,metadata:{taskId:B?.id,title:Q,complexity:V,affectedFiles:X,dependencies:Y,totalTasks:q.total}}}});import{z as l2}from"zod";var i8=E({name:"EnterSpecMode",displayName:"Enter Spec Mode",kind:"readonly",schema:l2.object({featureName:l2.string().min(1).describe("The name of the feature/change (used as directory name)"),description:l2.string().min(1).describe("Brief description of what this feature/change does")}),description:{short:"Enter Spec-Driven Development mode for complex features",long:`Use this tool to enter Spec mode when you need to implement a complex feature that benefits from structured planning.
1012
1018
 
1013
1019
  ## Spec-Driven Development (SDD)
1014
1020
 
@@ -1138,15 +1144,15 @@ ExitSpecMode({})
1138
1144
  // Complete and archive
1139
1145
  ExitSpecMode({ archive: true, summary: "Implemented OAuth2 authentication" })
1140
1146
  \`\`\`
1141
- `},async execute($,W){let{archive:Q,summary:Z}=$,V=u.getInstance(),X=V.getCurrentSpec();if(!X)return{success:!1,llmContent:"No active spec to exit from.",displayContent:"❌ No active spec",error:{type:"validation_error",message:"No active spec project"}};try{let{name:Y,phase:J}=X,G=V.getTaskProgress();if(Q&&W.confirmationHandler){let B=G.total>0&&G.completed<G.total?`
1147
+ `},async execute($,W){let{archive:Q,summary:Z}=$,V=u.getInstance(),X=V.getCurrentSpec();if(!X)return{success:!1,llmContent:"No active spec to exit from.",displayContent:"❌ No active spec",error:{type:"validation_error",message:"No active spec project"}};try{let{name:Y,phase:J}=X,G=V.getTaskProgress();if(Q&&W.confirmationHandler){let K=G.total>0&&G.completed<G.total?`
1142
1148
 
1143
1149
  ⚠️ Warning: ${G.total-G.completed} tasks are not completed.`:"";if(!(await W.confirmationHandler.requestConfirmation({title:"Archive Spec",message:`Archive spec "${Y}"?
1144
1150
 
1145
- Phase: ${q$[J]}
1146
- Tasks: ${G.completed}/${G.total} completed`+B,details:"This will move the spec to archive and merge any spec deltas."})).approved)return{success:!0,llmContent:"Archive cancelled. Still in Spec mode.",displayContent:"⚠️ Archive cancelled",metadata:{archived:!1,stillActive:!0}}}if(Q){let B=await V.archiveCurrentSpec();if(!B.success)return{success:!1,llmContent:`Failed to archive: ${B.message}`,displayContent:"❌ Archive failed",error:{type:"execution_error",message:B.error||"Archive failed"}};return{success:!0,llmContent:`✅ Spec "${Y}" archived successfully!
1151
+ Phase: ${U$[J]}
1152
+ Tasks: ${G.completed}/${G.total} completed`+K,details:"This will move the spec to archive and merge any spec deltas."})).approved)return{success:!0,llmContent:"Archive cancelled. Still in Spec mode.",displayContent:"⚠️ Archive cancelled",metadata:{archived:!1,stillActive:!0}}}if(Q){let K=await V.archiveCurrentSpec();if(!K.success)return{success:!1,llmContent:`Failed to archive: ${K.message}`,displayContent:"❌ Archive failed",error:{type:"execution_error",message:K.error||"Archive failed"}};return{success:!0,llmContent:`✅ Spec "${Y}" archived successfully!
1147
1153
 
1148
1154
  `+`\uD83D\uDCCA Final Status:
1149
- `+`- Phase: ${q$[J]}
1155
+ `+`- Phase: ${U$[J]}
1150
1156
  - Tasks: ${G.completed}/${G.total} completed
1151
1157
  `+(Z?`- Summary: ${Z}
1152
1158
  `:"")+`
@@ -1155,7 +1161,7 @@ Tasks: ${G.completed}/${G.total} completed`+B,details:"This will move the spec t
1155
1161
  Exited Spec mode. You can start a new spec or continue with regular work.`,displayContent:`✅ Archived: ${Y}`,metadata:{archived:!0,featureName:Y,phase:J,taskProgress:G,summary:Z,shouldExitSpecMode:!0}}}return V.exitSpecMode(),{success:!0,llmContent:`✅ Exited Spec mode for "${Y}"
1156
1162
 
1157
1163
  `+`\uD83D\uDCCA Current Status:
1158
- `+`- Phase: ${q$[J]}
1164
+ `+`- Phase: ${U$[J]}
1159
1165
  - Tasks: ${G.completed}/${G.total} completed
1160
1166
 
1161
1167
  `+`\uD83D\uDCC1 Spec preserved at: .blade/changes/${Y}/
@@ -1187,8 +1193,8 @@ You can now work on other tasks or start a new spec.`,displayContent:`✅ Exited
1187
1193
 
1188
1194
  [File contents and steering docs follow...]
1189
1195
  \`\`\`
1190
- `},async execute($,W){let{includeFiles:Q,includeSteering:Z}=$,V=u.getInstance(),X=V.getCurrentSpec();if(!X)return{success:!1,llmContent:"No active spec. Use EnterSpecMode or /spec load <name> first.",displayContent:"❌ No active spec",error:{type:"validation_error",message:"No active spec project"}};try{let Y=V.getFileManager(),J=[];J.push(`# \uD83D\uDCCB Spec: ${X.name}`),J.push(`**Description**: ${X.description}`),J.push(`**Phase**: ${q$[X.phase]} (${X.phase})`),J.push(`**Created**: ${new Date(X.createdAt).toLocaleString()}`),J.push(`**Updated**: ${new Date(X.updatedAt).toLocaleString()}`);let G=V.getTaskProgress();if(G.total>0){if(J.push(`**Tasks**: ${G.completed}/${G.total} completed (${G.percentage}%)`),X.currentTaskId){let q=X.tasks.find((w)=>w.id===X.currentTaskId);if(q)J.push(`**Current Task**: ${q.title}`)}let K=X.tasks.filter((q)=>q.status==="blocked");if(K.length>0)J.push(`**⚠️ Blocked**: ${K.map((q)=>q.title).join(", ")}`)}if(J.push(""),Z){let K=await V.getSteeringContextString();if(K)J.push("---"),J.push("## \uD83D\uDCD6 Steering Documents"),J.push(""),J.push(K),J.push("")}if(Q){let K=["proposal","spec","requirements","design","tasks"];for(let q of K){let w=await Y.readSpecFile(X.name,q);if(w)J.push("---"),J.push(`## \uD83D\uDCC4 ${q}.md`),J.push(""),J.push(w),J.push("")}}if(X.tasks.length>0){J.push("---"),J.push("## \uD83D\uDCDD Task List"),J.push("");for(let K of X.tasks){let q={pending:"⏳",in_progress:"\uD83D\uDD04",completed:"✅",blocked:"\uD83D\uDEAB",skipped:"⏭️"}[K.status];if(J.push(`- ${q} **${K.title}** (${K.complexity}) - ${K.status}`),K.description)J.push(` ${K.description}`)}}return{success:!0,llmContent:J.join(`
1191
- `),displayContent:`\uD83D\uDCCB Spec context: ${X.name} (${X.phase})`,metadata:{featureName:X.name,phase:X.phase,taskProgress:G,filesIncluded:Q,steeringIncluded:Z}}}catch(Y){return{success:!1,llmContent:`Failed to get spec context: ${Y instanceof Error?Y.message:"Unknown error"}`,displayContent:"❌ Failed to get spec context",error:{type:"execution_error",message:Y instanceof Error?Y.message:"Read error"}}}}});import{z as a8}from"zod";function t9($){switch($){case"requirements":return`## Requirements Phase Instructions
1196
+ `},async execute($,W){let{includeFiles:Q,includeSteering:Z}=$,V=u.getInstance(),X=V.getCurrentSpec();if(!X)return{success:!1,llmContent:"No active spec. Use EnterSpecMode or /spec load <name> first.",displayContent:"❌ No active spec",error:{type:"validation_error",message:"No active spec project"}};try{let Y=V.getFileManager(),J=[];J.push(`# \uD83D\uDCCB Spec: ${X.name}`),J.push(`**Description**: ${X.description}`),J.push(`**Phase**: ${U$[X.phase]} (${X.phase})`),J.push(`**Created**: ${new Date(X.createdAt).toLocaleString()}`),J.push(`**Updated**: ${new Date(X.updatedAt).toLocaleString()}`);let G=V.getTaskProgress();if(G.total>0){if(J.push(`**Tasks**: ${G.completed}/${G.total} completed (${G.percentage}%)`),X.currentTaskId){let q=X.tasks.find((w)=>w.id===X.currentTaskId);if(q)J.push(`**Current Task**: ${q.title}`)}let B=X.tasks.filter((q)=>q.status==="blocked");if(B.length>0)J.push(`**⚠️ Blocked**: ${B.map((q)=>q.title).join(", ")}`)}if(J.push(""),Z){let B=await V.getSteeringContextString();if(B)J.push("---"),J.push("## \uD83D\uDCD6 Steering Documents"),J.push(""),J.push(B),J.push("")}if(Q){let B=["proposal","spec","requirements","design","tasks"];for(let q of B){let w=await Y.readSpecFile(X.name,q);if(w)J.push("---"),J.push(`## \uD83D\uDCC4 ${q}.md`),J.push(""),J.push(w),J.push("")}}if(X.tasks.length>0){J.push("---"),J.push("## \uD83D\uDCDD Task List"),J.push("");for(let B of X.tasks){let q={pending:"⏳",in_progress:"\uD83D\uDD04",completed:"✅",blocked:"\uD83D\uDEAB",skipped:"⏭️"}[B.status];if(J.push(`- ${q} **${B.title}** (${B.complexity}) - ${B.status}`),B.description)J.push(` ${B.description}`)}}return{success:!0,llmContent:J.join(`
1197
+ `),displayContent:`\uD83D\uDCCB Spec context: ${X.name} (${X.phase})`,metadata:{featureName:X.name,phase:X.phase,taskProgress:G,filesIncluded:Q,steeringIncluded:Z}}}catch(Y){return{success:!1,llmContent:`Failed to get spec context: ${Y instanceof Error?Y.message:"Unknown error"}`,displayContent:"❌ Failed to get spec context",error:{type:"execution_error",message:Y instanceof Error?Y.message:"Read error"}}}}});import{z as a8}from"zod";function Q3($){switch($){case"requirements":return`## Requirements Phase Instructions
1192
1198
 
1193
1199
  1. Use UpdateSpec to write requirements.md
1194
1200
  2. Use EARS format:
@@ -1272,14 +1278,14 @@ AddTask({
1272
1278
 
1273
1279
  After adding tasks, try transitioning again.`,displayContent:"❌ No tasks defined - 我需要先添加任务",error:{type:"validation_error",message:"No tasks defined. Use AddTask tool to add tasks first."}}}if(Q==="done"){let Y=Z.getTaskProgress();if(Y.total>0&&Y.completed<Y.total){if(W.confirmationHandler){if(!(await W.confirmationHandler.requestConfirmation({title:"Incomplete Tasks",message:`⚠️ ${Y.total-Y.completed} tasks are not completed.
1274
1280
 
1275
- Are you sure you want to mark this spec as done?`,details:`Completed: ${Y.completed}/${Y.total}`})).approved)return{success:!1,llmContent:"User cancelled transition to done phase.",displayContent:"⚠️ Transition cancelled",error:{type:"validation_error",message:"User cancelled"}}}}}try{let Y=await Z.transitionPhase(Q);if(!Y.success)return{success:!1,llmContent:Y.message,displayContent:`❌ ${Y.message}`,error:{type:"execution_error",message:Y.error||"Transition failed"}};let J=q$[V.phase],G=q$[Q];return{success:!0,llmContent:`✅ Transitioned from "${J}" to "${G}"
1281
+ Are you sure you want to mark this spec as done?`,details:`Completed: ${Y.completed}/${Y.total}`})).approved)return{success:!1,llmContent:"User cancelled transition to done phase.",displayContent:"⚠️ Transition cancelled",error:{type:"validation_error",message:"User cancelled"}}}}}try{let Y=await Z.transitionPhase(Q);if(!Y.success)return{success:!1,llmContent:Y.message,displayContent:`❌ ${Y.message}`,error:{type:"execution_error",message:Y.error||"Transition failed"}};let J=U$[V.phase],G=U$[Q];return{success:!0,llmContent:`✅ Transitioned from "${J}" to "${G}"
1276
1282
 
1277
- `+t9(Q),displayContent:`✅ Phase: ${J} → ${G}`,metadata:{fromPhase:V.phase,toPhase:Q,featureName:V.name}}}catch(Y){return{success:!1,llmContent:`Transition failed: ${Y instanceof Error?Y.message:"Unknown error"}`,displayContent:"❌ Transition failed",error:{type:"execution_error",message:Y instanceof Error?Y.message:"Transition error"}}}}});import{z as M1}from"zod";function e9($,W){let Q=["init","requirements","design","tasks","implementation"],V={proposal:"init",requirements:"requirements",design:"design",tasks:"tasks"}[$];if(!V)return"";let X=Q.indexOf(W);if(Q.indexOf(V)>X)return`
1283
+ `+Q3(Q),displayContent:`✅ Phase: ${J} → ${G}`,metadata:{fromPhase:V.phase,toPhase:Q,featureName:V.name}}}catch(Y){return{success:!1,llmContent:`Transition failed: ${Y instanceof Error?Y.message:"Unknown error"}`,displayContent:"❌ Transition failed",error:{type:"execution_error",message:Y instanceof Error?Y.message:"Transition error"}}}}});import{z as C1}from"zod";function Z3($,W){let Q=["init","requirements","design","tasks","implementation"],V={proposal:"init",requirements:"requirements",design:"design",tasks:"tasks"}[$];if(!V)return"";let X=Q.indexOf(W);if(Q.indexOf(V)>X)return`
1278
1284
  \uD83D\uDCA1 Consider transitioning to "${V}" phase using TransitionSpecPhase tool.`;switch($){case"proposal":return`
1279
1285
  \uD83D\uDCDD Next: Define requirements in requirements.md using EARS format.`;case"requirements":return`
1280
1286
  \uD83D\uDCDD Next: Create technical design in design.md (diagrams, API contracts).`;case"design":return`
1281
1287
  \uD83D\uDCDD Next: Break down into tasks in tasks.md (atomic, with dependencies).`;case"tasks":return`
1282
- \uD83D\uDCDD Next: Start implementation. Update task status as you progress.`;default:return""}}var s8=E({name:"UpdateSpec",displayName:"Update Spec",kind:"write",schema:M1.object({fileType:M1.enum(["proposal","spec","requirements","design","tasks"]).describe("The type of spec file to update"),content:M1.string().min(1).describe("The content to write to the file"),append:M1.boolean().optional().default(!1).describe("If true, append to existing content instead of replacing")}),description:{short:"Update a spec file in the current Spec project",long:`Use this tool to update spec files in the current Spec-Driven Development project.
1288
+ \uD83D\uDCDD Next: Start implementation. Update task status as you progress.`;default:return""}}var s8=E({name:"UpdateSpec",displayName:"Update Spec",kind:"write",schema:C1.object({fileType:C1.enum(["proposal","spec","requirements","design","tasks"]).describe("The type of spec file to update"),content:C1.string().min(1).describe("The content to write to the file"),append:C1.boolean().optional().default(!1).describe("If true, append to existing content instead of replacing")}),description:{short:"Update a spec file in the current Spec project",long:`Use this tool to update spec files in the current Spec-Driven Development project.
1283
1289
 
1284
1290
  ## Available File Types
1285
1291
 
@@ -1314,12 +1320,12 @@ UpdateSpec({
1314
1320
  - Use append: true to add to existing content
1315
1321
  `},async execute($,W){let{fileType:Q,content:Z,append:V}=$,X=u.getInstance(),Y=X.getCurrentSpec();if(!Y)return{success:!1,llmContent:"No active spec. Use EnterSpecMode to start a new spec project, or use the /spec command to load an existing one.",displayContent:"❌ No active spec",error:{type:"validation_error",message:"No active spec project"}};try{let J=X.getFileManager(),G=Z;if(V){let q=await J.readSpecFile(Y.name,Q);G=q?`${q}
1316
1322
 
1317
- ${Z}`:Z}await J.writeSpecFile(Y.name,Q,G);let B=G.split(`
1318
- `).length,K=G.length;return{success:!0,llmContent:`✅ Updated ${Q}.md for "${Y.name}"
1323
+ ${Z}`:Z}await J.writeSpecFile(Y.name,Q,G);let K=G.split(`
1324
+ `).length,B=G.length;return{success:!0,llmContent:`✅ Updated ${Q}.md for "${Y.name}"
1319
1325
 
1320
- `+`\uD83D\uDCCA Stats: ${B} lines, ${K} characters
1326
+ `+`\uD83D\uDCCA Stats: ${K} lines, ${B} characters
1321
1327
 
1322
- `+e9(Q,Y.phase),displayContent:`✅ Updated ${Q}.md (${B} lines)`,metadata:{featureName:Y.name,fileType:Q,lines:B,chars:K,append:V}}}catch(J){return{success:!1,llmContent:`Failed to update ${Q}.md: ${J instanceof Error?J.message:"Unknown error"}`,displayContent:`❌ Failed to update ${Q}.md`,error:{type:"execution_error",message:J instanceof Error?J.message:"Write error"}}}}});import{z as S1}from"zod";var o8={pending:"⏳ 待处理",in_progress:"\uD83D\uDD04 进行中",completed:"✅ 已完成",blocked:"\uD83D\uDEAB 已阻塞",skipped:"⏭️ 已跳过"},t8=E({name:"UpdateTaskStatus",displayName:"Update Task Status",kind:"write",schema:S1.object({taskId:S1.string().min(1).describe("The ID of the task to update"),status:S1.enum(["pending","in_progress","completed","blocked","skipped"]).describe("The new status for the task"),notes:S1.string().optional().describe("Optional notes about the status change (e.g., why blocked)")}),description:{short:"Update the status of a task in the current Spec",long:`Use this tool to update the status of tasks in the current Spec project.
1328
+ `+Z3(Q,Y.phase),displayContent:`✅ Updated ${Q}.md (${K} lines)`,metadata:{featureName:Y.name,fileType:Q,lines:K,chars:B,append:V}}}catch(J){return{success:!1,llmContent:`Failed to update ${Q}.md: ${J instanceof Error?J.message:"Unknown error"}`,displayContent:`❌ Failed to update ${Q}.md`,error:{type:"execution_error",message:J instanceof Error?J.message:"Write error"}}}}});import{z as M1}from"zod";var o8={pending:"⏳ 待处理",in_progress:"\uD83D\uDD04 进行中",completed:"✅ 已完成",blocked:"\uD83D\uDEAB 已阻塞",skipped:"⏭️ 已跳过"},t8=E({name:"UpdateTaskStatus",displayName:"Update Task Status",kind:"write",schema:M1.object({taskId:M1.string().min(1).describe("The ID of the task to update"),status:M1.enum(["pending","in_progress","completed","blocked","skipped"]).describe("The new status for the task"),notes:M1.string().optional().describe("Optional notes about the status change (e.g., why blocked)")}),description:{short:"Update the status of a task in the current Spec",long:`Use this tool to update the status of tasks in the current Spec project.
1323
1329
 
1324
1330
  ## Task Statuses
1325
1331
 
@@ -1354,9 +1360,9 @@ UpdateTaskStatus({
1354
1360
 
1355
1361
  Available tasks:
1356
1362
  ${Y.tasks.map((w)=>`- ${w.id}: ${w.title}`).join(`
1357
- `)||"No tasks"}`,displayContent:`❌ Task not found: ${Q}`,error:{type:"validation_error",message:"Task not found"}};let G=await X.updateTaskStatus(Q,Z);if(!G.success)return{success:!1,llmContent:`Failed to update task status: ${G.message}`,displayContent:`❌ Failed to update: ${G.message}`,error:{type:"execution_error",message:G.message}};let B=X.getTaskProgress(),K=X.getNextTask(),q="";if(Z==="completed"&&K)q=`
1363
+ `)||"No tasks"}`,displayContent:`❌ Task not found: ${Q}`,error:{type:"validation_error",message:"Task not found"}};let G=await X.updateTaskStatus(Q,Z);if(!G.success)return{success:!1,llmContent:`Failed to update task status: ${G.message}`,displayContent:`❌ Failed to update: ${G.message}`,error:{type:"execution_error",message:G.message}};let K=X.getTaskProgress(),B=X.getNextTask(),q="";if(Z==="completed"&&B)q=`
1358
1364
 
1359
- \uD83C\uDFAF Next task: "${K.title}" (${K.id})`;else if(Z==="completed"&&B.completed===B.total)q=`
1365
+ \uD83C\uDFAF Next task: "${B.title}" (${B.id})`;else if(Z==="completed"&&K.completed===K.total)q=`
1360
1366
 
1361
1367
  \uD83C\uDF89 All tasks completed! Use /spec archive to archive this spec.`;return{success:!0,llmContent:`✅ Updated task "${J.title}"
1362
1368
 
@@ -1364,7 +1370,7 @@ ${Y.tasks.map((w)=>`- ${w.id}: ${w.title}`).join(`
1364
1370
  `+`\uD83D\uDCCA Status: ${o8[Z]}
1365
1371
  `+(V?`\uD83D\uDCDD Notes: ${V}
1366
1372
  `:"")+`
1367
- \uD83D\uDCC8 Progress: ${B.completed}/${B.total} tasks (${B.percentage}%)`+q,displayContent:`✅ ${J.title}: ${o8[Z]}`,metadata:{taskId:Q,title:J.title,status:Z,notes:V,progress:{completed:B.completed,total:B.total,percentage:B.percentage}}}}});import{z as $3}from"zod";var e8=E({name:"ValidateSpec",displayName:"Validate Spec",kind:"readonly",schema:$3.object({}),description:{short:"Validate the completeness and consistency of the current Spec",long:`Use this tool to check if the current Spec project is complete and ready for the next phase.
1373
+ \uD83D\uDCC8 Progress: ${K.completed}/${K.total} tasks (${K.percentage}%)`+q,displayContent:`✅ ${J.title}: ${o8[Z]}`,metadata:{taskId:Q,title:J.title,status:Z,notes:V,progress:{completed:K.completed,total:K.total,percentage:K.percentage}}}}});import{z as V3}from"zod";var e8=E({name:"ValidateSpec",displayName:"Validate Spec",kind:"readonly",schema:V3.object({}),description:{short:"Validate the completeness and consistency of the current Spec",long:`Use this tool to check if the current Spec project is complete and ready for the next phase.
1368
1374
 
1369
1375
  ## What's Validated
1370
1376
 
@@ -1385,8 +1391,8 @@ ${Y.tasks.map((w)=>`- ${w.id}: ${w.title}`).join(`
1385
1391
  - To review what's missing
1386
1392
  - Before marking spec as done
1387
1393
  - To get improvement suggestions
1388
- `},async execute($,W){let Q=u.getInstance(),Z=Q.getCurrentSpec();if(!Z)return{success:!1,llmContent:"No active spec. Use EnterSpecMode or /spec load <name> first.",displayContent:"❌ No active spec",error:{type:"validation_error",message:"No active spec project"}};try{let V=await Q.validateCurrentSpec(),X=[];X.push(`# \uD83D\uDD0D Spec Validation: ${Z.name}`),X.push(""),X.push(`**Phase**: ${q$[V.phase]}`),X.push(`**Status**: ${V.valid?"✅ Valid":"⚠️ Has Issues"}`),X.push(""),X.push("## \uD83D\uDCC4 File Completeness"),X.push("");let Y=[["proposal.md",V.completeness.proposal],["spec.md",V.completeness.spec],["requirements.md",V.completeness.requirements],["design.md",V.completeness.design],["tasks.md",V.completeness.tasks]];for(let[B,K]of Y)X.push(`- ${K?"✅":"❌"} ${B}`);if(X.push(""),V.issues.length>0){X.push("## ⚠️ Issues"),X.push("");for(let B of V.issues){let K={error:"\uD83D\uDD34",warning:"\uD83D\uDFE1",info:"\uD83D\uDD35"}[B.severity];X.push(`- ${K} **${B.file}**: ${B.message}`)}X.push("")}if(V.suggestions.length>0){X.push("## \uD83D\uDCA1 Suggestions"),X.push("");for(let B of V.suggestions)X.push(`- ${B}`);X.push("")}let J=Q.getTaskProgress();if(J.total>0){X.push("## \uD83D\uDCCA Task Progress"),X.push(""),X.push(`- Total: ${J.total}`),X.push(`- Completed: ${J.completed}`),X.push(`- Remaining: ${J.total-J.completed}`),X.push(`- Progress: ${J.percentage}%`),X.push("");let B=Math.round(J.percentage/5),K=20-B;X.push(`[${"█".repeat(B)}${"░".repeat(K)}]`)}if(X.push(""),X.push("## \uD83D\uDE80 Next Steps"),X.push(""),!V.valid)X.push("1. Address the issues listed above"),X.push("2. Re-run ValidateSpec to verify fixes");else{let B=Q.getAllowedTransitions();if(B.length>0)X.push(`1. Ready to transition to: ${B.map((K)=>q$[K]).join(", ")}`),X.push("2. Use TransitionSpecPhase to proceed");else X.push("1. All phases complete!"),X.push("2. Use ExitSpecMode to finish and archive")}return{success:!0,llmContent:X.join(`
1389
- `),displayContent:V.valid?`✅ Spec valid: ${Z.name}`:`⚠️ Spec has ${V.issues.length} issue(s)`,metadata:{valid:V.valid,phase:V.phase,completeness:V.completeness,issueCount:V.issues.length,taskProgress:J}}}catch(V){return{success:!1,llmContent:`Validation failed: ${V instanceof Error?V.message:"Unknown error"}`,displayContent:"❌ Validation failed",error:{type:"execution_error",message:V instanceof Error?V.message:"Validation error"}}}}});var $5=[i8,s8,n8,r8,c8,t8,e8,l8];import{z as v$}from"zod";var W3=v$.object({label:v$.string().describe("The display text for this option that the user will see and select. Should be concise (1-5 words) and clearly describe the choice."),description:v$.string().describe("Explanation of what this option means or what will happen if chosen. Useful for providing context about trade-offs or implications.")}),Q3=v$.object({question:v$.string().describe('The complete question to ask the user. Should be clear, specific, and end with a question mark. Example: "Which library should we use for date formatting?" If multiSelect is true, phrase it accordingly, e.g. "Which features do you want to enable?"'),header:v$.string().max(12).describe('Very short label displayed as a chip/tag (max 12 chars). Examples: "Auth method", "Library", "Approach".'),multiSelect:v$.boolean().describe("Set to true to allow the user to select multiple options instead of just one. Use when choices are not mutually exclusive."),options:v$.array(W3).min(2).max(4).describe('The available choices for this question. Must have 2-4 options. Each option should be a distinct, mutually exclusive choice (unless multiSelect is enabled). There should be no "Other" option, that will be provided automatically.')}),Z3=v$.object({questions:v$.array(Q3).min(1).max(4).describe("Questions to ask the user (1-4 questions)")}),r2=E({name:"AskUserQuestion",displayName:"Ask User Question",kind:"readonly",schema:Z3,description:{short:"Ask user questions to gather preferences or clarify requirements",long:`Use this tool when you need to ask the user questions during execution. This allows you to:
1394
+ `},async execute($,W){let Q=u.getInstance(),Z=Q.getCurrentSpec();if(!Z)return{success:!1,llmContent:"No active spec. Use EnterSpecMode or /spec load <name> first.",displayContent:"❌ No active spec",error:{type:"validation_error",message:"No active spec project"}};try{let V=await Q.validateCurrentSpec(),X=[];X.push(`# \uD83D\uDD0D Spec Validation: ${Z.name}`),X.push(""),X.push(`**Phase**: ${U$[V.phase]}`),X.push(`**Status**: ${V.valid?"✅ Valid":"⚠️ Has Issues"}`),X.push(""),X.push("## \uD83D\uDCC4 File Completeness"),X.push("");let Y=[["proposal.md",V.completeness.proposal],["spec.md",V.completeness.spec],["requirements.md",V.completeness.requirements],["design.md",V.completeness.design],["tasks.md",V.completeness.tasks]];for(let[K,B]of Y)X.push(`- ${B?"✅":"❌"} ${K}`);if(X.push(""),V.issues.length>0){X.push("## ⚠️ Issues"),X.push("");for(let K of V.issues){let B={error:"\uD83D\uDD34",warning:"\uD83D\uDFE1",info:"\uD83D\uDD35"}[K.severity];X.push(`- ${B} **${K.file}**: ${K.message}`)}X.push("")}if(V.suggestions.length>0){X.push("## \uD83D\uDCA1 Suggestions"),X.push("");for(let K of V.suggestions)X.push(`- ${K}`);X.push("")}let J=Q.getTaskProgress();if(J.total>0){X.push("## \uD83D\uDCCA Task Progress"),X.push(""),X.push(`- Total: ${J.total}`),X.push(`- Completed: ${J.completed}`),X.push(`- Remaining: ${J.total-J.completed}`),X.push(`- Progress: ${J.percentage}%`),X.push("");let K=Math.round(J.percentage/5),B=20-K;X.push(`[${"█".repeat(K)}${"░".repeat(B)}]`)}if(X.push(""),X.push("## \uD83D\uDE80 Next Steps"),X.push(""),!V.valid)X.push("1. Address the issues listed above"),X.push("2. Re-run ValidateSpec to verify fixes");else{let K=Q.getAllowedTransitions();if(K.length>0)X.push(`1. Ready to transition to: ${K.map((B)=>U$[B]).join(", ")}`),X.push("2. Use TransitionSpecPhase to proceed");else X.push("1. All phases complete!"),X.push("2. Use ExitSpecMode to finish and archive")}return{success:!0,llmContent:X.join(`
1395
+ `),displayContent:V.valid?`✅ Spec valid: ${Z.name}`:`⚠️ Spec has ${V.issues.length} issue(s)`,metadata:{valid:V.valid,phase:V.phase,completeness:V.completeness,issueCount:V.issues.length,taskProgress:J}}}catch(V){return{success:!1,llmContent:`Validation failed: ${V instanceof Error?V.message:"Unknown error"}`,displayContent:"❌ Validation failed",error:{type:"execution_error",message:V instanceof Error?V.message:"Validation error"}}}}});var $5=[i8,s8,n8,r8,c8,t8,e8,l8];import{z as v$}from"zod";var X3=v$.object({label:v$.string().describe("The display text for this option that the user will see and select. Should be concise (1-5 words) and clearly describe the choice."),description:v$.string().describe("Explanation of what this option means or what will happen if chosen. Useful for providing context about trade-offs or implications.")}),Y3=v$.object({question:v$.string().describe('The complete question to ask the user. Should be clear, specific, and end with a question mark. Example: "Which library should we use for date formatting?" If multiSelect is true, phrase it accordingly, e.g. "Which features do you want to enable?"'),header:v$.string().max(12).describe('Very short label displayed as a chip/tag (max 12 chars). Examples: "Auth method", "Library", "Approach".'),multiSelect:v$.boolean().describe("Set to true to allow the user to select multiple options instead of just one. Use when choices are not mutually exclusive."),options:v$.array(X3).min(2).max(4).describe('The available choices for this question. Must have 2-4 options. Each option should be a distinct, mutually exclusive choice (unless multiSelect is enabled). There should be no "Other" option, that will be provided automatically.')}),J3=v$.object({questions:v$.array(Y3).min(1).max(4).describe("Questions to ask the user (1-4 questions)")}),r2=E({name:"AskUserQuestion",displayName:"Ask User Question",kind:"readonly",schema:J3,description:{short:"Ask user questions to gather preferences or clarify requirements",long:`Use this tool when you need to ask the user questions during execution. This allows you to:
1390
1396
  1. Gather user preferences or requirements
1391
1397
  2. Clarify ambiguous instructions
1392
1398
  3. Get decisions on implementation choices as you work
@@ -1416,7 +1422,7 @@ Important:
1416
1422
  <available_skills>
1417
1423
 
1418
1424
  </available_skills>
1419
- `},async execute($,W){let{skill:Q}=$,Z=m$();if(!Z.has(Q))return{success:!1,llmContent:`Skill "${Q}" not found. Available skills: ${Z.getAll().map((J)=>J.name).join(", ")||"none"}`,displayContent:`❌ Skill "${Q}" not found`,error:{type:"validation_error",message:`Skill "${Q}" is not registered`}};let V=await Z.loadContent(Q);if(!V)return{success:!1,llmContent:`Failed to load skill "${Q}" content`,displayContent:`❌ Failed to load skill "${Q}"`,error:{type:"execution_error",message:`Could not read SKILL.md for "${Q}"`}};let X=V3(V.metadata.name,V.instructions,V.metadata.basePath),Y=typeof V.metadata.model==="string"&&V.metadata.model!=="inherit"&&V.metadata.model.trim()!==""?V.metadata.model:void 0;return{success:!0,llmContent:X,displayContent:`<command-message>The "${Q}" skill is loading</command-message>`,metadata:{skillName:Q,basePath:V.metadata.basePath,version:V.metadata.version,allowedTools:V.metadata.allowedTools,modelId:Y}}}});function V3($,W,Q){return`# Skill: ${$}
1425
+ `},async execute($,W){let{skill:Q}=$,Z=d$();if(!Z.has(Q))return{success:!1,llmContent:`Skill "${Q}" not found. Available skills: ${Z.getAll().map((J)=>J.name).join(", ")||"none"}`,displayContent:`❌ Skill "${Q}" not found`,error:{type:"validation_error",message:`Skill "${Q}" is not registered`}};let V=await Z.loadContent(Q);if(!V)return{success:!1,llmContent:`Failed to load skill "${Q}" content`,displayContent:`❌ Failed to load skill "${Q}"`,error:{type:"execution_error",message:`Could not read SKILL.md for "${Q}"`}};let X=G3(V.metadata.name,V.instructions,V.metadata.basePath),Y=typeof V.metadata.model==="string"&&V.metadata.model!=="inherit"&&V.metadata.model.trim()!==""?V.metadata.model:void 0;return{success:!0,llmContent:X,displayContent:`<command-message>The "${Q}" skill is loading</command-message>`,metadata:{skillName:Q,basePath:V.metadata.basePath,version:V.metadata.version,allowedTools:V.metadata.allowedTools,modelId:Y}}}});function G3($,W,Q){return`# Skill: ${$}
1420
1426
 
1421
1427
  You are now operating in the "${$}" skill mode. Follow the instructions below to complete the task.
1422
1428
 
@@ -1429,7 +1435,7 @@ ${W}
1429
1435
 
1430
1436
  ---
1431
1437
 
1432
- Remember: Follow the above instructions carefully to complete the user's request.`}import{nanoid as B3}from"nanoid";import{z as J0}from"zod";import{nanoid as Y3}from"nanoid";import l$ from"node:fs";import X3 from"node:os";import W5 from"node:path";var F0=M("Agent");class X0{static instance=null;sessionsDir;cache=new Map;constructor(){this.sessionsDir=W5.join(X3.homedir(),".blade","agents","sessions"),this.ensureDirectory()}static getInstance(){if(!X0.instance)X0.instance=new X0;return X0.instance}ensureDirectory(){if(!l$.existsSync(this.sessionsDir))l$.mkdirSync(this.sessionsDir,{recursive:!0,mode:493})}getSessionPath($){let W=$.replace(/[^a-zA-Z0-9_-]/g,"_");return W5.join(this.sessionsDir,`${W}.json`)}saveSession($){try{let W=this.getSessionPath($.id),Q=JSON.stringify($,null,2);l$.writeFileSync(W,Q,"utf-8"),this.cache.set($.id,$),F0.debug(`Session saved: ${$.id}`)}catch(W){F0.warn(`Failed to save session ${$.id}:`,W)}}loadSession($){if(this.cache.has($))return this.cache.get($);try{let W=this.getSessionPath($);if(!l$.existsSync(W))return;let Q=l$.readFileSync(W,"utf-8"),Z=JSON.parse(Q);return this.cache.set($,Z),Z}catch(W){F0.warn(`Failed to load session ${$}:`,W);return}}updateSession($,W){let Q=this.loadSession($);if(!Q)return;let Z={...Q,...W,lastActiveAt:Date.now()};return this.saveSession(Z),Z}appendMessages($,W){let Q=this.loadSession($);if(!Q)return;return this.updateSession($,{messages:[...Q.messages,...W]})}markCompleted($,W,Q){return this.updateSession($,{status:W.success?"completed":"failed",result:W,stats:Q,completedAt:Date.now()})}deleteSession($){try{let W=this.getSessionPath($);if(l$.existsSync(W))l$.unlinkSync(W);return this.cache.delete($),!0}catch(W){return F0.warn(`Failed to delete session ${$}:`,W),!1}}listSessions(){try{let $=l$.readdirSync(this.sessionsDir),W=[];for(let Q of $){if(!Q.endsWith(".json"))continue;let Z=Q.replace(".json",""),V=this.loadSession(Z);if(V)W.push(V)}return W.sort((Q,Z)=>Z.lastActiveAt-Q.lastActiveAt)}catch($){return F0.warn("Failed to list sessions:",$),[]}}listRunningSessions(){return this.listSessions().filter(($)=>$.status==="running")}cleanupExpiredSessions($=604800000){let W=Date.now(),Q=this.listSessions(),Z=0;for(let V of Q){if(V.status==="running")continue;if(W-V.lastActiveAt>$){if(this.deleteSession(V.id))Z++}}if(Z>0)F0.info(`Cleaned up ${Z} expired agent sessions`);return Z}clearCache(){this.cache.clear()}}var Y0=M("Agent");class _${static instance=null;runningAgents=new Map;sessionStore=X0.getInstance();constructor(){this.cleanupOrphanedSessions()}static getInstance(){if(!_$.instance)_$.instance=new _$;return _$.instance}cleanupOrphanedSessions(){let $=this.sessionStore.listSessions(),W=Date.now(),Q=1800000;for(let Z of $)if(Z.status==="running"){let V=this.runningAgents.has(Z.id),X=W-Z.lastActiveAt;if(!V||X>1800000)Y0.warn(`Cleaning up orphaned agent session: ${Z.id}`),this.sessionStore.updateSession(Z.id,{status:"failed",result:{success:!1,message:"",error:"Session was orphaned (process restart or timeout)"},completedAt:W})}}startBackgroundAgent($){let{config:W,bladeConfig:Q,description:Z,prompt:V,parentSessionId:X,permissionMode:Y,agentId:J,existingMessages:G}=$,B=J||Y3(),K=new AbortController,q={id:B,subagentType:W.name,description:Z,prompt:V,messages:G||[],status:"running",createdAt:Date.now(),lastActiveAt:Date.now(),parentSessionId:X};this.sessionStore.saveSession(q);let w=Date.now(),O=this.executeAgent(B,W,Q,V,X,Y,K.signal,G);return this.runningAgents.set(B,{id:B,promise:O,abortController:K,startTime:w}),O.finally(()=>{this.runningAgents.delete(B)}),Y0.info(`Background agent started: ${B} (${W.name})`),B}async executeAgent($,W,Q,Z,V,X,Y,J){let G=Date.now();try{if(Y.aborted)throw Error("Agent execution was cancelled");let B=W.systemPrompt||"",K=W.model&&W.model!=="inherit"?W.model:void 0,q=await I$.create(Q,{systemPrompt:B,toolWhitelist:W.tools,modelId:K}),w={messages:J||[],userId:"subagent",sessionId:$,workspaceRoot:process.cwd(),permissionMode:X,subagentInfo:{parentSessionId:V||"",subagentType:W.name,isSidechain:!1}},O=await q.runAgenticLoop(Z,w,{signal:Y});this.sessionStore.updateSession($,{messages:w.messages});let b=Date.now()-G,U=O.success?{success:!0,message:O.finalMessage||"",agentId:$,stats:{tokens:O.metadata?.tokensUsed||0,toolCalls:O.metadata?.toolCallsCount||0,duration:b}}:{success:!1,message:"",agentId:$,error:O.error?.message||"Unknown error",stats:{duration:b}};return this.sessionStore.markCompleted($,{success:U.success,message:U.message,error:U.error},U.stats),Y0.info(`Background agent completed: ${$} (success=${U.success})`),U}catch(B){let K=Date.now()-G,q=B instanceof Error?B.message:String(B);return this.sessionStore.markCompleted($,{success:!1,message:"",error:q},{duration:K}),Y0.warn(`Background agent failed: ${$}`,B),{success:!1,message:"",agentId:$,error:q,stats:{duration:K}}}}getAgent($){return this.sessionStore.loadSession($)}isRunning($){return this.runningAgents.has($)}async waitForCompletion($,W=30000){let Q=this.runningAgents.get($);if(!Q)return this.sessionStore.loadSession($);if(W>0){let Z=new Promise((X)=>setTimeout(()=>X("timeout"),W));if(await Promise.race([Q.promise,Z])==="timeout")return this.sessionStore.loadSession($)}else await Q.promise;return this.sessionStore.loadSession($)}resumeAgent($,W,Q,Z,V,X){let Y=this.sessionStore.loadSession($);if(!Y){Y0.warn(`Cannot resume agent ${$}: session not found`);return}if(this.isRunning($)){Y0.warn(`Cannot resume agent ${$}: still running`);return}return this.startBackgroundAgent({config:Q,bladeConfig:Z,description:Y.description,prompt:W,parentSessionId:V||Y.parentSessionId,permissionMode:X,agentId:$,existingMessages:Y.messages})}killAgent($){let W=this.runningAgents.get($);if(!W){let Q=this.sessionStore.loadSession($);if(Q&&Q.status==="running")this.sessionStore.updateSession($,{status:"cancelled"});return!1}return W.abortController.abort(),this.sessionStore.updateSession($,{status:"cancelled"}),Y0.info(`Background agent cancelled: ${$}`),!0}listAll(){return this.sessionStore.listSessions()}listRunning(){return this.sessionStore.listRunningSessions()}getRunningCount(){return this.runningAgents.size}killAll(){for(let[$]of this.runningAgents)this.killAgent($)}cleanupExpiredSessions($){return this.sessionStore.cleanupExpiredSessions($)}}import{nanoid as J3}from"nanoid";class t2{config;bladeConfig;constructor($,W){this.config=$;this.bladeConfig=W}async execute($){let W=Date.now(),Q=$.subagentSessionId??J3();try{let Z=this.buildSystemPrompt($),V=this.config.model&&this.config.model!=="inherit"?this.config.model:void 0,X=await I$.create(this.bladeConfig,{toolWhitelist:this.config.tools,modelId:V}),Y="",J=0,G=0,B={parentSessionId:$.parentSessionId||"",subagentType:this.config.name,isSidechain:!1},K=await X.runAgenticLoop($.prompt,{messages:[],userId:"subagent",sessionId:Q,workspaceRoot:process.cwd(),permissionMode:$.permissionMode,systemPrompt:Z,subagentInfo:B},{onToolStart:$.onToolStart,onToolResult:$.onToolResult?async(w,O)=>{$.onToolResult?.(w,O)}:void 0,onContentDelta:$.onContentDelta,onThinkingDelta:$.onThinkingDelta,onStreamEnd:$.onStreamEnd});if(K.success)Y=K.finalMessage||"",J=K.metadata?.toolCallsCount||0,G=K.metadata?.tokensUsed||0;else throw Error(K.error?.message||"Subagent execution failed");let q=Date.now()-W;return{success:!0,message:Y,agentId:Q,stats:{tokens:G,toolCalls:J,duration:q}}}catch(Z){let V=Date.now()-W;return{success:!1,message:"",agentId:Q,error:Z instanceof Error?Z.message:String(Z),stats:{duration:V}}}}buildSystemPrompt($){return this.config.systemPrompt||""}}import $4 from"node:fs";import v1 from"node:os";import f$ from"node:path";import G3 from"yaml";var e2=[{name:"general-purpose",description:"General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you.",tools:[]},{name:"Explore",description:'Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions.',tools:["Glob","Grep","Read","WebFetch","WebSearch"],systemPrompt:`# Explore Subagent
1438
+ Remember: Follow the above instructions carefully to complete the user's request.`}import{nanoid as O3}from"nanoid";import{z as Y0}from"zod";import{nanoid as B3}from"nanoid";import i$ from"node:fs";import K3 from"node:os";import W5 from"node:path";var A0=M("Agent");class V0{static instance=null;sessionsDir;cache=new Map;constructor(){this.sessionsDir=W5.join(K3.homedir(),".blade","agents","sessions"),this.ensureDirectory()}static getInstance(){if(!V0.instance)V0.instance=new V0;return V0.instance}ensureDirectory(){if(!i$.existsSync(this.sessionsDir))i$.mkdirSync(this.sessionsDir,{recursive:!0,mode:493})}getSessionPath($){let W=$.replace(/[^a-zA-Z0-9_-]/g,"_");return W5.join(this.sessionsDir,`${W}.json`)}saveSession($){try{let W=this.getSessionPath($.id),Q=JSON.stringify($,null,2);i$.writeFileSync(W,Q,"utf-8"),this.cache.set($.id,$),A0.debug(`Session saved: ${$.id}`)}catch(W){A0.warn(`Failed to save session ${$.id}:`,W)}}loadSession($){if(this.cache.has($))return this.cache.get($);try{let W=this.getSessionPath($);if(!i$.existsSync(W))return;let Q=i$.readFileSync(W,"utf-8"),Z=JSON.parse(Q);return this.cache.set($,Z),Z}catch(W){A0.warn(`Failed to load session ${$}:`,W);return}}updateSession($,W){let Q=this.loadSession($);if(!Q)return;let Z={...Q,...W,lastActiveAt:Date.now()};return this.saveSession(Z),Z}appendMessages($,W){let Q=this.loadSession($);if(!Q)return;return this.updateSession($,{messages:[...Q.messages,...W]})}markCompleted($,W,Q){return this.updateSession($,{status:W.success?"completed":"failed",result:W,stats:Q,completedAt:Date.now()})}deleteSession($){try{let W=this.getSessionPath($);if(i$.existsSync(W))i$.unlinkSync(W);return this.cache.delete($),!0}catch(W){return A0.warn(`Failed to delete session ${$}:`,W),!1}}listSessions(){try{let $=i$.readdirSync(this.sessionsDir),W=[];for(let Q of $){if(!Q.endsWith(".json"))continue;let Z=Q.replace(".json",""),V=this.loadSession(Z);if(V)W.push(V)}return W.sort((Q,Z)=>Z.lastActiveAt-Q.lastActiveAt)}catch($){return A0.warn("Failed to list sessions:",$),[]}}listRunningSessions(){return this.listSessions().filter(($)=>$.status==="running")}cleanupExpiredSessions($=604800000){let W=Date.now(),Q=this.listSessions(),Z=0;for(let V of Q){if(V.status==="running")continue;if(W-V.lastActiveAt>$){if(this.deleteSession(V.id))Z++}}if(Z>0)A0.info(`Cleaned up ${Z} expired agent sessions`);return Z}clearCache(){this.cache.clear()}}var X0=M("Agent");class _${static instance=null;runningAgents=new Map;sessionStore=V0.getInstance();constructor(){this.cleanupOrphanedSessions()}static getInstance(){if(!_$.instance)_$.instance=new _$;return _$.instance}cleanupOrphanedSessions(){let $=this.sessionStore.listSessions(),W=Date.now(),Q=1800000;for(let Z of $)if(Z.status==="running"){let V=this.runningAgents.has(Z.id),X=W-Z.lastActiveAt;if(!V||X>1800000)X0.warn(`Cleaning up orphaned agent session: ${Z.id}`),this.sessionStore.updateSession(Z.id,{status:"failed",result:{success:!1,message:"",error:"Session was orphaned (process restart or timeout)"},completedAt:W})}}startBackgroundAgent($){let{config:W,bladeConfig:Q,description:Z,prompt:V,parentSessionId:X,permissionMode:Y,agentId:J,existingMessages:G}=$,K=J||B3(),B=new AbortController,q={id:K,subagentType:W.name,description:Z,prompt:V,messages:G||[],status:"running",createdAt:Date.now(),lastActiveAt:Date.now(),parentSessionId:X};this.sessionStore.saveSession(q);let w=Date.now(),O=this.executeAgent(K,W,Q,V,X,Y,B.signal,G);return this.runningAgents.set(K,{id:K,promise:O,abortController:B,startTime:w}),O.finally(()=>{this.runningAgents.delete(K)}),X0.info(`Background agent started: ${K} (${W.name})`),K}async executeAgent($,W,Q,Z,V,X,Y,J){let G=Date.now();try{if(Y.aborted)throw Error("Agent execution was cancelled");let K=W.systemPrompt||"",B=W.model&&W.model!=="inherit"?W.model:void 0,q=await k$.create(Q,{systemPrompt:K,toolWhitelist:W.tools,modelId:B}),w={messages:J||[],userId:"subagent",sessionId:$,workspaceRoot:process.cwd(),permissionMode:X,subagentInfo:{parentSessionId:V||"",subagentType:W.name,isSidechain:!1}},O=await q.runAgenticLoop(Z,w,{signal:Y});this.sessionStore.updateSession($,{messages:w.messages});let H=Date.now()-G,U=O.success?{success:!0,message:O.finalMessage||"",agentId:$,stats:{tokens:O.metadata?.tokensUsed||0,toolCalls:O.metadata?.toolCallsCount||0,duration:H}}:{success:!1,message:"",agentId:$,error:O.error?.message||"Unknown error",stats:{duration:H}};return this.sessionStore.markCompleted($,{success:U.success,message:U.message,error:U.error},U.stats),X0.info(`Background agent completed: ${$} (success=${U.success})`),U}catch(K){let B=Date.now()-G,q=K instanceof Error?K.message:String(K);return this.sessionStore.markCompleted($,{success:!1,message:"",error:q},{duration:B}),X0.warn(`Background agent failed: ${$}`,K),{success:!1,message:"",agentId:$,error:q,stats:{duration:B}}}}getAgent($){return this.sessionStore.loadSession($)}isRunning($){return this.runningAgents.has($)}async waitForCompletion($,W=30000){let Q=this.runningAgents.get($);if(!Q)return this.sessionStore.loadSession($);if(W>0){let Z=new Promise((X)=>setTimeout(()=>X("timeout"),W));if(await Promise.race([Q.promise,Z])==="timeout")return this.sessionStore.loadSession($)}else await Q.promise;return this.sessionStore.loadSession($)}resumeAgent($,W,Q,Z,V,X){let Y=this.sessionStore.loadSession($);if(!Y){X0.warn(`Cannot resume agent ${$}: session not found`);return}if(this.isRunning($)){X0.warn(`Cannot resume agent ${$}: still running`);return}return this.startBackgroundAgent({config:Q,bladeConfig:Z,description:Y.description,prompt:W,parentSessionId:V||Y.parentSessionId,permissionMode:X,agentId:$,existingMessages:Y.messages})}killAgent($){let W=this.runningAgents.get($);if(!W){let Q=this.sessionStore.loadSession($);if(Q&&Q.status==="running")this.sessionStore.updateSession($,{status:"cancelled"});return!1}return W.abortController.abort(),this.sessionStore.updateSession($,{status:"cancelled"}),X0.info(`Background agent cancelled: ${$}`),!0}listAll(){return this.sessionStore.listSessions()}listRunning(){return this.sessionStore.listRunningSessions()}getRunningCount(){return this.runningAgents.size}killAll(){for(let[$]of this.runningAgents)this.killAgent($)}cleanupExpiredSessions($){return this.sessionStore.cleanupExpiredSessions($)}}import{nanoid as q3}from"nanoid";class t2{config;bladeConfig;constructor($,W){this.config=$;this.bladeConfig=W}async execute($){let W=Date.now(),Q=$.subagentSessionId??q3();try{let Z=this.buildSystemPrompt($),V=this.config.model&&this.config.model!=="inherit"?this.config.model:void 0,X=await k$.create(this.bladeConfig,{toolWhitelist:this.config.tools,modelId:V}),Y="",J=0,G=0,K={parentSessionId:$.parentSessionId||"",subagentType:this.config.name,isSidechain:!1},B=await X.runAgenticLoop($.prompt,{messages:[],userId:"subagent",sessionId:Q,workspaceRoot:process.cwd(),permissionMode:$.permissionMode,systemPrompt:Z,subagentInfo:K},{onToolStart:$.onToolStart,onToolResult:$.onToolResult?async(w,O)=>{$.onToolResult?.(w,O)}:void 0,onContentDelta:$.onContentDelta,onThinkingDelta:$.onThinkingDelta,onStreamEnd:$.onStreamEnd});if(B.success)Y=B.finalMessage||"",J=B.metadata?.toolCallsCount||0,G=B.metadata?.tokensUsed||0;else throw Error(B.error?.message||"Subagent execution failed");let q=Date.now()-W;return{success:!0,message:Y,agentId:Q,stats:{tokens:G,toolCalls:J,duration:q}}}catch(Z){let V=Date.now()-W;return{success:!1,message:"",agentId:Q,error:Z instanceof Error?Z.message:String(Z),stats:{duration:V}}}}buildSystemPrompt($){return this.config.systemPrompt||""}}import $4 from"node:fs";import S1 from"node:os";import I$ from"node:path";import w3 from"yaml";var e2=[{name:"general-purpose",description:"General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you.",tools:[]},{name:"Explore",description:'Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions.',tools:["Glob","Grep","Read","WebFetch","WebSearch"],systemPrompt:`# Explore Subagent
1433
1439
 
1434
1440
  You are a specialized code exploration agent. Your job is to **directly execute searches** using the tools available to you.
1435
1441
 
@@ -1498,8 +1504,8 @@ You are a software architect specializing in implementation planning.
1498
1504
 
1499
1505
  Be thorough but concise. Focus on actionable steps.`},{name:"statusline-setup",description:"Use this agent to configure the user's Claude Code status line setting.",tools:["Read","Edit"]}];function Q5($){switch($){case"default":case"ignore":case void 0:return"default";case"acceptEdits":return"autoEdit";case"dontAsk":case"bypassPermissions":return"yolo";case"plan":return"plan";default:return"default"}}var W4=M("Agent");class Z5{subagents=new Map;register($){if(this.subagents.has($.name))throw Error(`Subagent '${$.name}' already registered`);this.subagents.set($.name,$)}getSubagent($){return this.subagents.get($)}getAllNames(){return Array.from(this.subagents.keys())}getAllSubagents(){return Array.from(this.subagents.values())}getDescriptionsForPrompt(){let $=this.getAllSubagents();if($.length===0)return"No subagents available.";return`Available agent types and the tools they have access to:
1500
1506
  ${$.map((Q)=>{let Z=!Q.tools||Q.tools.length===0?"All tools":Q.tools.join(", ");return`- ${Q.name}: ${Q.description} (Tools: ${Z})`}).join(`
1501
- `)}`}loadFromDirectory($,W){if(!$4.existsSync($))return;let Q=$4.readdirSync($);for(let Z of Q){if(!Z.endsWith(".md"))continue;let V=f$.join($,Z);try{let X=this.parseConfigFile(V,W);this.subagents.set(X.name,X)}catch(X){W4.warn(`Failed to load subagent config from ${V}:`,X)}}}parseConfigFile($,W){let Z=$4.readFileSync($,"utf-8").match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);if(!Z)throw Error(`No YAML frontmatter found in ${$}`);let[,V,X]=Z,Y=G3.parse(V);if(!Y.name||!Y.description)throw Error(`Missing required fields (name, description) in ${$}`);let J=X.trim(),G=this.parseStringOrArray(Y.tools),B=this.parseStringOrArray(Y.skills),K=Q5(Y.permissionMode);return{name:Y.name,description:Y.description,systemPrompt:J,tools:G,color:Y.color,configPath:$,model:Y.model||"inherit",permissionMode:K,skills:B,source:W}}parseStringOrArray($){if(!$)return;if(Array.isArray($))return $.map((W)=>W.trim()).filter(Boolean);return $.split(",").map((W)=>W.trim()).filter(Boolean)}loadFromStandardLocations(){this.loadBuiltinAgents();let $=f$.join(v1.homedir(),".claude","agents");this.loadFromDirectory($,"claude-code-user");let W=f$.join(process.cwd(),".claude","agents");this.loadFromDirectory(W,"claude-code-project");let Q=f$.join(v1.homedir(),".blade","agents");this.loadFromDirectory(Q,"blade-user");let Z=f$.join(process.cwd(),".blade","agents");this.loadFromDirectory(Z,"blade-project");let V=this.getAllNames().length;return W4.debug(`\uD83D\uDCE6 Loaded ${V} subagents from standard locations`),V}loadBuiltinAgents(){for(let $ of e2)this.subagents.set($.name,{...$,model:$.model||"inherit",source:"builtin"});W4.debug(`Loaded ${e2.length} builtin subagents`)}clear(){this.subagents.clear()}getSubagentsBySource(){let $={builtin:[],"claude-code-user":[],"claude-code-project":[],"blade-user":[],"blade-project":[],plugin:[]};for(let W of this.subagents.values()){let Q=W.source||"builtin",Z=Q.startsWith("plugin:")?"plugin":Q;$[Z].push(W)}return $}clearPluginAgents(){let $=[];for(let[W,Q]of this.subagents.entries())if(Q.source?.startsWith("plugin:"))$.push(W);for(let W of $)this.subagents.delete(W)}static getClaudeCodeAgentsDir($){if($==="user")return f$.join(v1.homedir(),".claude","agents");return f$.join(process.cwd(),".claude","agents")}static getBladeAgentsDir($){if($==="user")return f$.join(v1.homedir(),".blade","agents");return f$.join(process.cwd(),".blade","agents")}}var L$=new Z5;function K3($){let W=$.message||"Unknown error";if(W.includes("Too Many Requests")||W.includes("429")){let Q=$.cause;if(Q?.responseBody)try{let Z=JSON.parse(Q.responseBody);if(Z.message)return Z.message}catch{}return"API 请求过于频繁,请稍后重试"}if(W.includes("ECONNREFUSED")||W.includes("ETIMEDOUT"))return"网络连接失败,请检查网络设置";if(W.includes("401")||W.includes("Unauthorized"))return"API 认证失败,请检查 API Key 配置";return W.split(`
1502
- `)[0]}function q3($){return L$.getAllNames().includes($)}function w3(){let $=L$.getAllNames();return $.length>0?$.join(", "):"none (registry not initialized)"}function O3(){return`
1507
+ `)}`}loadFromDirectory($,W){if(!$4.existsSync($))return;let Q=$4.readdirSync($);for(let Z of Q){if(!Z.endsWith(".md"))continue;let V=I$.join($,Z);try{let X=this.parseConfigFile(V,W);this.subagents.set(X.name,X)}catch(X){W4.warn(`Failed to load subagent config from ${V}:`,X)}}}parseConfigFile($,W){let Z=$4.readFileSync($,"utf-8").match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);if(!Z)throw Error(`No YAML frontmatter found in ${$}`);let[,V,X]=Z,Y=w3.parse(V);if(!Y.name||!Y.description)throw Error(`Missing required fields (name, description) in ${$}`);let J=X.trim(),G=this.parseStringOrArray(Y.tools),K=this.parseStringOrArray(Y.skills),B=Q5(Y.permissionMode);return{name:Y.name,description:Y.description,systemPrompt:J,tools:G,color:Y.color,configPath:$,model:Y.model||"inherit",permissionMode:B,skills:K,source:W}}parseStringOrArray($){if(!$)return;if(Array.isArray($))return $.map((W)=>W.trim()).filter(Boolean);return $.split(",").map((W)=>W.trim()).filter(Boolean)}loadFromStandardLocations(){this.loadBuiltinAgents();let $=I$.join(S1.homedir(),".claude","agents");this.loadFromDirectory($,"claude-code-user");let W=I$.join(process.cwd(),".claude","agents");this.loadFromDirectory(W,"claude-code-project");let Q=I$.join(S1.homedir(),".blade","agents");this.loadFromDirectory(Q,"blade-user");let Z=I$.join(process.cwd(),".blade","agents");this.loadFromDirectory(Z,"blade-project");let V=this.getAllNames().length;return W4.debug(`\uD83D\uDCE6 Loaded ${V} subagents from standard locations`),V}loadBuiltinAgents(){for(let $ of e2)this.subagents.set($.name,{...$,model:$.model||"inherit",source:"builtin"});W4.debug(`Loaded ${e2.length} builtin subagents`)}clear(){this.subagents.clear()}getSubagentsBySource(){let $={builtin:[],"claude-code-user":[],"claude-code-project":[],"blade-user":[],"blade-project":[],plugin:[]};for(let W of this.subagents.values()){let Q=W.source||"builtin",Z=Q.startsWith("plugin:")?"plugin":Q;$[Z].push(W)}return $}clearPluginAgents(){let $=[];for(let[W,Q]of this.subagents.entries())if(Q.source?.startsWith("plugin:"))$.push(W);for(let W of $)this.subagents.delete(W)}static getClaudeCodeAgentsDir($){if($==="user")return I$.join(S1.homedir(),".claude","agents");return I$.join(process.cwd(),".claude","agents")}static getBladeAgentsDir($){if($==="user")return I$.join(S1.homedir(),".blade","agents");return I$.join(process.cwd(),".blade","agents")}}var L$=new Z5;function U3($){let W=$.message||"Unknown error";if(W.includes("Too Many Requests")||W.includes("429")){let Q=$.cause;if(Q?.responseBody)try{let Z=JSON.parse(Q.responseBody);if(Z.message)return Z.message}catch{}return"API 请求过于频繁,请稍后重试"}if(W.includes("ECONNREFUSED")||W.includes("ETIMEDOUT"))return"网络连接失败,请检查网络设置";if(W.includes("401")||W.includes("Unauthorized"))return"API 认证失败,请检查 API Key 配置";return W.split(`
1508
+ `)[0]}function F3($){return L$.getAllNames().includes($)}function H3(){let $=L$.getAllNames();return $.length>0?$.join(", "):"none (registry not initialized)"}function A3(){return`
1503
1509
  ## Task
1504
1510
 
1505
1511
  Launch a new agent to handle complex, multi-step tasks autonomously.
@@ -1530,34 +1536,34 @@ Usage notes:
1530
1536
  - Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent
1531
1537
  - If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.
1532
1538
  - If the user specifies that they want you to run agents "in parallel", you MUST send a single message with multiple Task tool use content blocks. For example, if you need to launch both a code-reviewer agent and a test-runner agent in parallel, send a single message with both tool calls.
1533
- `.trim()}var Q4=E({name:"Task",displayName:"Subagent Scheduler",kind:"readonly",isReadOnly:!0,schema:J0.object({subagent_type:J0.string().refine(q3,($)=>({message:`Invalid subagent type: "${$}". Available: ${w3()}`})).describe('Subagent type to use (e.g., "Explore", "Plan")'),description:J0.string().min(3).max(100).describe("Short task description (3-5 words)"),prompt:J0.string().min(10).describe("Detailed task instructions"),run_in_background:J0.boolean().default(!1).describe("Set to true to run this agent in the background. Use TaskOutput to read the output later."),resume:J0.string().optional().describe("Optional agent ID to resume from. If provided, the agent will continue from the previous execution transcript."),subagent_session_id:J0.string().optional().describe("Internal subagent session id for tracking")}),description:{short:"Launch a new agent to handle complex, multi-step tasks autonomously",get long(){return O3()},usageNotes:["subagent_type is required - choose from available agent types",'description should be 3-5 words (e.g., "Explore error handling")',"prompt should contain a highly detailed task description and specify exactly what information to return","Launch multiple agents concurrently when possible for better performance"],examples:[{description:"Explore codebase for API endpoints",params:{subagent_type:"Explore",description:"Find API endpoints",prompt:"Search the codebase for all API endpoint definitions. Look for route handlers, REST endpoints, and GraphQL resolvers. Return a structured list with file paths, endpoint URLs, HTTP methods, and descriptions."}},{description:"Plan authentication feature",params:{subagent_type:"Plan",description:"Plan user auth",prompt:"Create a detailed implementation plan for adding user authentication to this project. Analyze the existing architecture, then provide step-by-step instructions including: 1) Database schema changes 2) API routes to create 3) Frontend components needed 4) Security considerations 5) Testing strategy. Be specific about file names and code locations."}}]},async execute($,W){let{subagent_type:Q,description:Z,prompt:V,run_in_background:X=!1,resume:Y,subagent_session_id:J}=$,{updateOutput:G}=W,B=typeof J==="string"&&J.length>0?J:typeof Y==="string"&&Y.length>0?Y:B3();try{let K=L$.getAllNames(),q=L$.getSubagent(Q);if(!q)return{success:!1,llmContent:`Unknown subagent type: ${Q}. Available types: ${K.join(", ")||"none"}`,displayContent:`❌ 未知的 subagent 类型: ${Q}
1539
+ `.trim()}var Q4=E({name:"Task",displayName:"Subagent Scheduler",kind:"readonly",isReadOnly:!0,schema:Y0.object({subagent_type:Y0.string().refine(F3,($)=>({message:`Invalid subagent type: "${$}". Available: ${H3()}`})).describe('Subagent type to use (e.g., "Explore", "Plan")'),description:Y0.string().min(3).max(100).describe("Short task description (3-5 words)"),prompt:Y0.string().min(10).describe("Detailed task instructions"),run_in_background:Y0.boolean().default(!1).describe("Set to true to run this agent in the background. Use TaskOutput to read the output later."),resume:Y0.string().optional().describe("Optional agent ID to resume from. If provided, the agent will continue from the previous execution transcript."),subagent_session_id:Y0.string().optional().describe("Internal subagent session id for tracking")}),description:{short:"Launch a new agent to handle complex, multi-step tasks autonomously",get long(){return A3()},usageNotes:["subagent_type is required - choose from available agent types",'description should be 3-5 words (e.g., "Explore error handling")',"prompt should contain a highly detailed task description and specify exactly what information to return","Launch multiple agents concurrently when possible for better performance"],examples:[{description:"Explore codebase for API endpoints",params:{subagent_type:"Explore",description:"Find API endpoints",prompt:"Search the codebase for all API endpoint definitions. Look for route handlers, REST endpoints, and GraphQL resolvers. Return a structured list with file paths, endpoint URLs, HTTP methods, and descriptions."}},{description:"Plan authentication feature",params:{subagent_type:"Plan",description:"Plan user auth",prompt:"Create a detailed implementation plan for adding user authentication to this project. Analyze the existing architecture, then provide step-by-step instructions including: 1) Database schema changes 2) API routes to create 3) Frontend components needed 4) Security considerations 5) Testing strategy. Be specific about file names and code locations."}}]},async execute($,W){let{subagent_type:Q,description:Z,prompt:V,run_in_background:X=!1,resume:Y,subagent_session_id:J}=$,{updateOutput:G}=W,K=typeof J==="string"&&J.length>0?J:typeof Y==="string"&&Y.length>0?Y:O3();try{let B=L$.getAllNames(),q=L$.getSubagent(Q);if(!q)return{success:!1,llmContent:`Unknown subagent type: ${Q}. Available types: ${B.join(", ")||"none"}`,displayContent:`❌ 未知的 subagent 类型: ${Q}
1534
1540
 
1535
- 可用类型: ${K.join(", ")||"无"}`,error:{type:"execution_error",message:`Unknown subagent type: ${Q}`}};if(Y)return H3(Y,V,q,Z,W);if(X)return U3(q,Z,V,W,B);if(G?.(`\uD83D\uDE80 启动 ${Q} subagent: ${Z}`),!W.bladeConfig)return{success:!1,llmContent:"BladeConfig is required for subagent execution",displayContent:"❌ 缺少 BladeConfig 配置",error:{type:"execution_error",message:"BladeConfig is required"}};let w=new t2(q,W.bladeConfig),O={prompt:V,parentSessionId:W.sessionId,permissionMode:W.permissionMode,subagentSessionId:B};G?.("⚙️ 执行任务中...");let b=Date.now(),U=await w.execute(O),F=Date.now()-b;try{let D=await i.getInstance().executeSubagentStopHooks(Q,{projectDir:process.cwd(),sessionId:W.sessionId||"unknown",permissionMode:W.permissionMode||"default",taskDescription:Z,success:U.success,resultSummary:U.message.slice(0,500),error:U.error});if(!D.shouldStop&&D.continueReason){console.log(`[Task] SubagentStop hook 阻止停止,继续执行: ${D.continueReason}`);let N={prompt:D.continueReason,parentSessionId:W.sessionId,permissionMode:W.permissionMode},C=Date.now();U=await w.execute(N),F+=Date.now()-C}if(D.warning)console.warn(`[Task] SubagentStop hook warning: ${D.warning}`)}catch(A){console.warn("[Task] SubagentStop hook execution failed:",A)}if(U.success){let A=U.message.length>1000?U.message.slice(0,1000)+`
1541
+ 可用类型: ${B.join(", ")||"无"}`,error:{type:"execution_error",message:`Unknown subagent type: ${Q}`}};if(Y)return b3(Y,V,q,Z,W);if(X)return D3(q,Z,V,W,K);if(G?.(`\uD83D\uDE80 启动 ${Q} subagent: ${Z}`),!W.bladeConfig)return{success:!1,llmContent:"BladeConfig is required for subagent execution",displayContent:"❌ 缺少 BladeConfig 配置",error:{type:"execution_error",message:"BladeConfig is required"}};let w=new t2(q,W.bladeConfig),O={prompt:V,parentSessionId:W.sessionId,permissionMode:W.permissionMode,subagentSessionId:K};G?.("⚙️ 执行任务中...");let H=Date.now(),U=await w.execute(O),A=Date.now()-H;try{let b=await a.getInstance().executeSubagentStopHooks(Q,{projectDir:process.cwd(),sessionId:W.sessionId||"unknown",permissionMode:W.permissionMode||"default",taskDescription:Z,success:U.success,resultSummary:U.message.slice(0,500),error:U.error});if(!b.shouldStop&&b.continueReason){console.log(`[Task] SubagentStop hook 阻止停止,继续执行: ${b.continueReason}`);let z={prompt:b.continueReason,parentSessionId:W.sessionId,permissionMode:W.permissionMode},C=Date.now();U=await w.execute(z),A+=Date.now()-C}if(b.warning)console.warn(`[Task] SubagentStop hook warning: ${b.warning}`)}catch(D){console.warn("[Task] SubagentStop hook execution failed:",D)}if(U.success){let D=U.message.length>1000?U.message.slice(0,1000)+`
1536
1542
  ...(截断)`:U.message;return{success:!0,llmContent:U.message,displayContent:`✅ Subagent 任务完成
1537
1543
 
1538
1544
  `+`类型: ${Q}
1539
1545
  `+`任务: ${Z}
1540
1546
  Agent ID: ${U.agentId||"N/A"}
1541
- `+`耗时: ${F}ms
1547
+ `+`耗时: ${A}ms
1542
1548
  `+`工具调用: ${U.stats?.toolCalls||0} 次
1543
1549
  `+`Token: ${U.stats?.tokens||0}
1544
1550
 
1545
1551
  `+`结果:
1546
- ${A}`,metadata:{subagent_type:Q,description:Z,duration:F,stats:U.stats,subagentSessionId:B,subagentType:Q,subagentStatus:"completed",subagentSummary:U.message.slice(0,500)}}}else return{success:!1,llmContent:`Subagent execution failed: ${U.error}`,displayContent:`⚠️ Subagent 任务失败
1552
+ ${D}`,metadata:{subagent_type:Q,description:Z,duration:A,stats:U.stats,subagentSessionId:K,subagentType:Q,subagentStatus:"completed",subagentSummary:U.message.slice(0,500)}}}else return{success:!1,llmContent:`Subagent execution failed: ${U.error}`,displayContent:`⚠️ Subagent 任务失败
1547
1553
 
1548
1554
  `+`类型: ${Q}
1549
1555
  `+`任务: ${Z}
1550
1556
  Agent ID: ${U.agentId||"N/A"}
1551
- `+`耗时: ${F}ms
1552
- `+`错误: ${U.error}`,error:{type:"execution_error",message:U.error||"Unknown error"},metadata:{subagentSessionId:B,subagentType:Q,subagentStatus:"failed"}}}catch(K){let q=K,w=K3(q);return{success:!1,llmContent:`Subagent execution error: ${q.message}`,displayContent:`❌ Subagent 执行异常
1557
+ `+`耗时: ${A}ms
1558
+ `+`错误: ${U.error}`,error:{type:"execution_error",message:U.error||"Unknown error"},metadata:{subagentSessionId:K,subagentType:Q,subagentStatus:"failed"}}}catch(B){let q=B,w=U3(q);return{success:!1,llmContent:`Subagent execution error: ${q.message}`,displayContent:`❌ Subagent 执行异常
1553
1559
 
1554
- ${w}`,error:{type:"execution_error",message:q.message,details:K}}}},version:"4.0.0",category:"Subagent",tags:["task","subagent","delegation","explore","plan"],extractSignatureContent:($)=>`${$.subagent_type}:${$.description}`,abstractPermissionRule:()=>""});function U3($,W,Q,Z,V){if(!Z.bladeConfig)return{success:!1,llmContent:"BladeConfig is required for background agent execution",displayContent:"❌ 缺少 BladeConfig 配置",error:{type:"execution_error",message:"BladeConfig is required"}};let Y=_$.getInstance().startBackgroundAgent({config:$,bladeConfig:Z.bladeConfig,description:W,prompt:Q,parentSessionId:Z.sessionId,permissionMode:Z.permissionMode,agentId:V});return{success:!0,llmContent:{agent_id:Y,status:"running",message:`Agent started in background. Use TaskOutput(task_id: "${Y}") to retrieve results.`},displayContent:`\uD83D\uDE80 后台 Agent 已启动
1560
+ ${w}`,error:{type:"execution_error",message:q.message,details:B}}}},version:"4.0.0",category:"Subagent",tags:["task","subagent","delegation","explore","plan"],extractSignatureContent:($)=>`${$.subagent_type}:${$.description}`,abstractPermissionRule:()=>""});function D3($,W,Q,Z,V){if(!Z.bladeConfig)return{success:!1,llmContent:"BladeConfig is required for background agent execution",displayContent:"❌ 缺少 BladeConfig 配置",error:{type:"execution_error",message:"BladeConfig is required"}};let Y=_$.getInstance().startBackgroundAgent({config:$,bladeConfig:Z.bladeConfig,description:W,prompt:Q,parentSessionId:Z.sessionId,permissionMode:Z.permissionMode,agentId:V});return{success:!0,llmContent:{agent_id:Y,status:"running",message:`Agent started in background. Use TaskOutput(task_id: "${Y}") to retrieve results.`},displayContent:`\uD83D\uDE80 后台 Agent 已启动
1555
1561
 
1556
1562
  `+`Agent ID: ${Y}
1557
1563
  `+`类型: ${$.name}
1558
1564
  `+`任务: ${W}
1559
1565
 
1560
- `+"\uD83D\uDCA1 使用 TaskOutput 工具获取结果",metadata:{agent_id:Y,subagent_type:$.name,description:W,background:!0,subagentSessionId:Y,subagentType:$.name,subagentStatus:"running"}}}function H3($,W,Q,Z,V){if(!V.bladeConfig)return{success:!1,llmContent:"BladeConfig is required for agent resume",displayContent:"❌ 缺少 BladeConfig 配置",error:{type:"execution_error",message:"BladeConfig is required"}};let X=_$.getInstance();if(!X.getAgent($))return{success:!1,llmContent:`Cannot resume agent ${$}: session not found`,displayContent:`❌ 无法恢复 Agent: ${$}
1566
+ `+"\uD83D\uDCA1 使用 TaskOutput 工具获取结果",metadata:{agent_id:Y,subagent_type:$.name,description:W,background:!0,subagentSessionId:Y,subagentType:$.name,subagentStatus:"running"}}}function b3($,W,Q,Z,V){if(!V.bladeConfig)return{success:!1,llmContent:"BladeConfig is required for agent resume",displayContent:"❌ 缺少 BladeConfig 配置",error:{type:"execution_error",message:"BladeConfig is required"}};let X=_$.getInstance();if(!X.getAgent($))return{success:!1,llmContent:`Cannot resume agent ${$}: session not found`,displayContent:`❌ 无法恢复 Agent: ${$}
1561
1567
 
1562
1568
  会话不存在或已过期`,error:{type:"execution_error",message:`Agent session not found: ${$}`}};if(X.isRunning($))return{success:!1,llmContent:`Cannot resume agent ${$}: still running`,displayContent:`❌ 无法恢复 Agent: ${$}
1563
1569
 
@@ -1568,7 +1574,7 @@ Agent 仍在运行中,我会使用 TaskOutput 获取结果`,error:{type:"execu
1568
1574
  `+`类型: ${Q.name}
1569
1575
  `+`任务: ${Z}
1570
1576
 
1571
- `+"\uD83D\uDCA1 使用 TaskOutput 工具获取结果",metadata:{agent_id:J,resumed_from:$,subagent_type:Q.name,description:Z,background:!0,subagentSessionId:J,subagentType:Q.name,subagentStatus:"running"}}}import{z as y1}from"zod";var Z4=E({name:"TaskOutput",displayName:"Task Output",kind:"readonly",schema:y1.object({task_id:y1.string().min(1).describe("The task ID to get output from"),block:y1.boolean().default(!0).describe("Whether to wait for completion"),timeout:y1.number().min(0).max(600000).default(30000).describe("Max wait time in ms")}),description:{short:"Retrieves output from a running or completed task",long:`
1577
+ `+"\uD83D\uDCA1 使用 TaskOutput 工具获取结果",metadata:{agent_id:J,resumed_from:$,subagent_type:Q.name,description:Z,background:!0,subagentSessionId:J,subagentType:Q.name,subagentStatus:"running"}}}import{z as v1}from"zod";var Z4=E({name:"TaskOutput",displayName:"Task Output",kind:"readonly",schema:v1.object({task_id:v1.string().min(1).describe("The task ID to get output from"),block:v1.boolean().default(!0).describe("Whether to wait for completion"),timeout:v1.number().min(0).max(600000).default(30000).describe("Max wait time in ms")}),description:{short:"Retrieves output from a running or completed task",long:`
1572
1578
  - Retrieves output from a running or completed task (background shell, agent, or remote session)
1573
1579
  - Takes a task_id parameter identifying the task
1574
1580
  - Returns the task output along with status information
@@ -1576,11 +1582,11 @@ Agent 仍在运行中,我会使用 TaskOutput 获取结果`,error:{type:"execu
1576
1582
  - Use block=false for non-blocking check of current status
1577
1583
  - Task IDs can be found using the /tasks command
1578
1584
  - Works with all task types: background shells, async agents, and remote sessions
1579
- `.trim(),usageNotes:["task_id is required - the ID returned when starting a background task","block=true (default) waits for task completion","block=false returns current status immediately","timeout defaults to 30000ms (30 seconds), max 600000ms (10 minutes)"],examples:[{description:"Get output from a background shell",params:{task_id:"bash_abc123",block:!0,timeout:30000}},{description:"Check agent status without blocking",params:{task_id:"session_xyz789",block:!1}}]},async execute($,W){let{task_id:Q,block:Z,timeout:V}=$;if(Q.startsWith("bash_"))return V5(Q,Z,V);let X=J$.getInstance(),Y=_$.getInstance();if(X.getProcess(Q))return V5(Q,Z,V);if(Y.getAgent(Q))return b3(Q,Z,V);return{success:!1,llmContent:`Unknown task ID: ${Q}.`,displayContent:`❌ 未知的任务 ID: ${Q}
1585
+ `.trim(),usageNotes:["task_id is required - the ID returned when starting a background task","block=true (default) waits for task completion","block=false returns current status immediately","timeout defaults to 30000ms (30 seconds), max 600000ms (10 minutes)"],examples:[{description:"Get output from a background shell",params:{task_id:"bash_abc123",block:!0,timeout:30000}},{description:"Check agent status without blocking",params:{task_id:"session_xyz789",block:!1}}]},async execute($,W){let{task_id:Q,block:Z,timeout:V}=$;if(Q.startsWith("bash_"))return V5(Q,Z,V);let X=B$.getInstance(),Y=_$.getInstance();if(X.getProcess(Q))return V5(Q,Z,V);if(Y.getAgent(Q))return _3(Q,Z,V);return{success:!1,llmContent:`Unknown task ID: ${Q}.`,displayContent:`❌ 未知的任务 ID: ${Q}
1580
1586
 
1581
1587
  任务 ID 格式:
1582
1588
  - bash_xxx: 后台 shell
1583
- - agent: 后台 agent`,error:{type:"validation_error",message:`Unknown task ID: ${Q}`}}},version:"1.0.0",category:"Task",tags:["task","output","background","shell","agent"],extractSignatureContent:($)=>$.task_id,abstractPermissionRule:()=>"*"});async function V5($,W,Q){let Z=J$.getInstance(),V=Z.getProcess($);if(!V)return{success:!1,llmContent:`Shell not found: ${$}`,displayContent:`❌ 未找到 Shell: ${$}`,error:{type:"execution_error",message:"Shell 会话不存在或已清理"}};if(W&&V.status==="running")await F3($,Q);let X=Z.consumeOutput($);if(!X)return{success:!1,llmContent:`Failed to get output for shell: ${$}`,displayContent:`❌ 获取 Shell 输出失败: ${$}`,error:{type:"execution_error",message:"Failed to consume output"}};let Y={task_id:X.id,type:"shell",status:X.status,command:X.command,pid:X.pid,exit_code:X.exitCode,signal:X.signal,started_at:new Date(X.startedAt).toISOString(),finished_at:X.endedAt?new Date(X.endedAt).toISOString():void 0,stdout:X.stdout,stderr:X.stderr},G=`${X5(X.status)} TaskOutput(${$}) - Shell
1589
+ - agent: 后台 agent`,error:{type:"validation_error",message:`Unknown task ID: ${Q}`}}},version:"1.0.0",category:"Task",tags:["task","output","background","shell","agent"],extractSignatureContent:($)=>$.task_id,abstractPermissionRule:()=>"*"});async function V5($,W,Q){let Z=B$.getInstance(),V=Z.getProcess($);if(!V)return{success:!1,llmContent:`Shell not found: ${$}`,displayContent:`❌ 未找到 Shell: ${$}`,error:{type:"execution_error",message:"Shell 会话不存在或已清理"}};if(W&&V.status==="running")await L3($,Q);let X=Z.consumeOutput($);if(!X)return{success:!1,llmContent:`Failed to get output for shell: ${$}`,displayContent:`❌ 获取 Shell 输出失败: ${$}`,error:{type:"execution_error",message:"Failed to consume output"}};let Y={task_id:X.id,type:"shell",status:X.status,command:X.command,pid:X.pid,exit_code:X.exitCode,signal:X.signal,started_at:new Date(X.startedAt).toISOString(),finished_at:X.endedAt?new Date(X.endedAt).toISOString():void 0,stdout:X.stdout,stderr:X.stderr},G=`${X5(X.status)} TaskOutput(${$}) - Shell
1584
1590
  `+`状态: ${X.status}
1585
1591
  `+`命令: ${X.command}
1586
1592
  `+(X.pid?`PID: ${X.pid}
@@ -1589,7 +1595,7 @@ Agent 仍在运行中,我会使用 TaskOutput 获取结果`,error:{type:"execu
1589
1595
  stdout:
1590
1596
  ${X.stdout}`:"")+(X.stderr?`
1591
1597
  stderr:
1592
- ${X.stderr}`:"");return{success:!0,llmContent:Y,displayContent:G,metadata:Y}}async function b3($,W,Q){let Z=_$.getInstance(),V=Z.getAgent($);if(!V)return{success:!1,llmContent:`Agent not found: ${$}`,displayContent:`❌ 未找到 Agent: ${$}`,error:{type:"execution_error",message:"Agent 会话不存在或已清理"}};if(W&&V.status==="running"){if(V=await Z.waitForCompletion($,Q),!V)return{success:!1,llmContent:`Failed to wait for agent: ${$}`,displayContent:`❌ 等待 Agent 失败: ${$}`,error:{type:"execution_error",message:"Wait for completion failed"}}}let X={task_id:V.id,type:"agent",status:V.status,subagent_type:V.subagentType,description:V.description,created_at:new Date(V.createdAt).toISOString(),last_active_at:new Date(V.lastActiveAt).toISOString(),completed_at:V.completedAt?new Date(V.completedAt).toISOString():void 0,result:V.result,stats:V.stats},Y=V.status==="completed"?"completed":V.status==="failed"?"failed":"running",G=`${X5(V.status)} TaskOutput(${$}) - Agent
1598
+ ${X.stderr}`:"");return{success:!0,llmContent:Y,displayContent:G,metadata:Y}}async function _3($,W,Q){let Z=_$.getInstance(),V=Z.getAgent($);if(!V)return{success:!1,llmContent:`Agent not found: ${$}`,displayContent:`❌ 未找到 Agent: ${$}`,error:{type:"execution_error",message:"Agent 会话不存在或已清理"}};if(W&&V.status==="running"){if(V=await Z.waitForCompletion($,Q),!V)return{success:!1,llmContent:`Failed to wait for agent: ${$}`,displayContent:`❌ 等待 Agent 失败: ${$}`,error:{type:"execution_error",message:"Wait for completion failed"}}}let X={task_id:V.id,type:"agent",status:V.status,subagent_type:V.subagentType,description:V.description,created_at:new Date(V.createdAt).toISOString(),last_active_at:new Date(V.lastActiveAt).toISOString(),completed_at:V.completedAt?new Date(V.completedAt).toISOString():void 0,result:V.result,stats:V.stats},Y=V.status==="completed"?"completed":V.status==="failed"?"failed":"running",G=`${X5(V.status)} TaskOutput(${$}) - Agent
1593
1599
  `+`状态: ${V.status}
1594
1600
  `+`类型: ${V.subagentType}
1595
1601
  `+`描述: ${V.description}
@@ -1598,7 +1604,7 @@ ${X.stderr}`:"");return{success:!0,llmContent:Y,displayContent:G,metadata:Y}}asy
1598
1604
  `:"")+(V.result?.message?`
1599
1605
  结果:
1600
1606
  ${V.result.message}`:"")+(V.result?.error?`
1601
- 错误: ${V.result.error}`:"");return{success:!0,llmContent:X,displayContent:G,metadata:{...X,subagentSessionId:V.id,subagentType:V.subagentType,subagentStatus:Y,subagentSummary:typeof V.result?.message==="string"?V.result.message.slice(0,500):void 0}}}async function F3($,W){let Q=J$.getInstance(),Z=Date.now();return new Promise((V)=>{let X=setInterval(()=>{let Y=Q.getProcess($);if(!Y||Y.status!=="running"){clearInterval(X),V();return}if(Date.now()-Z>=W){clearInterval(X),V();return}},100)})}function X5($){switch($){case"running":return"⏳";case"completed":case"exited":return"✅";case"failed":case"error":return"❌";case"killed":case"cancelled":return"✂️";default:return"❓"}}import{z as J5}from"zod";import{randomUUID as A3}from"crypto";import*as A0 from"fs/promises";import*as T1 from"path";class G0{static instances=new Map;todos=[];filePath;loaded=!1;constructor($,W){this.filePath=T1.join(W,"todos",`${$}-agent-${$}.json`)}static getInstance($,W){let Q=`${$}-${W}`;if(!G0.instances.has(Q))G0.instances.set(Q,new G0($,W));return G0.instances.get(Q)}validate($){if($.filter((Q)=>Q.status==="in_progress").length>1)return{valid:!1,error:"同时只能有一个任务处于 in_progress 状态"};return{valid:!0}}async updateTodos($){await this.ensureLoaded();let W=new Date().toISOString(),Q=$.map((V)=>{let X=V,Y=this.todos.find((J)=>J.id===X.id||J.content===V.content);return{...V,id:X.id||Y?.id||A3(),priority:V.priority||Y?.priority||"medium",createdAt:Y?.createdAt||W,startedAt:V.status==="in_progress"&&!Y?.startedAt?W:Y?.startedAt,completedAt:V.status==="completed"&&!Y?.completedAt?W:Y?.completedAt}}),Z=this.validate(Q);if(!Z.valid)throw Error(Z.error);this.todos=Q,await this.saveTodos()}getSortedTodos(){let $={completed:0,in_progress:1,pending:2},W={high:0,medium:1,low:2};return[...this.todos].sort((Q,Z)=>{let V=$[Q.status]-$[Z.status];if(V!==0)return V;return W[Q.priority]-W[Z.priority]})}getTodos(){return this.getSortedTodos()}async ensureLoaded(){if(!this.loaded)await this.loadTodos(),this.loaded=!0}async loadTodos(){try{let $=await A0.readFile(this.filePath,"utf-8");this.todos=JSON.parse($)}catch($){if($.code==="ENOENT")this.todos=[];else console.warn("加载 TODO 列表失败:",$),this.todos=[]}}async saveTodos(){try{await A0.mkdir(T1.dirname(this.filePath),{recursive:!0,mode:493}),await A0.writeFile(this.filePath,JSON.stringify(this.todos,null,2),"utf-8")}catch($){throw console.error("保存 TODO 列表失败:",$),$}}}import{z as D0}from"zod";var Y5=D0.object({id:D0.string().optional(),content:D0.string().min(1,"Content cannot be empty"),status:D0.enum(["pending","in_progress","completed"]),activeForm:D0.string().min(1,"ActiveForm cannot be empty"),priority:D0.enum(["high","medium","low"]).default("medium")});function V4($){let{sessionId:W,configDir:Q}=$;return E({name:"TodoWrite",displayName:"Todo Write",kind:"readonly",schema:J5.object({todos:J5.array(Y5).min(1,"At least one task is required")}),description:{short:"Use this tool to create and manage a structured task list for your current coding session",long:`Use this tool to create and manage a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
1607
+ 错误: ${V.result.error}`:"");return{success:!0,llmContent:X,displayContent:G,metadata:{...X,subagentSessionId:V.id,subagentType:V.subagentType,subagentStatus:Y,subagentSummary:typeof V.result?.message==="string"?V.result.message.slice(0,500):void 0}}}async function L3($,W){let Q=B$.getInstance(),Z=Date.now();return new Promise((V)=>{let X=setInterval(()=>{let Y=Q.getProcess($);if(!Y||Y.status!=="running"){clearInterval(X),V();return}if(Date.now()-Z>=W){clearInterval(X),V();return}},100)})}function X5($){switch($){case"running":return"⏳";case"completed":case"exited":return"✅";case"failed":case"error":return"❌";case"killed":case"cancelled":return"✂️";default:return"❓"}}import{z as J5}from"zod";import{randomUUID as j3}from"crypto";import*as D0 from"fs/promises";import*as y1 from"path";class J0{static instances=new Map;todos=[];filePath;loaded=!1;constructor($,W){this.filePath=y1.join(W,"todos",`${$}-agent-${$}.json`)}static getInstance($,W){let Q=`${$}-${W}`;if(!J0.instances.has(Q))J0.instances.set(Q,new J0($,W));return J0.instances.get(Q)}validate($){if($.filter((Q)=>Q.status==="in_progress").length>1)return{valid:!1,error:"同时只能有一个任务处于 in_progress 状态"};return{valid:!0}}async updateTodos($){await this.ensureLoaded();let W=new Date().toISOString(),Q=$.map((V)=>{let X=V,Y=this.todos.find((J)=>J.id===X.id||J.content===V.content);return{...V,id:X.id||Y?.id||j3(),priority:V.priority||Y?.priority||"medium",createdAt:Y?.createdAt||W,startedAt:V.status==="in_progress"&&!Y?.startedAt?W:Y?.startedAt,completedAt:V.status==="completed"&&!Y?.completedAt?W:Y?.completedAt}}),Z=this.validate(Q);if(!Z.valid)throw Error(Z.error);this.todos=Q,await this.saveTodos()}getSortedTodos(){let $={completed:0,in_progress:1,pending:2},W={high:0,medium:1,low:2};return[...this.todos].sort((Q,Z)=>{let V=$[Q.status]-$[Z.status];if(V!==0)return V;return W[Q.priority]-W[Z.priority]})}getTodos(){return this.getSortedTodos()}async ensureLoaded(){if(!this.loaded)await this.loadTodos(),this.loaded=!0}async loadTodos(){try{let $=await D0.readFile(this.filePath,"utf-8");this.todos=JSON.parse($)}catch($){if($.code==="ENOENT")this.todos=[];else console.warn("加载 TODO 列表失败:",$),this.todos=[]}}async saveTodos(){try{await D0.mkdir(y1.dirname(this.filePath),{recursive:!0,mode:493}),await D0.writeFile(this.filePath,JSON.stringify(this.todos,null,2),"utf-8")}catch($){throw console.error("保存 TODO 列表失败:",$),$}}}import{z as b0}from"zod";var Y5=b0.object({id:b0.string().optional(),content:b0.string().min(1,"Content cannot be empty"),status:b0.enum(["pending","in_progress","completed"]),activeForm:b0.string().min(1,"ActiveForm cannot be empty"),priority:b0.enum(["high","medium","low"]).default("medium")});function V4($){let{sessionId:W,configDir:Q}=$;return E({name:"TodoWrite",displayName:"Todo Write",kind:"readonly",schema:J5.object({todos:J5.array(Y5).min(1,"At least one task is required")}),description:{short:"Use this tool to create and manage a structured task list for your current coding session",long:`Use this tool to create and manage a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
1602
1608
  It also helps the user understand the progress of the task and overall progress of their requests.
1603
1609
 
1604
1610
  ## When to Use This Tool
@@ -1659,9 +1665,9 @@ NOTE that you should not use this tool if there is only one trivial task to do.
1659
1665
  - activeForm: "Fixing authentication bug"
1660
1666
 
1661
1667
  When in doubt, use this tool. Being proactive with task management demonstrates attentiveness and ensures you complete all requirements successfully.
1662
- `},async execute(Z,V){let{todos:X}=Z,{updateOutput:Y}=V;try{let J=V.sessionId||W,G=G0.getInstance(J,Q);Y?.("Updating TODO list..."),await G.updateTodos(X);let B=G.getTodos(),K=D3(B),q=_3(B,K);return Y?.(`✅ TODO list updated (${K.completed}/${K.total} completed)`),{success:!0,llmContent:{todos:B,stats:K},displayContent:q,metadata:{stats:K}}}catch(J){let G=J;return{success:!1,llmContent:`Update failed: ${G.message}`,displayContent:`❌ 更新 TODO 列表失败: ${G.message}`,error:{type:"execution_error",message:G.message,details:J}}}},version:"1.0.0",category:"TODO tools",tags:["todo","task","management","planning"],extractSignatureContent:(Z)=>`${Z.todos.length} todos`,abstractPermissionRule:()=>"*"})}function D3($){return{total:$.length,completed:$.filter((W)=>W.status==="completed").length,inProgress:$.filter((W)=>W.status==="in_progress").length,pending:$.filter((W)=>W.status==="pending").length}}function _3($,W){let Q=[],Z=W.total>0?Math.round(W.completed/W.total*100):0;if(Q.push(`\uD83D\uDCCB TODO 列表 (${W.completed}/${W.total} 完成,${Z}%)`),Q.push(""),$.length===0)return Q.push(" (暂无任务)"),Q.join(`
1668
+ `},async execute(Z,V){let{todos:X}=Z,{updateOutput:Y}=V;try{let J=V.sessionId||W,G=J0.getInstance(J,Q);Y?.("Updating TODO list..."),await G.updateTodos(X);let K=G.getTodos(),B=N3(K),q=z3(K,B);return Y?.(`✅ TODO list updated (${B.completed}/${B.total} completed)`),{success:!0,llmContent:{todos:K,stats:B},displayContent:q,metadata:{stats:B}}}catch(J){let G=J;return{success:!1,llmContent:`Update failed: ${G.message}`,displayContent:`❌ 更新 TODO 列表失败: ${G.message}`,error:{type:"execution_error",message:G.message,details:J}}}},version:"1.0.0",category:"TODO tools",tags:["todo","task","management","planning"],extractSignatureContent:(Z)=>`${Z.todos.length} todos`,abstractPermissionRule:()=>"*"})}function N3($){return{total:$.length,completed:$.filter((W)=>W.status==="completed").length,inProgress:$.filter((W)=>W.status==="in_progress").length,pending:$.filter((W)=>W.status==="pending").length}}function z3($,W){let Q=[],Z=W.total>0?Math.round(W.completed/W.total*100):0;if(Q.push(`\uD83D\uDCCB TODO 列表 (${W.completed}/${W.total} 完成,${Z}%)`),Q.push(""),$.length===0)return Q.push(" (暂无任务)"),Q.join(`
1663
1669
  `);for(let V of $){let X=V.status==="completed"?"☑":"☐",Y=`(P${V.priority==="high"?0:V.priority==="medium"?1:2})`,J=V.status==="in_progress"?" ⚡":"",G=V.status==="completed"?"~~":"";Q.push(` ${X} ${Y} ${G}${V.content}${G}${J}`)}return Q.join(`
1664
- `)}import{z as V$}from"zod";import{isPlainObject as G5}from"lodash-es";function B5($){if(!G5($))return;let W=$;return typeof W.name==="string"?W.name:void 0}function L3($){if($ instanceof Error)return $.message;if(typeof $==="string")return $;if(G5($)){let W=$;if(typeof W.message==="string")return W.message}return String($)}var Y4=E({name:"WebFetch",displayName:"Web Fetch",kind:"readonly",schema:V$.object({url:V$.string().url().describe("URL to request"),method:V$.enum(["GET","POST","PUT","DELETE","HEAD"]).default("GET").describe("HTTP method"),extract_content:V$.boolean().default(!1).describe("Use Jina Reader to extract clean content in Markdown format. Removes HTML clutter, scripts, and styling, returning only the main content."),jina_options:V$.object({with_generated_alt:V$.boolean().default(!1).describe("Generate alt text for images"),with_links_summary:V$.boolean().default(!1).describe("Include summary of all links"),wait_for_selector:V$.string().optional().describe("Wait for specific CSS selector to load")}).optional().describe("Jina Reader advanced options (only used when extract_content is true)"),headers:V$.record(V$.string()).optional().describe("Request headers (optional)"),body:V$.string().optional().describe("Request body (optional)"),timeout:p.timeout(1000,120000,30000),follow_redirects:V$.boolean().default(!0).describe("Follow redirects"),max_redirects:V$.number().int().min(0).max(10).default(5).describe("Maximum redirect hops"),return_headers:V$.boolean().default(!1).describe("Return response headers")}),description:{short:"Fetches content from a specified URL and processes it using an AI model",long:`
1670
+ `)}import{z as V$}from"zod";import{isPlainObject as G5}from"lodash-es";function K5($){if(!G5($))return;let W=$;return typeof W.name==="string"?W.name:void 0}function R3($){if($ instanceof Error)return $.message;if(typeof $==="string")return $;if(G5($)){let W=$;if(typeof W.message==="string")return W.message}return String($)}var Y4=E({name:"WebFetch",displayName:"Web Fetch",kind:"readonly",schema:V$.object({url:V$.string().url().describe("URL to request"),method:V$.enum(["GET","POST","PUT","DELETE","HEAD"]).default("GET").describe("HTTP method"),extract_content:V$.boolean().default(!1).describe("Use Jina Reader to extract clean content in Markdown format. Removes HTML clutter, scripts, and styling, returning only the main content."),jina_options:V$.object({with_generated_alt:V$.boolean().default(!1).describe("Generate alt text for images"),with_links_summary:V$.boolean().default(!1).describe("Include summary of all links"),wait_for_selector:V$.string().optional().describe("Wait for specific CSS selector to load")}).optional().describe("Jina Reader advanced options (only used when extract_content is true)"),headers:V$.record(V$.string()).optional().describe("Request headers (optional)"),body:V$.string().optional().describe("Request body (optional)"),timeout:p.timeout(1000,120000,30000),follow_redirects:V$.boolean().default(!0).describe("Follow redirects"),max_redirects:V$.number().int().min(0).max(10).default(5).describe("Maximum redirect hops"),return_headers:V$.boolean().default(!1).describe("Return response headers")}),description:{short:"Fetches content from a specified URL and processes it using an AI model",long:`
1665
1671
  - Fetches content from a specified URL and processes it using an AI model
1666
1672
  - Takes a URL and a prompt as input
1667
1673
  - Fetches the URL content, converts HTML to markdown
@@ -1678,29 +1684,29 @@ Usage notes:
1678
1684
  - Results may be summarized if the content is very large
1679
1685
  - Includes a self-cleaning 15-minute cache for faster responses when repeatedly accessing the same URL
1680
1686
  - When a URL redirects to a different host, the tool will inform you and provide the redirect URL in a special format. You should then make a new WebFetch request with the redirect URL to fetch the content.
1681
- `},async execute($,W){let{url:Q,method:Z="GET",extract_content:V=!1,jina_options:X,headers:Y={},body:J,timeout:G=30000,follow_redirects:B=!0,max_redirects:K=5,return_headers:q=!1}=$,{updateOutput:w}=W,O=W.signal??new AbortController().signal;try{if(V)try{let D=Date.now(),N=await C3({url:Q,jinaOptions:X,timeout:G,signal:O,updateOutput:w}),C=Date.now()-D;if(N.response_time=C,!q)delete N.headers;let z={url:Q,method:"GET",status:N.status,response_time:C,content_length:Buffer.byteLength(N.body||"","utf8"),redirected:N.redirected||!1,redirect_count:N.redirect_count??0,final_url:N.url,content_type:N.content_type,redirect_chain:N.redirect_chain};return{success:!0,llmContent:N,displayContent:X4(N,z,!1),metadata:z}}catch{w?.("⚠️ Jina Reader 失败,使用标准方式获取")}w?.(`发送 ${Z} 请求到: ${Q}`);let b=Date.now(),U=await j3({url:Q,method:Z,headers:Y,body:J,timeout:G,follow_redirects:B,max_redirects:K,signal:O}),F=Date.now()-b;if(U.response_time=F,!q)delete U.headers;let A={url:Q,method:Z,status:U.status,response_time:F,content_length:Buffer.byteLength(U.body||"","utf8"),redirected:U.redirected||!1,redirect_count:U.redirect_count??0,final_url:U.url,content_type:U.content_type,redirect_chain:U.redirect_chain};if(U.status>=400)return{success:!1,llmContent:`HTTP error ${U.status}: ${U.status_text}`,displayContent:X4(U,A,!0),error:{type:"execution_error",message:`HTTP error ${U.status}: ${U.status_text}`,details:{...A,response_body:U.body}},metadata:A};return{success:!0,llmContent:U,displayContent:X4(U,A,!1),metadata:A}}catch(b){if(B5(b)==="AbortError")return{success:!1,llmContent:"Request aborted",displayContent:"⚠️ 请求被用户中止",error:{type:"execution_error",message:"操作被中止"}};let U=L3(b);return{success:!1,llmContent:`Network request failed: ${U}`,displayContent:`❌ 网络请求失败: ${U}`,error:{type:"execution_error",message:U,details:b}}}},version:"2.0.0",category:"网络工具",tags:["web","http","fetch","request","api"],extractSignatureContent:($)=>{try{return`domain:${new URL($.url).hostname}`}catch{return $.url}},abstractPermissionRule:($)=>{try{return`domain:${new URL($.url).hostname}`}catch{return"*"}}});async function j3($){let{url:W,method:Q,headers:Z,body:V,timeout:X,follow_redirects:Y,max_redirects:J,signal:G}=$,B={"User-Agent":"Blade-AI/1.0",...Z},K=W,q=Q,w=V,O=0,b=[];while(!0){let U={...B};if(w&&q!=="GET"&&q!=="HEAD"&&!E3(U,"content-type"))U["Content-Type"]="application/json";let F=await K5(K,{method:q,headers:U,body:w&&q!=="GET"&&q!=="HEAD"?w:void 0,redirect:"manual"},X,G),A=F.headers.get("location"),D=F.status>=300&&F.status<400,N=Y&&D&&A&&O<J;if(D&&Y&&!A)throw Error(`收到状态码 ${F.status} 但响应缺少 Location 头`);if(D&&Y&&O>=J)throw Error(`超过最大重定向次数 (${J})`);if(N&&A){O++;let y=R3(A,K);if(b.push(`${F.status} → ${y}`),F.status===303||(F.status===301||F.status===302)&&q!=="GET"&&q!=="HEAD")q="GET",w=void 0;K=y;continue}let C=await F.text(),z=q5(F.headers);return{status:F.status,status_text:F.statusText,headers:z,body:C,url:F.url||K,redirected:O>0,redirect_count:O,redirect_chain:b,content_type:z["content-type"],response_time:0}}}function X4($,W,Q){let{url:Z,method:V,status:X,response_time:Y,content_length:J}=W,G=Q?`❌ ${V} ${Z} - ${X} ${$.status_text}`:`✅ ${V} ${Z} - ${X} ${$.status_text}`;if(G+=`
1687
+ `},async execute($,W){let{url:Q,method:Z="GET",extract_content:V=!1,jina_options:X,headers:Y={},body:J,timeout:G=30000,follow_redirects:K=!0,max_redirects:B=5,return_headers:q=!1}=$,{updateOutput:w}=W,O=W.signal??new AbortController().signal;try{if(V)try{let b=Date.now(),z=await y3({url:Q,jinaOptions:X,timeout:G,signal:O,updateOutput:w}),C=Date.now()-b;if(z.response_time=C,!q)delete z.headers;let N={url:Q,method:"GET",status:z.status,response_time:C,content_length:Buffer.byteLength(z.body||"","utf8"),redirected:z.redirected||!1,redirect_count:z.redirect_count??0,final_url:z.url,content_type:z.content_type,redirect_chain:z.redirect_chain};return{success:!0,llmContent:z,displayContent:X4(z,N,!1),metadata:N}}catch{w?.("⚠️ Jina Reader 失败,使用标准方式获取")}w?.(`发送 ${Z} 请求到: ${Q}`);let H=Date.now(),U=await E3({url:Q,method:Z,headers:Y,body:J,timeout:G,follow_redirects:K,max_redirects:B,signal:O}),A=Date.now()-H;if(U.response_time=A,!q)delete U.headers;let D={url:Q,method:Z,status:U.status,response_time:A,content_length:Buffer.byteLength(U.body||"","utf8"),redirected:U.redirected||!1,redirect_count:U.redirect_count??0,final_url:U.url,content_type:U.content_type,redirect_chain:U.redirect_chain};if(U.status>=400)return{success:!1,llmContent:`HTTP error ${U.status}: ${U.status_text}`,displayContent:X4(U,D,!0),error:{type:"execution_error",message:`HTTP error ${U.status}: ${U.status_text}`,details:{...D,response_body:U.body}},metadata:D};return{success:!0,llmContent:U,displayContent:X4(U,D,!1),metadata:D}}catch(H){if(K5(H)==="AbortError")return{success:!1,llmContent:"Request aborted",displayContent:"⚠️ 请求被用户中止",error:{type:"execution_error",message:"操作被中止"}};let U=R3(H);return{success:!1,llmContent:`Network request failed: ${U}`,displayContent:`❌ 网络请求失败: ${U}`,error:{type:"execution_error",message:U,details:H}}}},version:"2.0.0",category:"网络工具",tags:["web","http","fetch","request","api"],extractSignatureContent:($)=>{try{return`domain:${new URL($.url).hostname}`}catch{return $.url}},abstractPermissionRule:($)=>{try{return`domain:${new URL($.url).hostname}`}catch{return"*"}}});async function E3($){let{url:W,method:Q,headers:Z,body:V,timeout:X,follow_redirects:Y,max_redirects:J,signal:G}=$,K={"User-Agent":"Blade-AI/1.0",...Z},B=W,q=Q,w=V,O=0,H=[];while(!0){let U={...K};if(w&&q!=="GET"&&q!=="HEAD"&&!v3(U,"content-type"))U["Content-Type"]="application/json";let A=await B5(B,{method:q,headers:U,body:w&&q!=="GET"&&q!=="HEAD"?w:void 0,redirect:"manual"},X,G),D=A.headers.get("location"),b=A.status>=300&&A.status<400,z=Y&&b&&D&&O<J;if(b&&Y&&!D)throw Error(`收到状态码 ${A.status} 但响应缺少 Location 头`);if(b&&Y&&O>=J)throw Error(`超过最大重定向次数 (${J})`);if(z&&D){O++;let y=S3(D,B);if(H.push(`${A.status} → ${y}`),A.status===303||(A.status===301||A.status===302)&&q!=="GET"&&q!=="HEAD")q="GET",w=void 0;B=y;continue}let C=await A.text(),N=q5(A.headers);return{status:A.status,status_text:A.statusText,headers:N,body:C,url:A.url||B,redirected:O>0,redirect_count:O,redirect_chain:H,content_type:N["content-type"],response_time:0}}}function X4($,W,Q){let{url:Z,method:V,status:X,response_time:Y,content_length:J}=W,G=Q?`❌ ${V} ${Z} - ${X} ${$.status_text}`:`✅ ${V} ${Z} - ${X} ${$.status_text}`;if(G+=`
1682
1688
  响应时间: ${Y}ms`,G+=`
1683
1689
  内容长度: ${J} 字节`,W.content_type)G+=`
1684
1690
  Content-Type: ${W.content_type}`;if($.redirected&&W.final_url&&W.final_url!==Z){if(G+=`
1685
1691
  最终URL: ${W.final_url}`,W.redirect_count)G+=`
1686
- 重定向次数: ${W.redirect_count}`}let B=z3($.body,$.content_type);if(B)G+=`
1692
+ 重定向次数: ${W.redirect_count}`}let K=C3($.body,$.content_type);if(K)G+=`
1687
1693
  响应内容:
1688
- ${B}`;return G}function z3($,W){if(!$)return"(空响应)";if(N3(W,$))return"[binary content omitted]";let Q=$.trim();if(!Q)return"(仅包含空白字符)";return Q.length>800?`${Q.slice(0,800)}...`:Q}function N3($,W){if($){let V=$.toLowerCase();if(["image/","audio/","video/","application/pdf","application/zip","application/octet-stream"].some((Y)=>V.startsWith(Y)))return!0}if(!W)return!1;let Q=0,Z=Math.min(W.length,200);for(let V=0;V<Z;V++){let X=W.charCodeAt(V);if(X===9||X===10||X===13)continue;if(X<32||X>126)Q++}return Q/(Z||1)>0.3}async function K5($,W,Q,Z){let V=new AbortController,X=setTimeout(()=>V.abort(),Q),Y=()=>V.abort();Z?.addEventListener("abort",Y);try{return await fetch($,{...W,signal:V.signal})}catch(J){if(B5(J)==="AbortError"){if(J instanceof Error)throw J.message="请求被中止或超时",J;let G=Error("请求被中止或超时");throw G.name="AbortError",G}throw J}finally{clearTimeout(X),Z?.removeEventListener("abort",Y)}}function R3($,W){try{return new URL($,W).toString()}catch{return $}}function q5($){let W={};return $.forEach((Q,Z)=>{W[Z.toLowerCase()]=Q}),W}function E3($,W){let Q=W.toLowerCase();return Object.keys($).some((Z)=>Z.toLowerCase()===Q)}async function C3($){let{url:W,jinaOptions:Q,timeout:Z,signal:V,updateOutput:X}=$,Y=`https://r.jina.ai/${encodeURIComponent(W)}`;X?.(`\uD83D\uDD0D 使用 Jina Reader 提取内容: ${W}`);let J={"User-Agent":"Blade-AI/1.0",Accept:"text/markdown"};if(Q?.with_generated_alt)J["X-With-Generated-Alt"]="true";if(Q?.with_links_summary)J["X-With-Links-Summary"]="true";if(Q?.wait_for_selector)J["X-Wait-For-Selector"]=Q.wait_for_selector;try{let G=await K5(Y,{method:"GET",headers:J},Z,V);if(!G.ok)throw Error(`Jina Reader error: ${G.status} ${G.statusText}`);let B=await G.text(),K=M3(B);return X?.(`✅ Jina Reader 成功提取内容 (${K.content.length} 字符)`),{status:G.status,status_text:G.statusText,headers:q5(G.headers),body:S3(K),url:K.sourceUrl||W,redirected:!1,redirect_count:0,content_type:"text/markdown",response_time:0}}catch(G){throw X?.("⚠️ Jina Reader 失败,回退到直接获取"),G}}function M3($){let W=$.split(`
1694
+ ${K}`;return G}function C3($,W){if(!$)return"(空响应)";if(M3(W,$))return"[binary content omitted]";let Q=$.trim();if(!Q)return"(仅包含空白字符)";return Q.length>800?`${Q.slice(0,800)}...`:Q}function M3($,W){if($){let V=$.toLowerCase();if(["image/","audio/","video/","application/pdf","application/zip","application/octet-stream"].some((Y)=>V.startsWith(Y)))return!0}if(!W)return!1;let Q=0,Z=Math.min(W.length,200);for(let V=0;V<Z;V++){let X=W.charCodeAt(V);if(X===9||X===10||X===13)continue;if(X<32||X>126)Q++}return Q/(Z||1)>0.3}async function B5($,W,Q,Z){let V=new AbortController,X=setTimeout(()=>V.abort(),Q),Y=()=>V.abort();Z?.addEventListener("abort",Y);try{return await fetch($,{...W,signal:V.signal})}catch(J){if(K5(J)==="AbortError"){if(J instanceof Error)throw J.message="请求被中止或超时",J;let G=Error("请求被中止或超时");throw G.name="AbortError",G}throw J}finally{clearTimeout(X),Z?.removeEventListener("abort",Y)}}function S3($,W){try{return new URL($,W).toString()}catch{return $}}function q5($){let W={};return $.forEach((Q,Z)=>{W[Z.toLowerCase()]=Q}),W}function v3($,W){let Q=W.toLowerCase();return Object.keys($).some((Z)=>Z.toLowerCase()===Q)}async function y3($){let{url:W,jinaOptions:Q,timeout:Z,signal:V,updateOutput:X}=$,Y=`https://r.jina.ai/${encodeURIComponent(W)}`;X?.(`\uD83D\uDD0D 使用 Jina Reader 提取内容: ${W}`);let J={"User-Agent":"Blade-AI/1.0",Accept:"text/markdown"};if(Q?.with_generated_alt)J["X-With-Generated-Alt"]="true";if(Q?.with_links_summary)J["X-With-Links-Summary"]="true";if(Q?.wait_for_selector)J["X-Wait-For-Selector"]=Q.wait_for_selector;try{let G=await B5(Y,{method:"GET",headers:J},Z,V);if(!G.ok)throw Error(`Jina Reader error: ${G.status} ${G.statusText}`);let K=await G.text(),B=T3(K);return X?.(`✅ Jina Reader 成功提取内容 (${B.content.length} 字符)`),{status:G.status,status_text:G.statusText,headers:q5(G.headers),body:P3(B),url:B.sourceUrl||W,redirected:!1,redirect_count:0,content_type:"text/markdown",response_time:0}}catch(G){throw X?.("⚠️ Jina Reader 失败,回退到直接获取"),G}}function T3($){let W=$.split(`
1689
1695
  `),Q="",Z="",V=0;for(let Y=0;Y<W.length;Y++){let J=W[Y];if(J.startsWith("Title: "))Q=J.substring(7).trim();else if(J.startsWith("URL Source: "))Z=J.substring(12).trim();else if(J.startsWith("Markdown Content:")){V=Y+1;break}}let X=W.slice(V).join(`
1690
- `).trim();return{title:Q||"Untitled",sourceUrl:Z||"",content:X||$}}function S3($){let W="";if($.title)W+=`# ${$.title}
1696
+ `).trim();return{title:Q||"Untitled",sourceUrl:Z||"",content:X||$}}function P3($){let W="";if($.title)W+=`# ${$.title}
1691
1697
 
1692
1698
  `;if($.sourceUrl)W+=`**Source**: ${$.sourceUrl}
1693
1699
 
1694
1700
  `;return W+=`---
1695
1701
 
1696
- `,W+=$.content,W}import{ProxyAgent as u3,fetch as d3}from"undici";import{z as _0}from"zod";import{LRUCache as w5}from"lru-cache";import v3 from"node:crypto";class O5{cache;config;hits=0;misses=0;constructor($){this.config={maxSize:$?.maxSize??100,ttl:$?.ttl??3600000,enabled:$?.enabled??!0},this.cache=new w5({max:this.config.maxSize,ttl:this.config.ttl,updateAgeOnGet:!0,updateAgeOnHas:!1})}generateKey($,W){let Q=W.toLowerCase().trim(),Z=v3.createHash("md5").update(Q).digest("hex").substring(0,8);return`${$}:${Z}`}get($,W){if(!this.config.enabled)return null;let Q=this.generateKey($,W),Z=this.cache.get(Q);if(!Z)return this.misses++,null;if(Date.now()>Z.expiresAt)return this.cache.delete(Q),this.misses++,null;return this.hits++,Z.results}set($,W,Q){if(!this.config.enabled||Q.length===0)return;let Z=this.generateKey($,W),V=Date.now(),X={query:W,provider:$,results:Q,timestamp:V,expiresAt:V+this.config.ttl};this.cache.set(Z,X)}clear(){this.cache.clear(),this.hits=0,this.misses=0}getStats(){let $=this.hits+this.misses,W=$>0?this.hits/$*100:0;return{size:this.cache.size,maxSize:this.config.maxSize,enabled:this.config.enabled,ttl:this.config.ttl,hits:this.hits,misses:this.misses,hitRate:Number.parseFloat(W.toFixed(2))}}cleanup(){let $=Date.now(),W=0;for(let[Q,Z]of this.cache.entries())if($>Z.expiresAt)this.cache.delete(Q),W++;return W}enable(){this.config.enabled=!0}disable(){this.config.enabled=!1}isEnabled(){return this.config.enabled}updateConfig($){if($.maxSize!==void 0&&$.maxSize!==this.config.maxSize){this.config.maxSize=$.maxSize;let W=Array.from(this.cache.entries());this.cache=new w5({max:this.config.maxSize,ttl:this.config.ttl,updateAgeOnGet:!0,updateAgeOnHas:!1});for(let[Q,Z]of W.slice(-this.config.maxSize))this.cache.set(Q,Z)}if($.ttl!==void 0)this.config.ttl=$.ttl;if($.enabled!==void 0)this.config.enabled=$.enabled}}var y3=new O5;function U5(){return y3}function T3($){return $.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'")}function H5($){let W=T3($).trim();if(!W.includes(" - "))return{title:W,snippet:W};let[Q,...Z]=W.split(" - "),V=Q.trim(),X=Z.join(" - ").trim()||W;return{title:V,snippet:X}}function n0($){try{let W=new URL($),Q=W.pathname==="/"?"":W.pathname;return`${W.hostname}${Q}`}catch{return $}}function a0($){try{return new URL($).hostname.toLowerCase()}catch{return""}}function P3($){if(!$.FirstURL||!$.Text)return null;let{title:W,snippet:Q}=H5($.Text);return{title:W,snippet:Q,url:$.FirstURL,display_url:n0($.FirstURL),source:a0($.FirstURL)}}function b5($){let W=[];for(let Q of $){if(Q.Topics&&Q.Topics.length>0){W.push(...b5(Q.Topics));continue}if(Q.FirstURL&&Q.Text){let{title:Z,snippet:V}=H5(Q.Text);W.push({title:Z,snippet:V,url:Q.FirstURL,display_url:n0(Q.FirstURL),source:a0(Q.FirstURL)})}}return W}function k3($){let W=$,Q=(W.Results??[]).map((V)=>P3(V)).filter((V)=>V!==null),Z=b5(W.RelatedTopics??[]);return[...Q,...Z]}var I3={name:"DuckDuckGo",endpoint:"https://duckduckgo.com/",buildUrl:($)=>{let W=new URL("https://duckduckgo.com/");return W.searchParams.set("q",$),W.searchParams.set("format","json"),W.searchParams.set("no_html","1"),W.searchParams.set("skip_disambig","1"),W.searchParams.set("t","blade-code"),W.searchParams.set("kl","us-en"),W.toString()},parseResponse:k3,getHeaders:()=>({Accept:"application/json, text/plain;q=0.9","User-Agent":"Blade-AI-WebSearch/1.0"})};function f3($){let W=$,Q=[];for(let Z of W.results??[]){if(!Z.url||!Z.title)continue;Q.push({title:Z.title,snippet:Z.content||Z.title,url:Z.url,display_url:n0(Z.url),source:a0(Z.url)})}return Q}var F5=["https://searx.be","https://search.ononoki.org","https://searx.tiekoetter.com","https://searx.work"];function x3($){return{name:`SearXNG(${(()=>{try{return new URL($).hostname}catch{return $}})()})`,endpoint:$,buildUrl:(Q)=>{let Z=new URL(`${$}/search`);return Z.searchParams.set("q",Q),Z.searchParams.set("format","json"),Z.searchParams.set("categories","general"),Z.toString()},parseResponse:f3,getHeaders:()=>({Accept:"application/json","User-Agent":"Blade-AI-WebSearch/1.0"})}}var n$={BASE_URL:"https://mcp.exa.ai",ENDPOINT:"/mcp",DEFAULT_NUM_RESULTS:10,TIMEOUT:25000};function h3($){let W=[],Q=$.split(`
1697
- `),Z={};for(let V=0;V<Q.length;V++){let X=Q[V].trim();if(X.startsWith("Title: ")){if(Z.title&&Z.url)W.push({title:Z.title,url:Z.url,snippet:Z.snippet||Z.title,display_url:n0(Z.url),source:a0(Z.url)});Z={title:X.substring(7).trim(),snippet:""}}else if(X.startsWith("URL: "))Z.url=X.substring(5).trim();else if(X.startsWith("Text: ")){let J=X.substring(6).trim().replace(/<[^>]*>/g,"").replace(/\s+/g," ").trim();Z.snippet=J.substring(0,300)}}if(Z.title&&Z.url)W.push({title:Z.title,url:Z.url,snippet:Z.snippet||Z.title,display_url:n0(Z.url),source:a0(Z.url)});return W}function p3(){return{name:"Exa",endpoint:`${n$.BASE_URL}${n$.ENDPOINT}`,searchFn:async($)=>{let W={jsonrpc:"2.0",id:1,method:"tools/call",params:{name:"web_search_exa",arguments:{query:$,type:"auto",numResults:n$.DEFAULT_NUM_RESULTS,contextMaxCharacters:1e4}}},Q=new AbortController,Z=setTimeout(()=>Q.abort(),n$.TIMEOUT);try{let V=await fetch(`${n$.BASE_URL}${n$.ENDPOINT}`,{method:"POST",headers:{accept:"application/json, text/event-stream","content-type":"application/json"},body:JSON.stringify(W),signal:Q.signal});if(clearTimeout(Z),!V.ok)throw Error(`MCP error (${V.status})`);let Y=(await V.text()).split(`
1698
- `);for(let J of Y)if(J.startsWith("data: ")){let G=JSON.parse(J.substring(6));if(G.result&&G.result.content&&G.result.content.length>0)return h3(G.result.content[0].text)}throw Error("No search results found")}catch(V){if(clearTimeout(Z),V.name==="AbortError")throw Error("MCP request timed out");throw V}},buildUrl:()=>`${n$.BASE_URL}${n$.ENDPOINT}`,parseResponse:()=>[],getHeaders:()=>({})}}function A5(){let $=[];return $.push(p3()),$.push(I3),$.push(...F5.map(x3)),$}function D5(){return 2+F5.length}var m3=15000,g3=8,r0={maxRetries:3,baseDelay:1000,maxDelay:8000};function c3(){let $=process.env.HTTPS_PROXY||process.env.HTTP_PROXY||process.env.https_proxy||process.env.http_proxy;if($)try{return new u3($)}catch(W){console.warn(`Invalid proxy URL: ${$}`)}return}async function i3($,W,Q,Z,V){let X=new AbortController,Y=setTimeout(()=>X.abort(),Q),J=()=>X.abort();Z?.addEventListener("abort",J);try{return await d3($,{...W,signal:X.signal,dispatcher:V})}catch(G){if(G.name==="AbortError")throw Error("搜索请求超时或被中止");throw G}finally{clearTimeout(Y),Z?.removeEventListener("abort",J)}}async function l3($,W,Q,Z,V,X){let Y=null;for(let J=0;J<r0.maxRetries;J++)try{return await i3($,W,Q,Z,V)}catch(G){if(Y=G,Z?.aborted)throw G;if(J<r0.maxRetries-1){let B=Math.min(r0.baseDelay*2**J,r0.maxDelay);X?.(`⏳ 请求失败,${B/1000}s 后重试 (${J+1}/${r0.maxRetries})...`),await new Promise((K)=>setTimeout(K,B))}}throw Y}async function n3($,W,Q,Z,V,X){let Y=U5(),J=Y.get($.name,W);if(J)return X?.(`\uD83D\uDCBE 使用缓存结果 (${$.name})`),{results:J,providerName:`${$.name} (cached)`};if($.searchFn)try{X?.(`\uD83D\uDD0D 搜索中 (${$.name})...`);let F=await $.searchFn(W);return Y.set($.name,W,F),{results:F,providerName:$.name}}catch(F){throw Error(`SDK search failed: ${F.message}`)}X?.(`\uD83D\uDD0D 搜索中 (${$.name})...`);let G=$.buildUrl(W),B=$.method||"GET",q={headers:$.getHeaders(),method:B};if(B==="POST"&&$.buildBody)q.body=JSON.stringify($.buildBody(W));let w=await l3(G,q,Q,Z,V,X);if(!w.ok)throw Error(`HTTP ${w.status}`);let O=await w.text(),b;try{b=JSON.parse(O)}catch{throw Error("Failed to parse search result JSON")}let U=$.parseResponse(b);return Y.set($.name,W,U),{results:U,providerName:$.name}}async function a3($,W,Q,Z){let V=A5(),X=c3(),Y=[];for(let J=0;J<V.length;J++){let G=V[J];if(Q?.aborted)throw Error("搜索被用户中止");try{return Z?.(`\uD83D\uDD0E 使用 ${G.name} 搜索...`),await n3(G,$,W,Q,X,Z)}catch(B){let K=B,q=`${G.name}: ${K.message}`;if(Y.push(q),Z?.(`⚠️ ${q}`),J===V.length-1)throw Error(`所有搜索提供商都失败了:
1702
+ `,W+=$.content,W}import{ProxyAgent as c3,fetch as i3}from"undici";import{z as _0}from"zod";import{LRUCache as w5}from"lru-cache";import k3 from"node:crypto";class O5{cache;config;hits=0;misses=0;constructor($){this.config={maxSize:$?.maxSize??100,ttl:$?.ttl??3600000,enabled:$?.enabled??!0},this.cache=new w5({max:this.config.maxSize,ttl:this.config.ttl,updateAgeOnGet:!0,updateAgeOnHas:!1})}generateKey($,W){let Q=W.toLowerCase().trim(),Z=k3.createHash("md5").update(Q).digest("hex").substring(0,8);return`${$}:${Z}`}get($,W){if(!this.config.enabled)return null;let Q=this.generateKey($,W),Z=this.cache.get(Q);if(!Z)return this.misses++,null;if(Date.now()>Z.expiresAt)return this.cache.delete(Q),this.misses++,null;return this.hits++,Z.results}set($,W,Q){if(!this.config.enabled||Q.length===0)return;let Z=this.generateKey($,W),V=Date.now(),X={query:W,provider:$,results:Q,timestamp:V,expiresAt:V+this.config.ttl};this.cache.set(Z,X)}clear(){this.cache.clear(),this.hits=0,this.misses=0}getStats(){let $=this.hits+this.misses,W=$>0?this.hits/$*100:0;return{size:this.cache.size,maxSize:this.config.maxSize,enabled:this.config.enabled,ttl:this.config.ttl,hits:this.hits,misses:this.misses,hitRate:Number.parseFloat(W.toFixed(2))}}cleanup(){let $=Date.now(),W=0;for(let[Q,Z]of this.cache.entries())if($>Z.expiresAt)this.cache.delete(Q),W++;return W}enable(){this.config.enabled=!0}disable(){this.config.enabled=!1}isEnabled(){return this.config.enabled}updateConfig($){if($.maxSize!==void 0&&$.maxSize!==this.config.maxSize){this.config.maxSize=$.maxSize;let W=Array.from(this.cache.entries());this.cache=new w5({max:this.config.maxSize,ttl:this.config.ttl,updateAgeOnGet:!0,updateAgeOnHas:!1});for(let[Q,Z]of W.slice(-this.config.maxSize))this.cache.set(Q,Z)}if($.ttl!==void 0)this.config.ttl=$.ttl;if($.enabled!==void 0)this.config.enabled=$.enabled}}var I3=new O5;function U5(){return I3}function f3($){return $.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'")}function F5($){let W=f3($).trim();if(!W.includes(" - "))return{title:W,snippet:W};let[Q,...Z]=W.split(" - "),V=Q.trim(),X=Z.join(" - ").trim()||W;return{title:V,snippet:X}}function n0($){try{let W=new URL($),Q=W.pathname==="/"?"":W.pathname;return`${W.hostname}${Q}`}catch{return $}}function a0($){try{return new URL($).hostname.toLowerCase()}catch{return""}}function x3($){if(!$.FirstURL||!$.Text)return null;let{title:W,snippet:Q}=F5($.Text);return{title:W,snippet:Q,url:$.FirstURL,display_url:n0($.FirstURL),source:a0($.FirstURL)}}function H5($){let W=[];for(let Q of $){if(Q.Topics&&Q.Topics.length>0){W.push(...H5(Q.Topics));continue}if(Q.FirstURL&&Q.Text){let{title:Z,snippet:V}=F5(Q.Text);W.push({title:Z,snippet:V,url:Q.FirstURL,display_url:n0(Q.FirstURL),source:a0(Q.FirstURL)})}}return W}function h3($){let W=$,Q=(W.Results??[]).map((V)=>x3(V)).filter((V)=>V!==null),Z=H5(W.RelatedTopics??[]);return[...Q,...Z]}var p3={name:"DuckDuckGo",endpoint:"https://duckduckgo.com/",buildUrl:($)=>{let W=new URL("https://duckduckgo.com/");return W.searchParams.set("q",$),W.searchParams.set("format","json"),W.searchParams.set("no_html","1"),W.searchParams.set("skip_disambig","1"),W.searchParams.set("t","blade-code"),W.searchParams.set("kl","us-en"),W.toString()},parseResponse:h3,getHeaders:()=>({Accept:"application/json, text/plain;q=0.9","User-Agent":"Blade-AI-WebSearch/1.0"})};function u3($){let W=$,Q=[];for(let Z of W.results??[]){if(!Z.url||!Z.title)continue;Q.push({title:Z.title,snippet:Z.content||Z.title,url:Z.url,display_url:n0(Z.url),source:a0(Z.url)})}return Q}var A5=["https://searx.be","https://search.ononoki.org","https://searx.tiekoetter.com","https://searx.work"];function d3($){return{name:`SearXNG(${(()=>{try{return new URL($).hostname}catch{return $}})()})`,endpoint:$,buildUrl:(Q)=>{let Z=new URL(`${$}/search`);return Z.searchParams.set("q",Q),Z.searchParams.set("format","json"),Z.searchParams.set("categories","general"),Z.toString()},parseResponse:u3,getHeaders:()=>({Accept:"application/json","User-Agent":"Blade-AI-WebSearch/1.0"})}}var l$={BASE_URL:"https://mcp.exa.ai",ENDPOINT:"/mcp",DEFAULT_NUM_RESULTS:10,TIMEOUT:25000};function m3($){let W=[],Q=$.split(`
1703
+ `),Z={};for(let V=0;V<Q.length;V++){let X=Q[V].trim();if(X.startsWith("Title: ")){if(Z.title&&Z.url)W.push({title:Z.title,url:Z.url,snippet:Z.snippet||Z.title,display_url:n0(Z.url),source:a0(Z.url)});Z={title:X.substring(7).trim(),snippet:""}}else if(X.startsWith("URL: "))Z.url=X.substring(5).trim();else if(X.startsWith("Text: ")){let J=X.substring(6).trim().replace(/<[^>]*>/g,"").replace(/\s+/g," ").trim();Z.snippet=J.substring(0,300)}}if(Z.title&&Z.url)W.push({title:Z.title,url:Z.url,snippet:Z.snippet||Z.title,display_url:n0(Z.url),source:a0(Z.url)});return W}function g3(){return{name:"Exa",endpoint:`${l$.BASE_URL}${l$.ENDPOINT}`,searchFn:async($)=>{let W={jsonrpc:"2.0",id:1,method:"tools/call",params:{name:"web_search_exa",arguments:{query:$,type:"auto",numResults:l$.DEFAULT_NUM_RESULTS,contextMaxCharacters:1e4}}},Q=new AbortController,Z=setTimeout(()=>Q.abort(),l$.TIMEOUT);try{let V=await fetch(`${l$.BASE_URL}${l$.ENDPOINT}`,{method:"POST",headers:{accept:"application/json, text/event-stream","content-type":"application/json"},body:JSON.stringify(W),signal:Q.signal});if(clearTimeout(Z),!V.ok)throw Error(`MCP error (${V.status})`);let Y=(await V.text()).split(`
1704
+ `);for(let J of Y)if(J.startsWith("data: ")){let G=JSON.parse(J.substring(6));if(G.result&&G.result.content&&G.result.content.length>0)return m3(G.result.content[0].text)}throw Error("No search results found")}catch(V){if(clearTimeout(Z),V.name==="AbortError")throw Error("MCP request timed out");throw V}},buildUrl:()=>`${l$.BASE_URL}${l$.ENDPOINT}`,parseResponse:()=>[],getHeaders:()=>({})}}function D5(){let $=[];return $.push(g3()),$.push(p3),$.push(...A5.map(d3)),$}function b5(){return 2+A5.length}var l3=15000,n3=8,r0={maxRetries:3,baseDelay:1000,maxDelay:8000};function a3(){let $=process.env.HTTPS_PROXY||process.env.HTTP_PROXY||process.env.https_proxy||process.env.http_proxy;if($)try{return new c3($)}catch(W){console.warn(`Invalid proxy URL: ${$}`)}return}async function r3($,W,Q,Z,V){let X=new AbortController,Y=setTimeout(()=>X.abort(),Q),J=()=>X.abort();Z?.addEventListener("abort",J);try{return await i3($,{...W,signal:X.signal,dispatcher:V})}catch(G){if(G.name==="AbortError")throw Error("搜索请求超时或被中止");throw G}finally{clearTimeout(Y),Z?.removeEventListener("abort",J)}}async function s3($,W,Q,Z,V,X){let Y=null;for(let J=0;J<r0.maxRetries;J++)try{return await r3($,W,Q,Z,V)}catch(G){if(Y=G,Z?.aborted)throw G;if(J<r0.maxRetries-1){let K=Math.min(r0.baseDelay*2**J,r0.maxDelay);X?.(`⏳ 请求失败,${K/1000}s 后重试 (${J+1}/${r0.maxRetries})...`),await new Promise((B)=>setTimeout(B,K))}}throw Y}async function o3($,W,Q,Z,V,X){let Y=U5(),J=Y.get($.name,W);if(J)return X?.(`\uD83D\uDCBE 使用缓存结果 (${$.name})`),{results:J,providerName:`${$.name} (cached)`};if($.searchFn)try{X?.(`\uD83D\uDD0D 搜索中 (${$.name})...`);let A=await $.searchFn(W);return Y.set($.name,W,A),{results:A,providerName:$.name}}catch(A){throw Error(`SDK search failed: ${A.message}`)}X?.(`\uD83D\uDD0D 搜索中 (${$.name})...`);let G=$.buildUrl(W),K=$.method||"GET",q={headers:$.getHeaders(),method:K};if(K==="POST"&&$.buildBody)q.body=JSON.stringify($.buildBody(W));let w=await s3(G,q,Q,Z,V,X);if(!w.ok)throw Error(`HTTP ${w.status}`);let O=await w.text(),H;try{H=JSON.parse(O)}catch{throw Error("Failed to parse search result JSON")}let U=$.parseResponse(H);return Y.set($.name,W,U),{results:U,providerName:$.name}}async function t3($,W,Q,Z){let V=D5(),X=a3(),Y=[];for(let J=0;J<V.length;J++){let G=V[J];if(Q?.aborted)throw Error("搜索被用户中止");try{return Z?.(`\uD83D\uDD0E 使用 ${G.name} 搜索...`),await o3(G,$,W,Q,X,Z)}catch(K){let B=K,q=`${G.name}: ${B.message}`;if(Y.push(q),Z?.(`⚠️ ${q}`),J===V.length-1)throw Error(`所有搜索提供商都失败了:
1699
1705
  ${Y.join(`
1700
- `)}`)}}throw Error("No search providers available")}function r3($){try{return new URL($).hostname.toLowerCase()}catch{return null}}function s3($){return $.trim().toLowerCase()}function _5($){if(!$||$.length===0)return[];return $.map(s3).filter(Boolean)}function L5($,W){return $===W||$.endsWith(`.${W}`)}function o3($,W,Q){return $.filter((Z)=>{let V=r3(Z.url);if(!V)return!1;if(Q.length>0&&Q.some((X)=>L5(V,X)))return!1;if(W.length>0&&!W.some((X)=>L5(V,X)))return!1;return!0})}function t3($,W,Q,Z){let V=`\uD83D\uDD0E WebSearch("${$}") via ${Z} - 返回 ${W.length}/${Q} 条结果`,X=W.map((Y,J)=>`${J+1}. ${Y.title}
1706
+ `)}`)}}throw Error("No search providers available")}function e3($){try{return new URL($).hostname.toLowerCase()}catch{return null}}function $W($){return $.trim().toLowerCase()}function _5($){if(!$||$.length===0)return[];return $.map($W).filter(Boolean)}function L5($,W){return $===W||$.endsWith(`.${W}`)}function WW($,W,Q){return $.filter((Z)=>{let V=e3(Z.url);if(!V)return!1;if(Q.length>0&&Q.some((X)=>L5(V,X)))return!1;if(W.length>0&&!W.some((X)=>L5(V,X)))return!1;return!0})}function QW($,W,Q,Z){let V=`\uD83D\uDD0E WebSearch("${$}") via ${Z} - 返回 ${W.length}/${Q} 条结果`,X=W.map((Y,J)=>`${J+1}. ${Y.title}
1701
1707
  ${Y.display_url}
1702
1708
  ${Y.snippet}`);return[V,...X].join(`
1703
- `)}function e3($){let W=$.trim().toLowerCase();return W.length>80?W.slice(0,80):W}var J4=E({name:"WebSearch",displayName:"Web Search",kind:"readonly",schema:_0.object({query:_0.string().min(2,"Search query must be at least 2 characters").describe("Search query"),allowed_domains:_0.array(_0.string().min(1)).optional().describe("Return results only from these domains (optional)"),blocked_domains:_0.array(_0.string().min(1)).optional().describe("Exclude results from these domains (optional)")}),description:{short:"Search the web and use the results to inform responses",long:`
1709
+ `)}function ZW($){let W=$.trim().toLowerCase();return W.length>80?W.slice(0,80):W}var J4=E({name:"WebSearch",displayName:"Web Search",kind:"readonly",schema:_0.object({query:_0.string().min(2,"Search query must be at least 2 characters").describe("Search query"),allowed_domains:_0.array(_0.string().min(1)).optional().describe("Return results only from these domains (optional)"),blocked_domains:_0.array(_0.string().min(1)).optional().describe("Exclude results from these domains (optional)")}),description:{short:"Search the web and use the results to inform responses",long:`
1704
1710
  - Search the web and use the results to inform responses
1705
1711
  - Provides up-to-date information for current events and recent data
1706
1712
  - Returns search result information formatted as search result blocks, including links as markdown hyperlinks
@@ -1728,19 +1734,19 @@ Usage notes:
1728
1734
  IMPORTANT - Use the correct year in search queries:
1729
1735
  - You MUST use the current year when searching for recent information, documentation, or current events.
1730
1736
  - Example: If the user asks for "latest React docs", search for "React documentation 2025", NOT "React documentation 2024"
1731
- `},async execute($,W){let{query:Q}=$,Z=_5($.allowed_domains),V=_5($.blocked_domains),{updateOutput:X}=W,Y=W.signal??new AbortController().signal;X?.(`\uD83D\uDD0E Searching: "${Q}" (${D5()} providers available)`);try{let{results:J,providerName:G}=await a3(Q,m3,Y,X),B=o3(J,Z,V),K=B.slice(0,g3),q={query:Q,results:K,provider:G,total_results:B.length,fetched_at:new Date().toISOString()},w={query:Q,provider:G,fetched_at:q.fetched_at,total_results:B.length,returned_results:K.length,allowed_domains:Z,blocked_domains:V};if(K.length===0)return{success:!0,llmContent:q,displayContent:`\uD83D\uDD0D WebSearch("${Q}") via ${G} - 未找到匹配结果`,metadata:w};return{success:!0,llmContent:q,displayContent:t3(Q,K,B.length,G),metadata:w}}catch(J){let G=J;return{success:!1,llmContent:`WebSearch call failed: ${G.message}`,displayContent:`❌ WebSearch 调用失败: ${G.message}`,error:{type:"execution_error",message:G.message,details:{query:Q,allowedDomains:Z,blockedDomains:V}}}}},version:"2.0.0",category:"网络工具",tags:["web","search","internet","news"],extractSignatureContent:($)=>`search:${e3($.query)}`,abstractPermissionRule:()=>"search:*"});async function $W(){try{return await E$.getInstance().getAvailableTools()}catch($){return console.warn("MCP协议工具加载失败:",$),[]}}async function G4($){let W=$?.sessionId||`session_${Date.now()}`,Q=$?.configDir||z5.join(j5.homedir(),".blade"),Z=[v2,S2,T2,P2,h2,d2,g2,c2,Y4,J4,Q4,Z4,V4({sessionId:W,configDir:Q}),k2,f2,...$5,r2,o2],V=await $W();return[...Z,...V]}import{EventEmitter as XW}from"events";import{nanoid as WW}from"nanoid";class B4{name="hook";hookManager;constructor(){this.hookManager=i.getInstance()}async process($){if(!this.hookManager.isEnabled())return;let W=$._internal.tool;if(!W)return;try{let Q=$.context.messageId||`tool_${WW()}`;$._internal.hookToolUseId=Q;let Z=$.context.workspaceRoot||process.cwd(),V=await this.hookManager.executePreToolHooks(W.name,Q,$.params,{projectDir:Z,sessionId:$.context.sessionId||"unknown",permissionMode:$.context.permissionMode??"default",abortSignal:$.context.signal});if(V.decision==="deny"){$.abort(V.reason||"Hook blocked execution");return}if(V.decision==="ask"){$._internal.needsConfirmation=!0,$._internal.confirmationReason=V.reason||"Hook requires confirmation";return}if(V.modifiedInput){let X={...$.params,...V.modifiedInput};if(W.build)try{W.build(X),$.params=X}catch(Y){$.abort(`Hook modified parameters are invalid: ${Y instanceof Error?Y.message:String(Y)}`);return}}if(V.warning)console.warn(`[Hook Warning] ${V.warning}`)}catch(Q){console.error("[HookStage] Error executing hooks:",Q)}}}import{nanoid as QW}from"nanoid";function ZW($){return typeof $==="object"&&$!==null&&!Array.isArray($)}class K4{name="post-hook";hookManager;constructor(){this.hookManager=i.getInstance()}async process($){if(!this.hookManager.isEnabled())return;let W=$._internal.tool;if(!W)return;let Q=$.getResult();if(!Q)return;try{let Z=$._internal.hookToolUseId||$.context.messageId||`tool_${QW()}`,V=$.context.workspaceRoot||process.cwd(),X=await this.hookManager.executePostToolHooks(W.name,Z,$.params,Q,{projectDir:V,sessionId:$.context.sessionId||"unknown",permissionMode:$.context.permissionMode??"default",abortSignal:$.context.signal});if(X.additionalContext){let Y=Q.llmContent||Q.displayContent||"";Q.llmContent=`${Y}
1737
+ `},async execute($,W){let{query:Q}=$,Z=_5($.allowed_domains),V=_5($.blocked_domains),{updateOutput:X}=W,Y=W.signal??new AbortController().signal;X?.(`\uD83D\uDD0E Searching: "${Q}" (${b5()} providers available)`);try{let{results:J,providerName:G}=await t3(Q,l3,Y,X),K=WW(J,Z,V),B=K.slice(0,n3),q={query:Q,results:B,provider:G,total_results:K.length,fetched_at:new Date().toISOString()},w={query:Q,provider:G,fetched_at:q.fetched_at,total_results:K.length,returned_results:B.length,allowed_domains:Z,blocked_domains:V};if(B.length===0)return{success:!0,llmContent:q,displayContent:`\uD83D\uDD0D WebSearch("${Q}") via ${G} - 未找到匹配结果`,metadata:w};return{success:!0,llmContent:q,displayContent:QW(Q,B,K.length,G),metadata:w}}catch(J){let G=J;return{success:!1,llmContent:`WebSearch call failed: ${G.message}`,displayContent:`❌ WebSearch 调用失败: ${G.message}`,error:{type:"execution_error",message:G.message,details:{query:Q,allowedDomains:Z,blockedDomains:V}}}}},version:"2.0.0",category:"网络工具",tags:["web","search","internet","news"],extractSignatureContent:($)=>`search:${ZW($.query)}`,abstractPermissionRule:()=>"search:*"});async function VW(){try{return await E$.getInstance().getAvailableTools()}catch($){return console.warn("MCP协议工具加载失败:",$),[]}}async function G4($){let W=$?.sessionId||`session_${Date.now()}`,Q=$?.configDir||N5.join(j5.homedir(),".blade"),Z=[v2,S2,T2,P2,h2,d2,g2,c2,Y4,J4,Q4,Z4,V4({sessionId:W,configDir:Q}),k2,f2,...$5,r2,o2],V=await VW();return[...Z,...V]}import{EventEmitter as KW}from"events";import{nanoid as XW}from"nanoid";class K4{name="hook";hookManager;constructor(){this.hookManager=a.getInstance()}async process($){if(!this.hookManager.isEnabled())return;let W=$._internal.tool;if(!W)return;try{let Q=$.context.messageId||`tool_${XW()}`;$._internal.hookToolUseId=Q;let Z=$.context.workspaceRoot||process.cwd(),V=await this.hookManager.executePreToolHooks(W.name,Q,$.params,{projectDir:Z,sessionId:$.context.sessionId||"unknown",permissionMode:$.context.permissionMode??"default",abortSignal:$.context.signal});if(V.decision==="deny"){$.abort(V.reason||"Hook blocked execution");return}if(V.decision==="ask"){$._internal.needsConfirmation=!0,$._internal.confirmationReason=V.reason||"Hook requires confirmation";return}if(V.modifiedInput){let X={...$.params,...V.modifiedInput};if(W.build)try{W.build(X),$.params=X}catch(Y){$.abort(`Hook modified parameters are invalid: ${Y instanceof Error?Y.message:String(Y)}`);return}}if(V.warning)console.warn(`[Hook Warning] ${V.warning}`)}catch(Q){console.error("[HookStage] Error executing hooks:",Q)}}}import{nanoid as YW}from"nanoid";function JW($){return typeof $==="object"&&$!==null&&!Array.isArray($)}class B4{name="post-hook";hookManager;constructor(){this.hookManager=a.getInstance()}async process($){if(!this.hookManager.isEnabled())return;let W=$._internal.tool;if(!W)return;let Q=$.getResult();if(!Q)return;try{let Z=$._internal.hookToolUseId||$.context.messageId||`tool_${YW()}`,V=$.context.workspaceRoot||process.cwd(),X=await this.hookManager.executePostToolHooks(W.name,Z,$.params,Q,{projectDir:V,sessionId:$.context.sessionId||"unknown",permissionMode:$.context.permissionMode??"default",abortSignal:$.context.signal});if(X.additionalContext){let Y=Q.llmContent||Q.displayContent||"";Q.llmContent=`${Y}
1732
1738
 
1733
1739
  ---
1734
1740
  **Hook Context:**
1735
- ${X.additionalContext}`}if(X.modifiedOutput!==void 0){let Y=X.modifiedOutput;if(ZW(Y))Object.assign(Q,Y)}if(X.warning)console.warn(`[PostToolUseHook Warning] ${X.warning}`)}catch(Z){console.error("[PostToolUseHookStage] Error executing post-tool hooks:",Z)}}}var q4=M("Execution");class a${static instance=null;locks=new Map;constructor(){}static getInstance(){if(!a$.instance)a$.instance=new a$;return a$.instance}async acquireLock($,W){let Q=this.locks.get($);if(Q)try{await Q}catch{}let Z=this.executeWithLock($,W);return this.locks.set($,Z.then(()=>{return})),Z}async executeWithLock($,W){q4.debug(`获取文件锁: ${$}`);try{let Q=await W();return q4.debug(`释放文件锁: ${$}`),Q}catch(Q){throw q4.debug(`操作失败,释放文件锁: ${$}`),Q}}isLocked($){return this.locks.has($)}clearLock($){this.locks.delete($)}clearAll(){this.locks.clear()}getLockedFiles(){return Array.from(this.locks.keys())}getLockedFileCount(){return this.locks.size}static resetInstance(){a$.instance=null}}import VW from"node:os";import w4 from"node:path";class w${static SENSITIVE_PATTERNS=[{pattern:/^\.?id_rsa$/i,level:"high",description:"SSH 私钥"},{pattern:/^\.?id_ed25519$/i,level:"high",description:"SSH Ed25519 私钥"},{pattern:/^\.?id_ecdsa$/i,level:"high",description:"SSH ECDSA 私钥"},{pattern:/\.pem$/i,level:"high",description:"PEM 格式私钥"},{pattern:/\.key$/i,level:"high",description:"密钥文件"},{pattern:/\.p12$/i,level:"high",description:"PKCS#12 证书"},{pattern:/\.pfx$/i,level:"high",description:"PFX 证书"},{pattern:/^\.?keystore$/i,level:"high",description:"Java Keystore"},{pattern:/^\.?pgpass$/i,level:"high",description:"PostgreSQL 密码文件"},{pattern:/^\.?my\.cnf$/i,level:"high",description:"MySQL 配置文件(可能含密码)"},{pattern:/credentials\.json$/i,level:"high",description:"Google Cloud 凭证"},{pattern:/^\.?aws[\\/]credentials$/i,level:"high",description:"AWS 凭证"},{pattern:/^\.?gcp[\\/]credentials$/i,level:"high",description:"GCP 凭证"},{pattern:/^\.?azure[\\/]credentials$/i,level:"high",description:"Azure 凭证"},{pattern:/^service-account.*\.json$/i,level:"high",description:"服务账号密钥"},{pattern:/^\.env$/i,level:"medium",description:"环境变量文件"},{pattern:/^\.env\./i,level:"medium",description:"环境变量文件(带环境后缀)"},{pattern:/^\.?npmrc$/i,level:"medium",description:"npm 配置文件(可能含 token)"},{pattern:/^\.?pypirc$/i,level:"medium",description:"PyPI 配置文件(可能含密码)"},{pattern:/^\.?dockercfg$/i,level:"medium",description:"Docker 配置文件"},{pattern:/^\.?docker[\\/]config\.json$/i,level:"medium",description:"Docker 配置文件"},{pattern:/^\.?netrc$/i,level:"medium",description:"FTP/HTTP 认证文件"},{pattern:/^\.?git-credentials$/i,level:"medium",description:"Git 凭证文件"},{pattern:/^config\.toml$/i,level:"medium",description:"配置文件(可能含敏感信息)"},{pattern:/^secrets\./i,level:"medium",description:"密钥配置文件"},{pattern:/\.sqlite$/i,level:"low",description:"SQLite 数据库"},{pattern:/\.db$/i,level:"low",description:"数据库文件"},{pattern:/\.sql$/i,level:"low",description:"SQL 文件(可能含敏感数据)"}];static SENSITIVE_PATHS=[{path:/\.ssh[\\/]/i,level:"high",description:"SSH 配置目录"},{path:/\.aws[\\/]/i,level:"high",description:"AWS 配置目录"},{path:/\.config[\\/]gcloud[\\/]/i,level:"high",description:"Google Cloud 配置目录"},{path:/\.kube[\\/]/i,level:"high",description:"Kubernetes 配置目录"}];static check($){let W=w$.normalizePath($),Q=w4.basename(W);for(let Z of w$.SENSITIVE_PATTERNS)if(w$.matchPattern(Q,Z.pattern))return{isSensitive:!0,level:Z.level,matchedPattern:Z.pattern instanceof RegExp?Z.pattern.source:Z.pattern,reason:Z.description};for(let Z of w$.SENSITIVE_PATHS)if(w$.matchPattern(W,Z.path))return{isSensitive:!0,level:Z.level,matchedPattern:Z.path instanceof RegExp?Z.path.source:Z.path,reason:Z.description};return{isSensitive:!1}}static checkMultiple($){let W=new Map;for(let Q of $)W.set(Q,w$.check(Q));return W}static filterSensitive($,W="low"){let Q={["high"]:3,["medium"]:2,["low"]:1},Z=Q[W];return $.map((V)=>({path:V,result:w$.check(V)})).filter(({result:V})=>V.isSensitive&&V.level&&Q[V.level]>=Z)}static normalizePath($){if($.startsWith("~/")||$==="~")return w4.join(VW.homedir(),$.slice(1));return w4.resolve($)}static matchPattern($,W){if(W instanceof RegExp)return W.test($);let Q=W.replace(/\*/g,".*");return new RegExp(`^${Q}$`,"i").test($)}static getSensitivePatterns(){return[...w$.SENSITIVE_PATTERNS]}static getSensitivePaths(){return[...w$.SENSITIVE_PATHS]}}class s0{config;constructor($){this.config=$}static buildSignature($){if($.tool?.extractSignatureContent)return`${$.toolName}:${$.tool.extractSignatureContent($.params)}`;return $.toolName}static abstractPattern($){if($.tool?.abstractPermissionRule)return`${$.toolName}:${$.tool.abstractPermissionRule($.params)}`;return`${$.toolName}:*`}check($){let W=s0.buildSignature($);if(this.config.deny?.some((Q)=>this.matchRule(W,Q)))return{result:"deny",matchedRule:"deny",reason:"Denied by permission rule"};if(this.config.allow?.some((Q)=>this.matchRule(W,Q)))return{result:"allow",matchedRule:"allow",reason:"Allowed by permission rule"};if(this.config.ask?.some((Q)=>this.matchRule(W,Q)))return{result:"ask",matchedRule:"ask",reason:"Requires user confirmation"};return{result:"ask",reason:"Default: requires user confirmation"}}replaceConfig($){this.config={...this.config,...$}}matchRule($,W){if(W==="*")return!0;if(W.endsWith("*"))return $.startsWith(W.slice(0,-1));return $===W}}var y$=M("Execution");class O4{registry;name="discovery";constructor($){this.registry=$}async process($){let W=this.registry.get($.toolName);if(!W){$.abort(`Tool "${$.toolName}" not found`);return}$._internal.tool=W}}class U4{name="permission";permissionChecker;sessionApprovals;defaultPermissionMode;constructor($,W,Q){this.permissionChecker=new s0($),this.sessionApprovals=W,this.defaultPermissionMode=Q}getPermissionChecker(){return this.permissionChecker}async process($){let W=$._internal.tool;if(!W){$.abort("Discovery stage failed; cannot perform permission check");return}try{let Q=W.build($.params),Z=Q.getAffectedPaths(),V={toolName:W.name,params:$.params,affectedPaths:Z,tool:W},X=s0.buildSignature(V);$._internal.permissionSignature=X;let Y=this.permissionChecker.check(V),J=$.context.permissionMode||this.defaultPermissionMode;switch(Y=this.applyModeOverrides(W.kind,Y,J),Y.result){case"deny":$.abort(Y.reason||`Tool invocation "${W.name}" was denied by permission rules: ${Y.matchedRule}`);return;case"ask":if(this.sessionApprovals.has(X))Y={result:"allow",matchedRule:"remembered:session",reason:"User already allowed this operation in this session"};else $._internal.needsConfirmation=!0,$._internal.confirmationReason=Y.reason||"User confirmation required";break;case"allow":break}if(Z.length>0){let G=["/etc/","/sys/","/proc/","/dev/","/boot/","/root/","C:\\Windows\\System32","C:\\Program Files","C:\\ProgramData"],B=Z.filter((q)=>{if(q.includes(".."))return!0;return G.some((w)=>q.includes(w))});if(B.length>0){$.abort(`Access to dangerous system paths denied: ${B.join(", ")}`);return}let K=w$.filterSensitive(Z,"medium");if(K.length>0){let q=K.map(({path:O,result:b})=>`${O} (${b.level}: ${b.reason})`);if(K.filter(({result:O})=>O.level==="high").length>0&&Y.result!=="allow"){$.abort(`Access to highly sensitive files denied:
1741
+ ${X.additionalContext}`}if(X.modifiedOutput!==void 0){let Y=X.modifiedOutput;if(JW(Y))Object.assign(Q,Y)}if(X.warning)console.warn(`[PostToolUseHook Warning] ${X.warning}`)}catch(Z){console.error("[PostToolUseHookStage] Error executing post-tool hooks:",Z)}}}var q4=M("Execution");class n${static instance=null;locks=new Map;constructor(){}static getInstance(){if(!n$.instance)n$.instance=new n$;return n$.instance}async acquireLock($,W){let Q=this.locks.get($);if(Q)try{await Q}catch{}let Z=this.executeWithLock($,W);return this.locks.set($,Z.then(()=>{return})),Z}async executeWithLock($,W){q4.debug(`获取文件锁: ${$}`);try{let Q=await W();return q4.debug(`释放文件锁: ${$}`),Q}catch(Q){throw q4.debug(`操作失败,释放文件锁: ${$}`),Q}}isLocked($){return this.locks.has($)}clearLock($){this.locks.delete($)}clearAll(){this.locks.clear()}getLockedFiles(){return Array.from(this.locks.keys())}getLockedFileCount(){return this.locks.size}static resetInstance(){n$.instance=null}}import GW from"node:os";import w4 from"node:path";class F${static SENSITIVE_PATTERNS=[{pattern:/^\.?id_rsa$/i,level:"high",description:"SSH 私钥"},{pattern:/^\.?id_ed25519$/i,level:"high",description:"SSH Ed25519 私钥"},{pattern:/^\.?id_ecdsa$/i,level:"high",description:"SSH ECDSA 私钥"},{pattern:/\.pem$/i,level:"high",description:"PEM 格式私钥"},{pattern:/\.key$/i,level:"high",description:"密钥文件"},{pattern:/\.p12$/i,level:"high",description:"PKCS#12 证书"},{pattern:/\.pfx$/i,level:"high",description:"PFX 证书"},{pattern:/^\.?keystore$/i,level:"high",description:"Java Keystore"},{pattern:/^\.?pgpass$/i,level:"high",description:"PostgreSQL 密码文件"},{pattern:/^\.?my\.cnf$/i,level:"high",description:"MySQL 配置文件(可能含密码)"},{pattern:/credentials\.json$/i,level:"high",description:"Google Cloud 凭证"},{pattern:/^\.?aws[\\/]credentials$/i,level:"high",description:"AWS 凭证"},{pattern:/^\.?gcp[\\/]credentials$/i,level:"high",description:"GCP 凭证"},{pattern:/^\.?azure[\\/]credentials$/i,level:"high",description:"Azure 凭证"},{pattern:/^service-account.*\.json$/i,level:"high",description:"服务账号密钥"},{pattern:/^\.env$/i,level:"medium",description:"环境变量文件"},{pattern:/^\.env\./i,level:"medium",description:"环境变量文件(带环境后缀)"},{pattern:/^\.?npmrc$/i,level:"medium",description:"npm 配置文件(可能含 token)"},{pattern:/^\.?pypirc$/i,level:"medium",description:"PyPI 配置文件(可能含密码)"},{pattern:/^\.?dockercfg$/i,level:"medium",description:"Docker 配置文件"},{pattern:/^\.?docker[\\/]config\.json$/i,level:"medium",description:"Docker 配置文件"},{pattern:/^\.?netrc$/i,level:"medium",description:"FTP/HTTP 认证文件"},{pattern:/^\.?git-credentials$/i,level:"medium",description:"Git 凭证文件"},{pattern:/^config\.toml$/i,level:"medium",description:"配置文件(可能含敏感信息)"},{pattern:/^secrets\./i,level:"medium",description:"密钥配置文件"},{pattern:/\.sqlite$/i,level:"low",description:"SQLite 数据库"},{pattern:/\.db$/i,level:"low",description:"数据库文件"},{pattern:/\.sql$/i,level:"low",description:"SQL 文件(可能含敏感数据)"}];static SENSITIVE_PATHS=[{path:/\.ssh[\\/]/i,level:"high",description:"SSH 配置目录"},{path:/\.aws[\\/]/i,level:"high",description:"AWS 配置目录"},{path:/\.config[\\/]gcloud[\\/]/i,level:"high",description:"Google Cloud 配置目录"},{path:/\.kube[\\/]/i,level:"high",description:"Kubernetes 配置目录"}];static check($){let W=F$.normalizePath($),Q=w4.basename(W);for(let Z of F$.SENSITIVE_PATTERNS)if(F$.matchPattern(Q,Z.pattern))return{isSensitive:!0,level:Z.level,matchedPattern:Z.pattern instanceof RegExp?Z.pattern.source:Z.pattern,reason:Z.description};for(let Z of F$.SENSITIVE_PATHS)if(F$.matchPattern(W,Z.path))return{isSensitive:!0,level:Z.level,matchedPattern:Z.path instanceof RegExp?Z.path.source:Z.path,reason:Z.description};return{isSensitive:!1}}static checkMultiple($){let W=new Map;for(let Q of $)W.set(Q,F$.check(Q));return W}static filterSensitive($,W="low"){let Q={["high"]:3,["medium"]:2,["low"]:1},Z=Q[W];return $.map((V)=>({path:V,result:F$.check(V)})).filter(({result:V})=>V.isSensitive&&V.level&&Q[V.level]>=Z)}static normalizePath($){if($.startsWith("~/")||$==="~")return w4.join(GW.homedir(),$.slice(1));return w4.resolve($)}static matchPattern($,W){if(W instanceof RegExp)return W.test($);let Q=W.replace(/\*/g,".*");return new RegExp(`^${Q}$`,"i").test($)}static getSensitivePatterns(){return[...F$.SENSITIVE_PATTERNS]}static getSensitivePaths(){return[...F$.SENSITIVE_PATHS]}}class T1{config;constructor($){this.config=$}static buildSignature($){if($.tool?.extractSignatureContent)return`${$.toolName}:${$.tool.extractSignatureContent($.params)}`;return $.toolName}static abstractPattern($){if($.tool?.abstractPermissionRule)return`${$.toolName}:${$.tool.abstractPermissionRule($.params)}`;return`${$.toolName}:*`}check($){let W=T1.buildSignature($);if(this.config.deny?.some((Q)=>this.matchRule(W,Q)))return{result:"deny",matchedRule:"deny",reason:"Denied by permission rule"};if(this.config.allow?.some((Q)=>this.matchRule(W,Q)))return{result:"allow",matchedRule:"allow",reason:"Allowed by permission rule"};if(this.config.ask?.some((Q)=>this.matchRule(W,Q)))return{result:"ask",matchedRule:"ask",reason:"Requires user confirmation"};return{result:"ask",reason:"Default: requires user confirmation"}}replaceConfig($){this.config={...this.config,...$}}matchRule($,W){if(W==="*")return!0;if(W.endsWith("*"))return $.startsWith(W.slice(0,-1));return $===W}}var G0=M("Execution");class O4{registry;name="discovery";constructor($){this.registry=$}async process($){let W=this.registry.get($.toolName);if(!W){$.abort(`Tool "${$.toolName}" not found`);return}$._internal.tool=W}}class U4{name="permission";permissionChecker;sessionApprovals;defaultPermissionMode;constructor($,W,Q){this.permissionChecker=new T1($),this.sessionApprovals=W,this.defaultPermissionMode=Q}getPermissionChecker(){return this.permissionChecker}async process($){let W=$._internal.tool;if(!W){$.abort("Discovery stage failed; cannot perform permission check");return}try{let Q=W.build($.params),Z=Q.getAffectedPaths(),V={toolName:W.name,params:$.params,affectedPaths:Z,tool:W},X=T1.buildSignature(V);$._internal.permissionSignature=X;let Y=this.permissionChecker.check(V),J=$.context.permissionMode||this.defaultPermissionMode;switch(Y=this.applyModeOverrides(W.kind,Y,J),Y.result){case"deny":$.abort(Y.reason||`Tool invocation "${W.name}" was denied by permission rules: ${Y.matchedRule}`);return;case"ask":if(this.sessionApprovals.has(X))Y={result:"allow",matchedRule:"remembered:session",reason:"User already allowed this operation in this session"};else $._internal.needsConfirmation=!0,$._internal.confirmationReason=Y.reason||"User confirmation required";break;case"allow":break}if(Z.length>0){let G=["/etc/","/sys/","/proc/","/dev/","/boot/","/root/","C:\\Windows\\System32","C:\\Program Files","C:\\ProgramData"],K=Z.filter((q)=>{if(q.includes(".."))return!0;return G.some((w)=>q.includes(w))});if(K.length>0){$.abort(`Access to dangerous system paths denied: ${K.join(", ")}`);return}let B=F$.filterSensitive(Z,"medium");if(B.length>0){let q=B.map(({path:O,result:H})=>`${O} (${H.level}: ${H.reason})`);if(B.filter(({result:O})=>O.level==="high").length>0&&Y.result!=="allow"){$.abort(`Access to highly sensitive files denied:
1736
1742
  ${q.join(`
1737
1743
  `)}
1738
1744
 
1739
- If access is required, add an explicit allow rule in permissions.`);return}if(Y.result==="allow"&&K.length>0)$._internal.confirmationReason=`Sensitive file access detected:
1745
+ If access is required, add an explicit allow rule in permissions.`);return}if(Y.result==="allow"&&B.length>0)$._internal.confirmationReason=`Sensitive file access detected:
1740
1746
  ${q.join(`
1741
1747
  `)}
1742
1748
 
1743
- Confirm to proceed?`,$._internal.needsConfirmation=!0}}$._internal.invocation=Q,$._internal.permissionCheckResult=Y}catch(Q){$.abort(`Permission check failed: ${Q.message}`)}}applyModeOverrides($,W,Q){if(Q==="yolo")return{result:"allow",matchedRule:"mode:yolo",reason:"YOLO mode: automatically approve all tool invocations"};if(Q==="plan"){if(!y0($))return{result:"deny",matchedRule:"mode:plan",reason:"Plan mode: modification tools are blocked; only read-only tools are allowed (Read/Glob/Grep/WebFetch/WebSearch/Task)"}}if(W.result==="deny")return W;if(W.result==="allow")return W;if(y0($))return{result:"allow",matchedRule:`mode:${Q}:readonly`,reason:"Read-only tools do not require confirmation"};if(Q==="autoEdit"&&$==="write")return{result:"allow",matchedRule:"mode:autoEdit:write",reason:"AUTO_EDIT mode: automatically approve write tools"};return W}}class H4{sessionApprovals;name="confirmation";permissionChecker;constructor($,W){this.sessionApprovals=$;this.permissionChecker=W}async process($){let{tool:W,invocation:Q,needsConfirmation:Z,confirmationReason:V,permissionCheckResult:X}=$._internal;if(!W||!Q){$.abort("Pre-confirmation stage failed; cannot request user approval");return}if(!Z)return;try{let Y=W.extractSignatureContent?W.extractSignatureContent($.params):W.name,J=i.getInstance();if(J.isEnabled()){let K=await J.executePermissionRequestHooks(W.name,$.context.sessionId||"unknown",$.params,{projectDir:process.cwd(),sessionId:$.context.sessionId||"unknown",permissionMode:$.context.permissionMode||"default"});switch(K.decision){case"approve":y$.debug(`PermissionRequest hook 自动批准: ${W.name}`);return;case"deny":$.abort(K.reason||`PermissionRequest hook denied: ${W.name}`,{shouldExitLoop:!0});return;case"ask":default:break}}let G={title:`权限确认: ${Y}`,message:V||"此操作需要用户确认",kind:W.kind,details:this.generatePreviewForTool(W.name,$.params),risks:this.extractRisksFromPermissionCheck(W,$.params,X),affectedFiles:Q.getAffectedPaths()||[]};if(y$.warn(`工具 "${W.name}" 需要用户确认: ${G.title}`),y$.warn(`详情: ${G.message}`),G.risks&&G.risks.length>0)y$.warn(`风险: ${G.risks.join(", ")}`);let B=$.context.confirmationHandler;if(B){y$.info(`[ConfirmationStage] Requesting confirmation for ${W.name}`);let K=await B.requestConfirmation(G);if(y$.info(`[ConfirmationStage] Confirmation response: approved=${K.approved}`),!K.approved){$.abort(`User rejected execution: ${K.reason||"No reason provided"}`,{shouldExitLoop:!0});return}if(y$.info("[ConfirmationStage] User approved, continuing to execution stage"),(K.scope||"once")==="session"&&$._internal.permissionSignature){let w=$._internal.permissionSignature;this.sessionApprovals.add(w);let O={toolName:W.name,params:$.params,affectedPaths:Q.getAffectedPaths()||[],tool:W};await this.persistSessionApproval(w,O)}}else y$.warn("⚠️ No ConfirmationHandler; auto-approving tool execution (non-interactive environment only)")}catch(Y){$.abort(`User confirmation failed: ${Y.message}`)}}async persistSessionApproval($,W){try{let Q=s0.abstractPattern(W);y$.debug(`保存权限规则到会话: "${Q}"`)}catch(Q){y$.warn(`Failed to persist permission rule: ${Q instanceof Error?Q.message:"Unknown error"}`)}}generatePreviewForTool($,W){switch($){case"Edit":{let{old_string:Q,new_string:Z}=W;if(!Q&&!Z)return;let V=20,X=(Y)=>{let J=Y.split(`
1749
+ Confirm to proceed?`,$._internal.needsConfirmation=!0}}$._internal.invocation=Q,$._internal.permissionCheckResult=Y}catch(Q){$.abort(`Permission check failed: ${Q.message}`)}}applyModeOverrides($,W,Q){if(Q==="yolo")return{result:"allow",matchedRule:"mode:yolo",reason:"YOLO mode: automatically approve all tool invocations"};if(Q==="plan"){if(!y0($))return{result:"deny",matchedRule:"mode:plan",reason:"Plan mode: modification tools are blocked; only read-only tools are allowed (Read/Glob/Grep/WebFetch/WebSearch/Task)"}}if(W.result==="deny")return W;if(W.result==="allow")return W;if(y0($))return{result:"allow",matchedRule:`mode:${Q}:readonly`,reason:"Read-only tools do not require confirmation"};if(Q==="autoEdit"&&$==="write")return{result:"allow",matchedRule:"mode:autoEdit:write",reason:"AUTO_EDIT mode: automatically approve write tools"};return W}}class F4{sessionApprovals;permissionChecker;canUseTool;name="confirmation";constructor($,W,Q){this.sessionApprovals=$;this.permissionChecker=W;this.canUseTool=Q}async process($){let{tool:W,invocation:Q,needsConfirmation:Z}=$._internal;if(!W||!Q){$.abort("Pre-confirmation stage failed; cannot request user approval");return}let V=Q.getAffectedPaths()||[];if(this.canUseTool){let X=await this.canUseTool(W.name,$.params,{signal:$.context.signal||new AbortController().signal,toolKind:W.kind,affectedPaths:V});await this.handleCanUseToolResult(X,$);return}if(!Z)return;await this.handleLegacyConfirmation($,W,Q,V)}async handleCanUseToolResult($,W){let{tool:Q,invocation:Z}=W._internal;switch($.behavior){case"allow":if($.updatedInput){if(Object.assign(W.params,$.updatedInput),Q&&Z)W._internal.invocation=Q.build(W.params)}if($.updatedPermissions)this.applyPermissionUpdates($.updatedPermissions);G0.debug(`canUseTool allowed: ${W.toolName}`);break;case"deny":W.abort($.message,{shouldExitLoop:$.interrupt});break;case"ask":if(W._internal.needsConfirmation=!0,Q&&Z)await this.handleLegacyConfirmation(W,Q,Z,Z.getAffectedPaths()||[]);break}}applyPermissionUpdates($){for(let W of $)switch(W.type){case"addRules":for(let Q of W.rules){let Z=Q.ruleContent?`${Q.toolName}:${Q.ruleContent}`:Q.toolName;if(W.behavior==="allow")this.sessionApprovals.add(Z);G0.debug(`Permission rule added: ${Z} -> ${W.behavior}`)}break;case"removeRules":for(let Q of W.rules){let Z=Q.ruleContent?`${Q.toolName}:${Q.ruleContent}`:Q.toolName;this.sessionApprovals.delete(Z),G0.debug(`Permission rule removed: ${Z}`)}break}}async handleLegacyConfirmation($,W,Q,Z){let{confirmationReason:V,permissionCheckResult:X}=$._internal;try{let J={title:`权限确认: ${W.extractSignatureContent?W.extractSignatureContent($.params):W.name}`,message:V||"此操作需要用户确认",kind:W.kind,details:this.generatePreviewForTool(W.name,$.params),risks:this.extractRisksFromPermissionCheck(W,$.params,X),affectedFiles:Z};G0.warn(`工具 "${W.name}" 需要用户确认: ${J.title}`);let G=$.context.confirmationHandler;if(G){G0.info(`[ConfirmationStage] Requesting confirmation for ${W.name}`);let K=await G.requestConfirmation(J);if(G0.info(`[ConfirmationStage] Confirmation response: approved=${K.approved}`),!K.approved){$.abort(`User rejected execution: ${K.reason||"No reason provided"}`,{shouldExitLoop:!0});return}if((K.scope||"once")==="session"&&$._internal.permissionSignature)this.sessionApprovals.add($._internal.permissionSignature)}else G0.warn("⚠️ No ConfirmationHandler; auto-approving tool execution")}catch(Y){$.abort(`User confirmation failed: ${Y.message}`)}}generatePreviewForTool($,W){switch($){case"Edit":{let{old_string:Q,new_string:Z}=W;if(!Q&&!Z)return;let V=20,X=(Y)=>{let J=Y.split(`
1744
1750
  `);if(J.length<=V)return Y;return`${J.slice(0,V).join(`
1745
1751
  `)}
1746
1752
  ... (还有 ${J.length-V} 行)`};return`**变更前:**
@@ -1761,28 +1767,28 @@ ${Q}
1761
1767
  ${Y}
1762
1768
  \`\`\`
1763
1769
 
1764
- ... (还有 ${X.length-V} 行)`}case"Bash":case"Shell":return;default:return}}extractRisksFromPermissionCheck($,W,Q){let Z=[];if(Q?.reason)Z.push(Q.reason);if($.name==="Bash"){let V=W.command||"",X=V.trim().split(/\s+/)[0];if(X==="cat"||X==="head"||X==="tail")Z.push(`\uD83D\uDCA1 建议使用 Read 工具代替 ${X} 命令(性能更好,支持大文件分页)`);else if(X==="grep"||X==="rg")Z.push("\uD83D\uDCA1 建议使用 Grep 工具代替 grep/rg 命令(支持更强大的过滤和上下文)");else if(X==="find")Z.push("\uD83D\uDCA1 建议使用 Glob 工具代替 find 命令(更快,支持 glob 模式)");else if(X==="sed"||X==="awk")Z.push(`\uD83D\uDCA1 建议使用 Edit 工具代替 ${X} 命令(更安全,支持预览和回滚)`);if(V.includes("rm"))Z.push("⚠️ 此命令可能删除文件");if(V.includes("sudo"))Z.push("⚠️ 此命令需要管理员权限");if(V.includes("git push"))Z.push("⚠️ 此命令将推送代码到远程仓库")}else if($.name==="Write"||$.name==="Edit")Z.push("此操作将修改文件内容");else if($.name==="Delete")Z.push("此操作将永久删除文件");return Z}}class b4{name="execution";async process($){let W=$._internal.invocation;if(!W){$.abort("Pre-execution stage failed; cannot run tool");return}try{let Q=await W.execute($.context.signal??new AbortController().signal,$.context.onProgress,$.context);$.setResult(Q)}catch(Q){$.abort(`Tool execution failed: ${Q.message}`)}}}class F4{name="formatting";async process($){try{let W=$.getResult();if(!W.llmContent)W.llmContent="Execution completed";if(!W.displayContent)W.displayContent=W.success?"执行成功":"执行失败";if(!W.metadata)W.metadata={};W.metadata.executionId=$.context.sessionId,W.metadata.toolName=$.toolName,W.metadata.timestamp=Date.now(),$.setResult(W)}catch(W){$.abort(`Result formatting failed: ${W.message}`)}}}class P1 extends XW{registry;stages;executionHistory=[];maxHistorySize;sessionApprovals=new Set;constructor($,W={}){super();this.registry=$;this.maxHistorySize=W.maxHistorySize||1000;let Q=W.permissionConfig||{allow:[],ask:[],deny:[]},Z=W.permissionMode??"default",V=new U4(Q,this.sessionApprovals,Z);this.stages=[new O4(this.registry),V,new B4,new H4(this.sessionApprovals,V.getPermissionChecker()),new b4,new K4,new F4]}async execute($,W,Q){let Z=Date.now(),V=this.generateExecutionId(),X=new U2($,W,{...Q,sessionId:Q.sessionId||V});this.emit("executionStarted",{executionId:V,toolName:$,params:W,context:Q,timestamp:Z});let Y=this.registry.get($),J=Y&&!Y.isConcurrencySafe,G=J&&W.file_path?String(W.file_path):null;if(J&&G)return a$.getInstance().acquireLock(G,()=>this.executeWithPipeline(X,V,Z));return this.executeWithPipeline(X,V,Z)}async executeWithPipeline($,W,Q){try{for(let X of this.stages){if($.context.signal?.aborted){$.abort("任务已被用户中止");break}if(this.emit("stageStarted",{executionId:W,stageName:X.name,timestamp:Date.now()}),await X.process($),this.emit("stageCompleted",{executionId:W,stageName:X.name,timestamp:Date.now()}),$.shouldAbort())break}let Z=$.getResult(),V=Date.now();return this.addToHistory({executionId:W,toolName:$.toolName,params:$.params,result:Z,startTime:Q,endTime:V,context:$.context}),this.emit("executionCompleted",{executionId:W,toolName:$.toolName,result:Z,duration:V-Q,timestamp:V}),Z}catch(Z){let V=Date.now(),X=Z.message?.includes("timeout")||Z.name==="TimeoutError",Y={success:!1,llmContent:`Tool execution failed: ${Z.message}`,displayContent:`错误: ${Z.message}`,error:{type:"execution_error",message:Z.message}};try{let G=await i.getInstance().executePostToolUseFailureHooks($.toolName,`tool_use_${W}`,$.params,Z.message,{projectDir:process.cwd(),sessionId:$.context.sessionId||"unknown",permissionMode:$.context.permissionMode||"default",isInterrupt:!1,isTimeout:X,abortSignal:$.context.signal});if(G.additionalContext)Y={...Y,llmContent:`${Y.llmContent}
1770
+ ... (还有 ${X.length-V} 行)`}default:return}}extractRisksFromPermissionCheck($,W,Q){let Z=[];if(Q?.reason)Z.push(Q.reason);if($.name==="Bash"){let V=W.command||"",X=V.trim().split(/\s+/)[0];if(["cat","head","tail"].includes(X))Z.push(`\uD83D\uDCA1 建议使用 Read 工具代替 ${X} 命令`);else if(["grep","rg"].includes(X))Z.push("\uD83D\uDCA1 建议使用 Grep 工具代替 grep/rg 命令");else if(X==="find")Z.push("\uD83D\uDCA1 建议使用 Glob 工具代替 find 命令");else if(["sed","awk"].includes(X))Z.push(`\uD83D\uDCA1 建议使用 Edit 工具代替 ${X} 命令`);if(V.includes("rm"))Z.push("⚠️ 此命令可能删除文件");if(V.includes("sudo"))Z.push("⚠️ 此命令需要管理员权限");if(V.includes("git push"))Z.push("⚠️ 此命令将推送代码到远程仓库")}else if(["Write","Edit"].includes($.name))Z.push("此操作将修改文件内容");else if($.name==="Delete")Z.push("此操作将永久删除文件");return Z}}class H4{name="execution";async process($){let W=$._internal.invocation;if(!W){$.abort("Pre-execution stage failed; cannot run tool");return}try{let Q=await W.execute($.context.signal??new AbortController().signal,$.context.onProgress,$.context);$.setResult(Q)}catch(Q){$.abort(`Tool execution failed: ${Q.message}`)}}}class A4{name="formatting";async process($){try{let W=$.getResult();if(!W.llmContent)W.llmContent="Execution completed";if(!W.displayContent)W.displayContent=W.success?"执行成功":"执行失败";if(!W.metadata)W.metadata={};W.metadata.executionId=$.context.sessionId,W.metadata.toolName=$.toolName,W.metadata.timestamp=Date.now(),$.setResult(W)}catch(W){$.abort(`Result formatting failed: ${W.message}`)}}}class P1 extends KW{registry;stages;executionHistory=[];maxHistorySize;sessionApprovals=new Set;constructor($,W={}){super();this.registry=$;this.maxHistorySize=W.maxHistorySize||1000;let Q=W.permissionConfig||{allow:[],ask:[],deny:[]},Z=W.permissionMode??"default",V=new U4(Q,this.sessionApprovals,Z);this.stages=[new O4(this.registry),V,new K4,new F4(this.sessionApprovals,V.getPermissionChecker(),W.canUseTool),new H4,new B4,new A4]}async execute($,W,Q){let Z=Date.now(),V=this.generateExecutionId(),X=new U2($,W,{...Q,sessionId:Q.sessionId||V});this.emit("executionStarted",{executionId:V,toolName:$,params:W,context:Q,timestamp:Z});let Y=this.registry.get($),J=Y&&!Y.isConcurrencySafe,G=J&&W.file_path?String(W.file_path):null;if(J&&G)return n$.getInstance().acquireLock(G,()=>this.executeWithPipeline(X,V,Z));return this.executeWithPipeline(X,V,Z)}async executeWithPipeline($,W,Q){try{for(let X of this.stages){if($.context.signal?.aborted){$.abort("任务已被用户中止");break}if(this.emit("stageStarted",{executionId:W,stageName:X.name,timestamp:Date.now()}),await X.process($),this.emit("stageCompleted",{executionId:W,stageName:X.name,timestamp:Date.now()}),$.shouldAbort())break}let Z=$.getResult(),V=Date.now();return this.addToHistory({executionId:W,toolName:$.toolName,params:$.params,result:Z,startTime:Q,endTime:V,context:$.context}),this.emit("executionCompleted",{executionId:W,toolName:$.toolName,result:Z,duration:V-Q,timestamp:V}),Z}catch(Z){let V=Date.now(),X=Z.message?.includes("timeout")||Z.name==="TimeoutError",Y={success:!1,llmContent:`Tool execution failed: ${Z.message}`,displayContent:`错误: ${Z.message}`,error:{type:"execution_error",message:Z.message}};try{let G=await a.getInstance().executePostToolUseFailureHooks($.toolName,`tool_use_${W}`,$.params,Z.message,{projectDir:process.cwd(),sessionId:$.context.sessionId||"unknown",permissionMode:$.context.permissionMode||"default",isInterrupt:!1,isTimeout:X,abortSignal:$.context.signal});if(G.additionalContext)Y={...Y,llmContent:`${Y.llmContent}
1765
1771
 
1766
- ${G.additionalContext}`};if(G.warning)console.warn(`[ExecutionPipeline] PostToolUseFailure hook warning: ${G.warning}`)}catch(J){console.warn("[ExecutionPipeline] PostToolUseFailure hook execution failed:",J)}return this.addToHistory({executionId:W,toolName:$.toolName,params:$.params,result:Y,startTime:Q,endTime:V,context:$.context}),this.emit("executionFailed",{executionId:W,toolName:$.toolName,error:Z,duration:V-Q,timestamp:V}),Y}}async executeAll($){let W=$.map((Q)=>this.execute(Q.toolName,Q.params,Q.context));return Promise.all(W)}async executeParallel($,W=5){let Q=[],Z=[];for(let V=0;V<$.length;V++){let X=$[V],Y=this.execute(X.toolName,X.params,X.context);if(Z.push(Y),Z.length>=W||V===$.length-1){let J=await Promise.all(Z);Q.push(...J),Z.length=0}}return Q}getExecutionHistory($){let W=[...this.executionHistory];return $?W.slice(-$):W}clearHistory(){this.executionHistory=[],this.emit("historyClear",{timestamp:Date.now()})}getStats(){let $={totalExecutions:this.executionHistory.length,successfulExecutions:0,failedExecutions:0,averageDuration:0,toolUsage:new Map,recentExecutions:this.executionHistory.slice(-10)},W=0;for(let Q of this.executionHistory){if(Q.result.success)$.successfulExecutions++;else $.failedExecutions++;let Z=Q.endTime-Q.startTime;W+=Z;let V=$.toolUsage.get(Q.toolName)||0;$.toolUsage.set(Q.toolName,V+1)}return $.averageDuration=$.totalExecutions>0?W/$.totalExecutions:0,$}addStage($,W=-1){if(W===-1){let Q=this.stages.findIndex((Z)=>Z.name==="execution");this.stages.splice(Q,0,$)}else this.stages.splice(W,0,$);this.emit("stageAdded",{stageName:$.name,position:W,timestamp:Date.now()})}removeStage($){let W=this.stages.findIndex((Q)=>Q.name===$);if(W===-1)return!1;return this.stages.splice(W,1),this.emit("stageRemoved",{stageName:$,timestamp:Date.now()}),!0}getStages(){return[...this.stages]}getRegistry(){return this.registry}generateExecutionId(){return`exec_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}addToHistory($){if(this.executionHistory.push($),this.executionHistory.length>this.maxHistorySize)this.executionHistory=this.executionHistory.slice(-this.maxHistorySize)}}import{EventEmitter as YW}from"events";class o0 extends YW{tools=new Map;mcpTools=new Map;categories=new Map;tags=new Map;constructor(){super()}register($){if(this.tools.has($.name))throw Error(`工具 '${$.name}' 已注册`);this.tools.set($.name,$),this.updateIndexes($),this.emit("toolRegistered",{type:"builtin",tool:$,timestamp:Date.now()})}registerAll($){let W=[];for(let Q of $)try{this.register(Q)}catch(Z){W.push(`${Q.name}: ${Z.message}`)}if(W.length>0)throw Error(`批量注册失败: ${W.join(", ")}`)}unregister($){let W=this.tools.get($);if(!W)return!1;return this.tools.delete($),this.removeFromIndexes(W),this.emit("toolUnregistered",{type:"builtin",toolName:$,timestamp:Date.now()}),!0}get($){return this.tools.get($)||this.mcpTools.get($)}has($){return this.tools.has($)||this.mcpTools.has($)}getAll(){return[...Array.from(this.tools.values()),...Array.from(this.mcpTools.values())]}getBuiltinTools(){return Array.from(this.tools.values())}getMcpTools(){return Array.from(this.mcpTools.values())}getByCategory($){let W=this.categories.get($);if(!W)return[];return Array.from(W).map((Q)=>this.get(Q)).filter((Q)=>Q!==void 0)}getByTag($){let W=this.tags.get($);if(!W)return[];return Array.from(W).map((Q)=>this.get(Q)).filter((Q)=>Q!==void 0)}search($){let W=$.toLowerCase();return this.getAll().filter((Q)=>{let Z=typeof Q.description==="string"?Q.description:Q.description.short;return Q.name.toLowerCase().includes(W)||Z.toLowerCase().includes(W)||Q.displayName.toLowerCase().includes(W)||Q.category&&Q.category.toLowerCase().includes(W)||Q.tags.some((V)=>V.toLowerCase().includes(W))})}getFunctionDeclarations(){return this.getAll().map(($)=>$.getFunctionDeclaration())}getReadOnlyFunctionDeclarations(){return this.getAll().filter(($)=>$.isReadOnly).map(($)=>$.getFunctionDeclaration())}getFunctionDeclarationsByMode($){if($==="plan")return this.getReadOnlyFunctionDeclarations();if($==="spec")return this.getSpecModeFunctionDeclarations();return this.getFunctionDeclarations()}static SPEC_TOOLS=["EnterSpecMode","UpdateSpec","GetSpecContext","TransitionSpecPhase","AddTask","UpdateTaskStatus","ValidateSpec","ExitSpecMode"];getSpecModeFunctionDeclarations(){return this.getFunctionDeclarations()}isSpecTool($){return o0.SPEC_TOOLS.includes($)}getReadOnlyTools(){return this.getAll().filter(($)=>$.isReadOnly)}getCategories(){return Array.from(this.categories.keys())}getTags(){return Array.from(this.tags.keys())}getStats(){return{totalTools:this.tools.size+this.mcpTools.size,builtinTools:this.tools.size,mcpTools:this.mcpTools.size,categories:this.categories.size,tags:this.tags.size,toolsByCategory:Object.fromEntries(Array.from(this.categories.entries()).map(([$,W])=>[$,W.size]))}}registerMcpTool($){if(this.mcpTools.has($.name))this.mcpTools.delete($.name);this.mcpTools.set($.name,$),this.updateIndexes($),this.emit("toolRegistered",{type:"mcp",tool:$,timestamp:Date.now()})}removeMcpTools($){let W=0,Q=`mcp__${$}__`;for(let[Z,V]of this.mcpTools.entries())if(Z.startsWith(Q))this.mcpTools.delete(Z),this.removeFromIndexes(V),W++,this.emit("toolUnregistered",{type:"mcp",toolName:Z,serverName:$,timestamp:Date.now()});return W}updateIndexes($){if($.category){if(!this.categories.has($.category))this.categories.set($.category,new Set);this.categories.get($.category).add($.name)}for(let W of $.tags){if(!this.tags.has(W))this.tags.set(W,new Set);this.tags.get(W).add($.name)}}removeFromIndexes($){if($.category){let W=this.categories.get($.category);if(W){if(W.delete($.name),W.size===0)this.categories.delete($.category)}}for(let W of $.tags){let Q=this.tags.get(W);if(Q){if(Q.delete($.name),Q.size===0)this.tags.delete(W)}}}}var JW=[/deepseek.*r1/i,/deepseek.*reasoner/i,/o1-preview/i,/o1-mini/i,/o1/i,/qwen.*qwq/i,/qwen.*think/i,/kimi.*k1/i,/moonshot.*think/i,/k1-32k/i,/doubao.*think/i,/doubao.*pro.*think/i,/claude.*opus.*4/i,/glm-4\.7/i];function GW($){return JW.some((W)=>W.test($))}function BW($){if($.supportsThinking!==void 0)return{supportsThinking:$.supportsThinking,thinkingBudget:$.thinkingBudget};return{supportsThinking:GW($.model),thinkingBudget:void 0}}function N5($){return BW($).supportsThinking}import E5 from"fast-glob";import*as L0 from"fs/promises";import*as C5 from"path";import*as k1 from"fs/promises";import*as e from"path";var R5=[".git",".claude","node_modules",".env",".env.local",".env.production",".env.development",".env.test"];class B0 extends Error{code;constructor($,W){super($);this.code=W;this.name="PathSecurityError"}}class K0{static normalize($,W){let Q=e.isAbsolute($)?$:e.resolve(W,$),Z=e.normalize(Q),V=e.normalize(W);if(!Z.startsWith(V))throw new B0(`Path outside workspace: ${$} (resolved to ${Z}, workspace: ${V})`,"PATH_OUTSIDE_WORKSPACE");return Z}static checkRestricted($){let W=$.split(e.sep);for(let Q of R5)if(W.includes(Q))throw new B0(`Access denied: "${Q}" is a protected directory`,"RESTRICTED_PATH")}static checkTraversal($){if($.includes(".."))throw new B0(`Path traversal not allowed: ${$}`,"PATH_TRAVERSAL")}static async validatePath($,W){K0.checkTraversal($);let Q=K0.normalize($,W);K0.checkRestricted(Q);try{await k1.access(Q)}catch(Z){throw new B0(`Path not found: ${$}`,"PATH_NOT_FOUND")}return Q}static async resolveSymlink($,W){try{let Q=await k1.realpath($),Z=e.normalize(W);if(!Q.startsWith(Z))throw new B0(`Symlink points outside workspace: ${$} -> ${Q}`,"SYMLINK_OUTSIDE_WORKSPACE");return Q}catch(Q){if(Q instanceof B0)throw Q;return $}}static getRelativePath($,W){return e.relative(W,$)}static isWithinWorkspace($,W){let Q=e.normalize($),Z=e.normalize(W);return Q.startsWith(Z)}static isRestricted($){let W=$.split(e.sep);return R5.some((Q)=>W.includes(Q))}}class O${static PATTERN=/@"([^"]+)"|@([^\s]+)/g;static LINE_RANGE_PATTERN=/#L(\d+)(?:-(\d+))?$/;static GLOB_PATTERN=/[*?[\]]/;static extract($){let W=[],Q;O$.PATTERN.lastIndex=0;while((Q=O$.PATTERN.exec($))!==null){let Z=Q[0],V=Q[1]||Q[2],X=O$.parseLineRange(V);if(X)V=V.replace(O$.LINE_RANGE_PATTERN,"");let Y=O$.GLOB_PATTERN.test(V);W.push({raw:Z,path:V.trim(),lineRange:X,startIndex:Q.index,endIndex:Q.index+Z.length,isGlob:Y})}return W}static parseLineRange($){let W=$.match(O$.LINE_RANGE_PATTERN);if(!W)return;let Q=parseInt(W[1],10),Z=W[2]?parseInt(W[2],10):void 0;return{start:Q,end:Z}}static hasAtMentions($){return $.includes("@")}static isValidPath($){if(!$||$.trim().length===0)return!1;let W=["<",">","|","\x00"];for(let Q of W)if($.includes(Q))return!1;return!0}static removeAtMentions($){return O$.PATTERN.lastIndex=0,$.replace(O$.PATTERN,"")}}var j$=M("Prompts");function I1($){return $ instanceof Map}class A4{fileCache=new Map;options;constructor($){this.options={maxFileSize:1048576,maxLines:2000,maxTokens:32000,...$},j$.debug("AttachmentCollector initialized",{maxFileSize:this.options.maxFileSize,maxLines:this.options.maxLines})}async collect($){if(!O$.hasAtMentions($))return[];let W=O$.extract($);if(W.length===0)return[];j$.debug(`Found ${W.length} @ mentions`);let Q=W.map((V)=>this.processOne(V));return(await Promise.allSettled(Q)).map((V,X)=>{if(V.status==="fulfilled")return V.value;else{let Y=W[X],J=V.reason instanceof Error?V.reason.message:String(V.reason);return j$.warn(`Failed to process @${Y.path}:`,J),{type:"error",path:Y.path,content:"",error:J}}})}async processOne($){if($.isGlob)return j$.debug(`Processing glob pattern: ${$.path}`),await this.processGlob($.path);let W=await K0.validatePath($.path,this.options.cwd),Q=await K0.resolveSymlink(W,this.options.cwd);if((await L0.stat(Q)).isDirectory())return j$.debug(`Processing directory: ${$.path}`),await this.renderDirectoryTree(Q,$.path);return j$.debug(`Processing file: ${$.path}`,{lineRange:$.lineRange}),await this.readFile(Q,$.path,$.lineRange)}async readFile($,W,Q){let Z=this.fileCache.get($);if(Z&&Date.now()-Z.timestamp<60000)return j$.debug(`Cache hit: ${W}`),this.formatFileAttachment(W,Z.content,Q);let V=await L0.stat($);if(V.size>this.options.maxFileSize)throw Error(`File too large: ${Math.round(V.size/1024/1024)}MB (max ${Math.round(this.options.maxFileSize/1024/1024)}MB)`);let X;try{X=await L0.readFile($,"utf-8")}catch(Y){throw Error(`Cannot read file as text: ${W}. It may be a binary file.`)}return this.fileCache.set($,{content:X,timestamp:Date.now()}),this.formatFileAttachment(W,X,Q)}formatFileAttachment($,W,Q){let Z=W.split(`
1767
- `),V=W,X=!1,Y=Q;if(Q){let J=Math.max(0,Q.start-1),G=Q.end?Q.end:Q.start;if(J>=Z.length)throw Error(`Line range start (${Q.start}) exceeds file length (${Z.length} lines)`);let B=Math.min(G,Z.length);V=Z.slice(J,B).join(`
1768
- `);let K=Array.from({length:B-J},(w,O)=>J+O+1);V=V.split(`
1769
- `).map((w,O)=>`${K[O]}: ${w}`).join(`
1770
- `),Y={start:Q.start,end:B}}else if(Z.length>this.options.maxLines)V=Z.slice(0,this.options.maxLines).join(`
1772
+ ${G.additionalContext}`};if(G.warning)console.warn(`[ExecutionPipeline] PostToolUseFailure hook warning: ${G.warning}`)}catch(J){console.warn("[ExecutionPipeline] PostToolUseFailure hook execution failed:",J)}return this.addToHistory({executionId:W,toolName:$.toolName,params:$.params,result:Y,startTime:Q,endTime:V,context:$.context}),this.emit("executionFailed",{executionId:W,toolName:$.toolName,error:Z,duration:V-Q,timestamp:V}),Y}}async executeAll($){let W=$.map((Q)=>this.execute(Q.toolName,Q.params,Q.context));return Promise.all(W)}async executeParallel($,W=5){let Q=[],Z=[];for(let V=0;V<$.length;V++){let X=$[V],Y=this.execute(X.toolName,X.params,X.context);if(Z.push(Y),Z.length>=W||V===$.length-1){let J=await Promise.all(Z);Q.push(...J),Z.length=0}}return Q}getExecutionHistory($){let W=[...this.executionHistory];return $?W.slice(-$):W}clearHistory(){this.executionHistory=[],this.emit("historyClear",{timestamp:Date.now()})}getStats(){let $={totalExecutions:this.executionHistory.length,successfulExecutions:0,failedExecutions:0,averageDuration:0,toolUsage:new Map,recentExecutions:this.executionHistory.slice(-10)},W=0;for(let Q of this.executionHistory){if(Q.result.success)$.successfulExecutions++;else $.failedExecutions++;let Z=Q.endTime-Q.startTime;W+=Z;let V=$.toolUsage.get(Q.toolName)||0;$.toolUsage.set(Q.toolName,V+1)}return $.averageDuration=$.totalExecutions>0?W/$.totalExecutions:0,$}addStage($,W=-1){if(W===-1){let Q=this.stages.findIndex((Z)=>Z.name==="execution");this.stages.splice(Q,0,$)}else this.stages.splice(W,0,$);this.emit("stageAdded",{stageName:$.name,position:W,timestamp:Date.now()})}removeStage($){let W=this.stages.findIndex((Q)=>Q.name===$);if(W===-1)return!1;return this.stages.splice(W,1),this.emit("stageRemoved",{stageName:$,timestamp:Date.now()}),!0}getStages(){return[...this.stages]}getRegistry(){return this.registry}generateExecutionId(){return`exec_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}addToHistory($){if(this.executionHistory.push($),this.executionHistory.length>this.maxHistorySize)this.executionHistory=this.executionHistory.slice(-this.maxHistorySize)}}import{EventEmitter as BW}from"events";class s0 extends BW{tools=new Map;mcpTools=new Map;categories=new Map;tags=new Map;constructor(){super()}register($){if(this.tools.has($.name))throw Error(`工具 '${$.name}' 已注册`);this.tools.set($.name,$),this.updateIndexes($),this.emit("toolRegistered",{type:"builtin",tool:$,timestamp:Date.now()})}registerAll($){let W=[];for(let Q of $)try{this.register(Q)}catch(Z){W.push(`${Q.name}: ${Z.message}`)}if(W.length>0)throw Error(`批量注册失败: ${W.join(", ")}`)}unregister($){let W=this.tools.get($);if(!W)return!1;return this.tools.delete($),this.removeFromIndexes(W),this.emit("toolUnregistered",{type:"builtin",toolName:$,timestamp:Date.now()}),!0}get($){return this.tools.get($)||this.mcpTools.get($)}has($){return this.tools.has($)||this.mcpTools.has($)}getAll(){return[...Array.from(this.tools.values()),...Array.from(this.mcpTools.values())]}getBuiltinTools(){return Array.from(this.tools.values())}getMcpTools(){return Array.from(this.mcpTools.values())}getByCategory($){let W=this.categories.get($);if(!W)return[];return Array.from(W).map((Q)=>this.get(Q)).filter((Q)=>Q!==void 0)}getByTag($){let W=this.tags.get($);if(!W)return[];return Array.from(W).map((Q)=>this.get(Q)).filter((Q)=>Q!==void 0)}search($){let W=$.toLowerCase();return this.getAll().filter((Q)=>{let Z=typeof Q.description==="string"?Q.description:Q.description.short;return Q.name.toLowerCase().includes(W)||Z.toLowerCase().includes(W)||Q.displayName.toLowerCase().includes(W)||Q.category&&Q.category.toLowerCase().includes(W)||Q.tags.some((V)=>V.toLowerCase().includes(W))})}getFunctionDeclarations(){return this.getAll().map(($)=>$.getFunctionDeclaration())}getReadOnlyFunctionDeclarations(){return this.getAll().filter(($)=>$.isReadOnly).map(($)=>$.getFunctionDeclaration())}getFunctionDeclarationsByMode($){if($==="plan")return this.getReadOnlyFunctionDeclarations();if($==="spec")return this.getSpecModeFunctionDeclarations();return this.getFunctionDeclarations()}static SPEC_TOOLS=["EnterSpecMode","UpdateSpec","GetSpecContext","TransitionSpecPhase","AddTask","UpdateTaskStatus","ValidateSpec","ExitSpecMode"];getSpecModeFunctionDeclarations(){return this.getFunctionDeclarations()}isSpecTool($){return s0.SPEC_TOOLS.includes($)}getReadOnlyTools(){return this.getAll().filter(($)=>$.isReadOnly)}getCategories(){return Array.from(this.categories.keys())}getTags(){return Array.from(this.tags.keys())}getStats(){return{totalTools:this.tools.size+this.mcpTools.size,builtinTools:this.tools.size,mcpTools:this.mcpTools.size,categories:this.categories.size,tags:this.tags.size,toolsByCategory:Object.fromEntries(Array.from(this.categories.entries()).map(([$,W])=>[$,W.size]))}}registerMcpTool($){if(this.mcpTools.has($.name))this.mcpTools.delete($.name);this.mcpTools.set($.name,$),this.updateIndexes($),this.emit("toolRegistered",{type:"mcp",tool:$,timestamp:Date.now()})}removeMcpTools($){let W=0,Q=`mcp__${$}__`;for(let[Z,V]of this.mcpTools.entries())if(Z.startsWith(Q))this.mcpTools.delete(Z),this.removeFromIndexes(V),W++,this.emit("toolUnregistered",{type:"mcp",toolName:Z,serverName:$,timestamp:Date.now()});return W}updateIndexes($){if($.category){if(!this.categories.has($.category))this.categories.set($.category,new Set);this.categories.get($.category).add($.name)}for(let W of $.tags){if(!this.tags.has(W))this.tags.set(W,new Set);this.tags.get(W).add($.name)}}removeFromIndexes($){if($.category){let W=this.categories.get($.category);if(W){if(W.delete($.name),W.size===0)this.categories.delete($.category)}}for(let W of $.tags){let Q=this.tags.get(W);if(Q){if(Q.delete($.name),Q.size===0)this.tags.delete(W)}}}}var qW=[/deepseek.*r1/i,/deepseek.*reasoner/i,/o1-preview/i,/o1-mini/i,/o1/i,/qwen.*qwq/i,/qwen.*think/i,/kimi.*k1/i,/moonshot.*think/i,/k1-32k/i,/doubao.*think/i,/doubao.*pro.*think/i,/claude.*opus.*4/i,/glm-4\.7/i];function wW($){return qW.some((W)=>W.test($))}function OW($){if($.supportsThinking!==void 0)return{supportsThinking:$.supportsThinking,thinkingBudget:$.thinkingBudget};return{supportsThinking:wW($.model),thinkingBudget:void 0}}function z5($){return OW($).supportsThinking}import E5 from"fast-glob";import*as L0 from"fs/promises";import*as C5 from"path";import*as k1 from"fs/promises";import*as e from"path";var R5=[".git",".claude","node_modules",".env",".env.local",".env.production",".env.development",".env.test"];class K0 extends Error{code;constructor($,W){super($);this.code=W;this.name="PathSecurityError"}}class B0{static normalize($,W){let Q=e.isAbsolute($)?$:e.resolve(W,$),Z=e.normalize(Q),V=e.normalize(W);if(!Z.startsWith(V))throw new K0(`Path outside workspace: ${$} (resolved to ${Z}, workspace: ${V})`,"PATH_OUTSIDE_WORKSPACE");return Z}static checkRestricted($){let W=$.split(e.sep);for(let Q of R5)if(W.includes(Q))throw new K0(`Access denied: "${Q}" is a protected directory`,"RESTRICTED_PATH")}static checkTraversal($){if($.includes(".."))throw new K0(`Path traversal not allowed: ${$}`,"PATH_TRAVERSAL")}static async validatePath($,W){B0.checkTraversal($);let Q=B0.normalize($,W);B0.checkRestricted(Q);try{await k1.access(Q)}catch(Z){throw new K0(`Path not found: ${$}`,"PATH_NOT_FOUND")}return Q}static async resolveSymlink($,W){try{let Q=await k1.realpath($),Z=e.normalize(W);if(!Q.startsWith(Z))throw new K0(`Symlink points outside workspace: ${$} -> ${Q}`,"SYMLINK_OUTSIDE_WORKSPACE");return Q}catch(Q){if(Q instanceof K0)throw Q;return $}}static getRelativePath($,W){return e.relative(W,$)}static isWithinWorkspace($,W){let Q=e.normalize($),Z=e.normalize(W);return Q.startsWith(Z)}static isRestricted($){let W=$.split(e.sep);return R5.some((Q)=>W.includes(Q))}}class H${static PATTERN=/@"([^"]+)"|@([^\s]+)/g;static LINE_RANGE_PATTERN=/#L(\d+)(?:-(\d+))?$/;static GLOB_PATTERN=/[*?[\]]/;static extract($){let W=[],Q;H$.PATTERN.lastIndex=0;while((Q=H$.PATTERN.exec($))!==null){let Z=Q[0],V=Q[1]||Q[2],X=H$.parseLineRange(V);if(X)V=V.replace(H$.LINE_RANGE_PATTERN,"");let Y=H$.GLOB_PATTERN.test(V);W.push({raw:Z,path:V.trim(),lineRange:X,startIndex:Q.index,endIndex:Q.index+Z.length,isGlob:Y})}return W}static parseLineRange($){let W=$.match(H$.LINE_RANGE_PATTERN);if(!W)return;let Q=parseInt(W[1],10),Z=W[2]?parseInt(W[2],10):void 0;return{start:Q,end:Z}}static hasAtMentions($){return $.includes("@")}static isValidPath($){if(!$||$.trim().length===0)return!1;let W=["<",">","|","\x00"];for(let Q of W)if($.includes(Q))return!1;return!0}static removeAtMentions($){return H$.PATTERN.lastIndex=0,$.replace(H$.PATTERN,"")}}var j$=M("Prompts");function I1($){return $ instanceof Map}class D4{fileCache=new Map;options;constructor($){this.options={maxFileSize:1048576,maxLines:2000,maxTokens:32000,...$},j$.debug("AttachmentCollector initialized",{maxFileSize:this.options.maxFileSize,maxLines:this.options.maxLines})}async collect($){if(!H$.hasAtMentions($))return[];let W=H$.extract($);if(W.length===0)return[];j$.debug(`Found ${W.length} @ mentions`);let Q=W.map((V)=>this.processOne(V));return(await Promise.allSettled(Q)).map((V,X)=>{if(V.status==="fulfilled")return V.value;else{let Y=W[X],J=V.reason instanceof Error?V.reason.message:String(V.reason);return j$.warn(`Failed to process @${Y.path}:`,J),{type:"error",path:Y.path,content:"",error:J}}})}async processOne($){if($.isGlob)return j$.debug(`Processing glob pattern: ${$.path}`),await this.processGlob($.path);let W=await B0.validatePath($.path,this.options.cwd),Q=await B0.resolveSymlink(W,this.options.cwd);if((await L0.stat(Q)).isDirectory())return j$.debug(`Processing directory: ${$.path}`),await this.renderDirectoryTree(Q,$.path);return j$.debug(`Processing file: ${$.path}`,{lineRange:$.lineRange}),await this.readFile(Q,$.path,$.lineRange)}async readFile($,W,Q){let Z=this.fileCache.get($);if(Z&&Date.now()-Z.timestamp<60000)return j$.debug(`Cache hit: ${W}`),this.formatFileAttachment(W,Z.content,Q);let V=await L0.stat($);if(V.size>this.options.maxFileSize)throw Error(`File too large: ${Math.round(V.size/1024/1024)}MB (max ${Math.round(this.options.maxFileSize/1024/1024)}MB)`);let X;try{X=await L0.readFile($,"utf-8")}catch(Y){throw Error(`Cannot read file as text: ${W}. It may be a binary file.`)}return this.fileCache.set($,{content:X,timestamp:Date.now()}),this.formatFileAttachment(W,X,Q)}formatFileAttachment($,W,Q){let Z=W.split(`
1773
+ `),V=W,X=!1,Y=Q;if(Q){let J=Math.max(0,Q.start-1),G=Q.end?Q.end:Q.start;if(J>=Z.length)throw Error(`Line range start (${Q.start}) exceeds file length (${Z.length} lines)`);let K=Math.min(G,Z.length);V=Z.slice(J,K).join(`
1774
+ `);let B=Array.from({length:K-J},(w,O)=>J+O+1);V=V.split(`
1775
+ `).map((w,O)=>`${B[O]}: ${w}`).join(`
1776
+ `),Y={start:Q.start,end:K}}else if(Z.length>this.options.maxLines)V=Z.slice(0,this.options.maxLines).join(`
1771
1777
  `),V+=`
1772
1778
 
1773
1779
  [... truncated ${Z.length-this.options.maxLines} lines ...]`,X=!0;return{type:"file",path:$,content:V,metadata:{size:W.length,lines:Z.length,truncated:X,lineRange:Y}}}async renderDirectoryTree($,W){let Q=await E5("**/*",{cwd:$,dot:!1,followSymbolicLinks:!1,onlyFiles:!0,unique:!0,ignore:["node_modules/**",".git/**","dist/**","build/**",".next/**",".cache/**","coverage/**"]});if(Q.length===0)return{type:"directory",path:W,content:"(empty directory)"};j$.debug(`Found ${Q.length} files in directory: ${W}`);let Z=this.buildFileTree(Q),V=this.printTree(Z,W),X=500,Y=Q.length>X?`
1774
1780
 
1775
- [... and ${Q.length-X} more files]`:"";return{type:"directory",path:W,content:V+Y,metadata:{lines:Q.length,truncated:Q.length>X}}}buildFileTree($){let W=new Map;for(let Q of $){let Z=g0(Q),V=W;for(let X=0;X<Z.length;X++){let Y=Z[X],J=X===Z.length-1;if(!V.has(Y))V.set(Y,J?null:new Map);if(!J){let G=V.get(Y);if(G&&I1(G))V=G}}}return W}printTree($,W,Q="",Z=!0){let V=[];if(Q==="")V.push(`${W}/`);let X=Array.from($.entries()).sort((Y,J)=>{let G=I1(Y[1]),B=I1(J[1]);if(G!==B)return B?1:-1;return Y[0].localeCompare(J[0])});return X.forEach(([Y,J],G)=>{let B=G===X.length-1,K=B?"└── ":"├── ",q=I1(J);if(V.push(`${Q}${K}${Y}${q?"/":""}`),q&&J.size>0){let w=Q+(B?" ":"│ ");V.push(this.printTree(J,"",w,B))}}),V.filter((Y)=>Y).join(`
1776
- `)}async processGlob($){let W=await E5($,{cwd:this.options.cwd,dot:!1,followSymbolicLinks:!1,onlyFiles:!0,unique:!0,ignore:["node_modules/**",".git/**","dist/**","build/**",".next/**",".cache/**","coverage/**"]});if(W.length===0)return{type:"error",path:$,content:"",error:`No files matched pattern: ${$}`};j$.debug(`Glob pattern "${$}" matched ${W.length} files`);let Q=30,Z=W.slice(0,Q),X=(await Promise.allSettled(Z.map(async(B)=>{let K=C5.join(this.options.cwd,B);try{let q=await L0.readFile(K,"utf-8"),w=q.split(`
1777
- `),O=200,b=q,U=!1;if(w.length>200)b=w.slice(0,200).join(`
1778
- `),b+=`
1781
+ [... and ${Q.length-X} more files]`:"";return{type:"directory",path:W,content:V+Y,metadata:{lines:Q.length,truncated:Q.length>X}}}buildFileTree($){let W=new Map;for(let Q of $){let Z=g0(Q),V=W;for(let X=0;X<Z.length;X++){let Y=Z[X],J=X===Z.length-1;if(!V.has(Y))V.set(Y,J?null:new Map);if(!J){let G=V.get(Y);if(G&&I1(G))V=G}}}return W}printTree($,W,Q="",Z=!0){let V=[];if(Q==="")V.push(`${W}/`);let X=Array.from($.entries()).sort((Y,J)=>{let G=I1(Y[1]),K=I1(J[1]);if(G!==K)return K?1:-1;return Y[0].localeCompare(J[0])});return X.forEach(([Y,J],G)=>{let K=G===X.length-1,B=K?"└── ":"├── ",q=I1(J);if(V.push(`${Q}${B}${Y}${q?"/":""}`),q&&J.size>0){let w=Q+(K?" ":"│ ");V.push(this.printTree(J,"",w,K))}}),V.filter((Y)=>Y).join(`
1782
+ `)}async processGlob($){let W=await E5($,{cwd:this.options.cwd,dot:!1,followSymbolicLinks:!1,onlyFiles:!0,unique:!0,ignore:["node_modules/**",".git/**","dist/**","build/**",".next/**",".cache/**","coverage/**"]});if(W.length===0)return{type:"error",path:$,content:"",error:`No files matched pattern: ${$}`};j$.debug(`Glob pattern "${$}" matched ${W.length} files`);let Q=30,Z=W.slice(0,Q),X=(await Promise.allSettled(Z.map(async(K)=>{let B=C5.join(this.options.cwd,K);try{let q=await L0.readFile(B,"utf-8"),w=q.split(`
1783
+ `),O=200,H=q,U=!1;if(w.length>200)H=w.slice(0,200).join(`
1784
+ `),H+=`
1779
1785
 
1780
- [... truncated ${w.length-200} lines ...]`,U=!0;return{path:B,content:b,lines:w.length,truncated:U}}catch(q){return{path:B,content:`[Error: ${q instanceof Error?q.message:"unknown error"}]`,lines:0,truncated:!1}}}))).map((B)=>B.status==="fulfilled"?B.value:null).filter((B)=>B!==null),J=X.map((B)=>`--- ${B.path} (${B.lines} lines${B.truncated?", truncated":""}) ---
1781
- ${B.content}`).join(`
1786
+ [... truncated ${w.length-200} lines ...]`,U=!0;return{path:K,content:H,lines:w.length,truncated:U}}catch(q){return{path:K,content:`[Error: ${q instanceof Error?q.message:"unknown error"}]`,lines:0,truncated:!1}}}))).map((K)=>K.status==="fulfilled"?K.value:null).filter((K)=>K!==null),J=X.map((K)=>`--- ${K.path} (${K.lines} lines${K.truncated?", truncated":""}) ---
1787
+ ${K.content}`).join(`
1782
1788
 
1783
1789
  `),G=W.length>Q?`
1784
1790
 
1785
- [... and ${W.length-Q} more files matched]`:"";return{type:"file",path:$,content:J+G,metadata:{lines:X.reduce((B,K)=>B+K.lines,0),truncated:W.length>Q||X.some((B)=>B.truncated)}}}clearExpiredCache(){let $=Date.now(),W=0;for(let[Q,Z]of this.fileCache.entries())if($-Z.timestamp>60000)this.fileCache.delete(Q),W++;if(W>0)j$.debug(`Cleared ${W} expired cache entries`)}clearCache(){this.fileCache.clear(),j$.debug("Cleared all cache")}getCacheStats(){return{size:this.fileCache.size,keys:Array.from(this.fileCache.keys())}}}var f1=M("Agent");class D4{attachmentCollector;constructor($){this.attachmentCollector=new A4({cwd:$,maxFileSize:1048576,maxLines:2000,maxTokens:32000})}async processAtMentionsForContent($){if(typeof $==="string")return this.processAtMentions($);let W=[];for(let Z of $)if(Z.type==="text")W.push(Z.text);if(W.length===0)return $;let Q=W.join(`
1791
+ [... and ${W.length-Q} more files matched]`:"";return{type:"file",path:$,content:J+G,metadata:{lines:X.reduce((K,B)=>K+B.lines,0),truncated:W.length>Q||X.some((K)=>K.truncated)}}}clearExpiredCache(){let $=Date.now(),W=0;for(let[Q,Z]of this.fileCache.entries())if($-Z.timestamp>60000)this.fileCache.delete(Q),W++;if(W>0)j$.debug(`Cleared ${W} expired cache entries`)}clearCache(){this.fileCache.clear(),j$.debug("Cleared all cache")}getCacheStats(){return{size:this.fileCache.size,keys:Array.from(this.fileCache.keys())}}}var f1=M("Agent");class b4{attachmentCollector;constructor($){this.attachmentCollector=new D4({cwd:$,maxFileSize:1048576,maxLines:2000,maxTokens:32000})}async processAtMentionsForContent($){if(typeof $==="string")return this.processAtMentions($);let W=[];for(let Z of $)if(Z.type==="text")W.push(Z.text);if(W.length===0)return $;let Q=W.join(`
1786
1792
  `);try{let Z=await this.attachmentCollector.collect(Q);if(Z.length===0)return $;f1.debug(`✅ Processed ${Z.length} @ file mentions in multimodal message`);let V=this.buildAttachmentText(Z);if(!V)return $;return[...$,{type:"text",text:V}]}catch(Z){return f1.error("Failed to process @ mentions in multimodal message:",Z),$}}buildAttachmentText($){let W=[],Q=[];for(let V of $)if(V.type==="file"){let X=V.metadata?.lineRange?` (lines ${V.metadata.lineRange.start}${V.metadata.lineRange.end?`-${V.metadata.lineRange.end}`:""})`:"";W.push(`<file path="${V.path}"${X?` range="${X}"`:""}>`,V.content,"</file>")}else if(V.type==="directory")W.push(`<directory path="${V.path}">`,V.content,"</directory>");else if(V.type==="error")Q.push(`- @${V.path}: ${V.error}`);let Z="";if(W.length>0)Z+=`
1787
1793
 
1788
1794
  <system-reminder>
@@ -1805,39 +1811,39 @@ ${B.content}`).join(`
1805
1811
 
1806
1812
  ⚠️ Some files could not be loaded:
1807
1813
  `,V+=Z.join(`
1808
- `);return V}}var U$=M("Agent");class _4{getChatService;getContextManager;constructor($,W){this.getChatService=$;this.getContextManager=W}async checkAndCompactInLoop($,W,Q,Z){if(Q===void 0)return U$.debug(`[Agent] [轮次 ${W}] 压缩检查: 跳过(无历史 usage 数据)`),!1;let X=this.getChatService().getConfig(),Y=X.model,J=X.maxContextTokens??128000,G=X.maxOutputTokens??8192,B=J-G,K=Math.floor(B*0.8);if(U$.debug(`[Agent] [轮次 ${W}] 压缩检查:`,{promptTokens:Q,maxContextTokens:J,maxOutputTokens:G,availableForInput:B,threshold:K,shouldCompact:Q>=K}),Q<K)return!1;let q=W===0?"[Agent] 触发自动压缩":`[Agent] [轮次 ${W}] 触发循环内自动压缩`;U$.debug(q),Z?.(!0);try{let w=await t.compact($.messages,{trigger:"auto",modelName:Y,maxContextTokens:J,apiKey:X.apiKey,baseURL:X.baseUrl,actualPreTokens:Q});if(w.success)$.messages=w.compactedMessages,U$.debug(`[Agent] [轮次 ${W}] 压缩完成: ${w.preTokens} → ${w.postTokens} tokens (-${((1-w.postTokens/w.preTokens)*100).toFixed(1)}%)`);else $.messages=w.compactedMessages,U$.warn(`[Agent] [轮次 ${W}] 压缩使用降级策略: ${w.preTokens} → ${w.postTokens} tokens`);try{let O=this.getContextManager();if(O&&$.sessionId)await O.saveCompaction($.sessionId,w.summary,{trigger:"auto",preTokens:w.preTokens,postTokens:w.postTokens,filesIncluded:w.filesIncluded},null),U$.debug(`[Agent] [轮次 ${W}] 压缩数据已保存到 JSONL`)}catch(O){U$.warn(`[Agent] [轮次 ${W}] 保存压缩数据失败:`,O)}return Z?.(!1),!0}catch(w){return Z?.(!1),U$.error(`[Agent] [轮次 ${W}] 压缩失败,继续执行`,w),!1}}async compactOnTurnLimit($,W,Q){try{let V=this.getChatService().getConfig(),X=await t.compact($.messages,{trigger:"auto",modelName:V.model,maxContextTokens:V.maxContextTokens??128000,apiKey:V.apiKey,baseURL:V.baseUrl,actualPreTokens:Q});$.messages=X.compactedMessages;let Y=W.find((B)=>B.role==="system"),J=[];if(Y)J.push(Y);J.push(...$.messages);let G={role:"user",content:`This session is being continued from a previous conversation. The conversation is summarized above.
1814
+ `);return V}}var A$=M("Agent");class _4{getChatService;getContextManager;constructor($,W){this.getChatService=$;this.getContextManager=W}async checkAndCompactInLoop($,W,Q,Z){if(Q===void 0)return A$.debug(`[Agent] [轮次 ${W}] 压缩检查: 跳过(无历史 usage 数据)`),!1;let X=this.getChatService().getConfig(),Y=X.model,J=X.maxContextTokens??128000,G=X.maxOutputTokens??8192,K=J-G,B=Math.floor(K*0.8);if(A$.debug(`[Agent] [轮次 ${W}] 压缩检查:`,{promptTokens:Q,maxContextTokens:J,maxOutputTokens:G,availableForInput:K,threshold:B,shouldCompact:Q>=B}),Q<B)return!1;let q=W===0?"[Agent] 触发自动压缩":`[Agent] [轮次 ${W}] 触发循环内自动压缩`;A$.debug(q),Z?.(!0);try{let w=await t.compact($.messages,{trigger:"auto",modelName:Y,maxContextTokens:J,apiKey:X.apiKey,baseURL:X.baseUrl,actualPreTokens:Q});if(w.success)$.messages=w.compactedMessages,A$.debug(`[Agent] [轮次 ${W}] 压缩完成: ${w.preTokens} → ${w.postTokens} tokens (-${((1-w.postTokens/w.preTokens)*100).toFixed(1)}%)`);else $.messages=w.compactedMessages,A$.warn(`[Agent] [轮次 ${W}] 压缩使用降级策略: ${w.preTokens} → ${w.postTokens} tokens`);try{let O=this.getContextManager();if(O&&$.sessionId)await O.saveCompaction($.sessionId,w.summary,{trigger:"auto",preTokens:w.preTokens,postTokens:w.postTokens,filesIncluded:w.filesIncluded},null),A$.debug(`[Agent] [轮次 ${W}] 压缩数据已保存到 JSONL`)}catch(O){A$.warn(`[Agent] [轮次 ${W}] 保存压缩数据失败:`,O)}return Z?.(!1),!0}catch(w){return Z?.(!1),A$.error(`[Agent] [轮次 ${W}] 压缩失败,继续执行`,w),!1}}async compactOnTurnLimit($,W,Q){try{let V=this.getChatService().getConfig(),X=await t.compact($.messages,{trigger:"auto",modelName:V.model,maxContextTokens:V.maxContextTokens??128000,apiKey:V.apiKey,baseURL:V.baseUrl,actualPreTokens:Q});$.messages=X.compactedMessages;let Y=W.find((K)=>K.role==="system"),J=[];if(Y)J.push(Y);J.push(...$.messages);let G={role:"user",content:`This session is being continued from a previous conversation. The conversation is summarized above.
1809
1815
 
1810
- Please continue the conversation from where we left it off without asking the user any further questions. Continue with the last task that you were asked to work on.`};J.push(G),$.messages.push(G);try{let B=this.getContextManager();if(B&&$.sessionId)await B.saveCompaction($.sessionId,X.summary,{trigger:"auto",preTokens:X.preTokens,postTokens:X.postTokens,filesIncluded:X.filesIncluded},null)}catch(B){U$.warn("[Agent] 保存压缩数据失败:",B)}return U$.info(`✅ 上下文已压缩 (${X.preTokens} → ${X.postTokens} tokens),重置轮次计数`),{success:!0,messages:J}}catch(Z){U$.error("[Agent] 压缩失败,使用降级策略:",Z);let V=W.find((J)=>J.role==="system"),X=W.slice(-80),Y=[];if(V&&!X.some((J)=>J.role==="system"))Y.push(V);return Y.push(...X),$.messages=Y.filter((J)=>J.role!=="system"),U$.warn(`⚠️ 降级压缩完成,保留 ${Y.length} 条消息`),{success:!1,messages:Y}}}}import*as v5 from"crypto";import{nanoid as S5}from"nanoid";class L4{maxSummaryLength;keyPointsLimit;recentMessagesLimit;constructor($=500,W=10,Q=20){this.maxSummaryLength=$,this.keyPointsLimit=W,this.recentMessagesLimit=Q}async compress($){let W=$.layers.conversation.messages,Q=$.layers.tool.recentCalls,Z=W.filter((q)=>q.role==="system"),V=W.filter((q)=>q.role!=="system"),X=this.getRecentMessages(V),Y=V.slice(0,-this.recentMessagesLimit),J=await this.generateSummary(Y),G=this.extractKeyPoints(Y,Q),B=this.generateToolSummary(Q),K=this.estimateTokenCount(J,G,X,B);return{summary:J,keyPoints:G,recentMessages:[...Z,...X],toolSummary:B,tokenCount:K}}getRecentMessages($){return $.slice(-this.recentMessagesLimit)}async generateSummary($){if($.length===0)return"";let W=new Set,Q=new Set,Z=new Set;for(let X of $){let Y=X.content.toLowerCase();["关于","讨论","问题","项目","功能","需求"].forEach((K)=>{if(Y.includes(K)){let q=this.extractContext(Y,K,50);if(q)W.add(q)}}),["创建","删除","修改","更新","实现","开发"].forEach((K)=>{if(Y.includes(K)){let q=this.extractContext(Y,K,30);if(q)Q.add(q)}}),["决定","选择","确定","采用","使用"].forEach((K)=>{if(Y.includes(K)){let q=this.extractContext(Y,K,40);if(q)Z.add(q)}})}let V=`对话涉及 ${$.length} 条消息。`;if(W.size>0)V+=` 主要讨论:${Array.from(W).slice(0,3).join("、")}。`;if(Q.size>0)V+=` 执行操作:${Array.from(Q).slice(0,3).join("、")}。`;if(Z.size>0)V+=` 关键决策:${Array.from(Z).slice(0,2).join("、")}。`;return V.length>this.maxSummaryLength?V.substring(0,this.maxSummaryLength)+"...":V}extractKeyPoints($,W){let Q=new Set;for(let V of $)if(V.role==="user")this.extractQuestions(V.content).forEach((J)=>Q.add(`用户问题:${J}`)),this.extractRequests(V.content).forEach((J)=>Q.add(`用户请求:${J}`));else if(V.role==="assistant")this.extractSolutions(V.content).forEach((Y)=>Q.add(`解决方案:${Y}`));return this.summarizeToolUsage(W).forEach((V)=>Q.add(`工具使用:${V}`)),Array.from(Q).slice(0,this.keyPointsLimit)}generateToolSummary($){if($.length===0)return"";let W=new Map,Q=Date.now()-600000;for(let V of $){let X=W.get(V.name)||{count:0,success:0,recent:0};if(X.count++,V.status==="success")X.success++;if(V.timestamp>Q)X.recent++;W.set(V.name,X)}let Z=[];for(let[V,X]of Array.from(W.entries())){let Y=Math.round(X.success/X.count*100);Z.push(`${V}(${X.count}次,成功率${Y}%)`)}return`工具调用:${Z.join("、")}`}estimateTokenCount($,W,Q,Z){let V=$.length+W.join(" ").length;if(Z)V+=Z.length;for(let X of Q)V+=X.content.length;return Math.ceil(V/4)}extractContext($,W,Q){let Z=$.indexOf(W);if(Z===-1)return null;let V=Math.max(0,Z-Q/2),X=Math.min($.length,Z+Q/2);return $.substring(V,X).trim()}extractQuestions($){let W=[],Q=["?","?","如何","怎么","什么","为什么"],Z=$.split(/[。!.!]/);for(let V of Z)if(Q.some((X)=>V.includes(X))){let X=V.trim();if(X.length>5&&X.length<100)W.push(X)}return W.slice(0,3)}extractRequests($){let W=[],Q=["请","帮我","需要","想要","希望","能否"],Z=$.split(/[。!.!]/);for(let V of Z)if(Q.some((X)=>V.includes(X))){let X=V.trim();if(X.length>5&&X.length<100)W.push(X)}return W.slice(0,3)}extractSolutions($){let W=[],Q=["可以","建议","推荐","应该","最好","解决方案"],Z=$.split(/[。!.!]/);for(let V of Z)if(Q.some((X)=>V.includes(X))){let X=V.trim();if(X.length>10&&X.length<150)W.push(X)}return W.slice(0,3)}summarizeToolUsage($){let W=[],Q=$.filter((Z)=>Date.now()-Z.timestamp<1800000);if(Q.length>0){let Z=new Map;Q.forEach((V)=>{let X=Z.get(V.name)||[];X.push(V),Z.set(V.name,X)});for(let[V,X]of Array.from(Z.entries())){let Y=X.filter((J)=>J.status==="success").length;W.push(`${V}(${X.length}次,${Y}成功)`)}}return W.slice(0,5)}shouldCompress($,W){return this.estimateCurrentTokens($)>W*0.8}estimateCurrentTokens($){let Q=$.layers.conversation.messages.reduce((Z,V)=>Z+V.content.length,0);return Math.ceil(Q/4)}}class q0{defaultOptions;constructor($){this.defaultOptions={maxTokens:32000,maxMessages:50,timeWindow:86400000,priority:1,includeTools:!0,includeWorkspace:!0,...$}}filter($,W){let Q={...this.defaultOptions,...W},Z={layers:{system:$.layers.system,session:$.layers.session,conversation:this.filterConversation($.layers.conversation,Q),tool:Q.includeTools?this.filterTools($.layers.tool,Q):{recentCalls:[],toolStates:{},dependencies:{}},workspace:Q.includeWorkspace?$.layers.workspace:{currentFiles:[],recentFiles:[],environment:{}}},metadata:{...$.metadata,lastUpdated:Date.now()}};return Z.metadata.totalTokens=this.estimateTokens(Z),Z}filterConversation($,W){let Q=[...$.messages];if(W.timeWindow>0){let Z=Date.now()-W.timeWindow;Q=Q.filter((V)=>V.timestamp>=Z||V.role==="system")}if(W.priority>1)Q=this.filterByPriority(Q,W.priority);if(W.maxMessages>0)Q=this.limitMessages(Q,W.maxMessages);if(W.maxTokens>0)Q=this.limitByTokens(Q,W.maxTokens);return{messages:Q,summary:$.summary,topics:this.updateTopics(Q,$.topics),lastActivity:$.lastActivity}}filterTools($,W){let Q=[...$.recentCalls];if(W.timeWindow>0){let G=Date.now()-W.timeWindow;Q=Q.filter((B)=>B.timestamp>=G)}let Z=Q.filter((G)=>G.status==="success"),V=Q.filter((G)=>G.status==="error"),X=Math.min(20,Z.length),Y=Math.min(10,V.length);return{recentCalls:[...Z.slice(-X),...V.slice(-Y)].sort((G,B)=>G.timestamp-B.timestamp),toolStates:$.toolStates,dependencies:$.dependencies}}filterByPriority($,W){return $.filter((Q)=>{if(Q.role==="system")return!0;return this.calculateMessagePriority(Q)>=W})}calculateMessagePriority($){let W=1;if($.role==="system")W+=3;else if($.role==="assistant")W+=1;let Q=$.content.toLowerCase();if(["错误","警告","重要","关键","问题","解决"].some((X)=>Q.includes(X)))W+=2;if(Q.includes("```")||Q.includes("function")||Q.includes("class"))W+=1;let V=(Date.now()-$.timestamp)/3600000;if(V<1)W+=2;else if(V<6)W+=1;return W}limitMessages($,W){if($.length<=W)return $;let Q=$.filter((Y)=>Y.role==="system"),Z=$.filter((Y)=>Y.role!=="system"),V=W-Q.length,X=V>0?Z.slice(-V):[];return[...Q,...X].sort((Y,J)=>Y.timestamp-J.timestamp)}limitByTokens($,W){if(W<=0)return $;let Q=0,Z=[];for(let V=$.length-1;V>=0;V--){let X=$[V],Y=this.estimateMessageTokens(X);if(X.role==="system")if(Q+Y<=W)Z.unshift(X),Q+=Y;else{let J=this.compressMessage(X,W-Q);Z.unshift(J),Q+=this.estimateMessageTokens(J)}else if(Q+Y<=W)Z.unshift(X),Q+=Y;else break}return Z.sort((V,X)=>V.timestamp-X.timestamp)}estimateMessageTokens($){return Math.ceil($.content.length/4)}compressMessage($,W){let Q=W*4;if($.content.length<=Q)return $;let Z=$.content.substring(0,Q-3)+"...";return{...$,content:Z,metadata:{...$.metadata,compressed:!0,originalLength:$.content.length}}}updateTopics($,W){let Q=new Set(W);for(let Z of $)this.extractTopicsFromMessage(Z).forEach((X)=>Q.add(X));return Array.from(Q).slice(0,10)}extractTopicsFromMessage($){let W=$.content.toLowerCase(),Q=[];return["项目","功能","模块","组件","服务","接口","数据库","前端","后端","算法","架构","设计"].forEach((V)=>{if(W.includes(V))Q.push(V)}),Q}estimateTokens($){let W=0;for(let Z of $.layers.conversation.messages)W+=this.estimateMessageTokens(Z);let Q=JSON.stringify($.layers.system);if(W+=Math.ceil(Q.length/4),$.layers.tool.recentCalls.length>0){let Z=JSON.stringify($.layers.tool);W+=Math.ceil(Z.length/8)}return W}static createPresets(){return{lightweight:new q0({maxTokens:1000,maxMessages:10,timeWindow:7200000,includeTools:!1,includeWorkspace:!1}),standard:new q0({maxTokens:4000,maxMessages:30,timeWindow:43200000,includeTools:!0,includeWorkspace:!0}),comprehensive:new q0({maxTokens:8000,maxMessages:100,timeWindow:86400000,includeTools:!0,includeWorkspace:!0}),debug:new q0({maxTokens:2000,maxMessages:20,timeWindow:21600000,priority:2,includeTools:!0,includeWorkspace:!1})}}}class j4{cache=new Map;maxSize;defaultTTL;constructor($=100,W=300000){this.maxSize=$,this.defaultTTL=W}set($,W,Q){let Z=Date.now(),V={data:W,timestamp:Z,accessCount:0,lastAccess:Z,ttl:Q||this.defaultTTL};if(this.cache.size>=this.maxSize&&!this.cache.has($))this.evictLeastUsed();this.cache.set($,V)}get($){let W=this.cache.get($);if(!W)return null;let Q=Date.now();if(Q-W.timestamp>W.ttl)return this.cache.delete($),null;return W.accessCount++,W.lastAccess=Q,W.data}has($){let W=this.cache.get($);if(!W)return!1;if(Date.now()-W.timestamp>W.ttl)return this.cache.delete($),!1;return!0}delete($){return this.cache.delete($)}clear(){this.cache.clear()}size(){return this.cleanExpired(),this.cache.size}cacheMessageSummary($,W,Q){let Z=`summary:${$}:${W.length}`;this.set(Z,{summary:Q,messageCount:W.length,lastMessage:W[W.length-1]?.timestamp||0},600000)}getMessageSummary($,W){let Q=`summary:${$}:${W}`;return this.get(Q)}cacheToolResult($,W,Q){let Z=this.hashInput(W),V=`tool:${$}:${Z}`;this.set(V,Q,1800000)}getToolResult($,W){let Q=this.hashInput(W),Z=`tool:${$}:${Q}`;return this.get(Z)}cacheCompressedContext($,W){let Q=`compressed:${$}`;this.set(Q,W,900000)}getCompressedContext($){let W=`compressed:${$}`;return this.get(W)}getStats(){this.cleanExpired();let $=0,W=0,Q=[];for(let[Z,V]of Array.from(this.cache.entries()))$+=V.accessCount,W+=this.estimateItemSize(V),Q.push({key:Z,accessCount:V.accessCount,lastAccess:V.lastAccess});return Q.sort((Z,V)=>V.accessCount-Z.accessCount),{size:this.cache.size,maxSize:this.maxSize,hitRate:$>0?$/($+this.cache.size):0,memoryUsage:W,topKeys:Q.slice(0,10)}}cleanExpired(){let $=Date.now(),W=[];for(let[Q,Z]of Array.from(this.cache.entries()))if($-Z.timestamp>Z.ttl)W.push(Q);W.forEach((Q)=>this.cache.delete(Q))}evictLeastUsed(){let $=null,W=1/0,Q=Date.now();for(let[Z,V]of Array.from(this.cache.entries())){let X=1/(Q-V.lastAccess+1),Y=V.accessCount,J=X*Y;if(J<W)W=J,$=Z}if($)this.cache.delete($)}hashInput($){let W=JSON.stringify($),Q=0;for(let Z=0;Z<W.length;Z++){let V=W.charCodeAt(Z);Q=(Q<<5)-Q+V,Q=Q&Q}return Math.abs(Q).toString(36)}estimateItemSize($){try{return JSON.stringify($).length*2}catch{return 1000}}setTTL($,W){let Q=this.cache.get($);if(Q)return Q.ttl=W,Q.timestamp=Date.now(),!0;return!1}getRemainingTTL($){let W=this.cache.get($);if(!W)return-1;let Q=W.ttl-(Date.now()-W.timestamp);return Math.max(0,Q)}warmup($){$.forEach(({key:W,value:Q,ttl:Z})=>{this.set(W,Q,Z)})}}class z4{contextData=null;maxSize;accessLog=new Map;constructor($=1000){this.maxSize=$}setContext($){this.contextData={...$},this.contextData.metadata.lastUpdated=Date.now(),this.recordAccess("context")}getContext(){if(this.contextData)this.recordAccess("context");return this.contextData}addMessage($){if(!this.contextData)throw Error("上下文数据未初始化");this.contextData.layers.conversation.messages.push($),this.contextData.layers.conversation.lastActivity=Date.now(),this.contextData.metadata.lastUpdated=Date.now(),this.enforceMemoryLimit(),this.recordAccess("messages")}getRecentMessages($=10){if(!this.contextData)return[];let W=this.contextData.layers.conversation.messages;return this.recordAccess("messages"),W.slice(-$)}addToolCall($){if(!this.contextData)throw Error("上下文数据未初始化");if(this.contextData.layers.tool.recentCalls.push($),this.contextData.metadata.lastUpdated=Date.now(),this.contextData.layers.tool.recentCalls.length>50)this.contextData.layers.tool.recentCalls=this.contextData.layers.tool.recentCalls.slice(-25);this.recordAccess("tools")}updateToolState($,W){if(!this.contextData)throw Error("上下文数据未初始化");this.contextData.layers.tool.toolStates[$]=W,this.contextData.metadata.lastUpdated=Date.now(),this.recordAccess("tools")}getToolState($){if(!this.contextData)return null;return this.recordAccess("tools"),this.contextData.layers.tool.toolStates[$]}updateWorkspace($){if(!this.contextData)throw Error("上下文数据未初始化");Object.assign(this.contextData.layers.workspace,$),this.contextData.metadata.lastUpdated=Date.now(),this.recordAccess("workspace")}clear(){this.contextData=null,this.accessLog.clear()}getMemoryInfo(){if(!this.contextData)return{hasData:!1,messageCount:0,toolCallCount:0,lastUpdated:null};return{hasData:!0,messageCount:this.contextData.layers.conversation.messages.length,toolCallCount:this.contextData.layers.tool.recentCalls.length,lastUpdated:this.contextData.metadata.lastUpdated}}recordAccess($){this.accessLog.set($,Date.now())}enforceMemoryLimit(){if(!this.contextData)return;let $=this.contextData.layers.conversation.messages;if($.length>this.maxSize){let W=Math.floor(this.maxSize*0.8);this.contextData.layers.conversation.messages=$.slice(-W)}}getMemoryUsage(){if(!this.contextData)return 0;return JSON.stringify(this.contextData).length}}import{nanoid as T$}from"nanoid";import*as x$ from"node:fs/promises";import*as M5 from"node:path";import*as x1 from"node:fs";import{createReadStream as KW}from"node:fs";import*as $$ from"node:fs/promises";import*as N4 from"node:path";import{createInterface as qW}from"node:readline";class X${filePath;constructor($){this.filePath=$}async append($){try{await $$.mkdir(N4.dirname(this.filePath),{recursive:!0,mode:493});let W=JSON.stringify($)+`
1811
- `;await $$.appendFile(this.filePath,W,"utf-8")}catch(W){throw console.error(`[JSONLStore] 追加写入失败: ${this.filePath}`,W),W}}async appendBatch($){try{await $$.mkdir(N4.dirname(this.filePath),{recursive:!0,mode:493});let W=$.map((Q)=>JSON.stringify(Q)).join(`
1816
+ Please continue the conversation from where we left it off without asking the user any further questions. Continue with the last task that you were asked to work on.`};J.push(G),$.messages.push(G);try{let K=this.getContextManager();if(K&&$.sessionId)await K.saveCompaction($.sessionId,X.summary,{trigger:"auto",preTokens:X.preTokens,postTokens:X.postTokens,filesIncluded:X.filesIncluded},null)}catch(K){A$.warn("[Agent] 保存压缩数据失败:",K)}return A$.info(`✅ 上下文已压缩 (${X.preTokens} → ${X.postTokens} tokens),重置轮次计数`),{success:!0,messages:J}}catch(Z){A$.error("[Agent] 压缩失败,使用降级策略:",Z);let V=W.find((J)=>J.role==="system"),X=W.slice(-80),Y=[];if(V&&!X.some((J)=>J.role==="system"))Y.push(V);return Y.push(...X),$.messages=Y.filter((J)=>J.role!=="system"),A$.warn(`⚠️ 降级压缩完成,保留 ${Y.length} 条消息`),{success:!1,messages:Y}}}}import*as v5 from"crypto";import{nanoid as S5}from"nanoid";class L4{maxSummaryLength;keyPointsLimit;recentMessagesLimit;constructor($=500,W=10,Q=20){this.maxSummaryLength=$,this.keyPointsLimit=W,this.recentMessagesLimit=Q}async compress($){let W=$.layers.conversation.messages,Q=$.layers.tool.recentCalls,Z=W.filter((q)=>q.role==="system"),V=W.filter((q)=>q.role!=="system"),X=this.getRecentMessages(V),Y=V.slice(0,-this.recentMessagesLimit),J=await this.generateSummary(Y),G=this.extractKeyPoints(Y,Q),K=this.generateToolSummary(Q),B=this.estimateTokenCount(J,G,X,K);return{summary:J,keyPoints:G,recentMessages:[...Z,...X],toolSummary:K,tokenCount:B}}getRecentMessages($){return $.slice(-this.recentMessagesLimit)}async generateSummary($){if($.length===0)return"";let W=new Set,Q=new Set,Z=new Set;for(let X of $){let Y=X.content.toLowerCase();["关于","讨论","问题","项目","功能","需求"].forEach((B)=>{if(Y.includes(B)){let q=this.extractContext(Y,B,50);if(q)W.add(q)}}),["创建","删除","修改","更新","实现","开发"].forEach((B)=>{if(Y.includes(B)){let q=this.extractContext(Y,B,30);if(q)Q.add(q)}}),["决定","选择","确定","采用","使用"].forEach((B)=>{if(Y.includes(B)){let q=this.extractContext(Y,B,40);if(q)Z.add(q)}})}let V=`对话涉及 ${$.length} 条消息。`;if(W.size>0)V+=` 主要讨论:${Array.from(W).slice(0,3).join("、")}。`;if(Q.size>0)V+=` 执行操作:${Array.from(Q).slice(0,3).join("、")}。`;if(Z.size>0)V+=` 关键决策:${Array.from(Z).slice(0,2).join("、")}。`;return V.length>this.maxSummaryLength?V.substring(0,this.maxSummaryLength)+"...":V}extractKeyPoints($,W){let Q=new Set;for(let V of $)if(V.role==="user")this.extractQuestions(V.content).forEach((J)=>Q.add(`用户问题:${J}`)),this.extractRequests(V.content).forEach((J)=>Q.add(`用户请求:${J}`));else if(V.role==="assistant")this.extractSolutions(V.content).forEach((Y)=>Q.add(`解决方案:${Y}`));return this.summarizeToolUsage(W).forEach((V)=>Q.add(`工具使用:${V}`)),Array.from(Q).slice(0,this.keyPointsLimit)}generateToolSummary($){if($.length===0)return"";let W=new Map,Q=Date.now()-600000;for(let V of $){let X=W.get(V.name)||{count:0,success:0,recent:0};if(X.count++,V.status==="success")X.success++;if(V.timestamp>Q)X.recent++;W.set(V.name,X)}let Z=[];for(let[V,X]of Array.from(W.entries())){let Y=Math.round(X.success/X.count*100);Z.push(`${V}(${X.count}次,成功率${Y}%)`)}return`工具调用:${Z.join("、")}`}estimateTokenCount($,W,Q,Z){let V=$.length+W.join(" ").length;if(Z)V+=Z.length;for(let X of Q)V+=X.content.length;return Math.ceil(V/4)}extractContext($,W,Q){let Z=$.indexOf(W);if(Z===-1)return null;let V=Math.max(0,Z-Q/2),X=Math.min($.length,Z+Q/2);return $.substring(V,X).trim()}extractQuestions($){let W=[],Q=["?","?","如何","怎么","什么","为什么"],Z=$.split(/[。!.!]/);for(let V of Z)if(Q.some((X)=>V.includes(X))){let X=V.trim();if(X.length>5&&X.length<100)W.push(X)}return W.slice(0,3)}extractRequests($){let W=[],Q=["请","帮我","需要","想要","希望","能否"],Z=$.split(/[。!.!]/);for(let V of Z)if(Q.some((X)=>V.includes(X))){let X=V.trim();if(X.length>5&&X.length<100)W.push(X)}return W.slice(0,3)}extractSolutions($){let W=[],Q=["可以","建议","推荐","应该","最好","解决方案"],Z=$.split(/[。!.!]/);for(let V of Z)if(Q.some((X)=>V.includes(X))){let X=V.trim();if(X.length>10&&X.length<150)W.push(X)}return W.slice(0,3)}summarizeToolUsage($){let W=[],Q=$.filter((Z)=>Date.now()-Z.timestamp<1800000);if(Q.length>0){let Z=new Map;Q.forEach((V)=>{let X=Z.get(V.name)||[];X.push(V),Z.set(V.name,X)});for(let[V,X]of Array.from(Z.entries())){let Y=X.filter((J)=>J.status==="success").length;W.push(`${V}(${X.length}次,${Y}成功)`)}}return W.slice(0,5)}shouldCompress($,W){return this.estimateCurrentTokens($)>W*0.8}estimateCurrentTokens($){let Q=$.layers.conversation.messages.reduce((Z,V)=>Z+V.content.length,0);return Math.ceil(Q/4)}}class q0{defaultOptions;constructor($){this.defaultOptions={maxTokens:32000,maxMessages:50,timeWindow:86400000,priority:1,includeTools:!0,includeWorkspace:!0,...$}}filter($,W){let Q={...this.defaultOptions,...W},Z={layers:{system:$.layers.system,session:$.layers.session,conversation:this.filterConversation($.layers.conversation,Q),tool:Q.includeTools?this.filterTools($.layers.tool,Q):{recentCalls:[],toolStates:{},dependencies:{}},workspace:Q.includeWorkspace?$.layers.workspace:{currentFiles:[],recentFiles:[],environment:{}}},metadata:{...$.metadata,lastUpdated:Date.now()}};return Z.metadata.totalTokens=this.estimateTokens(Z),Z}filterConversation($,W){let Q=[...$.messages];if(W.timeWindow>0){let Z=Date.now()-W.timeWindow;Q=Q.filter((V)=>V.timestamp>=Z||V.role==="system")}if(W.priority>1)Q=this.filterByPriority(Q,W.priority);if(W.maxMessages>0)Q=this.limitMessages(Q,W.maxMessages);if(W.maxTokens>0)Q=this.limitByTokens(Q,W.maxTokens);return{messages:Q,summary:$.summary,topics:this.updateTopics(Q,$.topics),lastActivity:$.lastActivity}}filterTools($,W){let Q=[...$.recentCalls];if(W.timeWindow>0){let G=Date.now()-W.timeWindow;Q=Q.filter((K)=>K.timestamp>=G)}let Z=Q.filter((G)=>G.status==="success"),V=Q.filter((G)=>G.status==="error"),X=Math.min(20,Z.length),Y=Math.min(10,V.length);return{recentCalls:[...Z.slice(-X),...V.slice(-Y)].sort((G,K)=>G.timestamp-K.timestamp),toolStates:$.toolStates,dependencies:$.dependencies}}filterByPriority($,W){return $.filter((Q)=>{if(Q.role==="system")return!0;return this.calculateMessagePriority(Q)>=W})}calculateMessagePriority($){let W=1;if($.role==="system")W+=3;else if($.role==="assistant")W+=1;let Q=$.content.toLowerCase();if(["错误","警告","重要","关键","问题","解决"].some((X)=>Q.includes(X)))W+=2;if(Q.includes("```")||Q.includes("function")||Q.includes("class"))W+=1;let V=(Date.now()-$.timestamp)/3600000;if(V<1)W+=2;else if(V<6)W+=1;return W}limitMessages($,W){if($.length<=W)return $;let Q=$.filter((Y)=>Y.role==="system"),Z=$.filter((Y)=>Y.role!=="system"),V=W-Q.length,X=V>0?Z.slice(-V):[];return[...Q,...X].sort((Y,J)=>Y.timestamp-J.timestamp)}limitByTokens($,W){if(W<=0)return $;let Q=0,Z=[];for(let V=$.length-1;V>=0;V--){let X=$[V],Y=this.estimateMessageTokens(X);if(X.role==="system")if(Q+Y<=W)Z.unshift(X),Q+=Y;else{let J=this.compressMessage(X,W-Q);Z.unshift(J),Q+=this.estimateMessageTokens(J)}else if(Q+Y<=W)Z.unshift(X),Q+=Y;else break}return Z.sort((V,X)=>V.timestamp-X.timestamp)}estimateMessageTokens($){return Math.ceil($.content.length/4)}compressMessage($,W){let Q=W*4;if($.content.length<=Q)return $;let Z=$.content.substring(0,Q-3)+"...";return{...$,content:Z,metadata:{...$.metadata,compressed:!0,originalLength:$.content.length}}}updateTopics($,W){let Q=new Set(W);for(let Z of $)this.extractTopicsFromMessage(Z).forEach((X)=>Q.add(X));return Array.from(Q).slice(0,10)}extractTopicsFromMessage($){let W=$.content.toLowerCase(),Q=[];return["项目","功能","模块","组件","服务","接口","数据库","前端","后端","算法","架构","设计"].forEach((V)=>{if(W.includes(V))Q.push(V)}),Q}estimateTokens($){let W=0;for(let Z of $.layers.conversation.messages)W+=this.estimateMessageTokens(Z);let Q=JSON.stringify($.layers.system);if(W+=Math.ceil(Q.length/4),$.layers.tool.recentCalls.length>0){let Z=JSON.stringify($.layers.tool);W+=Math.ceil(Z.length/8)}return W}static createPresets(){return{lightweight:new q0({maxTokens:1000,maxMessages:10,timeWindow:7200000,includeTools:!1,includeWorkspace:!1}),standard:new q0({maxTokens:4000,maxMessages:30,timeWindow:43200000,includeTools:!0,includeWorkspace:!0}),comprehensive:new q0({maxTokens:8000,maxMessages:100,timeWindow:86400000,includeTools:!0,includeWorkspace:!0}),debug:new q0({maxTokens:2000,maxMessages:20,timeWindow:21600000,priority:2,includeTools:!0,includeWorkspace:!1})}}}class j4{cache=new Map;maxSize;defaultTTL;constructor($=100,W=300000){this.maxSize=$,this.defaultTTL=W}set($,W,Q){let Z=Date.now(),V={data:W,timestamp:Z,accessCount:0,lastAccess:Z,ttl:Q||this.defaultTTL};if(this.cache.size>=this.maxSize&&!this.cache.has($))this.evictLeastUsed();this.cache.set($,V)}get($){let W=this.cache.get($);if(!W)return null;let Q=Date.now();if(Q-W.timestamp>W.ttl)return this.cache.delete($),null;return W.accessCount++,W.lastAccess=Q,W.data}has($){let W=this.cache.get($);if(!W)return!1;if(Date.now()-W.timestamp>W.ttl)return this.cache.delete($),!1;return!0}delete($){return this.cache.delete($)}clear(){this.cache.clear()}size(){return this.cleanExpired(),this.cache.size}cacheMessageSummary($,W,Q){let Z=`summary:${$}:${W.length}`;this.set(Z,{summary:Q,messageCount:W.length,lastMessage:W[W.length-1]?.timestamp||0},600000)}getMessageSummary($,W){let Q=`summary:${$}:${W}`;return this.get(Q)}cacheToolResult($,W,Q){let Z=this.hashInput(W),V=`tool:${$}:${Z}`;this.set(V,Q,1800000)}getToolResult($,W){let Q=this.hashInput(W),Z=`tool:${$}:${Q}`;return this.get(Z)}cacheCompressedContext($,W){let Q=`compressed:${$}`;this.set(Q,W,900000)}getCompressedContext($){let W=`compressed:${$}`;return this.get(W)}getStats(){this.cleanExpired();let $=0,W=0,Q=[];for(let[Z,V]of Array.from(this.cache.entries()))$+=V.accessCount,W+=this.estimateItemSize(V),Q.push({key:Z,accessCount:V.accessCount,lastAccess:V.lastAccess});return Q.sort((Z,V)=>V.accessCount-Z.accessCount),{size:this.cache.size,maxSize:this.maxSize,hitRate:$>0?$/($+this.cache.size):0,memoryUsage:W,topKeys:Q.slice(0,10)}}cleanExpired(){let $=Date.now(),W=[];for(let[Q,Z]of Array.from(this.cache.entries()))if($-Z.timestamp>Z.ttl)W.push(Q);W.forEach((Q)=>this.cache.delete(Q))}evictLeastUsed(){let $=null,W=1/0,Q=Date.now();for(let[Z,V]of Array.from(this.cache.entries())){let X=1/(Q-V.lastAccess+1),Y=V.accessCount,J=X*Y;if(J<W)W=J,$=Z}if($)this.cache.delete($)}hashInput($){let W=JSON.stringify($),Q=0;for(let Z=0;Z<W.length;Z++){let V=W.charCodeAt(Z);Q=(Q<<5)-Q+V,Q=Q&Q}return Math.abs(Q).toString(36)}estimateItemSize($){try{return JSON.stringify($).length*2}catch{return 1000}}setTTL($,W){let Q=this.cache.get($);if(Q)return Q.ttl=W,Q.timestamp=Date.now(),!0;return!1}getRemainingTTL($){let W=this.cache.get($);if(!W)return-1;let Q=W.ttl-(Date.now()-W.timestamp);return Math.max(0,Q)}warmup($){$.forEach(({key:W,value:Q,ttl:Z})=>{this.set(W,Q,Z)})}}class N4{contextData=null;maxSize;accessLog=new Map;constructor($=1000){this.maxSize=$}setContext($){this.contextData={...$},this.contextData.metadata.lastUpdated=Date.now(),this.recordAccess("context")}getContext(){if(this.contextData)this.recordAccess("context");return this.contextData}addMessage($){if(!this.contextData)throw Error("上下文数据未初始化");this.contextData.layers.conversation.messages.push($),this.contextData.layers.conversation.lastActivity=Date.now(),this.contextData.metadata.lastUpdated=Date.now(),this.enforceMemoryLimit(),this.recordAccess("messages")}getRecentMessages($=10){if(!this.contextData)return[];let W=this.contextData.layers.conversation.messages;return this.recordAccess("messages"),W.slice(-$)}addToolCall($){if(!this.contextData)throw Error("上下文数据未初始化");if(this.contextData.layers.tool.recentCalls.push($),this.contextData.metadata.lastUpdated=Date.now(),this.contextData.layers.tool.recentCalls.length>50)this.contextData.layers.tool.recentCalls=this.contextData.layers.tool.recentCalls.slice(-25);this.recordAccess("tools")}updateToolState($,W){if(!this.contextData)throw Error("上下文数据未初始化");this.contextData.layers.tool.toolStates[$]=W,this.contextData.metadata.lastUpdated=Date.now(),this.recordAccess("tools")}getToolState($){if(!this.contextData)return null;return this.recordAccess("tools"),this.contextData.layers.tool.toolStates[$]}updateWorkspace($){if(!this.contextData)throw Error("上下文数据未初始化");Object.assign(this.contextData.layers.workspace,$),this.contextData.metadata.lastUpdated=Date.now(),this.recordAccess("workspace")}clear(){this.contextData=null,this.accessLog.clear()}getMemoryInfo(){if(!this.contextData)return{hasData:!1,messageCount:0,toolCallCount:0,lastUpdated:null};return{hasData:!0,messageCount:this.contextData.layers.conversation.messages.length,toolCallCount:this.contextData.layers.tool.recentCalls.length,lastUpdated:this.contextData.metadata.lastUpdated}}recordAccess($){this.accessLog.set($,Date.now())}enforceMemoryLimit(){if(!this.contextData)return;let $=this.contextData.layers.conversation.messages;if($.length>this.maxSize){let W=Math.floor(this.maxSize*0.8);this.contextData.layers.conversation.messages=$.slice(-W)}}getMemoryUsage(){if(!this.contextData)return 0;return JSON.stringify(this.contextData).length}}import{nanoid as y$}from"nanoid";import*as f$ from"node:fs/promises";import*as M5 from"node:path";import*as x1 from"node:fs";import{createReadStream as UW}from"node:fs";import*as $$ from"node:fs/promises";import*as z4 from"node:path";import{createInterface as FW}from"node:readline";class X${filePath;constructor($){this.filePath=$}async append($){try{await $$.mkdir(z4.dirname(this.filePath),{recursive:!0,mode:493});let W=JSON.stringify($)+`
1817
+ `;await $$.appendFile(this.filePath,W,"utf-8")}catch(W){throw console.error(`[JSONLStore] 追加写入失败: ${this.filePath}`,W),W}}async appendBatch($){try{await $$.mkdir(z4.dirname(this.filePath),{recursive:!0,mode:493});let W=$.map((Q)=>JSON.stringify(Q)).join(`
1812
1818
  `)+`
1813
1819
  `;await $$.appendFile(this.filePath,W,"utf-8")}catch(W){throw console.error(`[JSONLStore] 批量追加写入失败: ${this.filePath}`,W),W}}async readAll(){try{if(!x1.existsSync(this.filePath))return[];let W=(await $$.readFile(this.filePath,"utf-8")).split(`
1814
- `).filter((Z)=>Z.trim().length>0),Q=[];for(let Z of W)try{Q.push(JSON.parse(Z))}catch(V){console.warn(`[JSONLStore] 解析 JSON 行失败: ${Z}`,V)}return Q}catch($){return console.error(`[JSONLStore] 读取文件失败: ${this.filePath}`,$),[]}}async readStream($){return new Promise((W,Q)=>{if(!x1.existsSync(this.filePath)){W();return}let Z=KW(this.filePath,"utf-8"),V=qW({input:Z,crlfDelay:Number.POSITIVE_INFINITY});V.on("line",async(X)=>{let Y=X.trim();if(Y.length===0)return;try{let J=JSON.parse(Y);await $(J)}catch(J){console.warn(`[JSONLStore] 解析 JSON 行失败: ${Y}`,J)}}),V.on("close",()=>W()),V.on("error",Q),Z.on("error",Q)})}async filter($){let W=[];return await this.readStream((Q)=>{if($(Q))W.push(Q)}),W}async readLast($){return(await this.readAll()).slice(-$)}async getStats(){try{if(!x1.existsSync(this.filePath))return{exists:!1,size:0,lineCount:0};let $=await $$.stat(this.filePath),Q=(await $$.readFile(this.filePath,"utf-8")).split(`
1815
- `).filter((Z)=>Z.trim().length>0).length;return{exists:!0,size:$.size,lineCount:Q}}catch($){return console.error(`[JSONLStore] 获取统计信息失败: ${this.filePath}`,$),{exists:!1,size:0,lineCount:0}}}async exists(){try{return await $$.access(this.filePath),!0}catch{return!1}}async delete(){try{if(await this.exists())await $$.unlink(this.filePath)}catch($){throw console.error(`[JSONLStore] 删除文件失败: ${this.filePath}`,$),$}}getFilePath(){return this.filePath}}class R4{projectPath;maxSessions;version;constructor($=process.cwd(),W=100,Q="0.0.10"){this.projectPath=$,this.maxSessions=W,this.version=Q}createEvent($,W,Q){return{id:T$(),sessionId:W,timestamp:new Date().toISOString(),type:$,cwd:this.projectPath,gitBranch:z8(this.projectPath),version:this.version,data:Q}}async ensureSessionCreated($,W){let Q=Y$(this.projectPath,$),Z=new X$(Q);if((await Z.getStats()).lineCount>0)return;let X=new Date().toISOString(),Y={sessionId:$,rootId:W?.parentSessionId??$,parentId:W?.parentSessionId,relationType:W?"subagent":void 0,title:void 0,status:"running",agentType:W?.subagentType,model:void 0,permission:void 0,createdAt:X,updatedAt:X},J=this.createEvent("session_created",$,Y);await Z.append(J)}buildCompactionMetadata($){let W={trigger:$.trigger,preTokens:$.preTokens};if($.postTokens!==void 0)W.postTokens=$.postTokens;if($.filesIncluded)W.filesIncluded=$.filesIncluded;return W}async initialize(){try{let $=u0(this.projectPath);await x$.mkdir($,{recursive:!0,mode:493}),console.log(`[PersistentStore] 初始化存储目录: ${$}`)}catch($){console.warn("[PersistentStore] 无法创建持久化存储目录:",$)}}async saveMessage($,W,Q,Z=null,V,X){try{let Y=Y$(this.projectPath,$),J=new X$(Y);await this.ensureSessionCreated($,X);let G=new Date().toISOString(),B=T$(),K={messageId:B,role:W,parentMessageId:Z??void 0,createdAt:G,model:V?.model,usage:V?.usage},q=this.createEvent("message_created",$,K),w={partId:T$(),messageId:B,partType:"text",payload:{text:Q},createdAt:G},O=this.createEvent("part_created",$,w);return await J.appendBatch([q,O]),B}catch(Y){throw console.error(`[PersistentStore] 保存消息失败 (session: ${$}):`,Y),Y}}async saveToolUse($,W,Q,Z=null,V){try{let X=Y$(this.projectPath,$),Y=new X$(X);await this.ensureSessionCreated($,V);let J=new Date().toISOString(),G=Z??T$(),B=[];if(!Z){let w={messageId:G,role:"assistant",parentMessageId:void 0,createdAt:J};B.push(this.createEvent("message_created",$,w))}let K=T$(),q={partId:K,messageId:G,partType:"tool_call",payload:{toolCallId:K,toolName:W,input:Q},createdAt:J};if(B.push(this.createEvent("part_created",$,q)),W==="Task"&&Q&&typeof Q==="object"){let w=Q,O=typeof w.subagent_session_id==="string"?w.subagent_session_id:void 0,b=typeof w.subagent_type==="string"?w.subagent_type:void 0;if(O&&b){let U={partId:T$(),messageId:G,partType:"subtask_ref",payload:{childSessionId:O,agentType:b,status:"running",summary:typeof w.description==="string"?w.description:"",startedAt:J},createdAt:J};B.push(this.createEvent("part_created",$,U))}}return await Y.appendBatch(B),K}catch(X){throw console.error(`[PersistentStore] 保存工具调用失败 (session: ${$}):`,X),X}}async saveToolResult($,W,Q,Z,V=null,X,Y,J){try{let G=Y$(this.projectPath,$),B=new X$(G);await this.ensureSessionCreated($,Y);let K=new Date().toISOString(),q=V??T$(),w=[];if(!V){let b={messageId:q,role:"assistant",parentMessageId:void 0,createdAt:K};w.push(this.createEvent("message_created",$,b))}let O={partId:W,messageId:q,partType:"tool_result",payload:{toolCallId:W,toolName:Q,output:Z,error:X??null},createdAt:K};if(w.push(this.createEvent("part_created",$,O)),J){let b=J.subagentStatus==="running"?null:K,U={partId:T$(),messageId:q,partType:"subtask_ref",payload:{childSessionId:J.subagentSessionId,agentType:J.subagentType,status:J.subagentStatus,summary:J.subagentSummary??"",startedAt:K,finishedAt:b},createdAt:K};w.push(this.createEvent("part_created",$,U))}return await B.appendBatch(w),W}catch(G){throw console.error(`[PersistentStore] 保存工具结果失败 (session: ${$}):`,G),G}}async saveCompaction($,W,Q,Z=null){try{let V=Y$(this.projectPath,$),X=new X$(V);await this.ensureSessionCreated($);let Y=new Date().toISOString(),J=T$(),G={messageId:J,role:"system",parentMessageId:Z??void 0,createdAt:Y},B=this.buildCompactionMetadata(Q),K={partId:T$(),messageId:J,partType:"summary",payload:{text:W,metadata:B},createdAt:Y},q=[this.createEvent("message_created",$,G),this.createEvent("part_created",$,K)];return await X.appendBatch(q),J}catch(V){throw console.error(`[PersistentStore] 保存压缩失败 (session: ${$}):`,V),V}}async saveContext($,W){try{let{conversation:Q}=W.layers;for(let Z of Q.messages)await this.saveMessage($,Z.role,Z.content,null)}catch(Q){console.warn(`[PersistentStore] 保存上下文失败 (session: ${$}):`,Q)}}async saveSession($,W){console.warn("[PersistentStore] saveSession 方法已废弃,请使用 saveMessage")}async saveConversation($,W){console.warn("[PersistentStore] saveConversation 方法已废弃,请使用 saveMessage")}async loadSession($){try{let W=Y$(this.projectPath,$),Z=await new X$(W).readAll();if(Z.length===0)return null;let V=Z.find((X)=>X.type==="session_created");return{sessionId:$,userId:void 0,preferences:{},configuration:{},startTime:new Date(V?.timestamp??Z[0].timestamp).getTime()}}catch{return null}}async loadConversation($){try{let W=Y$(this.projectPath,$),Z=await new X$(W).readAll();if(Z.length===0)return null;let V=new Map;for(let G of Z){if(G.type==="message_created")V.set(G.data.messageId,{id:G.data.messageId,role:G.data.role,content:"",timestamp:new Date(G.timestamp).getTime()});if(G.type==="part_created"&&G.data.partType==="text"){let B=V.get(G.data.messageId);if(B){let K=G.data.payload;B.content=K.text??""}}}let X=Array.from(V.values()),Y=Z[Z.length-1],J=new Date(Y.timestamp).getTime();return{messages:X,topics:[],lastActivity:J}}catch{return null}}async listSessions(){try{let $=u0(this.projectPath);return(await x$.readdir($)).filter((Q)=>Q.endsWith(".jsonl")).map((Q)=>Q.replace(".jsonl","")).sort()}catch{return[]}}async getSessionSummary($){try{let W=Y$(this.projectPath,$),Q=new X$(W);if(!(await Q.getStats()).exists)return null;let V=await Q.readAll();if(V.length===0)return null;let X=V[V.length-1],Y=V.filter((J)=>J.type==="message_created"&&["user","assistant"].includes(J.data.role)).length;return{sessionId:$,lastActivity:new Date(X.timestamp).getTime(),messageCount:Y,topics:[]}}catch{return null}}async deleteSession($){try{let W=Y$(this.projectPath,$);await new X$(W).delete()}catch(W){console.warn(`[PersistentStore] 删除会话失败 (session: ${$}):`,W)}}async cleanupOldSessions(){try{let $=await this.listSessions();if($.length<=this.maxSessions)return;let Z=(await Promise.all($.map((V)=>this.getSessionSummary(V)))).filter((V)=>V!==null).sort((V,X)=>X.lastActivity-V.lastActivity).slice(this.maxSessions).map((V)=>V.sessionId);await Promise.all(Z.map((V)=>this.deleteSession(V))),console.log(`[PersistentStore] 已清理 ${Z.length} 个旧会话`)}catch($){console.error("[PersistentStore] 清理旧会话失败:",$)}}async getStorageStats(){try{let $=await this.listSessions(),W=0;for(let Q of $){let Z=Y$(this.projectPath,Q),X=await new X$(Z).getStats();W+=X.size}return{totalSessions:$.length,totalSize:W,projectPath:this.projectPath}}catch{return{totalSessions:0,totalSize:0,projectPath:this.projectPath}}}async checkStorageHealth(){try{let $=u0(this.projectPath);await x$.mkdir($,{recursive:!0,mode:493});let W=M5.join($,".health-check");return await x$.writeFile(W,"test","utf-8"),await x$.unlink(W),{isAvailable:!0,canWrite:!0}}catch($){return{isAvailable:!1,canWrite:!1,error:$ instanceof Error?$.message:String($)}}}static async listAllProjects(){return N8()}}class h1{memory;persistent;cache;compressor;filter;options;currentSessionId=null;initialized=!1;constructor($={}){let W=$.storage?.persistentPath||d0();this.options={storage:{maxMemorySize:1000,persistentPath:W,cacheSize:100,compressionEnabled:!0,...$.storage},defaultFilter:{maxTokens:32000,maxMessages:50,timeWindow:86400000,...$.defaultFilter},compressionThreshold:$.compressionThreshold||6000,enableVectorSearch:$.enableVectorSearch||!1},this.memory=new z4(this.options.storage.maxMemorySize),this.persistent=new R4(process.cwd(),100),this.cache=new j4(this.options.storage.cacheSize,300000),this.compressor=new L4,this.filter=new q0(this.options.defaultFilter)}async initialize(){if(this.initialized)return;try{if(await this.persistent.initialize(),!(await this.persistent.checkStorageHealth()).isAvailable)console.warn("警告:持久化存储不可用,将仅使用内存存储");this.initialized=!0,console.log("上下文管理器初始化完成")}catch($){throw console.error("上下文管理器初始化失败:",$),$}}async createSession($,W={},Q={}){let Z=Q.sessionId||this.generateSessionId(),V=Date.now(),X={layers:{system:await this.createSystemContext(),session:{sessionId:Z,userId:$,preferences:W,configuration:Q,startTime:V},conversation:{messages:[],topics:[],lastActivity:V},tool:{recentCalls:[],toolStates:{},dependencies:{}},workspace:await this.createWorkspaceContext()},metadata:{totalTokens:0,priority:1,lastUpdated:V}};return this.memory.setContext(X),await this.persistent.saveContext(Z,X),this.currentSessionId=Z,console.log(`新会话已创建: ${Z}`),Z}async loadSession($){try{let W=this.memory.getContext();if(!W||W.layers.session.sessionId!==$){let[Q,Z]=await Promise.all([this.persistent.loadSession($),this.persistent.loadConversation($)]);if(!Q||!Z)return!1;W={layers:{system:await this.createSystemContext(),session:Q,conversation:Z,tool:{recentCalls:[],toolStates:{},dependencies:{}},workspace:await this.createWorkspaceContext()},metadata:{totalTokens:0,priority:1,lastUpdated:Date.now()}},this.memory.setContext(W)}return this.currentSessionId=$,console.log(`会话已加载: ${$}`),!0}catch(W){return console.error("加载会话失败:",W),!1}}async addMessage($,W,Q){if(!this.currentSessionId)throw Error("没有活动会话");let Z={id:this.generateMessageId(),role:$,content:W,timestamp:Date.now(),metadata:Q};this.memory.addMessage(Z);let V=this.memory.getContext();if(V&&this.shouldCompress(V))await this.compressCurrentContext();this.saveCurrentSessionAsync()}async addToolCall($){if(!this.currentSessionId)throw Error("没有活动会话");if(this.memory.addToolCall($),$.status==="success"&&$.output)this.cache.cacheToolResult($.name,$.input,$.output);this.saveCurrentSessionAsync()}async saveMessage($,W,Q,Z=null,V,X){return this.persistent.saveMessage($,W,Q,Z,V,X)}async saveToolUse($,W,Q,Z=null,V){return this.persistent.saveToolUse($,W,Q,Z,V)}async saveToolResult($,W,Q,Z,V=null,X,Y,J){return this.persistent.saveToolResult($,W,Q,Z,V,X,Y,J)}async saveCompaction($,W,Q,Z=null){return this.persistent.saveCompaction($,W,Q,Z)}updateToolState($,W){if(!this.currentSessionId)throw Error("没有活动会话");this.memory.updateToolState($,W)}updateWorkspace($){if(!this.currentSessionId)throw Error("没有活动会话");this.memory.updateWorkspace($)}async getFormattedContext($){let W=this.memory.getContext();if(!W)throw Error("没有可用的上下文数据");let Q=this.filter.filter(W,$),Z=this.shouldCompress(Q),V;if(Z){let X=this.hashContext(Q);if(V=this.cache.getCompressedContext(X)??void 0,!V)V=await this.compressor.compress(Q),this.cache.cacheCompressedContext(X,V)}return{context:Q,compressed:V,tokenCount:V?V.tokenCount:Q.metadata.totalTokens}}async searchSessions($,W=10){let Q=await this.persistent.listSessions(),Z=[];for(let V of Q){let X=await this.persistent.getSessionSummary(V);if(X){let Y=this.calculateRelevance($,X.topics);if(Y>0)Z.push({sessionId:V,summary:`${X.messageCount}条消息,主题:${X.topics.join("、")}`,lastActivity:X.lastActivity,relevanceScore:Y})}}return Z.sort((V,X)=>X.relevanceScore-V.relevanceScore).slice(0,W)}getCachedToolResult($,W){return this.cache.getToolResult($,W)}async getStats(){let[$,W,Q]=await Promise.all([Promise.resolve(this.memory.getMemoryInfo()),Promise.resolve(this.cache.getStats()),this.persistent.getStorageStats()]);return{currentSession:this.currentSessionId,memory:$,cache:W,storage:Q}}async cleanup(){if(this.currentSessionId)await this.saveCurrentSession();this.memory.clear(),this.cache.clear(),await this.persistent.cleanupOldSessions(),this.currentSessionId=null,console.log("上下文管理器资源清理完成")}generateSessionId(){return S5()}generateMessageId(){return S5()}async createSystemContext(){return{role:"AI助手",capabilities:["对话","工具调用","代码生成","文档分析"],tools:["文件操作","Git操作","代码分析"],version:"1.0.0"}}async createWorkspaceContext(){try{let $=process.cwd();return{projectPath:$,currentFiles:[],recentFiles:[],environment:{nodeVersion:process.version,platform:process.platform,cwd:$}}}catch($){return{currentFiles:[],recentFiles:[],environment:{}}}}shouldCompress($){return $.metadata.totalTokens>this.options.compressionThreshold}async compressCurrentContext(){let $=this.memory.getContext();if(!$)return;let W=await this.compressor.compress($);$.layers.conversation.summary=W.summary,this.memory.setContext($)}async saveCurrentSession(){if(!this.currentSessionId)return;let $=this.memory.getContext();if($)await this.persistent.saveContext(this.currentSessionId,$)}saveCurrentSessionAsync(){this.saveCurrentSession().catch(($)=>{console.warn("异步保存会话失败:",$)})}hashContext($){let W=JSON.stringify({messageCount:$.layers.conversation.messages.length,lastMessage:$.layers.conversation.messages[$.layers.conversation.messages.length-1]?.id,toolCallCount:$.layers.tool.recentCalls.length});return v5.createHash("md5").update(W).digest("hex")}calculateRelevance($,W){let Q=$.toLowerCase(),Z=0;for(let V of W)if(Q.includes(V.toLowerCase())||V.toLowerCase().includes(Q))Z+=1;return Z}}class E4{chatService;contextManager;memoryAdapter;constructor($,W){this.chatService=$,this.contextManager=W||new h1,this.memoryAdapter=this.createMemoryAdapter()}createMemoryAdapter(){let $=[];return{getMessages:()=>[...$],addMessage:(W)=>{$.push(W)},clearContext:()=>{$.length=0},getContextSize:()=>$.length}}getContextManager(){return this.contextManager}getMemoryAdapter(){return this.memoryAdapter}async executeTask($){let W=[{role:"user",content:$.prompt}],Q=await this.chatService.chat(W);return{taskId:$.id,content:Q.content,metadata:{taskType:$.type}}}}var y5=M("Agent");class C4{getChatService;constructor($){this.getChatService=$}async processStreamResponse($,W,Q){let Z=this.getChatService(),V="",X="",Y,J=new Map;try{let G=Z.streamChat($,W,Q?.signal),B=0;for await(let K of G){if(B++,Q?.signal?.aborted)break;if(K.content){let q=K.content.length;V+=K.content,k$("processStreamResponse","onContentDelta BEFORE",{chunkLen:q,accumulatedLen:V.length}),Q?.onContentDelta?.(K.content),k$("processStreamResponse","onContentDelta AFTER",{chunkLen:q,accumulatedLen:V.length})}if(K.reasoningContent)X+=K.reasoningContent,Q?.onThinkingDelta?.(K.reasoningContent);if(K.usage)Y=K.usage;if(K.toolCalls)for(let q of K.toolCalls)this.accumulateToolCall(J,q);if(K.finishReason){k$("processStreamResponse","finishReason received",{finishReason:K.finishReason,fullContentLen:V.length,fullReasoningContentLen:X.length,toolCallAccumulatorSize:J.size});break}}if(k$("processStreamResponse","stream ended",{fullContentLen:V.length,fullReasoningContentLen:X.length,toolCallAccumulatorSize:J.size}),B===0&&!Q?.signal?.aborted&&V.length===0&&J.size===0)return y5.warn("[Agent] 流式响应返回0个chunk,回退到非流式模式"),Z.chat($,W,Q?.signal);return{content:V,reasoningContent:X||void 0,toolCalls:this.buildFinalToolCalls(J),usage:Y}}catch(G){if(this.isStreamingNotSupportedError(G))return y5.warn("[Agent] 流式请求失败,降级到非流式模式"),Z.chat($,W,Q?.signal);throw G}}accumulateToolCall($,W){let Q=W,Z=Q.index??0;if(!$.has(Z))$.set(Z,{id:Q.id||"",name:Q.function?.name||"",arguments:""});let V=$.get(Z);if(Q.id&&!V.id)V.id=Q.id;if(Q.function?.name&&!V.name)V.name=Q.function.name;if(Q.function?.arguments)V.arguments+=Q.function.arguments}buildFinalToolCalls($){if($.size===0)return;return Array.from($.values()).filter((W)=>W.id&&W.name).map((W)=>({id:W.id,type:"function",function:{name:W.name,arguments:W.arguments}}))}isStreamingNotSupportedError($){if(!($ instanceof Error))return!1;return["stream not supported","streaming is not available","sse not supported","does not support streaming"].some((Q)=>$.message.toLowerCase().includes(Q.toLowerCase()))}}function OW($){if(typeof $==="string")return $;try{return JSON.parse(JSON.stringify($))}catch{return String($)}}var _=M("Agent");class I${config;runtimeOptions;isInitialized=!1;activeTask;executionPipeline;chatService;executionEngine;attachmentHandler;streamHandler;compactionHandler;activeSkillContext;currentModelMaxContextTokens;currentModelId;constructor($,W={},Q){this.config=$,this.runtimeOptions=W,this.executionPipeline=Q||this.createDefaultPipeline()}createDefaultPipeline(){let $=new o0,W={...this.config.permissions,...this.runtimeOptions.permissions},Q=this.runtimeOptions.permissionMode??"default";return new P1($,{permissionConfig:W,permissionMode:Q,maxHistorySize:1000})}resolveModelConfig($){let W=$&&$!=="inherit"?$:void 0,Q=this.config.models||[],Z=this.config.currentModelId,V=W?Q.find((X)=>X.id===W):Q.find((X)=>X.id===Z)||Q[0];if(!V)throw Error(`❌ 模型配置未找到: ${W??"current"}`);return V}async applyModelConfig($,W){this.log(`${W} ${$.name} (${$.model})`);let Q=N5($),Z=$.thinkingEnabled??!1,V=Q&&Z;if(Q&&!Z)this.log("\uD83E\uDDE0 模型支持 Thinking,但用户未开启(按 Tab 开启)");else if(V)this.log("\uD83E\uDDE0 Thinking 模式已启用,启用 reasoning_content 支持");let X=$.maxTokens??128000;this.currentModelMaxContextTokens=X,this.chatService=await B1({provider:$.provider,apiKey:$.apiKey||"",model:$.model,baseUrl:$.baseUrl||"",temperature:$.temperature??this.config.temperature,maxContextTokens:this.currentModelMaxContextTokens,supportsThinking:V});let Y=this.executionEngine?.getContextManager();this.executionEngine=new E4(this.chatService,Y),this.currentModelId=$.id}async switchModelIfNeeded($){if(!$||$===this.currentModelId)return;let Q=(this.config.models||[]).find((Z)=>Z.id===$);if(!Q){this.log(`⚠️ 模型配置未找到: ${$}`);return}await this.applyModelConfig(Q,"\uD83D\uDD01 切换模型")}static async create($,W={}){if(($.models||[]).length===0)throw Error(`❌ 没有可用的模型配置
1820
+ `).filter((Z)=>Z.trim().length>0),Q=[];for(let Z of W)try{Q.push(JSON.parse(Z))}catch(V){console.warn(`[JSONLStore] 解析 JSON 行失败: ${Z}`,V)}return Q}catch($){return console.error(`[JSONLStore] 读取文件失败: ${this.filePath}`,$),[]}}async readStream($){return new Promise((W,Q)=>{if(!x1.existsSync(this.filePath)){W();return}let Z=UW(this.filePath,"utf-8"),V=FW({input:Z,crlfDelay:Number.POSITIVE_INFINITY});V.on("line",async(X)=>{let Y=X.trim();if(Y.length===0)return;try{let J=JSON.parse(Y);await $(J)}catch(J){console.warn(`[JSONLStore] 解析 JSON 行失败: ${Y}`,J)}}),V.on("close",()=>W()),V.on("error",Q),Z.on("error",Q)})}async filter($){let W=[];return await this.readStream((Q)=>{if($(Q))W.push(Q)}),W}async readLast($){return(await this.readAll()).slice(-$)}async getStats(){try{if(!x1.existsSync(this.filePath))return{exists:!1,size:0,lineCount:0};let $=await $$.stat(this.filePath),Q=(await $$.readFile(this.filePath,"utf-8")).split(`
1821
+ `).filter((Z)=>Z.trim().length>0).length;return{exists:!0,size:$.size,lineCount:Q}}catch($){return console.error(`[JSONLStore] 获取统计信息失败: ${this.filePath}`,$),{exists:!1,size:0,lineCount:0}}}async exists(){try{return await $$.access(this.filePath),!0}catch{return!1}}async delete(){try{if(await this.exists())await $$.unlink(this.filePath)}catch($){throw console.error(`[JSONLStore] 删除文件失败: ${this.filePath}`,$),$}}getFilePath(){return this.filePath}}class R4{projectPath;maxSessions;version;constructor($=process.cwd(),W=100,Q="0.0.10"){this.projectPath=$,this.maxSessions=W,this.version=Q}createEvent($,W,Q){return{id:y$(),sessionId:W,timestamp:new Date().toISOString(),type:$,cwd:this.projectPath,gitBranch:N8(this.projectPath),version:this.version,data:Q}}async ensureSessionCreated($,W){let Q=K$(this.projectPath,$),Z=new X$(Q);if((await Z.getStats()).lineCount>0)return;let X=new Date().toISOString(),Y={sessionId:$,rootId:W?.parentSessionId??$,parentId:W?.parentSessionId,relationType:W?"subagent":void 0,title:void 0,status:"running",agentType:W?.subagentType,model:void 0,permission:void 0,createdAt:X,updatedAt:X},J=this.createEvent("session_created",$,Y);await Z.append(J)}buildCompactionMetadata($){let W={trigger:$.trigger,preTokens:$.preTokens};if($.postTokens!==void 0)W.postTokens=$.postTokens;if($.filesIncluded)W.filesIncluded=$.filesIncluded;return W}async initialize(){try{let $=u0(this.projectPath);await f$.mkdir($,{recursive:!0,mode:493}),console.log(`[PersistentStore] 初始化存储目录: ${$}`)}catch($){console.warn("[PersistentStore] 无法创建持久化存储目录:",$)}}async saveMessage($,W,Q,Z=null,V,X){try{let Y=K$(this.projectPath,$),J=new X$(Y);await this.ensureSessionCreated($,X);let G=new Date().toISOString(),K=y$(),B={messageId:K,role:W,parentMessageId:Z??void 0,createdAt:G,model:V?.model,usage:V?.usage},q=this.createEvent("message_created",$,B),w={partId:y$(),messageId:K,partType:"text",payload:{text:Q},createdAt:G},O=this.createEvent("part_created",$,w);return await J.appendBatch([q,O]),K}catch(Y){throw console.error(`[PersistentStore] 保存消息失败 (session: ${$}):`,Y),Y}}async saveToolUse($,W,Q,Z=null,V){try{let X=K$(this.projectPath,$),Y=new X$(X);await this.ensureSessionCreated($,V);let J=new Date().toISOString(),G=Z??y$(),K=[];if(!Z){let w={messageId:G,role:"assistant",parentMessageId:void 0,createdAt:J};K.push(this.createEvent("message_created",$,w))}let B=y$(),q={partId:B,messageId:G,partType:"tool_call",payload:{toolCallId:B,toolName:W,input:Q},createdAt:J};if(K.push(this.createEvent("part_created",$,q)),W==="Task"&&Q&&typeof Q==="object"){let w=Q,O=typeof w.subagent_session_id==="string"?w.subagent_session_id:void 0,H=typeof w.subagent_type==="string"?w.subagent_type:void 0;if(O&&H){let U={partId:y$(),messageId:G,partType:"subtask_ref",payload:{childSessionId:O,agentType:H,status:"running",summary:typeof w.description==="string"?w.description:"",startedAt:J},createdAt:J};K.push(this.createEvent("part_created",$,U))}}return await Y.appendBatch(K),B}catch(X){throw console.error(`[PersistentStore] 保存工具调用失败 (session: ${$}):`,X),X}}async saveToolResult($,W,Q,Z,V=null,X,Y,J){try{let G=K$(this.projectPath,$),K=new X$(G);await this.ensureSessionCreated($,Y);let B=new Date().toISOString(),q=V??y$(),w=[];if(!V){let H={messageId:q,role:"assistant",parentMessageId:void 0,createdAt:B};w.push(this.createEvent("message_created",$,H))}let O={partId:W,messageId:q,partType:"tool_result",payload:{toolCallId:W,toolName:Q,output:Z,error:X??null},createdAt:B};if(w.push(this.createEvent("part_created",$,O)),J){let H=J.subagentStatus==="running"?null:B,U={partId:y$(),messageId:q,partType:"subtask_ref",payload:{childSessionId:J.subagentSessionId,agentType:J.subagentType,status:J.subagentStatus,summary:J.subagentSummary??"",startedAt:B,finishedAt:H},createdAt:B};w.push(this.createEvent("part_created",$,U))}return await K.appendBatch(w),W}catch(G){throw console.error(`[PersistentStore] 保存工具结果失败 (session: ${$}):`,G),G}}async saveCompaction($,W,Q,Z=null){try{let V=K$(this.projectPath,$),X=new X$(V);await this.ensureSessionCreated($);let Y=new Date().toISOString(),J=y$(),G={messageId:J,role:"system",parentMessageId:Z??void 0,createdAt:Y},K=this.buildCompactionMetadata(Q),B={partId:y$(),messageId:J,partType:"summary",payload:{text:W,metadata:K},createdAt:Y},q=[this.createEvent("message_created",$,G),this.createEvent("part_created",$,B)];return await X.appendBatch(q),J}catch(V){throw console.error(`[PersistentStore] 保存压缩失败 (session: ${$}):`,V),V}}async saveContext($,W){try{let{conversation:Q}=W.layers;for(let Z of Q.messages)await this.saveMessage($,Z.role,Z.content,null)}catch(Q){console.warn(`[PersistentStore] 保存上下文失败 (session: ${$}):`,Q)}}async saveSession($,W){console.warn("[PersistentStore] saveSession 方法已废弃,请使用 saveMessage")}async saveConversation($,W){console.warn("[PersistentStore] saveConversation 方法已废弃,请使用 saveMessage")}async loadSession($){try{let W=K$(this.projectPath,$),Z=await new X$(W).readAll();if(Z.length===0)return null;let V=Z.find((X)=>X.type==="session_created");return{sessionId:$,userId:void 0,preferences:{},configuration:{},startTime:new Date(V?.timestamp??Z[0].timestamp).getTime()}}catch{return null}}async loadConversation($){try{let W=K$(this.projectPath,$),Z=await new X$(W).readAll();if(Z.length===0)return null;let V=new Map;for(let G of Z){if(G.type==="message_created")V.set(G.data.messageId,{id:G.data.messageId,role:G.data.role,content:"",timestamp:new Date(G.timestamp).getTime()});if(G.type==="part_created"&&G.data.partType==="text"){let K=V.get(G.data.messageId);if(K){let B=G.data.payload;K.content=B.text??""}}}let X=Array.from(V.values()),Y=Z[Z.length-1],J=new Date(Y.timestamp).getTime();return{messages:X,topics:[],lastActivity:J}}catch{return null}}async listSessions(){try{let $=u0(this.projectPath);return(await f$.readdir($)).filter((Q)=>Q.endsWith(".jsonl")).map((Q)=>Q.replace(".jsonl","")).sort()}catch{return[]}}async getSessionSummary($){try{let W=K$(this.projectPath,$),Q=new X$(W);if(!(await Q.getStats()).exists)return null;let V=await Q.readAll();if(V.length===0)return null;let X=V[V.length-1],Y=V.filter((J)=>J.type==="message_created"&&["user","assistant"].includes(J.data.role)).length;return{sessionId:$,lastActivity:new Date(X.timestamp).getTime(),messageCount:Y,topics:[]}}catch{return null}}async deleteSession($){try{let W=K$(this.projectPath,$);await new X$(W).delete()}catch(W){console.warn(`[PersistentStore] 删除会话失败 (session: ${$}):`,W)}}async cleanupOldSessions(){try{let $=await this.listSessions();if($.length<=this.maxSessions)return;let Z=(await Promise.all($.map((V)=>this.getSessionSummary(V)))).filter((V)=>V!==null).sort((V,X)=>X.lastActivity-V.lastActivity).slice(this.maxSessions).map((V)=>V.sessionId);await Promise.all(Z.map((V)=>this.deleteSession(V))),console.log(`[PersistentStore] 已清理 ${Z.length} 个旧会话`)}catch($){console.error("[PersistentStore] 清理旧会话失败:",$)}}async getStorageStats(){try{let $=await this.listSessions(),W=0;for(let Q of $){let Z=K$(this.projectPath,Q),X=await new X$(Z).getStats();W+=X.size}return{totalSessions:$.length,totalSize:W,projectPath:this.projectPath}}catch{return{totalSessions:0,totalSize:0,projectPath:this.projectPath}}}async checkStorageHealth(){try{let $=u0(this.projectPath);await f$.mkdir($,{recursive:!0,mode:493});let W=M5.join($,".health-check");return await f$.writeFile(W,"test","utf-8"),await f$.unlink(W),{isAvailable:!0,canWrite:!0}}catch($){return{isAvailable:!1,canWrite:!1,error:$ instanceof Error?$.message:String($)}}}static async listAllProjects(){return z8()}}class h1{memory;persistent;cache;compressor;filter;options;currentSessionId=null;initialized=!1;constructor($={}){let W=$.storage?.persistentPath||d0();this.options={storage:{maxMemorySize:1000,persistentPath:W,cacheSize:100,compressionEnabled:!0,...$.storage},defaultFilter:{maxTokens:32000,maxMessages:50,timeWindow:86400000,...$.defaultFilter},compressionThreshold:$.compressionThreshold||6000,enableVectorSearch:$.enableVectorSearch||!1},this.memory=new N4(this.options.storage.maxMemorySize),this.persistent=new R4(process.cwd(),100),this.cache=new j4(this.options.storage.cacheSize,300000),this.compressor=new L4,this.filter=new q0(this.options.defaultFilter)}async initialize(){if(this.initialized)return;try{if(await this.persistent.initialize(),!(await this.persistent.checkStorageHealth()).isAvailable)console.warn("警告:持久化存储不可用,将仅使用内存存储");this.initialized=!0,console.log("上下文管理器初始化完成")}catch($){throw console.error("上下文管理器初始化失败:",$),$}}async createSession($,W={},Q={}){let Z=Q.sessionId||this.generateSessionId(),V=Date.now(),X={layers:{system:await this.createSystemContext(),session:{sessionId:Z,userId:$,preferences:W,configuration:Q,startTime:V},conversation:{messages:[],topics:[],lastActivity:V},tool:{recentCalls:[],toolStates:{},dependencies:{}},workspace:await this.createWorkspaceContext()},metadata:{totalTokens:0,priority:1,lastUpdated:V}};return this.memory.setContext(X),await this.persistent.saveContext(Z,X),this.currentSessionId=Z,console.log(`新会话已创建: ${Z}`),Z}async loadSession($){try{let W=this.memory.getContext();if(!W||W.layers.session.sessionId!==$){let[Q,Z]=await Promise.all([this.persistent.loadSession($),this.persistent.loadConversation($)]);if(!Q||!Z)return!1;W={layers:{system:await this.createSystemContext(),session:Q,conversation:Z,tool:{recentCalls:[],toolStates:{},dependencies:{}},workspace:await this.createWorkspaceContext()},metadata:{totalTokens:0,priority:1,lastUpdated:Date.now()}},this.memory.setContext(W)}return this.currentSessionId=$,console.log(`会话已加载: ${$}`),!0}catch(W){return console.error("加载会话失败:",W),!1}}async addMessage($,W,Q){if(!this.currentSessionId)throw Error("没有活动会话");let Z={id:this.generateMessageId(),role:$,content:W,timestamp:Date.now(),metadata:Q};this.memory.addMessage(Z);let V=this.memory.getContext();if(V&&this.shouldCompress(V))await this.compressCurrentContext();this.saveCurrentSessionAsync()}async addToolCall($){if(!this.currentSessionId)throw Error("没有活动会话");if(this.memory.addToolCall($),$.status==="success"&&$.output)this.cache.cacheToolResult($.name,$.input,$.output);this.saveCurrentSessionAsync()}async saveMessage($,W,Q,Z=null,V,X){return this.persistent.saveMessage($,W,Q,Z,V,X)}async saveToolUse($,W,Q,Z=null,V){return this.persistent.saveToolUse($,W,Q,Z,V)}async saveToolResult($,W,Q,Z,V=null,X,Y,J){return this.persistent.saveToolResult($,W,Q,Z,V,X,Y,J)}async saveCompaction($,W,Q,Z=null){return this.persistent.saveCompaction($,W,Q,Z)}updateToolState($,W){if(!this.currentSessionId)throw Error("没有活动会话");this.memory.updateToolState($,W)}updateWorkspace($){if(!this.currentSessionId)throw Error("没有活动会话");this.memory.updateWorkspace($)}async getFormattedContext($){let W=this.memory.getContext();if(!W)throw Error("没有可用的上下文数据");let Q=this.filter.filter(W,$),Z=this.shouldCompress(Q),V;if(Z){let X=this.hashContext(Q);if(V=this.cache.getCompressedContext(X)??void 0,!V)V=await this.compressor.compress(Q),this.cache.cacheCompressedContext(X,V)}return{context:Q,compressed:V,tokenCount:V?V.tokenCount:Q.metadata.totalTokens}}async searchSessions($,W=10){let Q=await this.persistent.listSessions(),Z=[];for(let V of Q){let X=await this.persistent.getSessionSummary(V);if(X){let Y=this.calculateRelevance($,X.topics);if(Y>0)Z.push({sessionId:V,summary:`${X.messageCount}条消息,主题:${X.topics.join("、")}`,lastActivity:X.lastActivity,relevanceScore:Y})}}return Z.sort((V,X)=>X.relevanceScore-V.relevanceScore).slice(0,W)}getCachedToolResult($,W){return this.cache.getToolResult($,W)}async getStats(){let[$,W,Q]=await Promise.all([Promise.resolve(this.memory.getMemoryInfo()),Promise.resolve(this.cache.getStats()),this.persistent.getStorageStats()]);return{currentSession:this.currentSessionId,memory:$,cache:W,storage:Q}}async cleanup(){if(this.currentSessionId)await this.saveCurrentSession();this.memory.clear(),this.cache.clear(),await this.persistent.cleanupOldSessions(),this.currentSessionId=null,console.log("上下文管理器资源清理完成")}generateSessionId(){return S5()}generateMessageId(){return S5()}async createSystemContext(){return{role:"AI助手",capabilities:["对话","工具调用","代码生成","文档分析"],tools:["文件操作","Git操作","代码分析"],version:"1.0.0"}}async createWorkspaceContext(){try{let $=process.cwd();return{projectPath:$,currentFiles:[],recentFiles:[],environment:{nodeVersion:process.version,platform:process.platform,cwd:$}}}catch($){return{currentFiles:[],recentFiles:[],environment:{}}}}shouldCompress($){return $.metadata.totalTokens>this.options.compressionThreshold}async compressCurrentContext(){let $=this.memory.getContext();if(!$)return;let W=await this.compressor.compress($);$.layers.conversation.summary=W.summary,this.memory.setContext($)}async saveCurrentSession(){if(!this.currentSessionId)return;let $=this.memory.getContext();if($)await this.persistent.saveContext(this.currentSessionId,$)}saveCurrentSessionAsync(){this.saveCurrentSession().catch(($)=>{console.warn("异步保存会话失败:",$)})}hashContext($){let W=JSON.stringify({messageCount:$.layers.conversation.messages.length,lastMessage:$.layers.conversation.messages[$.layers.conversation.messages.length-1]?.id,toolCallCount:$.layers.tool.recentCalls.length});return v5.createHash("md5").update(W).digest("hex")}calculateRelevance($,W){let Q=$.toLowerCase(),Z=0;for(let V of W)if(Q.includes(V.toLowerCase())||V.toLowerCase().includes(Q))Z+=1;return Z}}class E4{chatService;contextManager;memoryAdapter;constructor($,W){this.chatService=$,this.contextManager=W||new h1,this.memoryAdapter=this.createMemoryAdapter()}createMemoryAdapter(){let $=[];return{getMessages:()=>[...$],addMessage:(W)=>{$.push(W)},clearContext:()=>{$.length=0},getContextSize:()=>$.length}}getContextManager(){return this.contextManager}getMemoryAdapter(){return this.memoryAdapter}async executeTask($){let W=[{role:"user",content:$.prompt}],Q=await this.chatService.chat(W);return{taskId:$.id,content:Q.content,metadata:{taskType:$.type}}}}var y5=M("Agent");class C4{getChatService;constructor($){this.getChatService=$}async processStreamResponse($,W,Q){let Z=this.getChatService(),V="",X="",Y,J=new Map;try{let G=Z.streamChat($,W,Q?.signal),K=0;for await(let B of G){if(K++,Q?.signal?.aborted)break;if(B.content){let q=B.content.length;V+=B.content,P$("processStreamResponse","onContentDelta BEFORE",{chunkLen:q,accumulatedLen:V.length}),Q?.onContentDelta?.(B.content),P$("processStreamResponse","onContentDelta AFTER",{chunkLen:q,accumulatedLen:V.length})}if(B.reasoningContent)X+=B.reasoningContent,Q?.onThinkingDelta?.(B.reasoningContent);if(B.usage)Y=B.usage;if(B.toolCalls)for(let q of B.toolCalls)this.accumulateToolCall(J,q);if(B.finishReason){P$("processStreamResponse","finishReason received",{finishReason:B.finishReason,fullContentLen:V.length,fullReasoningContentLen:X.length,toolCallAccumulatorSize:J.size});break}}if(P$("processStreamResponse","stream ended",{fullContentLen:V.length,fullReasoningContentLen:X.length,toolCallAccumulatorSize:J.size}),K===0&&!Q?.signal?.aborted&&V.length===0&&J.size===0)return y5.warn("[Agent] 流式响应返回0个chunk,回退到非流式模式"),Z.chat($,W,Q?.signal);return{content:V,reasoningContent:X||void 0,toolCalls:this.buildFinalToolCalls(J),usage:Y}}catch(G){if(this.isStreamingNotSupportedError(G))return y5.warn("[Agent] 流式请求失败,降级到非流式模式"),Z.chat($,W,Q?.signal);throw G}}accumulateToolCall($,W){let Q=W,Z=Q.index??0;if(!$.has(Z))$.set(Z,{id:Q.id||"",name:Q.function?.name||"",arguments:""});let V=$.get(Z);if(Q.id&&!V.id)V.id=Q.id;if(Q.function?.name&&!V.name)V.name=Q.function.name;if(Q.function?.arguments)V.arguments+=Q.function.arguments}buildFinalToolCalls($){if($.size===0)return;return Array.from($.values()).filter((W)=>W.id&&W.name).map((W)=>({id:W.id,type:"function",function:{name:W.name,arguments:W.arguments}}))}isStreamingNotSupportedError($){if(!($ instanceof Error))return!1;return["stream not supported","streaming is not available","sse not supported","does not support streaming"].some((Q)=>$.message.toLowerCase().includes(Q.toLowerCase()))}}function AW($){if(typeof $==="string")return $;try{return JSON.parse(JSON.stringify($))}catch{return String($)}}var _=M("Agent");class k${config;runtimeOptions;isInitialized=!1;activeTask;executionPipeline;chatService;executionEngine;attachmentHandler;streamHandler;compactionHandler;activeSkillContext;currentModelMaxContextTokens;currentModelId;constructor($,W={},Q){this.config=$,this.runtimeOptions=W,this.executionPipeline=Q||this.createDefaultPipeline()}createDefaultPipeline(){let $=new s0,W={...this.config.permissions,...this.runtimeOptions.permissions},Q=this.runtimeOptions.permissionMode??"default";return new P1($,{permissionConfig:W,permissionMode:Q,maxHistorySize:1000})}resolveModelConfig($){let W=$&&$!=="inherit"?$:void 0,Q=this.config.models||[],Z=this.config.currentModelId,V=W?Q.find((X)=>X.id===W):Q.find((X)=>X.id===Z)||Q[0];if(!V)throw Error(`❌ 模型配置未找到: ${W??"current"}`);return V}async applyModelConfig($,W){this.log(`${W} ${$.name} (${$.model})`);let Q=z5($),Z=$.thinkingEnabled??!1,V=Q&&Z;if(Q&&!Z)this.log("\uD83E\uDDE0 模型支持 Thinking,但用户未开启(按 Tab 开启)");else if(V)this.log("\uD83E\uDDE0 Thinking 模式已启用,启用 reasoning_content 支持");let X=$.maxTokens??128000;this.currentModelMaxContextTokens=X,this.chatService=await G1({provider:$.provider,apiKey:$.apiKey||"",model:$.model,baseUrl:$.baseUrl||"",temperature:$.temperature??this.config.temperature,maxContextTokens:this.currentModelMaxContextTokens,supportsThinking:V});let Y=this.executionEngine?.getContextManager();this.executionEngine=new E4(this.chatService,Y),this.currentModelId=$.id}async switchModelIfNeeded($){if(!$||$===this.currentModelId)return;let Q=(this.config.models||[]).find((Z)=>Z.id===$);if(!Q){this.log(`⚠️ 模型配置未找到: ${$}`);return}await this.applyModelConfig(Q,"\uD83D\uDD01 切换模型")}static async create($,W={}){if(($.models||[]).length===0)throw Error(`❌ 没有可用的模型配置
1816
1822
 
1817
1823
  `+`请先使用以下命令添加模型:
1818
1824
  `+` /model add
1819
1825
 
1820
1826
  `+`或运行初始化向导:
1821
- `+" /init");let Z=new I$($,W);if(await Z.initialize(),W.toolWhitelist&&W.toolWhitelist.length>0)Z.applyToolWhitelist(W.toolWhitelist);return Z}async initialize(){if(this.isInitialized)return;try{this.log("初始化Agent..."),await this.initializeSystemPrompt(),await this.registerBuiltinTools(),await this.loadSubagents(),await this.discoverSkills();let $=this.resolveModelConfig(this.runtimeOptions.modelId);await this.applyModelConfig($,"\uD83D\uDE80 使用模型:"),this.attachmentHandler=new D4(process.cwd()),this.streamHandler=new C4(()=>this.chatService),this.compactionHandler=new _4(()=>this.chatService,()=>this.executionEngine?.getContextManager()),this.isInitialized=!0,this.log(`Agent初始化完成,已加载 ${this.executionPipeline.getRegistry().getAll().length} 个工具`)}catch($){throw this.error("Agent初始化失败",$),$}}async executeTask($){if(!this.isInitialized)throw Error("Agent未初始化");this.activeTask=$;try{this.log(`开始执行任务: ${$.id}`);let W=await this.executionEngine.executeTask($);return this.activeTask=void 0,this.log(`任务执行完成: ${$.id}`),W}catch(W){throw this.activeTask=void 0,this.error(`任务执行失败: ${$.id}`,W),W}}async chat($,W,Q){if(!this.isInitialized)throw Error("Agent未初始化");let Z=this.attachmentHandler?await this.attachmentHandler.processAtMentionsForContent($):$;if(W){let J={signal:W.signal,...Q},G;if(W.permissionMode==="plan")G=await this.runPlanLoop(Z,W,J);else G=await this.runLoop(Z,W,J);if(!G.success){if(G.error?.type==="aborted"||G.metadata?.shouldExitLoop)return"";throw Error(G.error?.message||"执行失败")}if(G.metadata?.targetMode&&W.permissionMode==="plan"){let B=G.metadata.targetMode,K=G.metadata.planContent;_.debug(`\uD83D\uDD04 Plan 模式已批准,切换到 ${B} 模式并重新执行`);let q={...W,permissionMode:B},w=Z;if(K){let O=`
1827
+ `+" /init");let Z=new k$($,W);if(await Z.initialize(),W.toolWhitelist&&W.toolWhitelist.length>0)Z.applyToolWhitelist(W.toolWhitelist);return Z}async initialize(){if(this.isInitialized)return;try{this.log("初始化Agent..."),await this.initializeSystemPrompt(),await this.registerBuiltinTools(),await this.loadSubagents(),await this.discoverSkills();let $=this.resolveModelConfig(this.runtimeOptions.modelId);await this.applyModelConfig($,"\uD83D\uDE80 使用模型:"),this.attachmentHandler=new b4(process.cwd()),this.streamHandler=new C4(()=>this.chatService),this.compactionHandler=new _4(()=>this.chatService,()=>this.executionEngine?.getContextManager()),this.isInitialized=!0,this.log(`Agent初始化完成,已加载 ${this.executionPipeline.getRegistry().getAll().length} 个工具`)}catch($){throw this.error("Agent初始化失败",$),$}}async executeTask($){if(!this.isInitialized)throw Error("Agent未初始化");this.activeTask=$;try{this.log(`开始执行任务: ${$.id}`);let W=await this.executionEngine.executeTask($);return this.activeTask=void 0,this.log(`任务执行完成: ${$.id}`),W}catch(W){throw this.activeTask=void 0,this.error(`任务执行失败: ${$.id}`,W),W}}async chat($,W,Q){if(!this.isInitialized)throw Error("Agent未初始化");let Z=this.attachmentHandler?await this.attachmentHandler.processAtMentionsForContent($):$;if(W){let J={signal:W.signal,...Q},G;if(W.permissionMode==="plan")G=await this.runPlanLoop(Z,W,J);else G=await this.runLoop(Z,W,J);if(!G.success){if(G.error?.type==="aborted"||G.metadata?.shouldExitLoop)return"";throw Error(G.error?.message||"执行失败")}if(G.metadata?.targetMode&&W.permissionMode==="plan"){let K=G.metadata.targetMode,B=G.metadata.planContent;_.debug(`\uD83D\uDD04 Plan 模式已批准,切换到 ${K} 模式并重新执行`);let q={...W,permissionMode:K},w=Z;if(B){let O=`
1822
1828
 
1823
1829
  <approved-plan>
1824
- ${K}
1830
+ ${B}
1825
1831
  </approved-plan>
1826
1832
 
1827
- IMPORTANT: Execute according to the approved plan above. Follow the steps exactly as specified.`;if(typeof Z==="string")w=Z+O;else w=[...Z,{type:"text",text:O}];_.debug(`\uD83D\uDCCB 已将 plan 内容注入到消息中 (${K.length} 字符)`)}return this.runLoop(w,q,J).then((O)=>{if(!O.success)throw Error(O.error?.message||"执行失败");return O.finalMessage||""})}return G.finalMessage||""}let V=typeof Z==="string"?Z:Z.filter((J)=>J.type==="text").map((J)=>J.text).join(`
1828
- `),X={id:this.generateTaskId(),type:"simple",prompt:V};return(await this.executeTask(X)).content}async runPlanLoop($,W,Q){_.debug("\uD83D\uDD35 Processing Plan mode message...");let{prompt:Z}=await h0({projectPath:process.cwd(),mode:"plan",includeEnvironment:!0,language:this.config.language}),V;if(typeof $==="string")V=x0($);else{let X=$.filter((Y)=>Y.type==="text");if(X.length>0){let Y=X[0];V=$.map((J)=>J===Y?{type:"text",text:x0(Y.text)}:J)}else V=[{type:"text",text:x0("")},...$]}return this.executeLoop(V,W,Q,Z)}async runLoop($,W,Q){_.debug("\uD83D\uDCAC Processing enhanced chat message...");let Z=W.systemPrompt??await this.buildSystemPromptOnDemand(),V=_1(),X=Z?`${V}
1833
+ IMPORTANT: Execute according to the approved plan above. Follow the steps exactly as specified.`;if(typeof Z==="string")w=Z+O;else w=[...Z,{type:"text",text:O}];_.debug(`\uD83D\uDCCB 已将 plan 内容注入到消息中 (${B.length} 字符)`)}return this.runLoop(w,q,J).then((O)=>{if(!O.success)throw Error(O.error?.message||"执行失败");return O.finalMessage||""})}return G.finalMessage||""}let V=typeof Z==="string"?Z:Z.filter((J)=>J.type==="text").map((J)=>J.text).join(`
1834
+ `),X={id:this.generateTaskId(),type:"simple",prompt:V};return(await this.executeTask(X)).content}async runPlanLoop($,W,Q){_.debug("\uD83D\uDD35 Processing Plan mode message...");let{prompt:Z}=await h0({projectPath:process.cwd(),mode:"plan",includeEnvironment:!0,language:this.config.language}),V;if(typeof $==="string")V=x0($);else{let X=$.filter((Y)=>Y.type==="text");if(X.length>0){let Y=X[0];V=$.map((J)=>J===Y?{type:"text",text:x0(Y.text)}:J)}else V=[{type:"text",text:x0("")},...$]}return this.executeLoop(V,W,Q,Z)}async runLoop($,W,Q){_.debug("\uD83D\uDCAC Processing enhanced chat message...");let Z=W.systemPrompt??await this.buildSystemPromptOnDemand(),V=b1(),X=Z?`${V}
1829
1835
 
1830
1836
  ---
1831
1837
 
1832
- ${Z}`:V;return this.executeLoop($,W,Q,X)}async buildSystemPromptOnDemand(){let $=this.runtimeOptions.systemPrompt,W=this.runtimeOptions.appendSystemPrompt;return(await h0({projectPath:process.cwd(),replaceDefault:$,append:W,includeEnvironment:!1,language:this.config.language})).prompt}async executeLoop($,W,Q,Z){if(!this.isInitialized)throw Error("Agent未初始化");let V=Date.now();try{let X=this.executionPipeline.getRegistry(),Y=W.permissionMode,J=X.getFunctionDeclarationsByMode(Y);J=D1(J);let G=this.applySkillToolRestrictions(J);if(Y==="plan"){let z=X.getReadOnlyTools();_.debug(`\uD83D\uDD12 Plan mode: 使用只读工具 (${z.length} 个): ${z.map((y)=>y.name).join(", ")}`)}let K=W.messages.length===0||!W.messages.some((z)=>z.role==="system"),q=[];if(K&&Z)q.push({role:"system",content:[{type:"text",text:Z,providerOptions:{anthropic:{cacheControl:{type:"ephemeral"}}}}]});q.push(...W.messages,{role:"user",content:$});let w=null;try{let z=this.executionEngine?.getContextManager(),y=typeof $==="string"?$:$.filter((l)=>l.type==="text").map((l)=>l.text).join(`
1833
- `);if(z&&W.sessionId&&y.trim()!=="")w=await z.saveMessage(W.sessionId,"user",y,null,void 0,W.subagentInfo);else if(y.trim()==="")_.debug("[Agent] 跳过保存空用户消息")}catch(z){_.warn("[Agent] 保存用户消息失败:",z)}let O=100,b=W.permissionMode==="yolo",U=this.runtimeOptions.maxTurns??Q?.maxTurns??this.config.maxTurns??-1;if(U===0)return{success:!1,error:{type:"chat_disabled",message:`对话功能已被禁用 (maxTurns=0)。如需启用,请调整配置:
1838
+ ${Z}`:V;return this.executeLoop($,W,Q,X)}async buildSystemPromptOnDemand(){let $=this.runtimeOptions.systemPrompt,W=this.runtimeOptions.appendSystemPrompt;return(await h0({projectPath:process.cwd(),replaceDefault:$,append:W,includeEnvironment:!1,language:this.config.language})).prompt}async executeLoop($,W,Q,Z){if(!this.isInitialized)throw Error("Agent未初始化");let V=Date.now();try{let X=this.executionPipeline.getRegistry(),Y=W.permissionMode,J=X.getFunctionDeclarationsByMode(Y);J=D1(J);let G=this.applySkillToolRestrictions(J);if(Y==="plan"){let N=X.getReadOnlyTools();_.debug(`\uD83D\uDD12 Plan mode: 使用只读工具 (${N.length} 个): ${N.map((y)=>y.name).join(", ")}`)}let B=W.messages.length===0||!W.messages.some((N)=>N.role==="system"),q=[];if(B&&Z)q.push({role:"system",content:[{type:"text",text:Z,providerOptions:{anthropic:{cacheControl:{type:"ephemeral"}}}}]});q.push(...W.messages,{role:"user",content:$});let w=null;try{let N=this.executionEngine?.getContextManager(),y=typeof $==="string"?$:$.filter((i)=>i.type==="text").map((i)=>i.text).join(`
1839
+ `);if(N&&W.sessionId&&y.trim()!=="")w=await N.saveMessage(W.sessionId,"user",y,null,void 0,W.subagentInfo);else if(y.trim()==="")_.debug("[Agent] 跳过保存空用户消息")}catch(N){_.warn("[Agent] 保存用户消息失败:",N)}let O=100,H=W.permissionMode==="yolo",U=this.runtimeOptions.maxTurns??Q?.maxTurns??this.config.maxTurns??-1;if(U===0)return{success:!1,error:{type:"chat_disabled",message:`对话功能已被禁用 (maxTurns=0)。如需启用,请调整配置:
1834
1840
  `+` • CLI 参数: blade --max-turns -1
1835
1841
  `+` • 配置文件: ~/.blade/config.json 中设置 "maxTurns": -1
1836
- `+" • 环境变量: export BLADE_MAX_TURNS=-1"},metadata:{turnsCount:0,toolCallsCount:0,duration:0}};let F=U===-1?O:Math.min(U,O);if(this.config.debug)_.debug(`[MaxTurns] runtimeOptions: ${this.runtimeOptions.maxTurns}, options: ${Q?.maxTurns}, config: ${this.config.maxTurns}, 最终: ${U} → ${F}, YOLO: ${b}`);let A=0,D=[],N=0,C;while(!0){if(Q?.signal?.aborted)return{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:A,toolCallsCount:D.length,duration:Date.now()-V}};let z=W.messages.length;if(this.compactionHandler?await this.compactionHandler.checkAndCompactInLoop(W,A,C,Q?.onCompacting):!1){_.debug(`[Agent] [轮次 ${A}] 检测到压缩发生,重建 messages 数组 (${z} → ${W.messages.length} 条历史消息)`);let R=K&&Z?1:0,L=R+z,v=q.slice(0,R),a=q.slice(L);q.length=0,q.push(...v,...W.messages,...a),_.debug(`[Agent] [轮次 ${A}] messages 重建完成: ${v.length} system + ${W.messages.length} 历史 + ${a.length} 新增 = ${q.length} 总计`)}if(A++,_.debug(`\uD83D\uDD04 [轮次 ${A}/${F}] 调用 LLM...`),Q?.signal?.aborted)return{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:A-1,toolCallsCount:D.length,duration:Date.now()-V}};Q?.onTurnStart?.({turn:A,maxTurns:F}),_.debug(`
1837
- ========== 发送给 LLM ==========`),_.debug("轮次:",A+1),_.debug("消息数量:",q.length),_.debug("最后 3 条消息:"),q.slice(-3).forEach((R,L)=>{if(_.debug(` [${L}] ${R.role}:`,typeof R.content==="string"?R.content.substring(0,100)+(R.content.length>100?"...":""):JSON.stringify(R.content).substring(0,100)),R.tool_calls)_.debug(" tool_calls:",R.tool_calls.map((v)=>("function"in v)?v.function.name:v.type).join(", "))}),_.debug("可用工具数量:",G.length),_.debug(`================================
1838
- `);let l=Q?.stream!==!1,j=l&&this.streamHandler?await this.streamHandler.processStreamResponse(q,G,Q):await this.chatService.chat(q,G,Q?.signal);if(k$("executeLoop","after processStreamResponse/chat",{isStreamEnabled:l,turnResultContentLen:j.content?.length??0,turnResultToolCallsLen:j.toolCalls?.length??0,hasReasoningContent:!!j.reasoningContent}),j.usage){if(j.usage.totalTokens)N+=j.usage.totalTokens;if(C=j.usage.promptTokens,_.debug(`[Agent] LLM usage: prompt=${C}, completion=${j.usage.completionTokens}, total=${j.usage.totalTokens}`),Q?.onTokenUsage)Q.onTokenUsage({inputTokens:j.usage.promptTokens??0,outputTokens:j.usage.completionTokens??0,totalTokens:N,maxContextTokens:this.currentModelMaxContextTokens})}if(Q?.signal?.aborted)return{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:A-1,toolCallsCount:D.length,duration:Date.now()-V}};if(_.debug(`
1842
+ `+" • 环境变量: export BLADE_MAX_TURNS=-1"},metadata:{turnsCount:0,toolCallsCount:0,duration:0}};let A=U===-1?O:Math.min(U,O);if(this.config.debug)_.debug(`[MaxTurns] runtimeOptions: ${this.runtimeOptions.maxTurns}, options: ${Q?.maxTurns}, config: ${this.config.maxTurns}, 最终: ${U} → ${A}, YOLO: ${H}`);let D=0,b=[],z=0,C;while(!0){if(Q?.signal?.aborted)return{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:D,toolCallsCount:b.length,duration:Date.now()-V}};let N=W.messages.length;if(this.compactionHandler?await this.compactionHandler.checkAndCompactInLoop(W,D,C,Q?.onCompacting):!1){_.debug(`[Agent] [轮次 ${D}] 检测到压缩发生,重建 messages 数组 (${N} → ${W.messages.length} 条历史消息)`);let R=B&&Z?1:0,L=R+N,v=q.slice(0,R),n=q.slice(L);q.length=0,q.push(...v,...W.messages,...n),_.debug(`[Agent] [轮次 ${D}] messages 重建完成: ${v.length} system + ${W.messages.length} 历史 + ${n.length} 新增 = ${q.length} 总计`)}if(D++,_.debug(`\uD83D\uDD04 [轮次 ${D}/${A}] 调用 LLM...`),Q?.signal?.aborted)return{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:D-1,toolCallsCount:b.length,duration:Date.now()-V}};Q?.onTurnStart?.({turn:D,maxTurns:A}),_.debug(`
1843
+ ========== 发送给 LLM ==========`),_.debug("轮次:",D+1),_.debug("消息数量:",q.length),_.debug("最后 3 条消息:"),q.slice(-3).forEach((R,L)=>{if(_.debug(` [${L}] ${R.role}:`,typeof R.content==="string"?R.content.substring(0,100)+(R.content.length>100?"...":""):JSON.stringify(R.content).substring(0,100)),R.tool_calls)_.debug(" tool_calls:",R.tool_calls.map((v)=>("function"in v)?v.function.name:v.type).join(", "))}),_.debug("可用工具数量:",G.length),_.debug(`================================
1844
+ `);let i=Q?.stream!==!1,j=i&&this.streamHandler?await this.streamHandler.processStreamResponse(q,G,Q):await this.chatService.chat(q,G,Q?.signal);if(P$("executeLoop","after processStreamResponse/chat",{isStreamEnabled:i,turnResultContentLen:j.content?.length??0,turnResultToolCallsLen:j.toolCalls?.length??0,hasReasoningContent:!!j.reasoningContent}),j.usage){if(j.usage.totalTokens)z+=j.usage.totalTokens;if(C=j.usage.promptTokens,_.debug(`[Agent] LLM usage: prompt=${C}, completion=${j.usage.completionTokens}, total=${j.usage.totalTokens}`),Q?.onTokenUsage)Q.onTokenUsage({inputTokens:j.usage.promptTokens??0,outputTokens:j.usage.completionTokens??0,totalTokens:z,maxContextTokens:this.currentModelMaxContextTokens})}if(Q?.signal?.aborted)return{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:D-1,toolCallsCount:b.length,duration:Date.now()-V}};if(_.debug(`
1839
1845
  ========== LLM 返回 ==========`),_.debug("Content:",j.content),_.debug("Tool Calls:",JSON.stringify(j.toolCalls,null,2)),_.debug("当前权限模式:",W.permissionMode),_.debug(`================================
1840
- `),j.reasoningContent&&Q?.onThinking&&!Q.signal?.aborted)Q.onThinking(j.reasoningContent);if(j.content&&j.content.trim()&&!Q?.signal?.aborted){if(l)k$("executeLoop","calling onStreamEnd (stream mode)",{contentLen:j.content.length}),Q?.onStreamEnd?.();else if(Q?.onContent)k$("executeLoop","calling onContent (non-stream mode)",{contentLen:j.content.length}),Q.onContent(j.content)}if(!j.toolCalls||j.toolCalls.length===0){let R=[/:\s*$/,/:\s*$/,/\.\.\.\s*$/,/让我(先|来|开始|查看|检查|修复)/,/Let me (first|start|check|look|fix)/i],L=j.content||"",v=R.some((k)=>k.test(L)),a="请执行你提到的操作,不要只是描述。",I=q.slice(-10).filter((k)=>k.role==="user"&&k.content==="请执行你提到的操作,不要只是描述。").length;if(v&&I<2){_.debug(`⚠️ 检测到意图未完成(重试 ${I+1}/2): "${L.slice(-50)}"`),q.push({role:"user",content:"请执行你提到的操作,不要只是描述。"});continue}_.debug("✅ 任务完成 - LLM 未请求工具调用");try{let h=await i.getInstance().executeStopHooks({projectDir:process.cwd(),sessionId:W.sessionId,permissionMode:W.permissionMode,reason:j.content,abortSignal:Q?.signal});if(!h.shouldStop){_.debug(`\uD83D\uDD04 Stop hook 阻止停止,继续执行: ${h.continueReason||"(无原因)"}`);let W$=h.continueReason?`
1846
+ `),j.reasoningContent&&Q?.onThinking&&!Q.signal?.aborted)Q.onThinking(j.reasoningContent);if(j.content&&j.content.trim()&&!Q?.signal?.aborted){if(i)P$("executeLoop","calling onStreamEnd (stream mode)",{contentLen:j.content.length}),Q?.onStreamEnd?.();else if(Q?.onContent)P$("executeLoop","calling onContent (non-stream mode)",{contentLen:j.content.length}),Q.onContent(j.content)}if(!j.toolCalls||j.toolCalls.length===0){let R=[/:\s*$/,/:\s*$/,/\.\.\.\s*$/,/让我(先|来|开始|查看|检查|修复)/,/Let me (first|start|check|look|fix)/i],L=j.content||"",v=R.some((k)=>k.test(L)),n="请执行你提到的操作,不要只是描述。",I=q.slice(-10).filter((k)=>k.role==="user"&&k.content==="请执行你提到的操作,不要只是描述。").length;if(v&&I<2){_.debug(`⚠️ 检测到意图未完成(重试 ${I+1}/2): "${L.slice(-50)}"`),q.push({role:"user",content:"请执行你提到的操作,不要只是描述。"});continue}_.debug("✅ 任务完成 - LLM 未请求工具调用");try{let h=await a.getInstance().executeStopHooks({projectDir:process.cwd(),sessionId:W.sessionId,permissionMode:W.permissionMode,reason:j.content,abortSignal:Q?.signal});if(!h.shouldStop){_.debug(`\uD83D\uDD04 Stop hook 阻止停止,继续执行: ${h.continueReason||"(无原因)"}`);let W$=h.continueReason?`
1841
1847
 
1842
1848
  <system-reminder>
1843
1849
  ${h.continueReason}
@@ -1845,14 +1851,14 @@ ${h.continueReason}
1845
1851
 
1846
1852
  <system-reminder>
1847
1853
  Please continue the conversation from where we left it off without asking the user any further questions. Continue with the last task that you were asked to work on.
1848
- </system-reminder>`;q.push({role:"user",content:W$});continue}if(h.warning)_.warn(`[Agent] Stop hook warning: ${h.warning}`)}catch(k){_.warn("[Agent] Stop hook execution failed:",k)}try{let k=this.executionEngine?.getContextManager();if(k&&W.sessionId&&j.content)if(j.content.trim()!=="")w=await k.saveMessage(W.sessionId,"assistant",j.content,w,void 0,W.subagentInfo);else _.debug("[Agent] 跳过保存空响应(任务完成时)")}catch(k){_.warn("[Agent] 保存助手消息失败:",k)}return{success:!0,finalMessage:j.content,metadata:{turnsCount:A,toolCallsCount:D.length,duration:Date.now()-V,tokensUsed:N}}}q.push({role:"assistant",content:j.content||"",reasoningContent:j.reasoningContent,tool_calls:j.toolCalls});try{let R=this.executionEngine?.getContextManager();if(R&&W.sessionId&&j.content)if(j.content.trim()!=="")w=await R.saveMessage(W.sessionId,"assistant",j.content,w,void 0,W.subagentInfo);else _.debug("[Agent] 跳过保存空响应(工具调用时)")}catch(R){_.warn("[Agent] 保存助手工具调用消息失败:",R)}if(Q?.signal?.aborted)return _.info("[Agent] Aborting before tool execution due to signal.aborted=true"),{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:A,toolCallsCount:D.length,duration:Date.now()-V}};let d=j.toolCalls.filter((R)=>R.type==="function");if(Q?.onToolStart&&!Q.signal?.aborted)for(let R of d){let v=this.executionPipeline.getRegistry().get(R.function.name)?.kind;Q.onToolStart(R,v)}let N$=async(R)=>{try{let L=JSON.parse(R.function.arguments);if(R.function.name==="Task"&&(typeof L.subagent_session_id!=="string"||L.subagent_session_id.length===0))L.subagent_session_id=typeof L.resume==="string"&&L.resume.length>0?L.resume:wW();if(L.todos&&typeof L.todos==="string")try{L.todos=JSON.parse(L.todos),this.log("[Agent] 自动修复了字符串化的 todos 参数")}catch{this.error("[Agent] todos 参数格式异常,将由验证层处理")}let v=null;try{let k=this.executionEngine?.getContextManager();if(k&&W.sessionId)v=await k.saveToolUse(W.sessionId,R.function.name,L,w,W.subagentInfo)}catch(k){_.warn("[Agent] 保存工具调用失败:",k)}let a=Q?.signal;if(!a)_.error("[Agent] Missing signal in tool execution, this should not happen");_.debug("[Agent] Passing confirmationHandler to ExecutionPipeline.execute:",{toolName:R.function.name,hasHandler:!!W.confirmationHandler,hasMethod:!!W.confirmationHandler?.requestConfirmation,methodType:typeof W.confirmationHandler?.requestConfirmation});let I=await this.executionPipeline.execute(R.function.name,L,{sessionId:W.sessionId,userId:W.userId||"default",workspaceRoot:W.workspaceRoot||process.cwd(),signal:a,confirmationHandler:W.confirmationHandler,permissionMode:W.permissionMode});if(_.debug(`
1854
+ </system-reminder>`;q.push({role:"user",content:W$});continue}if(h.warning)_.warn(`[Agent] Stop hook warning: ${h.warning}`)}catch(k){_.warn("[Agent] Stop hook execution failed:",k)}try{let k=this.executionEngine?.getContextManager();if(k&&W.sessionId&&j.content)if(j.content.trim()!=="")w=await k.saveMessage(W.sessionId,"assistant",j.content,w,void 0,W.subagentInfo);else _.debug("[Agent] 跳过保存空响应(任务完成时)")}catch(k){_.warn("[Agent] 保存助手消息失败:",k)}return{success:!0,finalMessage:j.content,metadata:{turnsCount:D,toolCallsCount:b.length,duration:Date.now()-V,tokensUsed:z}}}q.push({role:"assistant",content:j.content||"",reasoningContent:j.reasoningContent,tool_calls:j.toolCalls});try{let R=this.executionEngine?.getContextManager();if(R&&W.sessionId&&j.content)if(j.content.trim()!=="")w=await R.saveMessage(W.sessionId,"assistant",j.content,w,void 0,W.subagentInfo);else _.debug("[Agent] 跳过保存空响应(工具调用时)")}catch(R){_.warn("[Agent] 保存助手工具调用消息失败:",R)}if(Q?.signal?.aborted)return _.info("[Agent] Aborting before tool execution due to signal.aborted=true"),{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:D,toolCallsCount:b.length,duration:Date.now()-V}};let d=j.toolCalls.filter((R)=>R.type==="function");if(Q?.onToolStart&&!Q.signal?.aborted)for(let R of d){let v=this.executionPipeline.getRegistry().get(R.function.name)?.kind;Q.onToolStart(R,v)}let z$=async(R)=>{try{let L=JSON.parse(R.function.arguments);if(R.function.name==="Task"&&(typeof L.subagent_session_id!=="string"||L.subagent_session_id.length===0))L.subagent_session_id=typeof L.resume==="string"&&L.resume.length>0?L.resume:HW();if(L.todos&&typeof L.todos==="string")try{L.todos=JSON.parse(L.todos),this.log("[Agent] 自动修复了字符串化的 todos 参数")}catch{this.error("[Agent] todos 参数格式异常,将由验证层处理")}let v=null;try{let k=this.executionEngine?.getContextManager();if(k&&W.sessionId)v=await k.saveToolUse(W.sessionId,R.function.name,L,w,W.subagentInfo)}catch(k){_.warn("[Agent] 保存工具调用失败:",k)}let n=Q?.signal;if(!n)_.error("[Agent] Missing signal in tool execution, this should not happen");_.debug("[Agent] Passing confirmationHandler to ExecutionPipeline.execute:",{toolName:R.function.name,hasHandler:!!W.confirmationHandler,hasMethod:!!W.confirmationHandler?.requestConfirmation,methodType:typeof W.confirmationHandler?.requestConfirmation});let I=await this.executionPipeline.execute(R.function.name,L,{sessionId:W.sessionId,userId:W.userId||"default",workspaceRoot:W.workspaceRoot||process.cwd(),signal:n,confirmationHandler:W.confirmationHandler,permissionMode:W.permissionMode});if(_.debug(`
1849
1855
  ========== 工具执行结果 ==========`),_.debug("工具名称:",R.function.name),_.debug("成功:",I.success),_.debug("LLM Content:",I.llmContent),_.debug("Display Content:",I.displayContent),I.error)_.debug("错误:",I.error);return _.debug(`==================================
1850
- `),{toolCall:R,result:I,toolUseUuid:v}}catch(L){return _.error(`Tool execution failed for ${R.function.name}:`,L),{toolCall:R,result:{success:!1,llmContent:"",displayContent:"",error:{type:"execution_error",message:L instanceof Error?L.message:"Unknown error"}},toolUseUuid:null,error:L instanceof Error?L:Error("Unknown error")}}};_.info(`[Agent] Executing ${d.length} tool calls in parallel`);let R$=await Promise.all(d.map(N$));for(let{toolCall:R,result:L,toolUseUuid:v}of R$){if(D.push(L),L.metadata?.shouldExitLoop){_.debug("\uD83D\uDEAA 检测到退出循环标记,结束 Agent 循环");let h=typeof L.llmContent==="string"?L.llmContent:"循环已退出";return{success:L.success,finalMessage:h,metadata:{turnsCount:A,toolCallsCount:D.length,duration:Date.now()-V,shouldExitLoop:!0,targetMode:L.metadata?.targetMode}}}if(Q?.onToolResult&&!Q.signal?.aborted){_.debug("[Agent] Calling onToolResult:",{toolName:R.function.name,hasCallback:!0,resultSuccess:L.success,resultKeys:Object.keys(L),hasMetadata:!!L.metadata,metadataKeys:L.metadata?Object.keys(L.metadata):[],hasSummary:!!L.metadata?.summary,summary:L.metadata?.summary});try{await Q.onToolResult(R,L),_.debug("[Agent] onToolResult callback completed successfully")}catch(h){_.error("[Agent] onToolResult callback error:",h)}}try{let h=this.executionEngine?.getContextManager();if(h&&W.sessionId){let W$=L.metadata&&typeof L.metadata==="object"?L.metadata:void 0,d1=((W1)=>W1==="running"||W1==="completed"||W1==="failed"||W1==="cancelled")(W$?.subagentStatus)?W$.subagentStatus:"completed",m1=W$&&typeof W$.subagentSessionId==="string"?{subagentSessionId:W$.subagentSessionId,subagentType:typeof W$.subagentType==="string"?W$.subagentType:R.function.name,subagentStatus:d1,subagentSummary:typeof W$.subagentSummary==="string"?W$.subagentSummary:void 0}:void 0;w=await h.saveToolResult(W.sessionId,R.id,R.function.name,L.success?OW(L.llmContent):null,v,L.success?void 0:L.error?.message,W.subagentInfo,m1)}}catch(h){_.warn("[Agent] 保存工具结果失败:",h)}if(R.function.name==="TodoWrite"&&L.success&&L.llmContent){let h=typeof L.llmContent==="object"?L.llmContent:{},u1=Array.isArray(h)?h:h.todos||[];Q?.onTodoUpdate?.(u1)}if(R.function.name==="Skill"&&L.success&&L.metadata){let h=L.metadata;if(h.skillName)this.activeSkillContext={skillName:h.skillName,allowedTools:h.allowedTools,basePath:h.basePath||""},_.debug(`\uD83C\uDFAF Skill "${this.activeSkillContext.skillName}" activated`+(this.activeSkillContext.allowedTools?` with allowed tools: ${this.activeSkillContext.allowedTools.join(", ")}`:""))}let a=L.metadata?.modelId?.trim()||L.metadata?.model?.trim()||void 0;if(a)await this.switchModelIfNeeded(a);let I=L.success?L.llmContent||L.displayContent||"":L.error?.message||"执行失败";if(typeof I==="object"&&I!==null)I=JSON.stringify(I,null,2);let k=typeof I==="string"?I:JSON.stringify(I);q.push({role:"tool",tool_call_id:R.id,name:R.function.name,content:k})}if(Q?.signal?.aborted)return{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:A,toolCallsCount:D.length,duration:Date.now()-V}};if(A>=F&&!b){if(_.info(`⚠️ 达到轮次上限 ${F} 轮,等待用户确认...`),Q?.onTurnLimitReached){let R=await Q.onTurnLimitReached({turnsCount:A});if(R?.continue){_.info("✅ 用户选择继续,压缩上下文...");try{let L=this.chatService.getConfig(),v=await t.compact(W.messages,{trigger:"auto",modelName:L.model,maxContextTokens:L.maxContextTokens??128000,apiKey:L.apiKey,baseURL:L.baseUrl,actualPreTokens:C});W.messages=v.compactedMessages;let a=q.find((k)=>k.role==="system");if(q.length=0,a)q.push(a);q.push(...W.messages);let I={role:"user",content:`This session is being continued from a previous conversation. The conversation is summarized above.
1856
+ `),{toolCall:R,result:I,toolUseUuid:v}}catch(L){return _.error(`Tool execution failed for ${R.function.name}:`,L),{toolCall:R,result:{success:!1,llmContent:"",displayContent:"",error:{type:"execution_error",message:L instanceof Error?L.message:"Unknown error"}},toolUseUuid:null,error:L instanceof Error?L:Error("Unknown error")}}};_.info(`[Agent] Executing ${d.length} tool calls in parallel`);let R$=await Promise.all(d.map(z$));for(let{toolCall:R,result:L,toolUseUuid:v}of R$){if(b.push(L),L.metadata?.shouldExitLoop){_.debug("\uD83D\uDEAA 检测到退出循环标记,结束 Agent 循环");let h=typeof L.llmContent==="string"?L.llmContent:"循环已退出";return{success:L.success,finalMessage:h,metadata:{turnsCount:D,toolCallsCount:b.length,duration:Date.now()-V,shouldExitLoop:!0,targetMode:L.metadata?.targetMode}}}if(Q?.onToolResult&&!Q.signal?.aborted){_.debug("[Agent] Calling onToolResult:",{toolName:R.function.name,hasCallback:!0,resultSuccess:L.success,resultKeys:Object.keys(L),hasMetadata:!!L.metadata,metadataKeys:L.metadata?Object.keys(L.metadata):[],hasSummary:!!L.metadata?.summary,summary:L.metadata?.summary});try{await Q.onToolResult(R,L),_.debug("[Agent] onToolResult callback completed successfully")}catch(h){_.error("[Agent] onToolResult callback error:",h)}}try{let h=this.executionEngine?.getContextManager();if(h&&W.sessionId){let W$=L.metadata&&typeof L.metadata==="object"?L.metadata:void 0,d1=(($1)=>$1==="running"||$1==="completed"||$1==="failed"||$1==="cancelled")(W$?.subagentStatus)?W$.subagentStatus:"completed",m1=W$&&typeof W$.subagentSessionId==="string"?{subagentSessionId:W$.subagentSessionId,subagentType:typeof W$.subagentType==="string"?W$.subagentType:R.function.name,subagentStatus:d1,subagentSummary:typeof W$.subagentSummary==="string"?W$.subagentSummary:void 0}:void 0;w=await h.saveToolResult(W.sessionId,R.id,R.function.name,L.success?AW(L.llmContent):null,v,L.success?void 0:L.error?.message,W.subagentInfo,m1)}}catch(h){_.warn("[Agent] 保存工具结果失败:",h)}if(R.function.name==="TodoWrite"&&L.success&&L.llmContent){let h=typeof L.llmContent==="object"?L.llmContent:{},u1=Array.isArray(h)?h:h.todos||[];Q?.onTodoUpdate?.(u1)}if(R.function.name==="Skill"&&L.success&&L.metadata){let h=L.metadata;if(h.skillName)this.activeSkillContext={skillName:h.skillName,allowedTools:h.allowedTools,basePath:h.basePath||""},_.debug(`\uD83C\uDFAF Skill "${this.activeSkillContext.skillName}" activated`+(this.activeSkillContext.allowedTools?` with allowed tools: ${this.activeSkillContext.allowedTools.join(", ")}`:""))}let n=L.metadata?.modelId?.trim()||L.metadata?.model?.trim()||void 0;if(n)await this.switchModelIfNeeded(n);let I=L.success?L.llmContent||L.displayContent||"":L.error?.message||"执行失败";if(typeof I==="object"&&I!==null)I=JSON.stringify(I,null,2);let k=typeof I==="string"?I:JSON.stringify(I);q.push({role:"tool",tool_call_id:R.id,name:R.function.name,content:k})}if(Q?.signal?.aborted)return{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:D,toolCallsCount:b.length,duration:Date.now()-V}};if(D>=A&&!H){if(_.info(`⚠️ 达到轮次上限 ${A} 轮,等待用户确认...`),Q?.onTurnLimitReached){let R=await Q.onTurnLimitReached({turnsCount:D});if(R?.continue){_.info("✅ 用户选择继续,压缩上下文...");try{let L=this.chatService.getConfig(),v=await t.compact(W.messages,{trigger:"auto",modelName:L.model,maxContextTokens:L.maxContextTokens??128000,apiKey:L.apiKey,baseURL:L.baseUrl,actualPreTokens:C});W.messages=v.compactedMessages;let n=q.find((k)=>k.role==="system");if(q.length=0,n)q.push(n);q.push(...W.messages);let I={role:"user",content:`This session is being continued from a previous conversation. The conversation is summarized above.
1851
1857
 
1852
- Please continue the conversation from where we left it off without asking the user any further questions. Continue with the last task that you were asked to work on.`};q.push(I),W.messages.push(I);try{let k=this.executionEngine?.getContextManager();if(k&&W.sessionId)await k.saveCompaction(W.sessionId,v.summary,{trigger:"auto",preTokens:v.preTokens,postTokens:v.postTokens,filesIncluded:v.filesIncluded},null)}catch(k){_.warn("[Agent] 保存压缩数据失败:",k)}_.info(`✅ 上下文已压缩 (${v.preTokens} → ${v.postTokens} tokens),重置轮次计数`)}catch(L){_.error("[Agent] 压缩失败,使用降级策略:",L);let v=q.find((I)=>I.role==="system"),a=q.slice(-80);if(q.length=0,v&&!a.some((I)=>I.role==="system"))q.push(v);q.push(...a),W.messages=q.filter((I)=>I.role!=="system"),_.warn(`⚠️ 降级压缩完成,保留 ${q.length} 条消息`)}A=0;continue}return{success:!0,finalMessage:R?.reason||"已达到对话轮次上限,用户选择停止",metadata:{turnsCount:A,toolCallsCount:D.length,duration:Date.now()-V,tokensUsed:N}}}return{success:!1,error:{type:"max_turns_exceeded",message:`已达到轮次上限 (${F} 轮)。使用 --permission-mode yolo 跳过此限制。`},metadata:{turnsCount:A,toolCallsCount:D.length,duration:Date.now()-V,tokensUsed:N}}}}}catch(X){if(X instanceof Error&&(X.name==="AbortError"||X.message.includes("aborted")))return{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:0,toolCallsCount:0,duration:Date.now()-V}};return _.error("Enhanced chat processing error:",X),{success:!1,error:{type:"api_error",message:`处理消息时发生错误: ${X instanceof Error?X.message:"未知错误"}`,details:X},metadata:{turnsCount:0,toolCallsCount:0,duration:Date.now()-V}}}}async runAgenticLoop($,W,Q){if(!this.isInitialized)throw Error("Agent未初始化");let Z={messages:W.messages,userId:W.userId||"subagent",sessionId:W.sessionId||`subagent_${Date.now()}`,workspaceRoot:W.workspaceRoot||process.cwd(),signal:W.signal,confirmationHandler:W.confirmationHandler,permissionMode:W.permissionMode,systemPrompt:W.systemPrompt,subagentInfo:W.subagentInfo};return await this.runLoop($,Z,Q)}async chatWithSystem($,W){if(!this.isInitialized)throw Error("Agent未初始化");let Q=[{role:"system",content:$},{role:"user",content:W}];return(await this.chatService.chat(Q)).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.executionPipeline?this.executionPipeline.getRegistry().getAll():[]}getToolRegistry(){return this.executionPipeline.getRegistry()}applyToolWhitelist($){let W=this.executionPipeline.getRegistry(),Z=W.getAll().filter((V)=>!$.includes(V.name));for(let V of Z)W.unregister(V.name);_.debug(`\uD83D\uDD12 Applied tool whitelist: ${$.join(", ")} (removed ${Z.length} tools)`)}getToolStats(){let $=this.getAvailableTools(),W=new Map;return $.forEach((Q)=>{let Z=W.get(Q.kind)||0;W.set(Q.kind,Z+1)}),{totalTools:$.length,toolsByKind:Object.fromEntries(W),toolNames:$.map((Q)=>Q.name)}}async destroy(){this.log("销毁Agent...");try{this.isInitialized=!1,this.log("Agent已销毁")}catch($){throw this.error("Agent销毁失败",$),$}}generateTaskId(){return`task_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}log($,W){_.debug(`[MainAgent] ${$}`,W||"")}error($,W){_.error(`[MainAgent] ${$}`,W||"")}async initializeSystemPrompt(){try{let $=this.runtimeOptions.systemPrompt,W=this.runtimeOptions.appendSystemPrompt,Q=await h0({projectPath:process.cwd(),replaceDefault:$,append:W,includeEnvironment:!1,language:this.config.language});if(Q.prompt)this.log("系统提示配置验证成功"),_.debug(`[SystemPrompt] 可用来源: ${Q.sources.filter((Z)=>Z.loaded).map((Z)=>Z.name).join(", ")}`)}catch($){this.error("系统提示配置验证失败",$)}}async getSystemPrompt(){return this.buildSystemPromptOnDemand()}async registerBuiltinTools(){try{let $=await G4({sessionId:"default",configDir:P5.join(T5.homedir(),".blade")});_.debug(`\uD83D\uDCE6 Registering ${$.length} builtin tools...`),this.executionPipeline.getRegistry().registerAll($);let W=this.executionPipeline.getRegistry().getAll().length;_.debug(`✅ Builtin tools registered: ${W} tools`),_.debug(`[Tools] ${this.executionPipeline.getRegistry().getAll().map((Q)=>Q.name).join(", ")}`),await this.registerMcpTools()}catch($){throw _.error("Failed to register builtin tools:",$),$}}async registerMcpTools(){try{let $=this.config.mcpServers||{};if(Object.keys($).length===0){_.debug("\uD83D\uDCE6 No MCP servers configured");return}let W=E$.getInstance();for(let[Z,V]of Object.entries($)){if(V.disabled){_.debug(`⏭️ MCP server "${Z}" is disabled, skipping`);continue}try{_.debug(`\uD83D\uDD0C Connecting to MCP server: ${Z}`),await W.registerServer(Z,V),_.debug(`✅ MCP server "${Z}" connected`)}catch(X){_.warn(`⚠️ MCP server "${Z}" connection failed:`,X)}}let Q=await W.getAvailableTools();if(Q.length>0)this.executionPipeline.getRegistry().registerAll(Q),_.debug(`✅ Registered ${Q.length} MCP tools`),_.debug(`[MCP Tools] ${Q.map((Z)=>Z.name).join(", ")}`)}catch($){_.warn("Failed to register MCP tools:",$)}}async loadSubagents(){if(L$.getAllNames().length>0){_.debug(`\uD83D\uDCE6 Subagents already loaded: ${L$.getAllNames().join(", ")}`);return}try{let $=L$.loadFromStandardLocations();if($>0)_.debug(`✅ Loaded ${$} subagents: ${L$.getAllNames().join(", ")}`);else _.debug("\uD83D\uDCE6 No subagents configured")}catch($){_.warn("Failed to load subagents:",$)}}async discoverSkills(){try{let $=await A1({cwd:process.cwd()});if($.skills.length>0)_.debug(`✅ Discovered ${$.skills.length} skills: ${$.skills.map((W)=>W.name).join(", ")}`);else _.debug("\uD83D\uDCE6 No skills configured");for(let W of $.errors)_.warn(`⚠️ Skill loading error at ${W.path}: ${W.error}`)}catch($){_.warn("Failed to discover skills:",$)}}applySkillToolRestrictions($){if(!this.activeSkillContext?.allowedTools)return $;let W=this.activeSkillContext.allowedTools;_.debug(`\uD83D\uDD12 Applying Skill tool restrictions: ${W.join(", ")}`);let Q=$.filter((Z)=>{return W.some((V)=>{if(V===Z.name)return!0;let X=V.match(/^(\w+)\(.*\)$/);if(X&&X[1]===Z.name)return!0;return!1})});return _.debug(`\uD83D\uDD12 Filtered tools: ${Q.map((Z)=>Z.name).join(", ")} (${Q.length}/${$.length})`),Q}clearSkillContext(){if(this.activeSkillContext)_.debug(`\uD83C\uDFAF Skill "${this.activeSkillContext.skillName}" deactivated`),this.activeSkillContext=void 0}}import{execSync as UW}from"node:child_process";import k5 from"node:fs";import I5 from"node:path";class t0{async execute($,W){let Q=$.content;if(W.signal?.aborted)throw Error("Command execution aborted");return Q=this.interpolateArgs(Q,W.args),Q=await this.executeBashEmbeds(Q,W),Q=await this.resolveFileReferences(Q,W.workspaceRoot),Q}interpolateArgs($,W){$=$.replace(/\$ARGUMENTS/g,W.join(" "));for(let Q=9;Q>=1;Q--){let Z=`$${Q}`,V=W[Q-1]??"";$=$.split(Z).join(V)}return $}async executeBashEmbeds($,W){let Q=/!`([^`]+)`/g,Z=[];for(let X of $.matchAll(Q))Z.push({match:X[0],command:X[1]});let V=$;for(let{match:X,command:Y}of Z){if(W.signal?.aborted){V=V.replace(X,"[Execution aborted]");continue}try{let J=UW(Y,{cwd:W.workspaceRoot,encoding:"utf-8",timeout:30000,maxBuffer:1048576,stdio:["pipe","pipe","pipe"]}).trim();V=V.replace(X,J)}catch(J){let G=J instanceof Error?J.message:String(J);V=V.replace(X,`[Error executing '${Y}': ${G}]`)}}return V}async resolveFileReferences($,W){let Q=/@([\w./-]+(?:\/[\w./-]+|\.[\w]+))/g,Z=[];for(let X of $.matchAll(Q))Z.push({match:X[0],relativePath:X[1]});let V=$;for(let{match:X,relativePath:Y}of Z){let J=I5.resolve(W,Y);try{if(k5.statSync(J).isFile()){let B=k5.readFileSync(J,"utf-8"),q=`\`\`\`${I5.extname(Y).slice(1)||"text"}
1853
- ${B}
1854
- \`\`\``;V=V.replace(X,q)}}catch{}}return V}hasDynamicContent($){return{hasArgs:/\$ARGUMENTS|\$\d/.test($),hasBashEmbeds:/!`[^`]+`/.test($),hasFileRefs:/@[\w./-]+(?:\/[\w./-]+|\.[\w]+)/.test($)}}}import M4 from"node:fs";import x5 from"node:os";import h$ from"node:path";import HW from"node:fs";import f5 from"node:path";import bW from"gray-matter";class e0{parse($,W,Q,Z){try{let V=HW.readFileSync($,"utf-8"),{data:X,content:Y}=bW(V),{name:J,namespace:G}=this.extractNameAndNamespace($,W);if(!J)return null;return{name:J,namespace:G,config:this.normalizeConfig(X),content:Y.trim(),path:$,source:Q,sourceDir:Z}}catch{return null}}normalizeConfig($){return{description:this.asString($.description),allowedTools:this.parseAllowedTools($["allowed-tools"]),argumentHint:this.asString($["argument-hint"]),model:this.asString($.model),disableModelInvocation:$["disable-model-invocation"]===!0}}asString($){if(typeof $==="string"&&$.trim())return $.trim();return}parseAllowedTools($){if(!$)return;if(Array.isArray($))return $.map((W)=>String(W).trim()).filter(Boolean);if(typeof $==="string")return $.split(",").map((W)=>W.trim()).filter(Boolean);return}extractNameAndNamespace($,W){let Z=f5.relative(W,$).split(f5.sep),V=Z.pop();if(!V)return{name:""};let X=V.replace(/\.md$/i,""),Y=Z.length>0?Z.join("/"):void 0;return{name:X,namespace:Y}}validateConfig($){let W=[];if($.model&&!this.isValidModelId($.model))W.push(`Invalid model ID: ${$.model}`);return W}isValidModelId($){return $.length>0&&$.length<200}}class $1{parser=new e0;async discover($){let W=[],Q=[],Z=[],V=this.getSearchDirs($);for(let X of V){if(!M4.existsSync(X.path))continue;Q.push(X.path);try{let Y=await this.scanDirectory(X.path);for(let J of Y)try{let G=this.parser.parse(J,X.path,X.source,X.sourceDir);if(G)W.push(G)}catch(G){Z.push({path:J,error:G instanceof Error?G.message:String(G)})}}catch(Y){Z.push({path:X.path,error:Y instanceof Error?Y.message:String(Y)})}}return{commands:W,scannedDirs:Q,errors:Z}}getSearchDirs($){let W=x5.homedir();return[{path:h$.join(W,".blade","commands"),source:"user",sourceDir:"blade"},{path:h$.join(W,".claude","commands"),source:"user",sourceDir:"claude"},{path:h$.join($,".blade","commands"),source:"project",sourceDir:"blade"},{path:h$.join($,".claude","commands"),source:"project",sourceDir:"claude"}]}async scanDirectory($){let W=[],Q=async(Z)=>{let V=await M4.promises.readdir(Z,{withFileTypes:!0});for(let X of V){let Y=h$.join(Z,X.name);if(X.isDirectory())await Q(Y);else if(X.isFile()&&X.name.endsWith(".md"))W.push(Y)}};return await Q($),W}async hasCommands($){let W=this.getSearchDirs($);for(let Q of W){if(!M4.existsSync(Q.path))continue;if((await this.scanDirectory(Q.path)).length>0)return!0}return!1}getCommandDirs($){let W=x5.homedir();return{projectBlade:h$.join($,".blade","commands"),projectClaude:h$.join($,".claude","commands"),userBlade:h$.join(W,".blade","commands"),userClaude:h$.join(W,".claude","commands")}}}class z${static instance;commands=new Map;loader=new $1;executor=new t0;initialized=!1;workspaceRoot="";lastDiscoveryResult=null;static getInstance(){if(!z$.instance)z$.instance=new z$;return z$.instance}static resetInstance(){z$.instance=new z$}constructor(){}async initialize($){this.workspaceRoot=$;let W=await this.loader.discover($);this.lastDiscoveryResult=W,this.commands.clear();for(let Q of W.commands)this.commands.set(Q.name,Q);return this.initialized=!0,W}async refresh(){if(!this.workspaceRoot)throw Error("Registry not initialized. Call initialize() first.");return this.initialize(this.workspaceRoot)}isInitialized(){return this.initialized}getCommand($){return this.commands.get($)}hasCommand($){return this.commands.has($)}getAllCommands(){return Array.from(this.commands.values())}getCommandCount(){return this.commands.size}getModelInvocableCommands(){return this.getAllCommands().filter(($)=>$.config.description&&!$.config.disableModelInvocation)}async executeCommand($,W){let Q=this.getCommand($);if(!Q)return null;return this.executor.execute(Q,W)}getCommandLabel($){let W=$.source==="project"?"project":"user";if($.namespace)return`(${W}:${$.namespace})`;return`(${W})`}getCommandDisplayName($){let W=[`/${$.name}`];if($.config.argumentHint)W.push($.config.argumentHint);if($.config.description)W.push("-",$.config.description);return W.push(this.getCommandLabel($)),W.join(" ")}getCommandsBySource(){let $=[],W=[];for(let Q of this.commands.values())if(Q.source==="project")$.push(Q);else W.push(Q);return{project:$,user:W}}getLastDiscoveryResult(){return this.lastDiscoveryResult}getCommandDirs(){if(!this.workspaceRoot)return null;return this.loader.getCommandDirs(this.workspaceRoot)}generateCommandListDescription($=15000){let W=this.getModelInvocableCommands(),Q=W.length;if(Q===0)return{text:"No custom commands available.",includedCount:0,totalCount:0};let Z=`Available custom commands:
1858
+ Please continue the conversation from where we left it off without asking the user any further questions. Continue with the last task that you were asked to work on.`};q.push(I),W.messages.push(I);try{let k=this.executionEngine?.getContextManager();if(k&&W.sessionId)await k.saveCompaction(W.sessionId,v.summary,{trigger:"auto",preTokens:v.preTokens,postTokens:v.postTokens,filesIncluded:v.filesIncluded},null)}catch(k){_.warn("[Agent] 保存压缩数据失败:",k)}_.info(`✅ 上下文已压缩 (${v.preTokens} → ${v.postTokens} tokens),重置轮次计数`)}catch(L){_.error("[Agent] 压缩失败,使用降级策略:",L);let v=q.find((I)=>I.role==="system"),n=q.slice(-80);if(q.length=0,v&&!n.some((I)=>I.role==="system"))q.push(v);q.push(...n),W.messages=q.filter((I)=>I.role!=="system"),_.warn(`⚠️ 降级压缩完成,保留 ${q.length} 条消息`)}D=0;continue}return{success:!0,finalMessage:R?.reason||"已达到对话轮次上限,用户选择停止",metadata:{turnsCount:D,toolCallsCount:b.length,duration:Date.now()-V,tokensUsed:z}}}return{success:!1,error:{type:"max_turns_exceeded",message:`已达到轮次上限 (${A} 轮)。使用 --permission-mode yolo 跳过此限制。`},metadata:{turnsCount:D,toolCallsCount:b.length,duration:Date.now()-V,tokensUsed:z}}}}}catch(X){if(X instanceof Error&&(X.name==="AbortError"||X.message.includes("aborted")))return{success:!1,error:{type:"aborted",message:"任务已被用户中止"},metadata:{turnsCount:0,toolCallsCount:0,duration:Date.now()-V}};return _.error("Enhanced chat processing error:",X),{success:!1,error:{type:"api_error",message:`处理消息时发生错误: ${X instanceof Error?X.message:"未知错误"}`,details:X},metadata:{turnsCount:0,toolCallsCount:0,duration:Date.now()-V}}}}async runAgenticLoop($,W,Q){if(!this.isInitialized)throw Error("Agent未初始化");let Z={messages:W.messages,userId:W.userId||"subagent",sessionId:W.sessionId||`subagent_${Date.now()}`,workspaceRoot:W.workspaceRoot||process.cwd(),signal:W.signal,confirmationHandler:W.confirmationHandler,permissionMode:W.permissionMode,systemPrompt:W.systemPrompt,subagentInfo:W.subagentInfo};return await this.runLoop($,Z,Q)}async chatWithSystem($,W){if(!this.isInitialized)throw Error("Agent未初始化");let Q=[{role:"system",content:$},{role:"user",content:W}];return(await this.chatService.chat(Q)).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.executionPipeline?this.executionPipeline.getRegistry().getAll():[]}getToolRegistry(){return this.executionPipeline.getRegistry()}applyToolWhitelist($){let W=this.executionPipeline.getRegistry(),Z=W.getAll().filter((V)=>!$.includes(V.name));for(let V of Z)W.unregister(V.name);_.debug(`\uD83D\uDD12 Applied tool whitelist: ${$.join(", ")} (removed ${Z.length} tools)`)}getToolStats(){let $=this.getAvailableTools(),W=new Map;return $.forEach((Q)=>{let Z=W.get(Q.kind)||0;W.set(Q.kind,Z+1)}),{totalTools:$.length,toolsByKind:Object.fromEntries(W),toolNames:$.map((Q)=>Q.name)}}async destroy(){this.log("销毁Agent...");try{this.isInitialized=!1,this.log("Agent已销毁")}catch($){throw this.error("Agent销毁失败",$),$}}generateTaskId(){return`task_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}log($,W){_.debug(`[MainAgent] ${$}`,W||"")}error($,W){_.error(`[MainAgent] ${$}`,W||"")}async initializeSystemPrompt(){try{let $=this.runtimeOptions.systemPrompt,W=this.runtimeOptions.appendSystemPrompt,Q=await h0({projectPath:process.cwd(),replaceDefault:$,append:W,includeEnvironment:!1,language:this.config.language});if(Q.prompt)this.log("系统提示配置验证成功"),_.debug(`[SystemPrompt] 可用来源: ${Q.sources.filter((Z)=>Z.loaded).map((Z)=>Z.name).join(", ")}`)}catch($){this.error("系统提示配置验证失败",$)}}async getSystemPrompt(){return this.buildSystemPromptOnDemand()}async registerBuiltinTools(){try{let $=await G4({sessionId:"default",configDir:P5.join(T5.homedir(),".blade")});_.debug(`\uD83D\uDCE6 Registering ${$.length} builtin tools...`),this.executionPipeline.getRegistry().registerAll($);let W=this.executionPipeline.getRegistry().getAll().length;_.debug(`✅ Builtin tools registered: ${W} tools`),_.debug(`[Tools] ${this.executionPipeline.getRegistry().getAll().map((Q)=>Q.name).join(", ")}`),await this.registerMcpTools()}catch($){throw _.error("Failed to register builtin tools:",$),$}}async registerMcpTools(){try{let $=this.config.mcpServers||{};if(Object.keys($).length===0){_.debug("\uD83D\uDCE6 No MCP servers configured");return}let W=E$.getInstance();for(let[Z,V]of Object.entries($)){if(V.disabled){_.debug(`⏭️ MCP server "${Z}" is disabled, skipping`);continue}try{_.debug(`\uD83D\uDD0C Connecting to MCP server: ${Z}`),await W.registerServer(Z,V),_.debug(`✅ MCP server "${Z}" connected`)}catch(X){_.warn(`⚠️ MCP server "${Z}" connection failed:`,X)}}let Q=await W.getAvailableTools();if(Q.length>0)this.executionPipeline.getRegistry().registerAll(Q),_.debug(`✅ Registered ${Q.length} MCP tools`),_.debug(`[MCP Tools] ${Q.map((Z)=>Z.name).join(", ")}`)}catch($){_.warn("Failed to register MCP tools:",$)}}async loadSubagents(){if(L$.getAllNames().length>0){_.debug(`\uD83D\uDCE6 Subagents already loaded: ${L$.getAllNames().join(", ")}`);return}try{let $=L$.loadFromStandardLocations();if($>0)_.debug(`✅ Loaded ${$} subagents: ${L$.getAllNames().join(", ")}`);else _.debug("\uD83D\uDCE6 No subagents configured")}catch($){_.warn("Failed to load subagents:",$)}}async discoverSkills(){try{let $=await A1({cwd:process.cwd()});if($.skills.length>0)_.debug(`✅ Discovered ${$.skills.length} skills: ${$.skills.map((W)=>W.name).join(", ")}`);else _.debug("\uD83D\uDCE6 No skills configured");for(let W of $.errors)_.warn(`⚠️ Skill loading error at ${W.path}: ${W.error}`)}catch($){_.warn("Failed to discover skills:",$)}}applySkillToolRestrictions($){if(!this.activeSkillContext?.allowedTools)return $;let W=this.activeSkillContext.allowedTools;_.debug(`\uD83D\uDD12 Applying Skill tool restrictions: ${W.join(", ")}`);let Q=$.filter((Z)=>{return W.some((V)=>{if(V===Z.name)return!0;let X=V.match(/^(\w+)\(.*\)$/);if(X&&X[1]===Z.name)return!0;return!1})});return _.debug(`\uD83D\uDD12 Filtered tools: ${Q.map((Z)=>Z.name).join(", ")} (${Q.length}/${$.length})`),Q}clearSkillContext(){if(this.activeSkillContext)_.debug(`\uD83C\uDFAF Skill "${this.activeSkillContext.skillName}" deactivated`),this.activeSkillContext=void 0}}import{execSync as DW}from"node:child_process";import k5 from"node:fs";import I5 from"node:path";class o0{async execute($,W){let Q=$.content;if(W.signal?.aborted)throw Error("Command execution aborted");return Q=this.interpolateArgs(Q,W.args),Q=await this.executeBashEmbeds(Q,W),Q=await this.resolveFileReferences(Q,W.workspaceRoot),Q}interpolateArgs($,W){$=$.replace(/\$ARGUMENTS/g,W.join(" "));for(let Q=9;Q>=1;Q--){let Z=`$${Q}`,V=W[Q-1]??"";$=$.split(Z).join(V)}return $}async executeBashEmbeds($,W){let Q=/!`([^`]+)`/g,Z=[];for(let X of $.matchAll(Q))Z.push({match:X[0],command:X[1]});let V=$;for(let{match:X,command:Y}of Z){if(W.signal?.aborted){V=V.replace(X,"[Execution aborted]");continue}try{let J=DW(Y,{cwd:W.workspaceRoot,encoding:"utf-8",timeout:30000,maxBuffer:1048576,stdio:["pipe","pipe","pipe"]}).trim();V=V.replace(X,J)}catch(J){let G=J instanceof Error?J.message:String(J);V=V.replace(X,`[Error executing '${Y}': ${G}]`)}}return V}async resolveFileReferences($,W){let Q=/@([\w./-]+(?:\/[\w./-]+|\.[\w]+))/g,Z=[];for(let X of $.matchAll(Q))Z.push({match:X[0],relativePath:X[1]});let V=$;for(let{match:X,relativePath:Y}of Z){let J=I5.resolve(W,Y);try{if(k5.statSync(J).isFile()){let K=k5.readFileSync(J,"utf-8"),q=`\`\`\`${I5.extname(Y).slice(1)||"text"}
1859
+ ${K}
1860
+ \`\`\``;V=V.replace(X,q)}}catch{}}return V}hasDynamicContent($){return{hasArgs:/\$ARGUMENTS|\$\d/.test($),hasBashEmbeds:/!`[^`]+`/.test($),hasFileRefs:/@[\w./-]+(?:\/[\w./-]+|\.[\w]+)/.test($)}}}import M4 from"node:fs";import x5 from"node:os";import x$ from"node:path";import bW from"node:fs";import f5 from"node:path";import _W from"gray-matter";class t0{parse($,W,Q,Z){try{let V=bW.readFileSync($,"utf-8"),{data:X,content:Y}=_W(V),{name:J,namespace:G}=this.extractNameAndNamespace($,W);if(!J)return null;return{name:J,namespace:G,config:this.normalizeConfig(X),content:Y.trim(),path:$,source:Q,sourceDir:Z}}catch{return null}}normalizeConfig($){return{description:this.asString($.description),allowedTools:this.parseAllowedTools($["allowed-tools"]),argumentHint:this.asString($["argument-hint"]),model:this.asString($.model),disableModelInvocation:$["disable-model-invocation"]===!0}}asString($){if(typeof $==="string"&&$.trim())return $.trim();return}parseAllowedTools($){if(!$)return;if(Array.isArray($))return $.map((W)=>String(W).trim()).filter(Boolean);if(typeof $==="string")return $.split(",").map((W)=>W.trim()).filter(Boolean);return}extractNameAndNamespace($,W){let Z=f5.relative(W,$).split(f5.sep),V=Z.pop();if(!V)return{name:""};let X=V.replace(/\.md$/i,""),Y=Z.length>0?Z.join("/"):void 0;return{name:X,namespace:Y}}validateConfig($){let W=[];if($.model&&!this.isValidModelId($.model))W.push(`Invalid model ID: ${$.model}`);return W}isValidModelId($){return $.length>0&&$.length<200}}class e0{parser=new t0;async discover($){let W=[],Q=[],Z=[],V=this.getSearchDirs($);for(let X of V){if(!M4.existsSync(X.path))continue;Q.push(X.path);try{let Y=await this.scanDirectory(X.path);for(let J of Y)try{let G=this.parser.parse(J,X.path,X.source,X.sourceDir);if(G)W.push(G)}catch(G){Z.push({path:J,error:G instanceof Error?G.message:String(G)})}}catch(Y){Z.push({path:X.path,error:Y instanceof Error?Y.message:String(Y)})}}return{commands:W,scannedDirs:Q,errors:Z}}getSearchDirs($){let W=x5.homedir();return[{path:x$.join(W,".blade","commands"),source:"user",sourceDir:"blade"},{path:x$.join(W,".claude","commands"),source:"user",sourceDir:"claude"},{path:x$.join($,".blade","commands"),source:"project",sourceDir:"blade"},{path:x$.join($,".claude","commands"),source:"project",sourceDir:"claude"}]}async scanDirectory($){let W=[],Q=async(Z)=>{let V=await M4.promises.readdir(Z,{withFileTypes:!0});for(let X of V){let Y=x$.join(Z,X.name);if(X.isDirectory())await Q(Y);else if(X.isFile()&&X.name.endsWith(".md"))W.push(Y)}};return await Q($),W}async hasCommands($){let W=this.getSearchDirs($);for(let Q of W){if(!M4.existsSync(Q.path))continue;if((await this.scanDirectory(Q.path)).length>0)return!0}return!1}getCommandDirs($){let W=x5.homedir();return{projectBlade:x$.join($,".blade","commands"),projectClaude:x$.join($,".claude","commands"),userBlade:x$.join(W,".blade","commands"),userClaude:x$.join(W,".claude","commands")}}}class N${static instance;commands=new Map;loader=new e0;executor=new o0;initialized=!1;workspaceRoot="";lastDiscoveryResult=null;static getInstance(){if(!N$.instance)N$.instance=new N$;return N$.instance}static resetInstance(){N$.instance=new N$}constructor(){}async initialize($){this.workspaceRoot=$;let W=await this.loader.discover($);this.lastDiscoveryResult=W,this.commands.clear();for(let Q of W.commands)this.commands.set(Q.name,Q);return this.initialized=!0,W}async refresh(){if(!this.workspaceRoot)throw Error("Registry not initialized. Call initialize() first.");return this.initialize(this.workspaceRoot)}isInitialized(){return this.initialized}getCommand($){return this.commands.get($)}hasCommand($){return this.commands.has($)}getAllCommands(){return Array.from(this.commands.values())}getCommandCount(){return this.commands.size}getModelInvocableCommands(){return this.getAllCommands().filter(($)=>$.config.description&&!$.config.disableModelInvocation)}async executeCommand($,W){let Q=this.getCommand($);if(!Q)return null;return this.executor.execute(Q,W)}getCommandLabel($){let W=$.source==="project"?"project":"user";if($.namespace)return`(${W}:${$.namespace})`;return`(${W})`}getCommandDisplayName($){let W=[`/${$.name}`];if($.config.argumentHint)W.push($.config.argumentHint);if($.config.description)W.push("-",$.config.description);return W.push(this.getCommandLabel($)),W.join(" ")}getCommandsBySource(){let $=[],W=[];for(let Q of this.commands.values())if(Q.source==="project")$.push(Q);else W.push(Q);return{project:$,user:W}}getLastDiscoveryResult(){return this.lastDiscoveryResult}getCommandDirs(){if(!this.workspaceRoot)return null;return this.loader.getCommandDirs(this.workspaceRoot)}generateCommandListDescription($=15000){let W=this.getModelInvocableCommands(),Q=W.length;if(Q===0)return{text:"No custom commands available.",includedCount:0,totalCount:0};let Z=`Available custom commands:
1855
1861
 
1856
- `,V=Z.length,X=0;for(let Y of W){let J=this.getCommandLabel(Y),G=Y.config.argumentHint?` ${Y.config.argumentHint}`:"",B=`- /${Y.name}${G}: ${Y.config.description} ${J}
1857
- `;if(V+B.length>$)break;Z+=B,V+=B.length,X++}if(X<Q)Z+=`
1858
- (${X} of ${Q} commands shown due to character budget)`;return{text:Z,includedCount:X,totalCount:Q}}}import{nanoid as FW}from"nanoid";var r$=M("Agent");class p1{sessionId;agent=null;abortController=null;_messages=[];options;maxTurns;permissionMode;initialized=!1;pendingMessage=null;pendingSendOptions=null;constructor($,W){this.sessionId=W||FW(),this.options=$,this.maxTurns=$.maxTurns??200,this.permissionMode=$.permissionMode??"default"}get messages(){return[...this._messages]}async initialize(){if(this.initialized)return;let $=this.buildBladeConfig();this.agent=await I$.create($,{permissionMode:this.permissionMode,systemPrompt:this.options.systemPrompt,maxTurns:this.maxTurns}),this.initialized=!0,r$.debug(`[Session] Initialized session ${this.sessionId}`)}async loadHistory(){let $=this.options.cwd||process.cwd(),W=Y$($,this.sessionId),Q=new X$(W);try{let Z=await Q.readAll();if(Z.length===0){r$.debug(`[Session] No history found for session ${this.sessionId}`);return}let V=new Map,X=new Map;for(let Y of Z){if(Y.type==="message_created"){let J=Y.data;V.set(J.messageId,{role:J.role,content:"",toolCalls:[]})}if(Y.type==="part_created"){let J=Y.data,G=V.get(J.messageId);if(!G)G={role:J.partType==="tool_result"?"tool":"assistant",content:"",toolCalls:[]},V.set(J.messageId,G);switch(J.partType){case"text":{let B=J.payload;G.content=B.text??"";break}case"tool_call":{let B=J.payload,K={id:B.toolCallId,type:"function",function:{name:B.toolName,arguments:typeof B.input==="string"?B.input:JSON.stringify(B.input)}};G.toolCalls.push(K),X.set(B.toolCallId,{messageId:J.messageId,toolCallId:B.toolCallId});break}case"tool_result":{let B=J.payload;if(G.role="tool",G.toolCallId=B.toolCallId,G.name=B.toolName,B.error)G.content=`Error: ${B.error}`;else if(B.output===null||B.output===void 0)G.content="";else if(typeof B.output==="string")G.content=B.output;else G.content=JSON.stringify(B.output);break}case"summary":{let B=J.payload;G.content=B.text??"";break}}}}this._messages=Array.from(V.values()).map((Y)=>{let J={role:Y.role,content:Y.content};if(Y.toolCalls.length>0)J.tool_calls=Y.toolCalls;if(Y.toolCallId)J.tool_call_id=Y.toolCallId;if(Y.name)J.name=Y.name;return J}),r$.debug(`[Session] Loaded ${this._messages.length} messages from history`)}catch(Z){r$.warn(`[Session] Failed to load history for session ${this.sessionId}:`,Z)}}buildBladeConfig(){let $=this.buildModelConfig();return{models:[$],currentModelId:$.id,temperature:0.7,mcpServers:this.options.mcpServers,permissions:{allow:[],deny:[]}}}buildModelConfig(){let $=this.options.provider;return{id:"default",name:this.options.model,provider:this.mapProviderType($.type),model:this.options.model,apiKey:$.apiKey||"",baseUrl:$.baseUrl||this.getDefaultBaseUrl($.type),maxTokens:128000}}mapProviderType($){return{"openai-compatible":"openai-compatible",anthropic:"anthropic",gemini:"gemini","azure-openai":"azure-openai",antigravity:"antigravity",copilot:"copilot"}[$]||"openai-compatible"}getDefaultBaseUrl($){return{"openai-compatible":"https://api.openai.com/v1",anthropic:"https://api.anthropic.com",gemini:"https://generativelanguage.googleapis.com","azure-openai":"",antigravity:"",copilot:""}[$]||""}async send($,W){if(await this.ensureInitialized(),this.pendingMessage!==null)throw Error("Cannot send a new message while a previous message is pending. Call stream() first.");this.pendingMessage=$,this.pendingSendOptions=W||null}async*stream($){if(this.pendingMessage===null)throw Error("No pending message. Call send() before stream().");let W=this.pendingMessage,Q=this.pendingSendOptions;this.pendingMessage=null,this.pendingSendOptions=null;let Z=[],V={inputTokens:0,outputTokens:0,totalTokens:0};this.abortController=new AbortController;let X=Q?.signal?this.combineSignals(Q.signal,this.abortController.signal):this.abortController.signal,Y=[],J=null,G=(O)=>{if(Y.push(O),J)J(),J=null},B={messages:this._messages,userId:"sdk-user",sessionId:this.sessionId,workspaceRoot:this.options.cwd||process.cwd(),signal:X,permissionMode:this.permissionMode},K={maxTurns:Q?.maxTurns??this.maxTurns,signal:X,stream:!0,onTurnStart:(O)=>{G({type:"turn_start",turn:O.turn,sessionId:this.sessionId})},onContentDelta:(O)=>{G({type:"content",delta:O,sessionId:this.sessionId})},onThinkingDelta:$?.includeThinking?(O)=>{G({type:"thinking",delta:O,sessionId:this.sessionId})}:void 0,onToolStart:(O)=>{if(O.type!=="function")return;let b=this.safeParseJson(O.function.arguments);Z.push({id:O.id,name:O.function.name,input:b,output:null,duration:0}),G({type:"tool_use",id:O.id,name:O.function.name,input:b,sessionId:this.sessionId})},onToolResult:async(O,b)=>{if(O.type!=="function")return;let U=Z.find((F)=>F.id===O.id);if(U)U.output=b.llmContent,U.isError=!b.success;G({type:"tool_result",id:O.id,name:O.function.name,output:b.llmContent,isError:!b.success,sessionId:this.sessionId})},onTokenUsage:(O)=>{V={inputTokens:O.inputTokens,outputTokens:O.outputTokens,totalTokens:O.totalTokens}}},q=!1,w=this.agent.chat(W,B,K).then((O)=>{G({type:"usage",usage:V,sessionId:this.sessionId}),this._messages=B.messages,G({type:"result",subtype:"success",content:O,sessionId:this.sessionId})}).catch((O)=>{let b=O instanceof Error?O:Error(String(O));G({type:"error",message:b.message,sessionId:this.sessionId})}).finally(()=>{if(q=!0,J)J()});try{while(!q||Y.length>0){if(Y.length===0&&!q)await new Promise((O)=>{J=O});while(Y.length>0)yield Y.shift()}await w}finally{this.abortController=null}}close(){this.abort(),this.agent=null,this.initialized=!1,this.pendingMessage=null,this.pendingSendOptions=null,r$.debug(`[Session] Closed session ${this.sessionId}`)}abort(){if(this.abortController)this.abortController.abort(),this.abortController=null}setPermissionMode($){this.permissionMode=$}async setModel($){r$.warn("[Session] setModel is not yet implemented")}setMaxTurns($){this.maxTurns=$}async supportedCommands(){let $=z$.getInstance();if(!$.isInitialized())await $.initialize(this.options.cwd||process.cwd());return $.getAllCommands().map((W)=>({name:W.name,description:W.config.description||"",usage:W.config.argumentHint}))}async supportedModels(){return[{id:"default",name:this.options.model,provider:this.options.provider.type}]}async mcpServerStatus(){if(!this.agent)return[];let $=this.options.mcpServers||{},W=[];for(let[Q]of Object.entries($))W.push({name:Q,status:"connected",toolCount:0});return W}async[Symbol.asyncDispose](){this.close()}async ensureInitialized(){if(!this.initialized)await this.initialize()}combineSignals($,W){let Q=new AbortController,Z=()=>Q.abort();if($.aborted||W.aborted)Q.abort();else $.addEventListener("abort",Z),W.addEventListener("abort",Z);return Q.signal}safeParseJson($){try{return JSON.parse($)}catch{return $}}}async function h5($){let W=new p1($);return await W.initialize(),r$.debug(`[Session] Created new session: ${W.sessionId}`),W}async function p5($){let{sessionId:W,...Q}=$,Z=new p1(Q,W);return await Z.initialize(),await Z.loadHistory(),r$.debug(`[Session] Resumed session: ${W} with ${Z.messages.length} messages`),Z}async function u5($,W){let Q=Date.now(),Z=new p1(W);await Z.initialize();let V=[],X={inputTokens:0,outputTokens:0,totalTokens:0},Y=0,J="",G=null;try{await Z.send($);for await(let B of Z.stream())if(B.type==="turn_start")Y=B.turn;else if(B.type==="tool_use")V.push({id:B.id,name:B.name,input:B.input,output:null,duration:0});else if(B.type==="tool_result"){let K=V.find((q)=>q.id===B.id);if(K)K.output=B.output,K.isError=B.isError}else if(B.type==="usage")X=B.usage;else if(B.type==="result"&&B.subtype==="success")J=B.content||"";else if(B.type==="error")G=B.message;else if(B.type==="result"&&B.subtype==="error")G=B.error||"Unknown error";if(G)throw Error(G);return{result:J,toolCalls:V,usage:X,duration:Date.now()-Q,turnsCount:Y}}finally{Z.close()}}export{sW as shutdownLogger,rW as setLoggerSessionId,p5 as resumeSession,u5 as prompt,oW as logger,y0 as isReadOnlyKind,VZ as isGlobMetadata,XZ as isEditMetadata,D1 as injectSkillsMetadata,G4 as getBuiltinTools,A1 as discoverSkills,E as createTool,h5 as createSession,M as createLogger,B1 as createChatServiceAsync,o0 as ToolRegistry,f as ToolKind,U2 as ToolExecution,P as ToolErrorType,u as SpecManager,V0 as STEERING_FILES,d8 as SPEC_FILE_NAMES,Z0 as SPEC_DIRS,G$ as PermissionMode,i0 as PHASE_TRANSITIONS,m8 as PHASE_PRIMARY_FILE,$J as PHASE_ORDER,q$ as PHASE_DISPLAY_NAMES,E$ as McpRegistry,w1 as McpConnectionStatus,P$ as Logger,Z2 as LogLevel,m as LogCategory,i as HookManager,P1 as ExecutionPipeline,h1 as ContextManager,t as CompactionService,z$ as CommandRegistry,e0 as CommandParser,$1 as CommandLoader,t0 as CommandExecutor,I$ as Agent};
1862
+ `,V=Z.length,X=0;for(let Y of W){let J=this.getCommandLabel(Y),G=Y.config.argumentHint?` ${Y.config.argumentHint}`:"",K=`- /${Y.name}${G}: ${Y.config.description} ${J}
1863
+ `;if(V+K.length>$)break;Z+=K,V+=K.length,X++}if(X<Q)Z+=`
1864
+ (${X} of ${Q} commands shown due to character budget)`;return{text:Z,includedCount:X,totalCount:Q}}}import{nanoid as LW}from"nanoid";var a$=M("Agent");class p1{sessionId;agent=null;abortController=null;_messages=[];options;maxTurns;permissionMode;initialized=!1;pendingMessage=null;pendingSendOptions=null;constructor($,W){this.sessionId=W||LW(),this.options=$,this.maxTurns=$.maxTurns??200,this.permissionMode=$.permissionMode??"default"}get messages(){return[...this._messages]}async initialize(){if(this.initialized)return;let $=this.buildBladeConfig();this.agent=await k$.create($,{permissionMode:this.permissionMode,systemPrompt:this.options.systemPrompt,maxTurns:this.maxTurns}),this.initialized=!0,a$.debug(`[Session] Initialized session ${this.sessionId}`)}async loadHistory(){let $=this.options.cwd||process.cwd(),W=K$($,this.sessionId),Q=new X$(W);try{let Z=await Q.readAll();if(Z.length===0){a$.debug(`[Session] No history found for session ${this.sessionId}`);return}let V=new Map,X=new Map;for(let Y of Z){if(Y.type==="message_created"){let J=Y.data;V.set(J.messageId,{role:J.role,content:"",toolCalls:[]})}if(Y.type==="part_created"){let J=Y.data,G=V.get(J.messageId);if(!G)G={role:J.partType==="tool_result"?"tool":"assistant",content:"",toolCalls:[]},V.set(J.messageId,G);switch(J.partType){case"text":{let K=J.payload;G.content=K.text??"";break}case"tool_call":{let K=J.payload,B={id:K.toolCallId,type:"function",function:{name:K.toolName,arguments:typeof K.input==="string"?K.input:JSON.stringify(K.input)}};G.toolCalls.push(B),X.set(K.toolCallId,{messageId:J.messageId,toolCallId:K.toolCallId});break}case"tool_result":{let K=J.payload;if(G.role="tool",G.toolCallId=K.toolCallId,G.name=K.toolName,K.error)G.content=`Error: ${K.error}`;else if(K.output===null||K.output===void 0)G.content="";else if(typeof K.output==="string")G.content=K.output;else G.content=JSON.stringify(K.output);break}case"summary":{let K=J.payload;G.content=K.text??"";break}}}}this._messages=Array.from(V.values()).map((Y)=>{let J={role:Y.role,content:Y.content};if(Y.toolCalls.length>0)J.tool_calls=Y.toolCalls;if(Y.toolCallId)J.tool_call_id=Y.toolCallId;if(Y.name)J.name=Y.name;return J}),a$.debug(`[Session] Loaded ${this._messages.length} messages from history`)}catch(Z){a$.warn(`[Session] Failed to load history for session ${this.sessionId}:`,Z)}}buildBladeConfig(){let $=this.buildModelConfig();return{models:[$],currentModelId:$.id,temperature:0.7,mcpServers:this.options.mcpServers,permissions:{allow:[],deny:[]}}}buildModelConfig(){let $=this.options.provider;return{id:"default",name:this.options.model,provider:this.mapProviderType($.type),model:this.options.model,apiKey:$.apiKey||"",baseUrl:$.baseUrl||this.getDefaultBaseUrl($.type),maxTokens:128000}}mapProviderType($){return{"openai-compatible":"openai-compatible",anthropic:"anthropic",gemini:"gemini","azure-openai":"azure-openai",antigravity:"antigravity",copilot:"copilot"}[$]||"openai-compatible"}getDefaultBaseUrl($){return{"openai-compatible":"https://api.openai.com/v1",anthropic:"https://api.anthropic.com",gemini:"https://generativelanguage.googleapis.com","azure-openai":"",antigravity:"",copilot:""}[$]||""}async send($,W){if(await this.ensureInitialized(),this.pendingMessage!==null)throw Error("Cannot send a new message while a previous message is pending. Call stream() first.");this.pendingMessage=$,this.pendingSendOptions=W||null}async*stream($){if(this.pendingMessage===null)throw Error("No pending message. Call send() before stream().");let W=this.pendingMessage,Q=this.pendingSendOptions;this.pendingMessage=null,this.pendingSendOptions=null;let Z=[],V={inputTokens:0,outputTokens:0,totalTokens:0};this.abortController=new AbortController;let X=Q?.signal?this.combineSignals(Q.signal,this.abortController.signal):this.abortController.signal,Y=[],J=null,G=(O)=>{if(Y.push(O),J)J(),J=null},K={messages:this._messages,userId:"sdk-user",sessionId:this.sessionId,workspaceRoot:this.options.cwd||process.cwd(),signal:X,permissionMode:this.permissionMode},B={maxTurns:Q?.maxTurns??this.maxTurns,signal:X,stream:!0,onTurnStart:(O)=>{G({type:"turn_start",turn:O.turn,sessionId:this.sessionId})},onContentDelta:(O)=>{G({type:"content",delta:O,sessionId:this.sessionId})},onThinkingDelta:$?.includeThinking?(O)=>{G({type:"thinking",delta:O,sessionId:this.sessionId})}:void 0,onToolStart:(O)=>{if(O.type!=="function")return;let H=this.safeParseJson(O.function.arguments);Z.push({id:O.id,name:O.function.name,input:H,output:null,duration:0}),G({type:"tool_use",id:O.id,name:O.function.name,input:H,sessionId:this.sessionId})},onToolResult:async(O,H)=>{if(O.type!=="function")return;let U=Z.find((A)=>A.id===O.id);if(U)U.output=H.llmContent,U.isError=!H.success;G({type:"tool_result",id:O.id,name:O.function.name,output:H.llmContent,isError:!H.success,sessionId:this.sessionId})},onTokenUsage:(O)=>{V={inputTokens:O.inputTokens,outputTokens:O.outputTokens,totalTokens:O.totalTokens}}},q=!1,w=this.agent.chat(W,K,B).then((O)=>{G({type:"usage",usage:V,sessionId:this.sessionId}),this._messages=K.messages,G({type:"result",subtype:"success",content:O,sessionId:this.sessionId})}).catch((O)=>{let H=O instanceof Error?O:Error(String(O));G({type:"error",message:H.message,sessionId:this.sessionId})}).finally(()=>{if(q=!0,J)J()});try{while(!q||Y.length>0){if(Y.length===0&&!q)await new Promise((O)=>{J=O});while(Y.length>0)yield Y.shift()}await w}finally{this.abortController=null}}close(){this.abort(),this.agent=null,this.initialized=!1,this.pendingMessage=null,this.pendingSendOptions=null,a$.debug(`[Session] Closed session ${this.sessionId}`)}abort(){if(this.abortController)this.abortController.abort(),this.abortController=null}setPermissionMode($){this.permissionMode=$}async setModel($){a$.warn("[Session] setModel is not yet implemented")}setMaxTurns($){this.maxTurns=$}async supportedCommands(){let $=N$.getInstance();if(!$.isInitialized())await $.initialize(this.options.cwd||process.cwd());return $.getAllCommands().map((W)=>({name:W.name,description:W.config.description||"",usage:W.config.argumentHint}))}async supportedModels(){return[{id:"default",name:this.options.model,provider:this.options.provider.type}]}async mcpServerStatus(){if(!this.agent)return[];let $=this.options.mcpServers||{},W=[];for(let[Q]of Object.entries($))W.push({name:Q,status:"connected",toolCount:0});return W}async[Symbol.asyncDispose](){this.close()}async ensureInitialized(){if(!this.initialized)await this.initialize()}combineSignals($,W){let Q=new AbortController,Z=()=>Q.abort();if($.aborted||W.aborted)Q.abort();else $.addEventListener("abort",Z),W.addEventListener("abort",Z);return Q.signal}safeParseJson($){try{return JSON.parse($)}catch{return $}}}async function h5($){let W=new p1($);return await W.initialize(),a$.debug(`[Session] Created new session: ${W.sessionId}`),W}async function p5($){let{sessionId:W,...Q}=$,Z=new p1(Q,W);return await Z.initialize(),await Z.loadHistory(),a$.debug(`[Session] Resumed session: ${W} with ${Z.messages.length} messages`),Z}async function u5($,W){let Q=Date.now(),Z=new p1(W);await Z.initialize();let V=[],X={inputTokens:0,outputTokens:0,totalTokens:0},Y=0,J="",G=null;try{await Z.send($);for await(let K of Z.stream())if(K.type==="turn_start")Y=K.turn;else if(K.type==="tool_use")V.push({id:K.id,name:K.name,input:K.input,output:null,duration:0});else if(K.type==="tool_result"){let B=V.find((q)=>q.id===K.id);if(B)B.output=K.output,B.isError=K.isError}else if(K.type==="usage")X=K.usage;else if(K.type==="result"&&K.subtype==="success")J=K.content||"";else if(K.type==="error")G=K.message;else if(K.type==="result"&&K.subtype==="error")G=K.error||"Unknown error";if(G)throw Error(G);return{result:J,toolCalls:V,usage:X,duration:Date.now()-Q,turnsCount:Y}}finally{Z.close()}}export{$Q as shutdownLogger,eW as setLoggerSessionId,p5 as resumeSession,u5 as prompt,WQ as logger,y0 as isReadOnlyKind,GZ as isGlobMetadata,KZ as isEditMetadata,D1 as injectSkillsMetadata,G4 as getBuiltinTools,A1 as discoverSkills,E as createTool,h5 as createSession,M as createLogger,G1 as createChatServiceAsync,s0 as ToolRegistry,f as ToolKind,U2 as ToolExecution,P as ToolErrorType,u as SpecManager,Z0 as STEERING_FILES,d8 as SPEC_FILE_NAMES,Q0 as SPEC_DIRS,q$ as PermissionMode,i0 as PHASE_TRANSITIONS,m8 as PHASE_PRIMARY_FILE,VJ as PHASE_ORDER,U$ as PHASE_DISPLAY_NAMES,E$ as McpRegistry,q1 as McpConnectionStatus,T$ as Logger,Z2 as LogLevel,m as LogCategory,a as HookManager,P1 as ExecutionPipeline,h1 as ContextManager,t as CompactionService,N$ as CommandRegistry,t0 as CommandParser,e0 as CommandLoader,o0 as CommandExecutor,k$ as Agent};