alchemylab 1.4.12 → 1.4.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ var module=o[t]={exports:{}}
4
4
  return s[t].call(module.exports,module,module.exports,e),module.exports}var t,r,n,s={184(e,exports,t){"use strict"
5
5
  function r(e,t,r,n,s={}){const o=d.default.resolve(e)
6
6
  if(M.has(o))return t.child({component:"mcp-server-registry"}).debug("Using existing server for path",{path:o}),M.get(o)
7
- const i=new R(o,t,r,n,s)
7
+ const i=new P(o,t,r,n,s)
8
8
  return M.set(o,i),i}var n,s=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
9
9
  var s=Object.getOwnPropertyDescriptor(t,r)
10
10
  s&&!("get"in s?!t.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get(){return t[r]}}),Object.defineProperty(e,n,s)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),o=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(n=function(e){return n=Object.getOwnPropertyNames||function(e){var t=[]
@@ -14,9 +14,9 @@ var t={}
14
14
  if(null!=e)for(var r=n(e),i=0;i<r.length;i++)"default"!==r[i]&&s(t,e,r[i])
15
15
  return o(t,e),t}),a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
16
16
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.McpServer=void 0,exports.resetStdoutWrite=function(){process.stdout.write=x},exports.getMcpServer=r,exports.createServer=function(e,t,n,s,o={}){return r(e,t,n,s,o)}
17
- const c=t(3807),l=t(8909),d=a(t(6928)),u=a(t(9896)),h=a(t(1943)),p=t(9567),m=t(3444),g=t(7660),f=t(1253),y=i(t(7478)),w=t(4139),b=new Set,I=t(9860),k=t(1472),v=t(3328),C=t(8955),_=t(3217),E=t(5278),S=t(9060),q=t(8824),T=(0,m.createLogger)({serviceName:"stdout-capture",console:!1,logToFile:!1}),x=process.stdout.write,P=process.argv.includes("--stdio")||"true"===process.env.MCP_DIRECT_MODE
18
- !(0,m.isDebugToolsEnabled)()||P&&"true"!==process.env.DEBUG_STDOUT_CAPTURE||(process.stdout.write=function(e){try{return(0,m.isDebugToolsEnabled)()&&"true"===process.env.DEBUG_LOGGING?.toLowerCase()&&"string"==typeof e&&!e.trim().startsWith('{"jsonrpc":"2.0"')&&e.trim().length>0&&T.debug("Stdout output",{content:e.substring(0,100),length:e.length}),x.call(process.stdout,e)}catch(e){return T.error("Error in safeStdoutWrite",{error:e+""}),!0}})
19
- class R{constructor(e,t,r,n,s={}){this.git=null,this.currentSSEConnection=null,this.stdioTransport=null,this.isInitializing=!1,this.isInitialized=!1,this.logger=t.child({component:"mcp-server"}),this.logger.info("Creating McpServer instance",{basePath:e,remoteServerUrl:n,hasExistingProjectId:!!s.existingProjectId}),this.basePath=e,this.alchemyPath=d.default.join(e,w.ALCHEMY_DIR_NAME),this.metrics=r,this.remoteServerUrl=n,this.existingProjectId=s.existingProjectId,this.gitBinary=(0,l.detectGitBinary)(),this.logger.info("Detected git binary",{gitBinary:this.gitBinary,version:(0,l.getGitVersion)()}),this.projectContext=new g.ProjectContext(e,t),this.tokenManager=new f.TokenManager(t,e,{remoteServerUrl:n}),this.configManager=new S.ConfigManager(t),this.logger.debug("Server paths initialized",{basePath:this.basePath,alchemyPath:this.alchemyPath}),this.server=new p.Server({name:"alchemy",version:"1.0.0"},{capabilities:{tools:{listChanged:!0}}}),this.metrics.incrementCounter("mcp_server_init_started",1),this.logger.info("Starting initialization for server instance"),this.initializationPromise=this.initialize()}get branchState(){if(!this.workspaceManager)return{currentBranch:null,activeRequestId:null,isOnMainBranch:!0}
17
+ const c=t(3807),l=t(8909),d=a(t(6928)),u=a(t(9896)),h=a(t(1943)),p=t(9567),m=t(3444),g=t(7660),f=t(1253),y=i(t(7478)),w=t(4139),b=new Set,I=t(9860),k=t(1472),v=t(3328),C=t(8955),_=t(3217),E=t(5278),S=t(9060),q=t(8824),T=(0,m.createLogger)({serviceName:"stdout-capture",console:!1,logToFile:!1}),x=process.stdout.write,R=process.argv.includes("--stdio")||"true"===process.env.MCP_DIRECT_MODE
18
+ !(0,m.isDebugToolsEnabled)()||R&&"true"!==process.env.DEBUG_STDOUT_CAPTURE||(process.stdout.write=function(e){try{return(0,m.isDebugToolsEnabled)()&&"true"===process.env.DEBUG_LOGGING?.toLowerCase()&&"string"==typeof e&&!e.trim().startsWith('{"jsonrpc":"2.0"')&&e.trim().length>0&&T.debug("Stdout output",{content:e.substring(0,100),length:e.length}),x.call(process.stdout,e)}catch(e){return T.error("Error in safeStdoutWrite",{error:e+""}),!0}})
19
+ class P{constructor(e,t,r,n,s={}){this.git=null,this.currentSSEConnection=null,this.stdioTransport=null,this.isInitializing=!1,this.isInitialized=!1,this.logger=t.child({component:"mcp-server"}),this.logger.info("Creating McpServer instance",{basePath:e,remoteServerUrl:n,hasExistingProjectId:!!s.existingProjectId}),this.basePath=e,this.alchemyPath=d.default.join(e,w.ALCHEMY_DIR_NAME),this.metrics=r,this.remoteServerUrl=n,this.existingProjectId=s.existingProjectId,this.gitBinary=(0,l.detectGitBinary)(),this.logger.info("Detected git binary",{gitBinary:this.gitBinary,version:(0,l.getGitVersion)()}),this.projectContext=new g.ProjectContext(e,t),this.tokenManager=new f.TokenManager(t,e,{remoteServerUrl:n}),this.configManager=new S.ConfigManager(t),this.logger.debug("Server paths initialized",{basePath:this.basePath,alchemyPath:this.alchemyPath}),this.server=new p.Server({name:"alchemy",version:"1.0.0"},{capabilities:{tools:{listChanged:!0}}}),this.metrics.incrementCounter("mcp_server_init_started",1),this.logger.info("Starting initialization for server instance"),this.initializationPromise=this.initialize()}get branchState(){if(!this.workspaceManager)return{currentBranch:null,activeRequestId:null,isOnMainBranch:!0}
20
20
  const e=this.workspaceManager.getCurrentContext("__server__")
21
21
  return{currentBranch:e.branchName,activeRequestId:e.requestId,isOnMainBranch:e.isMainBranch}}async updateBranchState(e,t){this.logger.debug("updateBranchState called - managed by WorkspaceManager",{branch:e,requestId:t})}async getCurrentBranchContext(){if(!this.workspaceManager)return{branch:null,requestId:null,isMain:!0}
22
22
  const e=this.workspaceManager.getCurrentContext("__server__")
@@ -93,7 +93,7 @@ const r=await y.switchToBranch(this.git,n.branchName,this.logger,this.metrics)
93
93
  r.success?this.logger.info("Successfully switched workspace to correct branch",{requestId:e,branchName:n.branchName}):this.logger.error("Failed to switch workspace to correct branch",{requestId:e,expectedBranch:n.branchName,error:r.message})}}catch(t){this.logger.error("Failed to verify workspace branch status",{requestId:e,workspacePath:n.basePath,error:t instanceof Error?t.message:t+""})}return this.logger.info("Switched to request context",{requestId:e,workspacePath:n.basePath,branchName:n.branchName}),{success:!0,message:"Switched to workspace for request "+e,worktreePath:n.basePath}}catch(t){const r=(0,q.getErrorMessage)(t)
94
94
  return this.logger.error("Failed to switch to request context",{requestId:e,error:r}),{success:!1,message:"Failed to switch context: "+r}}}async getEffectiveBasePath(e){if(!this.workspaceManager||!e)return this.basePath
95
95
  const t=await this.workspaceManager.getWorkspaceInfo(e)
96
- return t?.path||this.basePath}}exports.McpServer=R
96
+ return t?.path||this.basePath}}exports.McpServer=P
97
97
  const M=new Map},213(e,exports,t){"use strict"
98
98
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.def=void 0
99
99
  const r=t(6183),n=t(3707)
@@ -443,9 +443,9 @@ _=r}else _=t.workspaceManager?.getCurrentContext(t.currentSessionId)?.basePath||
443
443
  v.resolvedPath=_
444
444
  let E=!1
445
445
  try{E=(await p.default.stat(_)).isFile()}catch(e){const t=`Cannot access path ${_}: ${(0,I.getErrorMessage)(e)}`
446
- throw v.errors.push(t),Error(t)}const S=C.maxResults||50,q=C.caseSensitive||!1,T=C.useRegex||!1,x=C.fileExtension,P=C.searchIn||"content"
447
- let R=void 0!==C.contextLines?C.contextLines:0
448
- if(0>R?R=0:R>10&&(l.warn(`contextLines ${R} exceeds maximum of 10, clamping to 10`),R=10),!E&&!x)throw v.errors.push('File extension is required for directory search (use "*" for any extension, or formats like "ts", ".ts", "*.ts")'),(0,g.createValidationError)('File extension is required for directory search (use "*" for any extension, or formats like "ts", ".ts", "*.ts")')
446
+ throw v.errors.push(t),Error(t)}const S=C.maxResults||50,q=C.caseSensitive||!1,T=C.useRegex||!1,x=C.fileExtension,R=C.searchIn||"content"
447
+ let P=void 0!==C.contextLines?C.contextLines:0
448
+ if(0>P?P=0:P>10&&(l.warn(`contextLines ${P} exceeds maximum of 10, clamping to 10`),P=10),!E&&!x)throw v.errors.push('File extension is required for directory search (use "*" for any extension, or formats like "ts", ".ts", "*.ts")'),(0,g.createValidationError)('File extension is required for directory search (use "*" for any extension, or formats like "ts", ".ts", "*.ts")')
449
449
  let M,$=""
450
450
  if(E)$="*"
451
451
  else if("*"===x)$="*"
@@ -454,7 +454,7 @@ throw v.errors.push(t),(0,g.createValidationError)(t)}if(v.patternInfo={needle:n
454
454
  for(const e of t)e.isDirectory()?r.push(e.name):e.isFile()&&n.push(e.name)
455
455
  v.initialScan={totalEntries:t.length,directories:r,files:n,firstFewFiles:n.slice(0,10),scanTime:Date.now()-e},v.phases.directoryListingTime=v.initialScan.scanTime}catch(e){const t="Failed to scan directory contents: "+(0,I.getErrorMessage)(e)
456
456
  v.errors.push(t),l.error(t)}const j=E?"file":"directory"
457
- l.info(`Searching for "${n}" in ${j} ${_} (mode: ${P})`,{needle:n,searchTarget:j,path:_,options:{maxResults:S,caseSensitive:q,fileExtension:$,searchIn:P}}),k=Date.now(),v.phases.initializationTime=k-u
457
+ l.info(`Searching for "${n}" in ${j} ${_} (mode: ${R})`,{needle:n,searchTarget:j,path:_,options:{maxResults:S,caseSensitive:q,fileExtension:$,searchIn:R}}),k=Date.now(),v.phases.initializationTime=k-u
458
458
  const O=Date.now()
459
459
  let D=[],A=0,F=0
460
460
  try{const e=await async function(e,t,n,s,o,i){const{maxResults:a,fileExtension:c,searchIn:l,isFile:d,contextLines:u}=n,m=[]
@@ -472,7 +472,7 @@ s.errors.push(r),n.error(r)}return{matches:i,totalFiles:1}}(e,t,l,o,i,u)
472
472
  const g={path:e,filesProcessed:0,filesMatched:0,subdirectories:0,errors:[]}
473
473
  try{const{filesCount:n,fileMatchesCount:c,subdirCount:d,subdirStats:h}=await r(e,t,m,a,s,o,0,g,l,u)
474
474
  return g.filesProcessed=n,g.filesMatched=c,g.subdirectories=d,i.directoryStats.push(g),h&&h.length>0&&i.directoryStats.push(...h),o.info("performLocalSearch completed",{totalFiles:n,matchesFound:m.length,directories:d+1}),{matches:m,totalFiles:n}}catch(t){const r="Error in performLocalSearch: "+(0,I.getErrorMessage)(t)
475
- return g.errors.push(r),i.directoryStats.push(g),i.errors.push(r),o.error(r,{error:t instanceof Error?t.stack:t+"",searchPath:e}),{matches:m,totalFiles:g.filesProcessed}}}(_,M,{maxResults:S,fileExtension:$,searchIn:P,isFile:E,contextLines:R},$,l,v)
475
+ return g.errors.push(r),i.directoryStats.push(g),i.errors.push(r),o.error(r,{error:t instanceof Error?t.stack:t+"",searchPath:e}),{matches:m,totalFiles:g.filesProcessed}}}(_,M,{maxResults:S,fileExtension:$,searchIn:R,isFile:E,contextLines:P},$,l,v)
476
476
  D=e.matches,A=e.totalFiles
477
477
  const t=1e3
478
478
  D.length>0&&D.length<=t?(D.sort(((e,t)=>void 0!==e.modifiedTime&&void 0!==t.modifiedTime?t.modifiedTime-e.modifiedTime:void 0!==e.modifiedTime&&void 0===t.modifiedTime?-1:void 0===e.modifiedTime&&void 0!==t.modifiedTime?1:0)),l.info(`Sorted ${D.length} matches by modification time (newest first)`)):D.length>t&&l.info(`Skipped sorting ${D.length} matches (exceeds hard cap of ${t} for performance)`),F=D.length,D.length>S&&(D=D.slice(0,S),l.info(`Limited results to ${S} (from ${F} total matches)`)),D.forEach((e=>{e.relativePath=function(e,t){const r=h.default.relative(e,t)
@@ -481,8 +481,8 @@ v.errors.push(t),l.error(t),v.phases.searchTime=Date.now()-O}v.totalFiles=A,v.to
481
481
  let N,z=""
482
482
  try{if(t.workspaceManager){const e=t.workspaceManager.getCurrentContext(t.currentSessionId)
483
483
  e.branchName&&!e.permanentBranch&&(z=e.isMainBranch?` (searched on main branch: ${e.branchName})`:` (searched on request branch: ${e.branchName}${e.requestId?" for "+e.requestId:""})`)}}catch(e){l.debug("Could not get branch context",{error:e}),z=" (branch context unavailable)"}l.debug("Search diagnostic information",{diagnostic:v})
484
- const L="content"===P?"content":"filename"===P?"filenames":"content and filenames"
485
- if(F>D.length?(N=`Found ${F} results for "${n}" (searching ${L})`,m&&(N+=" in "+m),x&&(N+=" with extension "+x),N+=`${z}. Showing first ${D.length}:\n\n`):(N=`Found ${D.length} results for "${n}" (searching ${L})`,m&&(N+=" in "+m),x&&(N+=" with extension "+x),N+=z+":\n\n"),D.length>0)if(R>0){const{filenameMatches:e,mergedGroups:t}=function(e,t){const r=e.filter((e=>"filename"===e.matchType)),n=e.filter((e=>"content"===e.matchType))
484
+ const L="content"===R?"content":"filename"===R?"filenames":"content and filenames"
485
+ if(F>D.length?(N=`Found ${F} results for "${n}" (searching ${L})`,m&&(N+=" in "+m),x&&(N+=" with extension "+x),N+=`${z}. Showing first ${D.length}:\n\n`):(N=`Found ${D.length} results for "${n}" (searching ${L})`,m&&(N+=" in "+m),x&&(N+=" with extension "+x),N+=z+":\n\n"),D.length>0)if(P>0){const{filenameMatches:e,mergedGroups:t}=function(e,t){const r=e.filter((e=>"filename"===e.matchType)),n=e.filter((e=>"content"===e.matchType))
486
486
  if(0===n.length)return{filenameMatches:r,mergedGroups:[]}
487
487
  const s=new Map
488
488
  for(const e of n){const t=s.get(e.file)||[]
@@ -490,7 +490,7 @@ t.push(e),s.set(e.file,t)}const i=[]
490
490
  for(const[e,r]of s.entries()){r.sort(((e,t)=>e.line-t.line))
491
491
  let e=[r[0]]
492
492
  for(let n=1;n<r.length;n++){const s=e[e.length-1],a=r[n],c=s.line+t
493
- a.line-t>c+1?(i.push(o(e,t)),e=[a]):e.push(a)}e.length>0&&i.push(o(e,t))}return{filenameMatches:r,mergedGroups:i}}(D,R),r=[]
493
+ a.line-t>c+1?(i.push(o(e,t)),e=[a]):e.push(a)}e.length>0&&i.push(o(e,t))}return{filenameMatches:r,mergedGroups:i}}(D,P),r=[]
494
494
  e.forEach((e=>{r.push(e.relativePath+" [filename match]")})),t.forEach((e=>{const t=[]
495
495
  e.lines.forEach((e=>{e.isMatch?t.push(`> ${e.lineNumber}: ${e.content}`):t.push(` ${e.lineNumber}: ${e.content}`)})),r.push(`${e.relativePath}:\n${t.join("\n")}`)})),N+=r.join("\n\n")}else N+=await async function(e){const t=e.filter((e=>"filename"===e.matchType)),r=e.filter((e=>"content"===e.matchType)),n=[]
496
496
  t.length>0&&t.forEach((e=>{n.push(e.relativePath+" [filename match]")}))
@@ -615,21 +615,21 @@ Date.now()
615
615
  let T=Date.now()
616
616
  if(l=r(b),Date.now(),T=Date.now(),C){const e=await _()
617
617
  if(Date.now(),!e)return k.warn("Unauthenticated tool call attempt",{tool:n}),{content:[{type:"text",text:"Authentication required. Please run 'alchemylab setup' to authenticate and configure your project."}],isError:!0}}const x=(0,f.getToolByName)(n)
618
- let P
618
+ let R
619
619
  if(T=Date.now(),o?(o.setOptions({createRecords:x?.createsRecords??!1}),k.info(`Setting record creation for tool ${n}: ${x?.createsRecords??!1}`)):k.debug(`No API client available for tool ${n} (minimal mode)`),Date.now(),Date.now(),T=Date.now(),S?.sessionId){const e=S.sessionId,t=S.messageId,r=h.sessionIdentity.getIdentity()
620
620
  if(r)r.sessionId!==e&&((0,g.logSessionIdentity)(n,"_meta-session-switch",{prevSessionId:r.sessionId,prevAgentType:r.agentType,newSessionId:e}),h.sessionIdentity.setIdentity({providerId:"opencode",sessionId:e,serverUrl:r.serverUrl}),s?.workspaceManager?.resetCurrentContext?.(e))
621
621
  else{const t=await(0,u.getServerUrl)(s,k)
622
- h.sessionIdentity.setIdentity({providerId:"opencode",sessionId:e,serverUrl:t||""})}P={providerId:"opencode",sessionId:e,messageId:t,createdAt:(new Date).toISOString()},(0,g.logSessionIdentity)(n,"_meta",{sessionId:e,messageId:t})}else if(m=n,E=S,v||(v=!0,k.warn("No _meta.sessionId on tool call \u2014 caller not on alchemylab-opencode fork.",{tool:m,metaKeys:E?Object.keys(E):null})),!1!==x?.requiresSession)throw(0,p.createMcpProtocolError)(`_meta.sessionId required for tool '${n}'`,{tool:n})
623
- h.sessionIdentity.setCurrentCallOrigin(P)
624
- const R=P?.sessionId||S?.sessionId
622
+ h.sessionIdentity.setIdentity({providerId:"opencode",sessionId:e,serverUrl:t||""})}R={providerId:"opencode",sessionId:e,messageId:t,createdAt:(new Date).toISOString()},(0,g.logSessionIdentity)(n,"_meta",{sessionId:e,messageId:t})}else if(m=n,E=S,v||(v=!0,k.warn("No _meta.sessionId on tool call \u2014 caller not on alchemylab-opencode fork.",{tool:m,metaKeys:E?Object.keys(E):null})),!1!==x?.requiresSession)throw(0,p.createMcpProtocolError)(`_meta.sessionId required for tool '${n}'`,{tool:n})
623
+ h.sessionIdentity.setCurrentCallOrigin(R)
624
+ const P=R?.sessionId||S?.sessionId
625
625
  if(s?.workspaceManager){T=Date.now()
626
626
  try{const e=await(0,u.getServerUrl)(s,k)
627
- e&&o&&await s.workspaceManager.ensureReadonlyBranchIfNeeded(e,n,o,R)}catch(e){k.debug("Error during workspace check",{error:(0,d.getErrorMessage)(e)})}Date.now()}const M=s?{...s,currentSessionId:R??"__server__"}:null,$=`${Date.now()}-${Math.random().toString(36).slice(2,10)}`,j=e=>{const{getActionServerBaseUrl:r}=t(9414)
627
+ e&&o&&await s.workspaceManager.ensureReadonlyBranchIfNeeded(e,n,o,P)}catch(e){k.debug("Error during workspace check",{error:(0,d.getErrorMessage)(e)})}Date.now()}const M=s?{...s,currentSessionId:P??"__server__"}:null,$=`${Date.now()}-${Math.random().toString(36).slice(2,10)}`,j=e=>{const{getActionServerBaseUrl:r}=t(9414)
628
628
  fetch(r()+"/api/mcp/tool-call-event",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:e,callId:$}),signal:AbortSignal.timeout(500)}).catch((()=>{}))}
629
629
  let O
630
630
  j("start")
631
- try{if(x){(0,y.preNormalize)(n,l),await(0,w.expandTaskRefsInArgs)(l,o,P?.sessionId,k),l=(0,f.resolveSchema)(x).parse(l)
632
- const t=e.params?._meta?.progressToken,r=c?.sendNotification,s={context:M,apiClient:o,logger:i,metrics:a,mcpServer:I,cliOrigin:P,progressToken:t,sendNotification:r}
631
+ try{if(x){(0,y.preNormalize)(n,l),await(0,w.expandTaskRefsInArgs)(l,o,R?.sessionId,k),l=(0,f.resolveSchema)(x).parse(l)
632
+ const t=e.params?._meta?.progressToken,r=c?.sendNotification,s={context:M,apiClient:o,logger:i,metrics:a,mcpServer:I,cliOrigin:R,progressToken:t,sendNotification:r}
633
633
  O=await x.handler(l,s)}else k.info(`Tool ${n} not found, returning negative response`),O={content:[{type:"text",text:`The tool '${n}' does not exist.`}]}}finally{j("end")}return Date.now(),Date.now(),q({tool:n,success:!0}),O}catch(t){k.error("Error executing tool:",{error:t instanceof Error?t.stack:t+"",tool:e.params.name}),a.incrementCounter("tool_errors_total",1,{tool:e.params.name,error:t instanceof Error?t.name:"unknown"})
634
634
  let r="Unknown error"
635
635
  return r=t instanceof b.ZodError?function(e,t){return 1===e.issues.length?n(e.issues[0],t):e.issues.map((e=>n(e,t))).join("; ")}(t,l):(0,d.getStructuredErrorMessage)(t),{content:[{type:"text",text:"Error: "+r}],isError:!0}}var m,E})),k.info("Tools registration complete")}
@@ -995,26 +995,26 @@ if(r.length>0){const e=r.map((e=>e.opencodeSessionId)).join(", ")
995
995
  if(!u)return o.warn("Blocked spawn: request already has active workers",{requestId:d,existingWorkerCount:r.length,existingSessionIds:r.map((e=>e.opencodeSessionId))}),{content:[{type:"text",text:`\u274c Cannot spawn: Request ${d} already has ${r.length} active worker(s): ${e}\n\nOptions:\n\u2022 Use \`useExistingSession: "${r[0].opencodeSessionId}"\` to send work to the existing session\n\u2022 Use \`allowParallel: true\` if you really need multiple workers on the same request`}],isError:!0}
996
996
  E=`\u26a0\ufe0f Warning: Request ${d} already has ${r.length} active worker(s): ${e}. Proceeding anyway (allowParallel=true).\n\n`,o.warn("Spawning parallel subagent for request with existing active workers",{requestId:d,existingWorkerCount:r.length,existingSessionIds:r.map((e=>e.opencodeSessionId)),allowParallel:!0})}}}catch(e){o.debug("Failed to check for existing workers",{error:(0,I.getErrorMessage)(e)})}let q,T,x=l
997
997
  d&&(q="requests/"+d,r(t,"Setting initialBranch for agent",{agent:c,requestId:d,initialBranch:q,agentRequestContextMode:p||"undefined"}),x="readonly"===p?`Working on request ${d} (READONLY mode - you cannot modify files, only explore and report).\n\n${l}`:`Working on request ${d}.\n\n${l}`)
998
- let P,R=!1
998
+ let R,P=!1
999
999
  if(h){if(T=h,o.info("Using existing session for spawn",{sessionId:T,requestId:d}),!m)throw new g.ValidationError("Could not determine OpenCode server URL")
1000
1000
  try{let e
1001
1001
  try{const t=await fetch(`http://localhost:${S}/api/project-settings`)
1002
1002
  if(t.ok){const r=await t.json()
1003
1003
  if(r.data?.defaultModel){const[t,...n]=r.data.defaultModel.split("/")
1004
- e={providerID:t,modelID:n.join("/")}}}}catch{}P=await s({apiClient:i,fromSessionId:a?.sessionId,toSessionId:T,body:x,requestId:d,logger:o})
1005
- const t=n(x,P),r=`${m.replace(/\/$/,"")}/session/${T}/prompt_async`,l={alchemy:{kind:"agent-delegation",payload:{body:x,fromSessionId:a?.sessionId,fromAgent:w.sessionIdentity.getIdentity()?.agentType,...d?{requestId:d}:{},...P?{instructionCode:P}:{}}}},u=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({parts:[{type:"text",text:t,metadata:l}],...c?{agent:c}:{},...e?{model:e}:{}}),signal:AbortSignal.timeout(1e4)})
1004
+ e={providerID:t,modelID:n.join("/")}}}}catch{}R=await s({apiClient:i,fromSessionId:a?.sessionId,toSessionId:T,body:x,requestId:d,logger:o})
1005
+ const t=n(x,R),r=`${m.replace(/\/$/,"")}/session/${T}/prompt_async`,l={alchemy:{kind:"agent-delegation",payload:{body:x,fromSessionId:a?.sessionId,fromAgent:w.sessionIdentity.getIdentity()?.agentType,...d?{requestId:d}:{},...R?{instructionCode:R}:{}}}},u=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({parts:[{type:"text",text:t,metadata:l}],...c?{agent:c}:{},...e?{model:e}:{}}),signal:AbortSignal.timeout(1e4)})
1006
1006
  if(!u.ok){const e=await u.text().catch((()=>"Unknown error"))
1007
- throw Error(`Failed to send to existing session: ${u.status} ${e}`)}o.info("Prompt sent to existing session",{sessionId:T,agent:c})}catch(e){throw Error("Failed to use existing session: "+(0,I.getErrorMessage)(e))}}else{R=!0,r(t,"Creating session via spawn-session endpoint")
1007
+ throw Error(`Failed to send to existing session: ${u.status} ${e}`)}o.info("Prompt sent to existing session",{sessionId:T,agent:c})}catch(e){throw Error("Failed to use existing session: "+(0,I.getErrorMessage)(e))}}else{P=!0,r(t,"Creating session via spawn-session endpoint")
1008
1008
  const h=v;(0,b.logSessionIdentity)("subagent_operations.spawn","_meta",{parentSessionId:h})
1009
1009
  try{const p=`http://localhost:${S}/api/spawn-session`,m=await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({agent:c,prompt:l,requestId:d,parentSessionId:h,title:e.title,specialization:e.specialization,specializationHeadline:e.specializationHeadline,allowParallel:u,callerAgentType:w.sessionIdentity.getIdentity()?.agentType}),signal:AbortSignal.timeout(15e3)})
1010
1010
  if(!m.ok){const e=await m.text().catch((()=>"Unknown error"))
1011
1011
  throw Error(`Spawn session endpoint failed: ${m.status} ${e}`)}const g=await m.json()
1012
1012
  if(!g.success||!g.data)throw Error(g.error||"Spawn session returned unsuccessful")
1013
1013
  const{sessionId:y,model:b,serverUrl:I,initialBranch:v}=g.data
1014
- q=v,P=await s({apiClient:i,fromSessionId:a?.sessionId,toSessionId:y,body:x,requestId:d,logger:o})
1015
- const C=n(x,P),_=(0,f.spawnDetachedSubagent)({agent:c,prompt:C,cwd:k,sessionId:y,model:b,initialBranch:q,allowParallel:u,serverUrl:I})
1014
+ q=v,R=await s({apiClient:i,fromSessionId:a?.sessionId,toSessionId:y,body:x,requestId:d,logger:o})
1015
+ const C=n(x,R),_=(0,f.spawnDetachedSubagent)({agent:c,prompt:C,cwd:k,sessionId:y,model:b,initialBranch:q,allowParallel:u,serverUrl:I})
1016
1016
  if(!_.success)throw Error("Failed to spawn subagent: "+_.error)
1017
- T=y,r(t,"Spawn successful via unified endpoint",{sessionId:y,pid:_.pid,parentSessionId:h,model:b,instructionCode:P}),o.info("Background subagent spawned via unified endpoint",{agent:c,requestId:d,sessionId:y,pid:_.pid,parentSessionId:h,instructionCode:P}),async function(e){const{serverUrl:t,sessionId:r,payload:n,logger:s}=e,o=t.replace(/\/$/,""),i=Date.now()+3e4
1017
+ T=y,r(t,"Spawn successful via unified endpoint",{sessionId:y,pid:_.pid,parentSessionId:h,model:b,instructionCode:R}),o.info("Background subagent spawned via unified endpoint",{agent:c,requestId:d,sessionId:y,pid:_.pid,parentSessionId:h,instructionCode:R}),async function(e){const{serverUrl:t,sessionId:r,payload:n,logger:s}=e,o=t.replace(/\/$/,""),i=Date.now()+3e4
1018
1018
  let a=0
1019
1019
  for(;Date.now()<i;){a++
1020
1020
  try{const e=await fetch(`${o}/session/${r}/message`,{signal:AbortSignal.timeout(5e3)})
@@ -1022,10 +1022,10 @@ if(e.ok){const t=(await e.json()).find((e=>"user"===e.info?.role)),i=t?.parts.fi
1022
1022
  if(t&&i){const e={...i,metadata:{...i.metadata||{},alchemy:{kind:"agent-delegation",payload:n}}},c=`${o}/session/${r}/message/${t.info.id}/part/${i.id}`,l=await fetch(c,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),signal:AbortSignal.timeout(5e3)})
1023
1023
  if(l.ok)return void s.info("Tagged initial delegation message",{sessionId:r,messageId:t.info.id,partId:i.id,attempt:a})
1024
1024
  const d=await l.text().catch((()=>"unknown"))
1025
- s.warn("PATCH initial delegation failed",{sessionId:r,status:l.status,body:d.slice(0,200)})}}}catch{}await new Promise((e=>setTimeout(e,500)))}s.warn("Timed out tagging initial delegation; message will appear as plain user bubble",{sessionId:r,attempts:a})}({serverUrl:I,sessionId:y,payload:{body:x,fromSessionId:a?.sessionId,fromAgent:w.sessionIdentity.getIdentity()?.agentType,...d?{requestId:d}:{},...P?{instructionCode:P}:{}},logger:o})}catch(e){throw Error("Failed to spawn subagent: "+(0,I.getErrorMessage)(e))}}let M=E
1026
- M+=h?`Prompt sent to existing session ${T}.`:`Background ${c} subagent spawned successfully.`,d&&(M+="\nWorking on: "+d),P&&(M+=`\nInstruction code: ${P} (the specialist will cite this on their reports/questions via relatesTo)`),M+="\n\nThe subagent is now working independently. You can continue with other tasks.","coder"===c&&(M+="\n\nIf this work has shifted or expanded your area of expertise, update your specialization summary with `update_specialization`.")
1025
+ s.warn("PATCH initial delegation failed",{sessionId:r,status:l.status,body:d.slice(0,200)})}}}catch{}await new Promise((e=>setTimeout(e,500)))}s.warn("Timed out tagging initial delegation; message will appear as plain user bubble",{sessionId:r,attempts:a})}({serverUrl:I,sessionId:y,payload:{body:x,fromSessionId:a?.sessionId,fromAgent:w.sessionIdentity.getIdentity()?.agentType,...d?{requestId:d}:{},...R?{instructionCode:R}:{}},logger:o})}catch(e){throw Error("Failed to spawn subagent: "+(0,I.getErrorMessage)(e))}}let M=E
1026
+ M+=h?`Prompt sent to existing session ${T}.`:`Background ${c} subagent spawned successfully.`,d&&(M+="\nWorking on: "+d),R&&(M+=`\nInstruction code: ${R} (the specialist will cite this on their reports/questions via relatesTo)`),M+="\n\nThe subagent is now working independently. You can continue with other tasks.","coder"===c&&(M+="\n\nIf this work has shifted or expanded your area of expertise, update your specialization summary with `update_specialization`.")
1027
1027
  const $=!!T&&"unknown"!==T&&"spawning"!==T
1028
- return{content:[{type:"text",text:M}],...(0,_.alchemyMeta)({kind:"spawn-subagent",spawnedSessionId:$?T:void 0,agentType:c,requestId:d||void 0,description:e.title||l.slice(0,50)||c,...P?{instructionCode:P}:{}}),...P?{instructionCode:P}:{}}}async function i(e,t,r,o,i,a,c){const l=await(0,y.getServerUrl)(r,o)
1028
+ return{content:[{type:"text",text:M}],...(0,_.alchemyMeta)({kind:"spawn-subagent",spawnedSessionId:$?T:void 0,agentType:c,requestId:d||void 0,description:e.title||l.slice(0,50)||c,...R?{instructionCode:R}:{}}),...R?{instructionCode:R}:{}}}async function i(e,t,r,o,i,a,c){const l=await(0,y.getServerUrl)(r,o)
1029
1029
  if(!l)throw new g.ValidationError("Could not determine OpenCode server URL")
1030
1030
  if(o.info("Sending message to subagent session",{sessionId:e,promptLength:t.length}),i)try{const t=c?.sessionId
1031
1031
  if(t){const r=i.getCLISessionClient()
@@ -1241,7 +1241,8 @@ Object.defineProperty(exports,"__esModule",{value:!0}),exports.handleMergeReques
1241
1241
  try{if(!h)throw(0,n.createValidationError)("requestId is required")
1242
1242
  d.info("Starting merge request",{requestId:h,verificationCount:p.length})
1243
1243
  const e=a.getRequestClient(),o=await e.getRequest(h)
1244
- if("ready_for_review"===o?.status)return u({success:!1,reason:"testing_in_progress"}),{content:[{type:"text",text:`STOP: Cannot merge request ${h} \u2014 testing is in progress. Wait for tests to complete. The request will be moved to ready_for_merge when tests pass.`}],isError:!0}
1244
+ if("running"===o?.testStatus)return u({success:!1,reason:"testing_in_progress"}),{content:[{type:"text",text:`STOP: Cannot merge request ${h} \u2014 tests are still running. Wait for the test report; you'll be cleared to merge when they pass.`}],isError:!0}
1245
+ if("ready_for_review"===o?.status)return u({success:!1,reason:"awaiting_human"}),{content:[{type:"text",text:`STOP: Cannot merge request ${h} \u2014 it is awaiting human action (sign-off or review). A maintainer finalizes it from the UI.`}],isError:!0}
1245
1246
  if(p.length>0)try{await a.proxyPost(`/api/projects/${t.projectId}/requests/${h}/verify-criteria`,{verifications:p}),d.info("Criteria verified",{requestId:h,count:p.length})}catch(e){const t=(0,i.getErrorMessage)(e)
1246
1247
  d.warn("Criteria verification failed, continuing with merge",{requestId:h,error:t})}let c,l,m
1247
1248
  try{const e=await a.proxyPost(`/api/projects/${t.projectId}/requests/${h}/validate-completion`,{})
@@ -1284,23 +1285,24 @@ const s=process.config||{},o=s.commands||[]
1284
1285
  let a=`## ${process.name}\n`
1285
1286
  process.description&&(a+=process.description+"\n"),process.scope&&(a+=`**Scope:** \`${process.scope}\`\n`),a+=`**Status:** ${process.isActive?"Active":"Inactive"}\n\n`,s.setup?.length&&(a+=`### Setup\n${s.setup.map((e=>`\`\`\`\n${e}\n\`\`\``)).join("\n")}\n\n`),a+=`### Test Commands (${o.length})\n`
1286
1287
  for(let e=0;e<o.length;e++){const t=o[e]
1287
- a+=`\n**${e+1}. ${t.name}**${t.required?" \u2014 REQUIRED":" \u2014 optional"}\n`,a+=` Command: \`${t.command}\`\n`,t.timeout&&(a+=` Timeout: ${t.timeout}s\n`)}return Array.isArray(s.fingerprint)&&s.fingerprint.length>0&&(a+=`\n### Fingerprint Files\n${s.fingerprint.map((e=>`- \`${e}\``)).join("\n")}\n`),"number"==typeof s.poolSize&&(a+=`\n**Pool size:** ${s.poolSize}\n`),i({success:!0}),{content:[{type:"text",text:a}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to get test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessCreate=async function(e,t,n,s,o){const i=o.startTimer("tool_execution_time")
1288
- try{const r={setup:e.setup||[],commands:e.commands.map((e=>({name:e.name,command:e.command,required:!1!==e.required,timeout:e.timeout||300})))}
1289
- void 0!==e.fingerprint&&(r.fingerprint=e.fingerprint),void 0!==e.poolSize&&(r.poolSize=e.poolSize)
1290
- const s=await n.proxyPost(`/api/projects/${t.projectId}/test-processes`,{name:e.name,description:e.description,scope:e.scope,config:r,createdBy:"test-architect"}),process=s?.data||s
1291
- return i({success:!0}),{content:[{type:"text",text:`\u2705 Created test process **${process.name}** (${process.id}) with ${r.commands.length} test commands.${e.scope?`\nScope: \`${e.scope}\``:""}\n\nThe process is now active and will run when requests are completed.`}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to create test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessUpdate=async function(e,t,n,s,o){const i=o.startTimer("tool_execution_time")
1288
+ a+=`\n**${e+1}. ${t.name}**${t.required?" \u2014 REQUIRED":" \u2014 optional"}\n`,a+=` Command: \`${t.command}\`\n`,t.timeout&&(a+=` Timeout: ${t.timeout}s\n`)}return Array.isArray(s.fingerprint)&&s.fingerprint.length>0&&(a+=`\n### Fingerprint Files\n${s.fingerprint.map((e=>`- \`${e}\``)).join("\n")}\n`),"number"==typeof s.poolSize&&(a+=`\n**Pool size:** ${s.poolSize}\n`),i({success:!0}),{content:[{type:"text",text:a}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to get test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessCreate=async function(e,n,s,o,i){const a=i.startTimer("tool_execution_time")
1289
+ try{const i={setup:e.setup||[],commands:e.commands.map((e=>({name:e.name,command:e.command,required:!1!==e.required,timeout:e.timeout||300})))}
1290
+ void 0!==e.fingerprint&&(i.fingerprint=e.fingerprint),void 0!==e.poolSize&&(i.poolSize=e.poolSize)
1291
+ const c=await s.proxyPost(`/api/projects/${n.projectId}/test-processes`,{name:e.name,description:e.description,scope:e.scope,config:i,createdBy:"test-architect"}),process=c?.data||c
1292
+ try{const{sessionIdentity:e}=await Promise.resolve().then(t.bind(t,6688)),r=e.getIdentity()
1293
+ r?.sessionId&&process?.id&&await s.proxyPost(`/api/projects/${n.projectId}/session-test-process-associations`,{opencodeSessionId:r.sessionId,testProcessId:process.id})}catch(e){o.warn("Failed to write session-test-process association",{error:(0,r.getErrorMessage)(e)})}return a({success:!0}),{content:[{type:"text",text:`\u2705 Created test process **${process.name}** (${process.id}) with ${i.commands.length} test commands.${e.scope?`\nScope: \`${e.scope}\``:""}\n\nThe process is now active and will run when requests are completed.`}]}}catch(e){return a({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to create test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessUpdate=async function(e,t,n,s,o){const i=o.startTimer("tool_execution_time")
1292
1294
  try{const r={}
1293
1295
  if(void 0!==e.name&&(r.name=e.name),void 0!==e.description&&(r.description=e.description),void 0!==e.scope&&(r.scope=e.scope),void 0!==e.isActive&&(r.isActive=e.isActive),void 0!==e.commands||void 0!==e.setup||void 0!==e.fingerprint||void 0!==e.poolSize){const s=await n.proxyGet(`/api/projects/${t.projectId}/test-processes/${e.processId}`),o=s?.data||s,i=o?.config||{},a={setup:e.setup??i.setup??[],commands:e.commands?e.commands.map((e=>({name:e.name,command:e.command,required:!1!==e.required,timeout:e.timeout||300}))):i.commands??[]}
1294
1296
  void 0!==e.fingerprint?a.fingerprint=e.fingerprint:void 0!==i.fingerprint&&(a.fingerprint=i.fingerprint),void 0!==e.poolSize?a.poolSize=e.poolSize:void 0!==i.poolSize&&(a.poolSize=i.poolSize),void 0!==i.verifyAcceptanceCriteria&&(a.verifyAcceptanceCriteria=i.verifyAcceptanceCriteria),r.config=a}const s=await n.proxyPatch(`/api/projects/${t.projectId}/test-processes/${e.processId}`,r),process=s?.data||s
1295
- return i({success:!0}),{content:[{type:"text",text:`\u2705 Updated test process **${process.name}** (${process.id}).`}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to update test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleExecuteTestCommand=async function(e,n,s,o,a,c,l){const d=a.startTimer("tool_execution_time"),u=o.child({tool:"execute_test_command"})
1296
- try{const a=await s.proxyGet(`/api/projects/${n.projectId}/test-processes/${e.processId}`),process=a?.data||a
1297
+ return i({success:!0}),{content:[{type:"text",text:`\u2705 Updated test process **${process.name}** (${process.id}).`}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to update test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleExecuteTestCommand=async function(e,n,s,o,i,a,l){const d=i.startTimer("tool_execution_time"),u=o.child({tool:"execute_test_command"})
1298
+ try{const i=await s.proxyGet(`/api/projects/${n.projectId}/test-processes/${e.processId}`),process=i?.data||i
1297
1299
  if(!process?.config)return d({success:!1,error:"not_found"}),{content:[{type:"text",text:`Test process ${e.processId} not found or has no config.`}],isError:!0}
1298
- let c
1300
+ let a
1299
1301
  if("setup"===e.commandName){const e=process.config.setup||[]
1300
1302
  if(0===e.length)return d({success:!0}),{content:[{type:"text",text:"No setup commands configured for this test process."}]}
1301
- c=e.map(((e,t)=>({name:"setup-"+(t+1),command:e,timeout:120})))}else{const t=process.config.commands||[],r=t.find((t=>t.name===e.commandName))
1303
+ a=e.map(((e,t)=>({name:"setup-"+(t+1),command:e,timeout:120})))}else{const t=process.config.commands||[],r=t.find((t=>t.name===e.commandName))
1302
1304
  if(!r){const r=t.map((e=>e.name)).join(", ")
1303
- return d({success:!1,error:"command_not_found"}),{content:[{type:"text",text:`Command "${e.commandName}" not found in test process "${process.name}".\nAvailable commands: ${r}\nUse "setup" to run setup commands.`}],isError:!0}}c=[{name:r.name,command:r.command,timeout:r.timeout||300}]}const{runShellCommand:h}=await Promise.resolve().then(t.bind(t,4600)),p=globalThis.process
1305
+ return d({success:!1,error:"command_not_found"}),{content:[{type:"text",text:`Command "${e.commandName}" not found in test process "${process.name}".\nAvailable commands: ${r}\nUse "setup" to run setup commands.`}],isError:!0}}a=[{name:r.name,command:r.command,timeout:r.timeout||300}]}const{runShellCommand:h}=await Promise.resolve().then(t.bind(t,4600)),p=globalThis.process
1304
1306
  let m=null
1305
1307
  const g=[]
1306
1308
  try{const{sessionIdentity:e}=await Promise.resolve().then(t.bind(t,6688)),r=e.getIdentity()
@@ -1309,53 +1311,60 @@ if(g.push("reqId: "+(t||"NONE")),t){const e=await s.proxyGet(`/api/projects/${n.
1309
1311
  g.push(`runs: ${Array.isArray(r)?r.length:0}, withWorktree: ${o?.id||"NONE"}, path: ${o?.worktreePath||o?.worktree_path||"NONE"}`),o&&(m=o.worktreePath||o.worktree_path,u.info("Using test worktree from request test run",{worktreePath:m,reqId:t}))}}}catch(e){u.warn("Failed to resolve test worktree",{error:(0,r.getErrorMessage)(e)})}if(!m)return d({success:!1,error:"no_worktree"}),{content:[{type:"text",text:`No test worktree found.\n\nDiagnostics:\n${g.length>0?g.map((e=>"\u2022 "+e)).join("\n"):"\u2022 No session identity found"}\n\nEnsure this session is linked to a test process and a test run has been created.`}],isError:!0}
1310
1312
  const f=[],{default:y}=await Promise.resolve().then(t.t.bind(t,6928,23)),{default:w}=await Promise.resolve().then(t.t.bind(t,9896,23)),{ALCHEMY_DIR_NAME:b}=await Promise.resolve().then(t.bind(t,4139)),I=y.join(m,b,"command-logs")
1311
1313
  try{w.mkdirSync(I,{recursive:!0})}catch{}const{runTrackedShellCommand:k}=await Promise.resolve().then(t.bind(t,4600)),{formatCombinedOutput:v}=await Promise.resolve().then(t.bind(t,1816)),{sessionIdentity:C}=await Promise.resolve().then(t.bind(t,6688)),_=C.getIdentity()?.sessionId
1312
- for(const t of c){u.info("Executing test command",{name:t.name,command:t.command,timeout:t.timeout,cwd:m})
1314
+ for(const t of a){u.info("Executing test command",{name:t.name,command:t.command,timeout:t.timeout,cwd:m})
1313
1315
  const r=`${t.name.replace(/[^a-zA-Z0-9._-]/g,"_")}-${Date.now()}`,n=y.join(I,r+".log")
1314
1316
  let s=null
1315
- try{s=w.createWriteStream(n,{flags:"w"}),s.write(`# ${(new Date).toISOString()} starting: ${t.command}\n# cwd: ${m}\n# timeout: ${t.timeout}s\n\n`)}catch(e){u.warn("Failed to open command log file",{logPath:n,error:e+""})}const o=await(0,i.runTrackedShellWithHeartbeat)(t.command,{cwd:m,timeoutMs:1e3*t.timeout,env:{...p.env,FORCE_COLOR:"0"},onChunk:s?(e,t)=>{s?.write(t)}:void 0},{id:r,name:t.name,sessionId:_,logPath:n},l)
1317
+ try{s=w.createWriteStream(n,{flags:"w"}),s.write(`# ${(new Date).toISOString()} starting: ${t.command}\n# cwd: ${m}\n# timeout: ${t.timeout}s\n\n`)}catch(e){u.warn("Failed to open command log file",{logPath:n,error:e+""})}const o=await(0,c.runTrackedShellWithHeartbeat)(t.command,{cwd:m,timeoutMs:1e3*t.timeout,env:{...p.env,FORCE_COLOR:"0"},onChunk:s?(e,t)=>{s?.write(t)}:void 0},{id:r,name:t.name,sessionId:_,logPath:n},l)
1316
1318
  s&&(s.write(`\n# exit: ${o.exitCode}${o.timedOut?" (timed out)":""}\n`),s.end())
1317
- const a=(o.stdout+(o.stderr?"\n"+o.stderr:"")).trim(),{output:c,truncatedNote:d,logFooter:h}=v(a,{invocationId:r})
1318
- if(f.push({name:t.name,command:t.command,exitCode:o.exitCode,output:c,timedOut:o.timedOut,invocationId:r,truncatedNote:d,logFooter:h}),"setup"===e.commandName&&0!==o.exitCode)break}const E=f.every((e=>0===e.exitCode)),S=f.map((e=>{const t=e.timedOut?"\u23f1 TIMEOUT":0===e.exitCode?"\u2705 PASS":`\u274c FAIL (exit ${e.exitCode})`
1319
+ const i=(o.stdout+(o.stderr?"\n"+o.stderr:"")).trim(),{output:a,truncatedNote:d,logFooter:h}=v(i,{invocationId:r})
1320
+ if(f.push({name:t.name,command:t.command,exitCode:o.exitCode,output:a,timedOut:o.timedOut,invocationId:r,truncatedNote:d,logFooter:h}),"setup"===e.commandName&&0!==o.exitCode)break}const E=f.every((e=>0===e.exitCode)),S=f.map((e=>{const t=e.timedOut?"\u23f1 TIMEOUT":0===e.exitCode?"\u2705 PASS":`\u274c FAIL (exit ${e.exitCode})`
1319
1321
  return`### ${e.name}: ${t}\n\`\`\`\n$ ${e.command}\n${e.output}\n\`\`\`${e.truncatedNote}\n${e.logFooter}`})).join("\n\n")
1320
- return d({success:!0}),{content:[{type:"text",text:`## ${"setup"===e.commandName?"Setup":e.commandName} \u2014 ${E?"PASSED":"FAILED"}\n\n${S}`}]}}catch(e){return d({success:!1,error:"execution_error"}),{content:[{type:"text",text:"Failed to execute test command: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleReportTestResults=async function(e,o,i,a,c,l){const d=c.startTimer("tool_execution_time")
1321
- try{const{resolveRequestIdOrError:u}=await Promise.resolve().then(t.bind(t,9032)),h=await u(i,a,l?.sessionId,"Cannot report test results: this session is not associated with a request.")
1322
- if(!h.ok)return d({success:!1,error:"no_request_association"}),h.errorResult
1323
- const p=h.requestId,m=await i.proxyGet(`/api/projects/${o.projectId}/requests/${p}/test-runs`),g=m?.data||m||[],f=Array.isArray(g)?g:[],y=f.find((e=>"pending"===e.status||"running"===e.status))||f[0]
1324
- if(!y)return d({success:!1,error:"no_test_run"}),{content:[{type:"text",text:`No test run found for request ${p}.`}],isError:!0}
1325
- const w=y.id
1326
- await i.proxyPatch(`/api/projects/${o.projectId}/test-runs/${w}`,{status:e.status,results:e.results}),y.worktreePath&&fetch((0,s.getActionServerBaseUrl)()+"/api/release-pool-slot",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({worktreePath:y.worktreePath}),signal:AbortSignal.timeout(5e3)}).catch((e=>a.debug("release-pool-slot fire-and-forget failed (non-fatal)",{error:(0,r.getErrorMessage)(e)})))
1327
- const b="passed"===e.status?"\u2705":"failed"===e.status?"\u274c":"\u26a0\ufe0f"
1328
- try{const t=i.getRequestClient()
1329
- "passed"===e.status?(await t.updateRequest(p,{status:"ready_for_merge"}),a.info("Tests passed, set request to ready_for_merge",{requestId:p})):(await t.updateRequest(p,{status:"in_progress"}),a.info("Tests failed, set request back to in_progress",{requestId:p}))}catch(e){a.warn("Failed to update request status after test results",{requestId:p,error:(0,r.getErrorMessage)(e)})}const I="passed"===e.status?"\n\nAll tests passed \u2014 the coder can now call `merge` to merge this request.":"\n\nTests failed \u2014 the coder should fix the issues and call `complete` again.",k=`${b} Test run ${e.status} for request ${p}\n\n${e.results.summary}${I}`
1330
- try{const t=await(0,n.handleSessionMessageOperations)({operation:"send",type:"report",status:"passed"===e.status?"success":"failure",summary:k,details:e.results.commands?.map((e=>`${"passed"===e.status?"\u2705":"\u274c"} ${e.name}: ${e.status}${e.diagnosis?" - "+e.diagnosis:""}`)).join("\n"),finish:!0},o,a,c,i,l),r=t?.content?.[0]?.text||"unknown",s=t?.isError
1331
- return d({success:!0}),{content:[{type:"text",text:`Test run for request ${p} reported as **${e.status}**.${s?" Parent notification FAILED: "+r:" Parent session notified."}\n\n${e.results.summary}`}]}}catch(t){return d({success:!0}),{content:[{type:"text",text:`Test run for request ${p} reported as **${e.status}** but failed to notify parent: ${(0,r.getErrorMessage)(t)}\n\n${e.results.summary}`}]}}}catch(e){return d({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to report test results: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingReference=async function(e,t,r,n,s){return s.startTimer("tool_execution_time")({success:!0}),{content:[{type:"text",text:'# Test Process Design Guide\n\n## Overview\n\nA test process defines how to verify code changes for a project. It consists of:\n- **Setup**: Commands to prepare the environment (install deps, link node_modules, etc.) \u2014 runs once per worktree\n- **Commands**: The actual test commands (build, lint, test, etc.) \u2014 the verification steps\n\n## Command Properties\n\n- **name**: Human-readable name (e.g., "Build", "Unit Tests")\n- **command**: Shell command to run (e.g., `npm test`)\n- **required** (default: true): If a required command fails, the request won\'t be merged\n- **timeout** (default: 300s): Maximum execution time. Exit code 0 = pass, non-zero = fail.\n\n## Scope (Monorepo Support)\n\nSet `scope` to a path prefix to limit when a process runs:\n- `scope: "packages/api/"` \u2192 only runs when files under packages/api/ change\n- omit `scope` \u2192 runs for all changes (global process)\n\nMultiple active processes per project are supported.\n\n## Common Patterns\n\n### Node.js / TypeScript\n```json\n{\n "setup": ["ln -s ../../node_modules node_modules"],\n "commands": [\n { "name": "Build", "command": "npm run build" },\n { "name": "Lint", "command": "npm run lint", "required": false },\n { "name": "Unit Tests", "command": "npm test" }\n ]\n}\n```\n\n### Python\n```json\n{\n "setup": ["pip install -e \'.[dev]\'"],\n "commands": [\n { "name": "Type Check", "command": "mypy src/" },\n { "name": "Lint", "command": "ruff check .", "required": false },\n { "name": "Tests", "command": "pytest" }\n ]\n}\n```\n\n### Go\n```json\n{\n "setup": ["go mod download"],\n "commands": [\n { "name": "Build", "command": "go build ./..." },\n { "name": "Vet", "command": "go vet ./...", "required": false },\n { "name": "Tests", "command": "go test ./..." }\n ]\n}\n```\n\n### Rust\n```json\n{\n "setup": ["cargo fetch"],\n "commands": [\n { "name": "Build", "command": "cargo build" },\n { "name": "Clippy", "command": "cargo clippy -- -D warnings", "required": false },\n { "name": "Tests", "command": "cargo test" }\n ]\n}\n```\n\n## Project Analysis Checklist\n\nWhen setting up testing for a new project, check for:\n1. **package.json** \u2192 Node.js/TypeScript (check "scripts" for test/build/lint commands)\n2. **Cargo.toml** \u2192 Rust\n3. **go.mod** \u2192 Go\n4. **pyproject.toml** / **requirements.txt** \u2192 Python\n5. **Makefile** \u2192 Custom build system (check for test/build targets)\n6. **.github/workflows/** \u2192 Existing CI configuration (great source of test commands)\n7. **.gitlab-ci.yml** \u2192 GitLab CI\n8. **tsconfig.json** \u2192 TypeScript type checking\n9. **.eslintrc** / **biome.json** \u2192 Linting configuration\n10. **vitest.config.ts** / **jest.config.ts** / **pytest.ini** \u2192 Test framework configuration'}]}},exports.handleTestingProcessDelete=async function(e,t,n,s,o){const i=o.startTimer("tool_execution_time")
1332
- try{return await n.proxyDelete(`/api/projects/${t.projectId}/test-processes/${e.processId}`),s.info("Deleted test process",{processId:e.processId}),i({success:!0}),{content:[{type:"text",text:`Deleted test process ${e.processId}.`}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to delete test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTests=async function(e,n,i,a,c,l){const d=c.startTimer("tool_execution_time")
1333
- try{if("list"===e.operation){const e=await i.proxyGet(`/api/projects/${n.projectId}/test-processes`),t=e?.data||e||[],r=Array.isArray(t)?t:[]
1322
+ return d({success:!0}),{content:[{type:"text",text:`## ${"setup"===e.commandName?"Setup":e.commandName} \u2014 ${E?"PASSED":"FAILED"}\n\n${S}`}]}}catch(e){return d({success:!1,error:"execution_error"}),{content:[{type:"text",text:"Failed to execute test command: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleReportTestResults=async function(e,a,c,l,d,u){const h=d.startTimer("tool_execution_time")
1323
+ try{const{resolveRequestIdOrError:p}=await Promise.resolve().then(t.bind(t,9032)),m=await p(c,l,u?.sessionId,"Cannot report test results: this session is not associated with a request.")
1324
+ if(!m.ok)return h({success:!1,error:"no_request_association"}),m.errorResult
1325
+ const g=m.requestId,f=await c.proxyGet(`/api/projects/${a.projectId}/requests/${g}/test-runs`),y=f?.data||f||[],w=Array.isArray(y)?y:[],b=w.find((e=>"pending"===e.status||"running"===e.status))||w[0]
1326
+ if(!b)return h({success:!1,error:"no_test_run"}),{content:[{type:"text",text:`No test run found for request ${g}.`}],isError:!0}
1327
+ const I=b.id
1328
+ await c.proxyPatch(`/api/projects/${a.projectId}/test-runs/${I}`,{status:e.status,results:e.results})
1329
+ const k=e.results.acceptanceCriteria
1330
+ if(k&&k.length>0)try{const e=c.getRequestClient(),t=await e.getRequest(g),r=t?.acceptanceCriteria||[]
1331
+ if(r.length>0){const e=(0,n.buildCriteriaKeyMap)(r),t=k.filter((t=>"verified"===t.status&&!!t.key&&e.has(t.key))).map((t=>({criterionId:e.get(t.key).id,evidence:t.evidence,testRunId:I})))
1332
+ t.length>0&&await c.proxyPost(`/api/projects/${a.projectId}/requests/${g}/verify-criteria`,{verifications:t,dimension:"test"})}}catch(e){l.warn("Failed to persist test-dimension criteria verdicts",{error:(0,r.getErrorMessage)(e)})}b.worktreePath&&fetch((0,i.getActionServerBaseUrl)()+"/api/release-pool-slot",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({worktreePath:b.worktreePath}),signal:AbortSignal.timeout(5e3)}).catch((e=>l.debug("release-pool-slot fire-and-forget failed (non-fatal)",{error:(0,r.getErrorMessage)(e)})))
1333
+ const v="passed"===e.status?"\u2705":"failed"===e.status?"\u274c":"\u26a0\ufe0f"
1334
+ let C=!1,_=!1
1335
+ try{const t=c.getRequestClient()
1336
+ if("passed"===e.status){const e=await t.updateRequest(g,{status:"ready_for_merge"})
1337
+ _="ready_for_review"===e?.status,l.info("Tests passed",{requestId:g,status:e?.status})}else{const{escalate:e,failedRounds:r}=(0,s.decideTestRoundCap)(w,I,s.TEST_MAX_ROUNDS)
1338
+ e?(await t.updateRequest(g,{status:"ready_for_review"}),C=!0,l.warn("Test gate cap reached; escalating to human review",{requestId:g,failedRounds:r,cap:s.TEST_MAX_ROUNDS})):(await t.updateRequest(g,{status:"in_progress"}),l.info("Tests failed, set request back to in_progress",{requestId:g,failedRounds:r}))}}catch(e){l.warn("Failed to update request status after test results",{requestId:g,error:(0,r.getErrorMessage)(e)})}const E="passed"===e.status?"\n\nAll tests passed \u2014 you can now call `merge` to finalize this request.":"\n\nTests failed \u2014 fix the issues and call `complete` again.",S=`${v} Test run ${e.status} for request ${g}\n\n${e.results.summary}${C?"\n\nTests failed repeatedly; escalated for human review. Stop here; do not call complete again.":_?"\n\nAll tests passed. Human sign-off is required, so the request now awaits a maintainer to finalize in the UI. Stop here; do not call merge.":E}`
1339
+ try{const t=await(0,o.handleSessionMessageOperations)({operation:"send",type:"report",status:"passed"===e.status?"success":"failure",summary:S,details:e.results.commands?.map((e=>`${"passed"===e.status?"\u2705":"\u274c"} ${e.name}: ${e.status}${e.diagnosis?" - "+e.diagnosis:""}`)).join("\n"),finish:!0},a,l,d,c,u),r=t?.content?.[0]?.text||"unknown",n=t?.isError
1340
+ return h({success:!0}),{content:[{type:"text",text:`Test run for request ${g} reported as **${e.status}**.${n?" Parent notification FAILED: "+r:" Parent session notified."}\n\n${e.results.summary}`}]}}catch(t){return h({success:!0}),{content:[{type:"text",text:`Test run for request ${g} reported as **${e.status}** but failed to notify parent: ${(0,r.getErrorMessage)(t)}\n\n${e.results.summary}`}]}}}catch(e){return h({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to report test results: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingReference=async function(e,t,r,n,s){return s.startTimer("tool_execution_time")({success:!0}),{content:[{type:"text",text:'# Test Process Design Guide\n\n## Overview\n\nA test process defines how to verify code changes for a project. It consists of:\n- **Setup**: Commands to prepare the environment (install deps, link node_modules, etc.) \u2014 runs once per worktree\n- **Commands**: The actual test commands (build, lint, test, etc.) \u2014 the verification steps\n\n## Command Properties\n\n- **name**: Human-readable name (e.g., "Build", "Unit Tests")\n- **command**: Shell command to run (e.g., `npm test`)\n- **required** (default: true): If a required command fails, the request won\'t be merged\n- **timeout** (default: 300s): Maximum execution time. Exit code 0 = pass, non-zero = fail.\n\n## Scope (Monorepo Support)\n\nSet `scope` to a path prefix to limit when a process runs:\n- `scope: "packages/api/"` \u2192 only runs when files under packages/api/ change\n- omit `scope` \u2192 runs for all changes (global process)\n\nMultiple active processes per project are supported.\n\n## Common Patterns\n\n### Node.js / TypeScript\n```json\n{\n "setup": ["ln -s ../../node_modules node_modules"],\n "commands": [\n { "name": "Build", "command": "npm run build" },\n { "name": "Lint", "command": "npm run lint", "required": false },\n { "name": "Unit Tests", "command": "npm test" }\n ]\n}\n```\n\n### Python\n```json\n{\n "setup": ["pip install -e \'.[dev]\'"],\n "commands": [\n { "name": "Type Check", "command": "mypy src/" },\n { "name": "Lint", "command": "ruff check .", "required": false },\n { "name": "Tests", "command": "pytest" }\n ]\n}\n```\n\n### Go\n```json\n{\n "setup": ["go mod download"],\n "commands": [\n { "name": "Build", "command": "go build ./..." },\n { "name": "Vet", "command": "go vet ./...", "required": false },\n { "name": "Tests", "command": "go test ./..." }\n ]\n}\n```\n\n### Rust\n```json\n{\n "setup": ["cargo fetch"],\n "commands": [\n { "name": "Build", "command": "cargo build" },\n { "name": "Clippy", "command": "cargo clippy -- -D warnings", "required": false },\n { "name": "Tests", "command": "cargo test" }\n ]\n}\n```\n\n## Project Analysis Checklist\n\nWhen setting up testing for a new project, check for:\n1. **package.json** \u2192 Node.js/TypeScript (check "scripts" for test/build/lint commands)\n2. **Cargo.toml** \u2192 Rust\n3. **go.mod** \u2192 Go\n4. **pyproject.toml** / **requirements.txt** \u2192 Python\n5. **Makefile** \u2192 Custom build system (check for test/build targets)\n6. **.github/workflows/** \u2192 Existing CI configuration (great source of test commands)\n7. **.gitlab-ci.yml** \u2192 GitLab CI\n8. **tsconfig.json** \u2192 TypeScript type checking\n9. **.eslintrc** / **biome.json** \u2192 Linting configuration\n10. **vitest.config.ts** / **jest.config.ts** / **pytest.ini** \u2192 Test framework configuration'}]}},exports.handleTestingProcessDelete=async function(e,t,n,s,o){const i=o.startTimer("tool_execution_time")
1341
+ try{return await n.proxyDelete(`/api/projects/${t.projectId}/test-processes/${e.processId}`),s.info("Deleted test process",{processId:e.processId}),i({success:!0}),{content:[{type:"text",text:`Deleted test process ${e.processId}.`}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to delete test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTests=async function(e,n,s,o,c,l){const d=c.startTimer("tool_execution_time")
1342
+ try{if("list"===e.operation){const e=await s.proxyGet(`/api/projects/${n.projectId}/test-processes`),t=e?.data||e||[],r=Array.isArray(t)?t:[]
1334
1343
  if(0===r.length)return d({success:!0}),{content:[{type:"text",text:'No test processes registered for this project. Use `tests` with `operation: "setup"` to spawn an interactive setup session that helps configure one.'}]}
1335
- const s=r.map((e=>`**${e.name}** (${e.id})${e.scope?` [scope: ${e.scope}]`:""}\n ${e.isActive?"\u2705 Active":"\u23f8 Inactive"} \u2014 ${e.config?.commands?.length||0} commands${e.description?"\n "+e.description:""}`)).join("\n\n")
1336
- return d({success:!0}),{content:[{type:"text",text:`## Test Processes (${r.length})\n\n${s}`}]}}if("run"===e.operation){let c,u=[]
1337
- try{const e=await i.proxyGet(`/api/projects/${n.projectId}/test-processes`),t=e?.data||e||[]
1338
- u=Array.isArray(t)?t:[]}catch(e){a.warn("tests run: existence check failed; proceeding optimistically",{error:(0,r.getErrorMessage)(e)})}if(0===u.length)return d({success:!1,error:"no_process"}),{content:[{type:"text",text:'No test process registered for this project. Run `tests` with `operation: "setup"` first to bootstrap one.'}],isError:!0}
1344
+ const o=r.map((e=>`**${e.name}** (${e.id})${e.scope?` [scope: ${e.scope}]`:""}\n ${e.isActive?"\u2705 Active":"\u23f8 Inactive"} \u2014 ${e.config?.commands?.length||0} commands${e.description?"\n "+e.description:""}`)).join("\n\n")
1345
+ return d({success:!0}),{content:[{type:"text",text:`## Test Processes (${r.length})\n\n${o}`}]}}if("run"===e.operation){let c,u=[]
1346
+ try{const e=await s.proxyGet(`/api/projects/${n.projectId}/test-processes`),t=e?.data||e||[]
1347
+ u=Array.isArray(t)?t:[]}catch(e){o.warn("tests run: existence check failed; proceeding optimistically",{error:(0,r.getErrorMessage)(e)})}if(0===u.length)return d({success:!1,error:"no_process"}),{content:[{type:"text",text:'No test process registered for this project. Run `tests` with `operation: "setup"` first to bootstrap one.'}],isError:!0}
1339
1348
  const h=e.process
1340
1349
  if(h){const e=h.toLowerCase(),t=u.find((t=>t.id===h||"string"==typeof t.name&&t.name.toLowerCase()===e))
1341
1350
  if(!t){const e=u.map((e=>`- ${e.name} (${e.id})`)).join("\n")
1342
- return d({success:!1,error:"process_not_found"}),{content:[{type:"text",text:`No test process matched "${h}". Available:\n${e}`}],isError:!0}}c=[t.id]}const p=l?.sessionId,{resolveRequestIdOrError:m}=await Promise.resolve().then(t.bind(t,9032)),g=await m(i,a,p,"tests run requires an associated request \u2014 your session is not currently linked to one. Open or create a request, then try again.")
1351
+ return d({success:!1,error:"process_not_found"}),{content:[{type:"text",text:`No test process matched "${h}". Available:\n${e}`}],isError:!0}}c=[t.id]}const p=l?.sessionId,{resolveRequestIdOrError:m}=await Promise.resolve().then(t.bind(t,9032)),g=await m(s,o,p,"tests run requires an associated request \u2014 your session is not currently linked to one. Open or create a request, then try again.")
1343
1352
  if(!g.ok)return d({success:!1,error:"no_request"}),g.errorResult
1344
1353
  const f=g.requestId,y=e.name?[e.name]:void 0
1345
- try{const e=await fetch((0,s.getActionServerBaseUrl)()+"/api/run-tests-now",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:f,parentSessionId:p,testProcessIds:c,commandNames:y}),signal:AbortSignal.timeout(15e3)})
1354
+ try{const e=await fetch((0,i.getActionServerBaseUrl)()+"/api/run-tests-now",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:f,parentSessionId:p,testProcessIds:c,commandNames:y}),signal:AbortSignal.timeout(15e3)})
1346
1355
  if(!e.ok){const t=await e.text().catch((()=>""))
1347
1356
  return d({success:!1,error:"run_failed"}),{content:[{type:"text",text:`tests run failed: action server returned ${e.status}: ${t.slice(0,300)}`}],isError:!0}}const t=await e.json()
1348
1357
  if(!t.success||!t.data)return d({success:!1,error:"run_failed"}),{content:[{type:"text",text:"tests run failed: "+(t.error||"unknown error")}],isError:!0}
1349
1358
  const r=t.data.spawnedSessionIds?.[0],n=y?` (filtered to: ${y.join(", ")})`:""
1350
- return d({success:!0}),{content:[{type:"text",text:`Test run started${n}.\nSpawned ${t.data.agentsSpawned} runner(s) for ${t.data.processCount} process(es). Test runs: ${t.data.testRunIds.join(", ")}.\n\nThe auto-tester is executing the registered commands. You will receive a notification on your next turn when results are reported \u2014 continue with other work in the meantime.`}],...(0,o.alchemyMeta)({kind:"spawn-subagent",spawnedSessionId:r,agentType:"auto-tester",requestId:f,description:y?"Test run: "+y.join(", "):"Test run"})}}catch(e){return d({success:!1,error:"fetch_error"}),{content:[{type:"text",text:"tests run failed: could not reach action server: "+(0,r.getErrorMessage)(e)}],isError:!0}}}if("setup"===e.operation){let e
1351
- try{const t=await i.proxyGet(`/api/projects/${n.projectId}/test-processes`),r=t?.data||t||[],s=Array.isArray(r)?r:[]
1352
- if(s.length>0){const t=s.map((e=>`- ${e.name}${e.scope?` (scope: ${e.scope})`:""} \u2014 ${e.config?.commands?.length||0} command(s), ${e.isActive?"active":"inactive"}`)).join("\n")
1353
- e=`${s.length} test process(es) already registered for this project:\n${t}\n\nPick a distinct name AND a non-overlapping scope for the new process. Confirm with the user what they want this new process to cover before registering.`}}catch(e){a.warn("tests setup: existing-processes lookup failed; proceeding without hint",{error:(0,r.getErrorMessage)(e)})}const{sessionIdentity:c}=await Promise.resolve().then(t.bind(t,6688)),u=l?.sessionId,h=u?await c.getSessionRequestId(i,a,u):void 0
1354
- try{const t=await fetch((0,s.getActionServerBaseUrl)()+"/api/setup-tests",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:h,parentSessionId:u,context:e}),signal:AbortSignal.timeout(15e3)})
1359
+ return d({success:!0}),{content:[{type:"text",text:`Test run started${n}.\nSpawned ${t.data.agentsSpawned} runner(s) for ${t.data.processCount} process(es). Test runs: ${t.data.testRunIds.join(", ")}.\n\nThe auto-tester is executing the registered commands. You will receive a notification on your next turn when results are reported \u2014 continue with other work in the meantime.`}],...(0,a.alchemyMeta)({kind:"spawn-subagent",spawnedSessionId:r,agentType:"auto-tester",requestId:f,description:y?"Test run: "+y.join(", "):"Test run"})}}catch(e){return d({success:!1,error:"fetch_error"}),{content:[{type:"text",text:"tests run failed: could not reach action server: "+(0,r.getErrorMessage)(e)}],isError:!0}}}if("setup"===e.operation){let e
1360
+ try{const t=await s.proxyGet(`/api/projects/${n.projectId}/test-processes`),r=t?.data||t||[],o=Array.isArray(r)?r:[]
1361
+ if(o.length>0){const t=o.map((e=>`- ${e.name}${e.scope?` (scope: ${e.scope})`:""} \u2014 ${e.config?.commands?.length||0} command(s), ${e.isActive?"active":"inactive"}`)).join("\n")
1362
+ e=`${o.length} test process(es) already registered for this project:\n${t}\n\nPick a distinct name AND a non-overlapping scope for the new process. Confirm with the user what they want this new process to cover before registering.`}}catch(e){o.warn("tests setup: existing-processes lookup failed; proceeding without hint",{error:(0,r.getErrorMessage)(e)})}const{sessionIdentity:c}=await Promise.resolve().then(t.bind(t,6688)),u=l?.sessionId,h=u?await c.getSessionRequestId(s,o,u):void 0
1363
+ try{const t=await fetch((0,i.getActionServerBaseUrl)()+"/api/setup-tests",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:h,parentSessionId:u,context:e}),signal:AbortSignal.timeout(15e3)})
1355
1364
  if(!t.ok){const e=await t.text().catch((()=>""))
1356
1365
  return d({success:!1,error:"spawn_failed"}),{content:[{type:"text",text:`tests setup failed: action server returned ${t.status}: ${e.slice(0,300)}`}],isError:!0}}const r=await t.json()
1357
- return r.success&&r.data?(d({success:!0}),{content:[{type:"text",text:`Test setup session started.\nWorktree: ${r.data.worktreePath} (branch: ${r.data.branch})\n\nThe test-architect agent is now interviewing the user. You will receive a notification on your next turn when configuration completes \u2014 continue with other work in the meantime.`}],...(0,o.alchemyMeta)({kind:"spawn-subagent",spawnedSessionId:r.data.sessionId,agentType:"test-architect",requestId:h??void 0,description:"Test setup"})}):(d({success:!1,error:"spawn_failed"}),{content:[{type:"text",text:"tests setup failed: "+(r.error||"unknown error")}],isError:!0})}catch(e){return d({success:!1,error:"fetch_error"}),{content:[{type:"text",text:"tests setup failed: could not reach action server: "+(0,r.getErrorMessage)(e)}],isError:!0}}}return d({success:!1,error:"unknown_operation"}),{content:[{type:"text",text:"Unknown operation: "+e.operation}],isError:!0}}catch(e){return d({success:!1,error:"api_error"}),{content:[{type:"text",text:"tests failed: "+(0,r.getErrorMessage)(e)}],isError:!0}}}
1358
- const r=t(8824),n=t(9072),s=t(9414),o=t(2272),i=t(1375)},2085(e,exports,t){"use strict"
1366
+ return r.success&&r.data?(d({success:!0}),{content:[{type:"text",text:`Test setup session started.\nWorktree: ${r.data.worktreePath} (branch: ${r.data.branch})\n\nThe test-architect agent is now interviewing the user. You will receive a notification on your next turn when configuration completes \u2014 continue with other work in the meantime.`}],...(0,a.alchemyMeta)({kind:"spawn-subagent",spawnedSessionId:r.data.sessionId,agentType:"test-architect",requestId:h??void 0,description:"Test setup"})}):(d({success:!1,error:"spawn_failed"}),{content:[{type:"text",text:"tests setup failed: "+(r.error||"unknown error")}],isError:!0})}catch(e){return d({success:!1,error:"fetch_error"}),{content:[{type:"text",text:"tests setup failed: could not reach action server: "+(0,r.getErrorMessage)(e)}],isError:!0}}}return d({success:!1,error:"unknown_operation"}),{content:[{type:"text",text:"Unknown operation: "+e.operation}],isError:!0}}catch(e){return d({success:!1,error:"api_error"}),{content:[{type:"text",text:"tests failed: "+(0,r.getErrorMessage)(e)}],isError:!0}}}
1367
+ const r=t(8824),n=t(5454),s=t(7499),o=t(9072),i=t(9414),a=t(2272),c=t(1375)},2085(e,exports,t){"use strict"
1359
1368
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.getRequestTimelineForFile=async function(e,t,o,i){let a=`# File History: ${t}\n\n`
1360
1369
  a+="**Context**: Main branch (request-level view)\n\n"
1361
1370
  try{const s=await e.log({file:t,n:100})
@@ -1492,9 +1501,9 @@ f.info("Initial branch context",{initialBranch:S.branch,initialRequestId:S.reque
1492
1501
  const q=[]
1493
1502
  for(const e of u){const{normalizedPath:t,fullPath:n}=l.validateAndNormalizePath(e.source,r),{normalizedPath:s,fullPath:o}=l.validateAndNormalizePath(e.destination,r)
1494
1503
  q.push({source:t,destination:s,fullSource:n,fullDestination:o})}I=l.FileOperationPhase.TASK_VALIDATION,m.incrementCounter("move_files_phase",1,{phase:I})
1495
- const T=await l.validateTaskId(E,q[0].source,n,f,m,k.metricsPrefix),x=T?.requestId,P=await l.validateWorkItemStates(E,q[0].source,n,o,r,f,m,k.metricsPrefix),R=await l.autoPromoteTaskStatus(E,T.status,x,P.request?.status,q[0].source,n,o,f,m,k.metricsPrefix)
1496
- R.taskPromoted&&f.info(`Auto-promoted task ${E} (${T.title||"Untitled"}) to in_progress for file operations`,{taskId:E,taskTitle:T.title,previousStatus:T.status,newStatus:R.newTaskStatus,operationCount:u.length}),R.requestPromoted&&f.info(`Auto-promoted request ${x} to in_progress for file operations`,{requestId:x,previousStatus:P.request?.status,newStatus:R.newRequestStatus,triggeringTaskId:E})
1497
- const M=await l.ensureCorrectWorkspaceContext({taskPromoted:R.taskPromoted,requestId:x,context:r,operation:"move-files",logger:f,metrics:m,metricsPrefix:k.metricsPrefix})
1504
+ const T=await l.validateTaskId(E,q[0].source,n,f,m,k.metricsPrefix),x=T?.requestId,R=await l.validateWorkItemStates(E,q[0].source,n,o,r,f,m,k.metricsPrefix),P=await l.autoPromoteTaskStatus(E,T.status,x,R.request?.status,q[0].source,n,o,f,m,k.metricsPrefix)
1505
+ P.taskPromoted&&f.info(`Auto-promoted task ${E} (${T.title||"Untitled"}) to in_progress for file operations`,{taskId:E,taskTitle:T.title,previousStatus:T.status,newStatus:P.newTaskStatus,operationCount:u.length}),P.requestPromoted&&f.info(`Auto-promoted request ${x} to in_progress for file operations`,{requestId:x,previousStatus:R.request?.status,newStatus:P.newRequestStatus,triggeringTaskId:E})
1506
+ const M=await l.ensureCorrectWorkspaceContext({taskPromoted:P.taskPromoted,requestId:x,context:r,operation:"move-files",logger:f,metrics:m,metricsPrefix:k.metricsPrefix})
1498
1507
  if(!M.success)throw Error(M.error)
1499
1508
  let $={hadUserMods:!1,userModsCommitHash:void 0}
1500
1509
  if(r.git)try{f.debug("[MOVE-FILES] Checking for user changes before move operations")
@@ -1533,7 +1542,7 @@ exports.def={name:"quick_manage",description:"WHEN TO USE: trivial single-file e
1533
1542
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.buildTaskEndpoint=function(e,t,r){const n=r?"/"+r.replace(/^\//,""):""
1534
1543
  return`/api/projects/${e}/tasks/${encodeURIComponent(t)}${n}`}},2462(e,exports,t){"use strict"
1535
1544
  Object.defineProperty(exports,"__esModule",{value:!0})
1536
- const r=t(2245),n=t(9080),s=t(5692),o=t(9030),i=t(2903),a=t(4607),c=t(9499),l=t(6770),d=t(8045),u=t(9697),h=t(9196),p=t(5459),m=t(4805),g=t(260),f=t(2283),y=t(4165),w=t(7834),b=t(9373),I=t(6111),k=t(700),v=t(1535),C=t(7257),_=t(9230),E=t(4150),S=t(6473),q=t(6309),T=t(4921),x=t(8850),P=t(3556),R=t(1391),M=t(6315),$=t(7713),j=t(6252),O=t(577),D=t(4206),A=t(213),F=t(7250),N=t(2425),z=t(1540),L=t(5767),H=t(4973),B=t(509),U=t(7613),G=t(8456),W=t(3322),V=t(5247),Q=t(8849),K=t(542);(0,r.registerTool)(n.def),(0,r.registerTool)(s.def),(0,r.registerTool)(o.def),(0,r.registerTool)(i.def),(0,r.registerTool)(a.def),(0,r.registerTool)(c.def),(0,r.registerTool)(l.def),(0,r.registerTool)(d.def),(0,r.registerTool)(u.def),(0,r.registerTool)(h.def),(0,r.registerTool)(p.def),(0,r.registerTool)(m.def),(0,r.registerTool)(g.def),(0,r.registerTool)(f.def),(0,r.registerTool)(y.def),(0,r.registerTool)(w.def),(0,r.registerTool)(b.def),(0,r.registerTool)(I.def),(0,r.registerTool)(k.def),(0,r.registerTool)(v.def),(0,r.registerTool)(E.def),(0,r.registerTool)(C.def),(0,r.registerTool)(_.def),(0,r.registerTool)(S.def),(0,r.registerTool)(q.def),(0,r.registerTool)(T.def),(0,r.registerTool)(x.def),(0,r.registerTool)(P.def),(0,r.registerTool)(R.def),(0,r.registerTool)(M.def),(0,r.registerTool)($.def),(0,r.registerTool)(j.def),(0,r.registerTool)(O.def),(0,r.registerTool)(D.def),(0,r.registerTool)(A.def),(0,r.registerTool)(F.def),(0,r.registerTool)(N.def),(0,r.registerTool)(z.def),(0,r.registerTool)(L.def),(0,r.registerTool)(H.def),(0,r.registerTool)(B.def),(0,r.registerTool)(U.def),(0,r.registerTool)(G.def),(0,r.registerTools)(W.metaDefs),(0,r.registerTools)(V.testingDefs),(0,r.registerTools)(Q.checkingDefs),(0,r.registerTools)(K.debugDefs),(0,t(2245).freezeRegistry)()},2478(e,exports){"use strict"
1545
+ const r=t(2245),n=t(9080),s=t(5692),o=t(9030),i=t(2903),a=t(4607),c=t(9499),l=t(6770),d=t(8045),u=t(9697),h=t(9196),p=t(5459),m=t(4805),g=t(260),f=t(2283),y=t(4165),w=t(7834),b=t(9373),I=t(6111),k=t(700),v=t(5837),C=t(1535),_=t(7257),E=t(9230),S=t(4150),q=t(6473),T=t(6309),x=t(4921),R=t(8850),P=t(3556),M=t(1391),$=t(6315),j=t(7713),O=t(6252),D=t(577),A=t(4206),F=t(213),N=t(7250),z=t(2425),L=t(1540),H=t(5767),B=t(4973),U=t(509),W=t(7613),G=t(8456),V=t(3322),Q=t(5247),K=t(8849),J=t(542);(0,r.registerTool)(n.def),(0,r.registerTool)(s.def),(0,r.registerTool)(o.def),(0,r.registerTool)(i.def),(0,r.registerTool)(a.def),(0,r.registerTool)(c.def),(0,r.registerTool)(l.def),(0,r.registerTool)(d.def),(0,r.registerTool)(u.def),(0,r.registerTool)(h.def),(0,r.registerTool)(p.def),(0,r.registerTool)(m.def),(0,r.registerTool)(g.def),(0,r.registerTool)(f.def),(0,r.registerTool)(y.def),(0,r.registerTool)(w.def),(0,r.registerTool)(b.def),(0,r.registerTool)(I.def),(0,r.registerTool)(k.def),(0,r.registerTool)(v.def),(0,r.registerTool)(C.def),(0,r.registerTool)(S.def),(0,r.registerTool)(_.def),(0,r.registerTool)(E.def),(0,r.registerTool)(q.def),(0,r.registerTool)(T.def),(0,r.registerTool)(x.def),(0,r.registerTool)(R.def),(0,r.registerTool)(P.def),(0,r.registerTool)(M.def),(0,r.registerTool)($.def),(0,r.registerTool)(j.def),(0,r.registerTool)(O.def),(0,r.registerTool)(D.def),(0,r.registerTool)(A.def),(0,r.registerTool)(F.def),(0,r.registerTool)(N.def),(0,r.registerTool)(z.def),(0,r.registerTool)(L.def),(0,r.registerTool)(H.def),(0,r.registerTool)(B.def),(0,r.registerTool)(U.def),(0,r.registerTool)(W.def),(0,r.registerTool)(G.def),(0,r.registerTools)(V.metaDefs),(0,r.registerTools)(Q.testingDefs),(0,r.registerTools)(K.checkingDefs),(0,r.registerTools)(J.debugDefs),(0,t(2245).freezeRegistry)()},2478(e,exports){"use strict"
1537
1546
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.requestConfig=void 0,exports.areTestsRequiredForCompletion=function(){return exports.requestConfig.requireTestsForCompletion},exports.setTestsRequiredForCompletion=function(e){exports.requestConfig.requireTestsForCompletion=e},exports.getCompletionMode=function(e){return e&&["auto-merge","ask-me","test-by-default","always-test"].includes(e)?e:"test-by-default"},exports.getReviewMode=function(e){return e&&["auto-finalize","manual-review"].includes(e)?e:"auto-finalize"},exports.getApprovalMode=function(e){return e&&["none","require-approval"].includes(e)?e:"none"},exports.requestConfig={requireTestsForCompletion:!1}},2537(e,exports,t){"use strict"
1538
1547
  async function r(e,t,r){if(v.has(r)&&C>=t){if(0===t)return 0
1539
1548
  try{return(await y.default.readFile(e,"utf-8")).split("\n").length}catch{return}}}function n(e,t,r){const n="depth"in e,s=n?e:r,o=n?e.isDirectory:e.isDirectory(),a=e.name,c=o?"[\u{1f4c1} DIR]":"[\u{1f4c4} FILE]"
@@ -2011,34 +2020,34 @@ try{const C=e,{operations:_,comment:E}=C,{enforceActiveTask:S}=await Promise.res
2011
2020
  if("errorResult"in q)return q.errorResult
2012
2021
  const{taskId:T}=q
2013
2022
  if(y.info("Replacing strings across files and documents",{taskId:T,operationCount:_.length,comment:E}),!_||0===_.length)throw new u.ValidationError("At least one operation is required")
2014
- const x=_.filter((e=>e.path)),P=_.filter((e=>e.documentId))
2015
- y.info("Operation breakdown",{fileOperations:x.length,documentOperations:P.length})
2016
- const R=[]
2023
+ const x=_.filter((e=>e.path)),R=_.filter((e=>e.documentId))
2024
+ y.info("Operation breakdown",{fileOperations:x.length,documentOperations:R.length})
2025
+ const P=[]
2017
2026
  for(const e of x){const{normalizedPath:t,fullPath:n}=d.validateAndNormalizePath(e.path,r)
2018
- R.push({type:"file",path:t,fullPath:n,replacements:e.replacements,mode:e.mode||"unique"})}const M=[]
2019
- if(P.length>0&&!r.documentFileManager)throw Error("Document file manager not available - cannot process document operations")
2020
- for(const e of P)M.push({type:"document",documentId:e.documentId,replacements:e.replacements,mode:e.mode||"unique"})
2027
+ P.push({type:"file",path:t,fullPath:n,replacements:e.replacements,mode:e.mode||"unique"})}const M=[]
2028
+ if(R.length>0&&!r.documentFileManager)throw Error("Document file manager not available - cannot process document operations")
2029
+ for(const e of R)M.push({type:"document",documentId:e.documentId,replacements:e.replacements,mode:e.mode||"unique"})
2021
2030
  if(M.length>0&&r.apiClient){const e=M.map((e=>e.documentId))
2022
2031
  try{await(0,m.ensureDocumentsNotLocked)(e,r.apiClient,y,c,"replace-strings-documents")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2023
2032
  throw e}}k=d.FileOperationPhase.TASK_VALIDATION,c.incrementCounter("replace_strings_phase",1,{phase:k})
2024
- const $=R.length>0?R[0].path:"document-operation",j=await d.validateTaskId(T,$,s,y,c,v.metricsPrefix),O=j?.requestId
2033
+ const $=P.length>0?P[0].path:"document-operation",j=await d.validateTaskId(T,$,s,y,c,v.metricsPrefix),O=j?.requestId
2025
2034
  let D=null
2026
- R.length>0&&O&&(D=await d.validateWorkItemStates(T,R[0].path,s,i,r,y,c,v.metricsPrefix))
2035
+ P.length>0&&O&&(D=await d.validateWorkItemStates(T,P[0].path,s,i,r,y,c,v.metricsPrefix))
2027
2036
  let A={taskPromoted:!1,requestPromoted:!1}
2028
- R.length>0&&O&&D&&(A=await d.autoPromoteTaskStatus(T,j.status,O,D.request?.status,R[0].path,s,i,y,c,v.metricsPrefix),A.taskPromoted&&y.info("Auto-promoted task to in_progress for replace-strings operation",{taskId:T,requestId:O,previousStatus:j.status,newStatus:A.newTaskStatus,triggeringOperation:"replace-strings"}))
2037
+ P.length>0&&O&&D&&(A=await d.autoPromoteTaskStatus(T,j.status,O,D.request?.status,P[0].path,s,i,y,c,v.metricsPrefix),A.taskPromoted&&y.info("Auto-promoted task to in_progress for replace-strings operation",{taskId:T,requestId:O,previousStatus:j.status,newStatus:A.newTaskStatus,triggeringOperation:"replace-strings"}))
2029
2038
  const F=await d.ensureCorrectWorkspaceContext({taskPromoted:A.taskPromoted,requestId:O,context:r,operation:"replace-strings",logger:y,metrics:c,metricsPrefix:v.metricsPrefix})
2030
2039
  if(!F.success)throw Error(F.error)
2031
- if(R.length>0){y.debug("Re-validating file paths with correct workspace context",{operationCount:R.length,workspaceBasePath:r.workspaceManager?.getCurrentContext(r.currentSessionId).basePath})
2032
- for(let e=0;e<R.length;e++){const t=R[e],n=x[e],{normalizedPath:s,fullPath:o}=d.validateAndNormalizePath(n.path,r)
2033
- R[e]={...t,path:s,fullPath:o}}}if(M.length>0&&O)try{await(0,h.validateRequestStatusForDocumentOperation)(O,i,y,c,"replace-strings-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2040
+ if(P.length>0){y.debug("Re-validating file paths with correct workspace context",{operationCount:P.length,workspaceBasePath:r.workspaceManager?.getCurrentContext(r.currentSessionId).basePath})
2041
+ for(let e=0;e<P.length;e++){const t=P[e],n=x[e],{normalizedPath:s,fullPath:o}=d.validateAndNormalizePath(n.path,r)
2042
+ P[e]={...t,path:s,fullPath:o}}}if(M.length>0&&O)try{await(0,h.validateRequestStatusForDocumentOperation)(O,i,y,c,"replace-strings-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2034
2043
  throw e}k=d.FileOperationPhase.RECORD_CREATION,c.incrementCounter("replace_strings_phase",1,{phase:k})
2035
- const N=[...R.map((e=>({type:"file",path:e.path,replacements:e.replacements,mode:e.mode}))),...M.map((e=>({type:"document",documentId:e.documentId,replacements:e.replacements,mode:e.mode})))],{toolRecordId:z}=await d.createFileOperationRecords(T,O,r.projectId,v.recordType,$,{operationCount:_.length,fileOperations:R.length,documentOperations:M.length,operations:N,userComment:E},s,o,y,c,v.metricsPrefix,f)
2036
- if(b=z,I=z,k=v.fileOperationPhase,c.incrementCounter("replace_strings_phase",1,{phase:k}),R.length>0&&r.git)try{y.debug("[REPLACE-STRINGS] Checking for user changes before replace operations")
2044
+ const N=[...P.map((e=>({type:"file",path:e.path,replacements:e.replacements,mode:e.mode}))),...M.map((e=>({type:"document",documentId:e.documentId,replacements:e.replacements,mode:e.mode})))],{toolRecordId:z}=await d.createFileOperationRecords(T,O,r.projectId,v.recordType,$,{operationCount:_.length,fileOperations:P.length,documentOperations:M.length,operations:N,userComment:E},s,o,y,c,v.metricsPrefix,f)
2045
+ if(b=z,I=z,k=v.fileOperationPhase,c.incrementCounter("replace_strings_phase",1,{phase:k}),P.length>0&&r.git)try{y.debug("[REPLACE-STRINGS] Checking for user changes before replace operations")
2037
2046
  const e=await(0,p.commitUserChangesBeforeToolOperation)(r.git,"replace-strings",{requestId:O,taskId:T,workspaceManager:r.workspaceManager},y,c)
2038
- e.userChangesCommitted&&(y.debug("[REPLACE-STRINGS] User changes committed before replace operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),y.info("User changes committed before replace-strings operation",{taskId:T,fileOperationsCount:R.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){y.debug("[REPLACE-STRINGS] Pre-tool commit failed, continuing with replacements",{error:e instanceof Error?e.message:e+""}),y.warn("Pre-tool user changes commit failed, continuing with replace operation",{taskId:T,fileOperationsCount:R.length,error:e instanceof Error?e.message:e+""})}y.debug("[REPLACE-STRINGS] Proceeding with file operations",{fileCount:R.length})
2047
+ e.userChangesCommitted&&(y.debug("[REPLACE-STRINGS] User changes committed before replace operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),y.info("User changes committed before replace-strings operation",{taskId:T,fileOperationsCount:P.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){y.debug("[REPLACE-STRINGS] Pre-tool commit failed, continuing with replacements",{error:e instanceof Error?e.message:e+""}),y.warn("Pre-tool user changes commit failed, continuing with replace operation",{taskId:T,fileOperationsCount:P.length,error:e instanceof Error?e.message:e+""})}y.debug("[REPLACE-STRINGS] Proceeding with file operations",{fileCount:P.length})
2039
2048
  const L=[]
2040
2049
  let H=0,B=0
2041
- for(const e of R){const t={type:"file",path:e.path,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0}
2050
+ for(const e of P){const t={type:"file",path:e.path,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0}
2042
2051
  try{if(await l.default.access(e.fullPath),!(await l.default.stat(e.fullPath)).isFile())throw Error("Path is not a file: "+e.path)
2043
2052
  const r=await l.default.readFile(e.fullPath,"utf8"),{newContent:s,results:o}=await n(r,e.replacements,e.mode)
2044
2053
  t.replacements=o,t.successfulReplacements=o.filter((e=>e.success)).length,t.failedReplacements=o.filter((e=>!e.success)).length,s!==r?(await l.default.writeFile(e.fullPath,s,"utf8"),t.success=!0,B++,y.info("File updated successfully",{path:e.path,successfulReplacements:t.successfulReplacements,failedReplacements:t.failedReplacements})):0===t.failedReplacements&&(t.success=!0),H+=t.failedReplacements}catch(r){t.error=(0,g.getErrorMessage)(r),t.failedReplacements=e.replacements.length,H+=t.failedReplacements,y.error("File operation failed",{path:e.path,error:t.error})}L.push(t)}for(const e of M){const t={type:"document",documentId:e.documentId,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0}
@@ -2046,17 +2055,17 @@ try{const s=await r.documentFileManager.getDocumentAsFile(e.documentId),o=r.docu
2046
2055
  t.filename=o?.filename
2047
2056
  const i=await l.default.readFile(s,"utf8"),{newContent:a,results:c}=await n(i,e.replacements,e.mode)
2048
2057
  t.replacements=c,t.successfulReplacements=c.filter((e=>e.success)).length,t.failedReplacements=c.filter((e=>!e.success)).length,a!==i?(await l.default.writeFile(s,a,"utf8"),r.documentFileManager.markForSync(e.documentId),t.success=!0,B++,y.info("Document updated successfully",{documentId:e.documentId,filename:t.filename,successfulReplacements:t.successfulReplacements,failedReplacements:t.failedReplacements})):0===t.failedReplacements&&(t.success=!0),H+=t.failedReplacements}catch(r){t.error=(0,g.getErrorMessage)(r),t.failedReplacements=e.replacements.length,H+=t.failedReplacements,y.error("Document operation failed",{documentId:e.documentId,error:t.error})}L.push(t)}if(M.length>0)try{for(const e of M){const t=L.find((t=>t.documentId===e.documentId))
2049
- t?.success&&await r.documentFileManager.syncDocument(e.documentId)}}catch(e){y.warn("Some documents may not have synced properly",{error:e})}const U=await d.handleMultiFileGitCommit(T,R,L,B,{operationType:"Replace strings",toolRecordId:I,successField:"successfulReplacements",logger:y,metrics:c,metricsPrefix:"replace_strings"},r),G=d.processMultiFileOperationResults(L,"successfulReplacements"),{successfulOperations:W,failedOperations:V,totalSuccessfulChanges:Q,overallSuccess:K,successfulFiles:J,failedFiles:Y}=G
2050
- try{await o.updateToolRecord(I,{metadata:{path:R.length>0?R[0].path:"document:"+M[0]?.documentId,status:K?"completed":"failed",error:K?void 0:V+" operations failed",totalOperations:L.length,successfulFiles:J,failedFiles:Y,operations:N,totalSuccessfulReplacements:Q,totalFailedReplacements:H,operationsWithChanges:B,processingTime:Date.now()-w,userComment:E,...R.length>0&&U.success&&U.commitHash&&{commitHash:U.commitHash,previousCommitHash:U.previousCommitHash||void 0}},note:K?`String replacement completed: ${W}/${L.length} operations successful${R.length>0?" (committed to git)":""}`:`String replacement partially failed: ${V}/${L.length} operations failed`})}catch(e){y.warn("Failed to update tool record",{recordError:e})}d.formatMultiFileToolResponse("String Replacement",{successfulOperations:W,failedOperations:V,totalSuccessfulChanges:Q,overallSuccess:K,successfulFiles:J,failedFiles:Y},U,F)
2058
+ t?.success&&await r.documentFileManager.syncDocument(e.documentId)}}catch(e){y.warn("Some documents may not have synced properly",{error:e})}const U=await d.handleMultiFileGitCommit(T,P,L,B,{operationType:"Replace strings",toolRecordId:I,successField:"successfulReplacements",logger:y,metrics:c,metricsPrefix:"replace_strings"},r),W=d.processMultiFileOperationResults(L,"successfulReplacements"),{successfulOperations:G,failedOperations:V,totalSuccessfulChanges:Q,overallSuccess:K,successfulFiles:J,failedFiles:Y}=W
2059
+ try{await o.updateToolRecord(I,{metadata:{path:P.length>0?P[0].path:"document:"+M[0]?.documentId,status:K?"completed":"failed",error:K?void 0:V+" operations failed",totalOperations:L.length,successfulFiles:J,failedFiles:Y,operations:N,totalSuccessfulReplacements:Q,totalFailedReplacements:H,operationsWithChanges:B,processingTime:Date.now()-w,userComment:E,...P.length>0&&U.success&&U.commitHash&&{commitHash:U.commitHash,previousCommitHash:U.previousCommitHash||void 0}},note:K?`String replacement completed: ${G}/${L.length} operations successful${P.length>0?" (committed to git)":""}`:`String replacement partially failed: ${V}/${L.length} operations failed`})}catch(e){y.warn("Failed to update tool record",{recordError:e})}d.formatMultiFileToolResponse("String Replacement",{successfulOperations:G,failedOperations:V,totalSuccessfulChanges:Q,overallSuccess:K,successfulFiles:J,failedFiles:Y},U,F)
2051
2060
  let Z="## String Replacement Results\n\n"
2052
2061
  if(r.workspaceManager){const e=r.workspaceManager.getCurrentContext(r.currentSessionId)
2053
- e.permanentBranch||(Z+=`**Branch:** \`${e.branchName}\`\n\n`)}if(Z+="**Summary:**\n",Z+=`- **Files processed:** ${W+V}\n`,Z+=`- **Successful operations:** ${W}\n`,Z+=`- **Failed operations:** ${V}\n`,Z+=`- **Total replacements:** ${Q} successful, ${H} failed\n\n`,U.success&&U.commitHash&&(Z+="**Git Commit:**\n",Z+=`- **Commit Hash:** ${U.commitHash.substring(0,8)}\n`,Z+=`- **Files Committed:** ${U.filesCommitted.length}\n`,U.previousCommitHash&&(Z+=`- **Previous Commit:** ${U.previousCommitHash.substring(0,8)}\n`),Z+="\n"),1===L.length){const e=L[0]
2062
+ e.permanentBranch||(Z+=`**Branch:** \`${e.branchName}\`\n\n`)}if(Z+="**Summary:**\n",Z+=`- **Files processed:** ${G+V}\n`,Z+=`- **Successful operations:** ${G}\n`,Z+=`- **Failed operations:** ${V}\n`,Z+=`- **Total replacements:** ${Q} successful, ${H} failed\n\n`,U.success&&U.commitHash&&(Z+="**Git Commit:**\n",Z+=`- **Commit Hash:** ${U.commitHash.substring(0,8)}\n`,Z+=`- **Files Committed:** ${U.filesCommitted.length}\n`,U.previousCommitHash&&(Z+=`- **Previous Commit:** ${U.previousCommitHash.substring(0,8)}\n`),Z+="\n"),1===L.length){const e=L[0]
2054
2063
  if(Z+=`**Operation:** ${e.success?"\u2705 Success":"\u274c Failed"}\n`,"file"===e.type?Z+=`**File:** ${e.path}\n`:(Z+="**Document:** "+e.documentId,e.filename&&(Z+=` (${e.filename})`),Z+="\n"),e.error?Z+=`**Error:** ${e.error}\n`:(Z+=`**Replacements:** ${e.successfulReplacements} successful`,e.failedReplacements>0&&(Z+=`, ${e.failedReplacements} failed`),Z+="\n"),e.replacements.some((e=>!e.success))){Z+="**Failed Replacement Details:**\n"
2055
- for(const t of e.replacements.filter((e=>!e.success)))Z+=`- "${t.old_str}" \u2192 "${t.new_str}": ${t.error}\n`}}else{Z+="**Summary:**\n",Z+=`- **Total Operations:** ${L.length}\n`,Z+=`- **Successful:** ${W}\n`,Z+=`- **Failed:** ${V}\n`,Z+=`- **Total Replacements:** ${Q} successful, ${H} failed\n\n`,Z+="**Detailed Results:**\n\n"
2064
+ for(const t of e.replacements.filter((e=>!e.success)))Z+=`- "${t.old_str}" \u2192 "${t.new_str}": ${t.error}\n`}}else{Z+="**Summary:**\n",Z+=`- **Total Operations:** ${L.length}\n`,Z+=`- **Successful:** ${G}\n`,Z+=`- **Failed:** ${V}\n`,Z+=`- **Total Replacements:** ${Q} successful, ${H} failed\n\n`,Z+="**Detailed Results:**\n\n"
2056
2065
  for(const e of L){if("file"===e.type?Z+=`### File: ${e.path}\n`:(Z+="### Document: "+e.documentId,e.filename&&(Z+=` (${e.filename})`),Z+="\n"),Z+=`- **Status:** ${e.success?"\u2705 Success":"\u274c Failed"}\n`,e.error?Z+=`- **Error:** ${e.error}\n`:(Z+=`- **Replacements:** ${e.successfulReplacements} successful`,e.failedReplacements>0&&(Z+=`, ${e.failedReplacements} failed`),Z+="\n"),e.replacements.some((e=>!e.success))){Z+="- **Failed Replacement Details:**\n"
2057
2066
  for(const t of e.replacements.filter((e=>!e.success)))Z+=` - "${t.old_str}" \u2192 "${t.new_str}": ${t.error}\n`}Z+="\n"}}M.length>0&&(Z+="\u{1f4c4} **Document Changes:** Modified documents have been automatically synced back to the tracking system.\n\n")
2058
2067
  const X=Date.now()-w
2059
- return y.info("Replace strings operation completed",{duration:X,success:K,totalOperations:L.length,successfulOperations:W,failedOperations:V}),c.incrementCounter("replace_strings_total",1,{success:K}),{content:[{type:"text",text:Z}],isError:!K}}catch(t){const r=Date.now()-w
2068
+ return y.info("Replace strings operation completed",{duration:X,success:K,totalOperations:L.length,successfulOperations:G,failedOperations:V}),c.incrementCounter("replace_strings_total",1,{success:K}),{content:[{type:"text",text:Z}],isError:!K}}catch(t){const r=Date.now()-w
2060
2069
  if(y.error("Replace strings operation failed",{error:t instanceof Error?t.stack:t+"",duration:r,phase:k}),I)try{await o.updateToolRecord(I,{metadata:{path:e?.operations?.[0]?.path||e?.operations?.[0]?.documentId,status:"failed",error:(0,g.getErrorMessage)(t),phase:k,duration:r,userComment:e?.comment},note:"String replacement failed: "+(0,g.getErrorMessage)(t)})}catch(e){}return c.incrementCounter("replace_strings_errors",1,{phase:k}),{content:[{type:"text",text:"\u274c **Replace Strings Failed:** "+(0,g.getErrorMessage)(t)}],isError:!0}}}
2061
2070
  const l=c(t(1943)),d=a(t(5967)),u=t(9860),h=t(5003),p=t(7478),m=t(9949),g=t(8824)},3322(e,exports,t){"use strict"
2062
2071
  var r,n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
@@ -2163,7 +2172,8 @@ let s=null,o=null},3545(e,exports){"use strict"
2163
2172
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.asInternal=exports.asExternal=void 0,exports.asExternal=e=>e,exports.asInternal=e=>e},3556(e,exports,t){"use strict"
2164
2173
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.def=void 0
2165
2174
  const r=t(6183),n=t(8317)
2166
- exports.def={name:"request_file_history",description:"Get file change history for an entire request. Supports summary mode (net diffs) or detailed mode (chronological operations). Can be filtered to specific task. Use query_history tool instead.",schema:r.QueryHistorySchema,annotations:{title:"Request File History",readOnlyHint:!0},hidden:!0,readOnly:!0,handler(e,t){return(0,n.handleRequestFileHistory)(e,t.context,t.apiClient,t.logger,t.metrics)}}},3626(e,exports,t){"use strict"
2175
+ exports.def={name:"request_file_history",description:"Get file change history for an entire request. Supports summary mode (net diffs) or detailed mode (chronological operations). Can be filtered to specific task. Use query_history tool instead.",schema:r.QueryHistorySchema,annotations:{title:"Request File History",readOnlyHint:!0},hidden:!0,readOnly:!0,handler(e,t){return(0,n.handleRequestFileHistory)(e,t.context,t.apiClient,t.logger,t.metrics)}}},3580(e,exports){"use strict"
2176
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.isAgentReviewMode=function(e){return"agent-review"===e||"agent-review-then-signoff"===e}},3626(e,exports,t){"use strict"
2167
2177
  function r(e){if(!e)return!1
2168
2178
  const t=e.toLowerCase().replace(/^\./,"")
2169
2179
  return u.has(t)}function n(e,t){if(r(t)){const t=e.match(/^([ \t]*)(.*?)\s*$/)
@@ -2283,19 +2293,19 @@ if(x=e.id,f.info("Created task",{taskId:x}),f.debug("Executing file operation",{
2283
2293
  else if("replace"===t)C=await(0,o.handleReplaceInFiles)({taskId:x,..._,comment:E},u,b,k,w,p,m,g)
2284
2294
  else{if("manage"!==t)throw new r.ValidationError("Unsupported operation type: "+t)
2285
2295
  C=await(0,i.handleManageFiles)({taskId:x,..._,comment:E||v},u,b,k,w,h,p,m,g)}if(C.isError){f.error("File operation failed, cleaning up request and task",{requestId:T,taskId:x})
2286
- try{await b.updateTaskStatus(x,"canceled"),f.info("Canceled task after operation failure",{taskId:x})}catch(e){f.warn("Failed to cancel task during cleanup",{taskId:x,error:e instanceof Error?e.message:e+""})}try{await w.updateRequest(T,{status:"canceled"}),f.info("Canceled request after operation failure",{requestId:T}),u.workspaceManager&&(await u.workspaceManager.cancelRequest(T),f.info("Cleaned up branch/worktree after operation failure",{requestId:T}))}catch(e){f.warn("Failed to cancel request during cleanup",{requestId:T,error:e instanceof Error?e.message:e+""})}return{content:[{type:"text",text:`\u274c Quick change failed during ${t} operation:\n\n${C.content[0].text}\n\nThe request (${T}) and task have been canceled and cleaned up.`}],isError:!0}}const q=C.content[0].text,P=q.includes("\u26a0\ufe0f Partial Success")||q.includes("\u274c Failed")||q.includes("\u274c 0 successful")
2287
- P?f.warn("File operation completed with partial failures",{requestId:T}):f.info("File operation completed successfully"),f.debug("Completing task")
2288
- try{await(0,a.handleCompleteTask)({taskId:x,summary:`Executed ${t} operation for quick fix: ${v}${P?" (partial success)":""}`},u,h,p,m),f.info("Task completed successfully",{taskId:x})}catch(e){f.error("Task completion via handleCompleteTask failed, attempting direct status update",{taskId:x,error:e instanceof Error?e.message:e+"",errorStack:e instanceof Error?e.stack:void 0})
2296
+ try{await b.updateTaskStatus(x,"canceled"),f.info("Canceled task after operation failure",{taskId:x})}catch(e){f.warn("Failed to cancel task during cleanup",{taskId:x,error:e instanceof Error?e.message:e+""})}try{await w.updateRequest(T,{status:"canceled"}),f.info("Canceled request after operation failure",{requestId:T}),u.workspaceManager&&(await u.workspaceManager.cancelRequest(T),f.info("Cleaned up branch/worktree after operation failure",{requestId:T}))}catch(e){f.warn("Failed to cancel request during cleanup",{requestId:T,error:e instanceof Error?e.message:e+""})}return{content:[{type:"text",text:`\u274c Quick change failed during ${t} operation:\n\n${C.content[0].text}\n\nThe request (${T}) and task have been canceled and cleaned up.`}],isError:!0}}const q=C.content[0].text,R=q.includes("\u26a0\ufe0f Partial Success")||q.includes("\u274c Failed")||q.includes("\u274c 0 successful")
2297
+ R?f.warn("File operation completed with partial failures",{requestId:T}):f.info("File operation completed successfully"),f.debug("Completing task")
2298
+ try{await(0,a.handleCompleteTask)({taskId:x,summary:`Executed ${t} operation for quick fix: ${v}${R?" (partial success)":""}`},u,h,p,m),f.info("Task completed successfully",{taskId:x})}catch(e){f.error("Task completion via handleCompleteTask failed, attempting direct status update",{taskId:x,error:e instanceof Error?e.message:e+"",errorStack:e instanceof Error?e.stack:void 0})
2289
2299
  try{await b.updateTaskStatus(x,"completed"),f.info("Task completed via direct updateTaskStatus call",{taskId:x})}catch(e){return f.error("Direct task completion ALSO failed - task may be stuck in in_progress",{taskId:x,error:e instanceof Error?e.message:e+"",errorStack:e instanceof Error?e.stack:void 0,operationType:t,isDocumentOperation:!!_.documentId}),{content:[{type:"text",text:`\u26a0\ufe0f Quick change operation succeeded but task completion failed.\n\n**Request:** ${T}\n**Task:** ${x}\n**Issue:** Could not mark task as completed - it remains in 'in_progress' state\n\nThe ${t} operation was successful, but we couldn't automatically complete the task. Please use the complete-task tool manually with taskId: ${x}\n\nError: `+(e instanceof Error?e.message:e+"")}],isError:!0}}}f.debug("Completing request")
2290
- const R=P?`Quick change completed with partial success: ${v}. Some replacements failed - see details below.`:"Quick change completed: "+v,M=P?t+" operation partially completed - some operations succeeded, some failed":t+" operation executed successfully"
2300
+ const P=R?`Quick change completed with partial success: ${v}. Some replacements failed - see details below.`:"Quick change completed: "+v,M=R?t+" operation partially completed - some operations succeeded, some failed":t+" operation executed successfully"
2291
2301
  let $=!1
2292
- try{const e=await(0,c.handleCompleteRequest)({requestId:T,summary:R,acceptanceEvidence:[{evidence:M}],testVerification:void 0},u,h,p,m,g)
2302
+ try{const e=await(0,c.handleCompleteRequest)({requestId:T,summary:P,acceptanceEvidence:[{evidence:M}],testVerification:void 0},u,h,p,m,g)
2293
2303
  if(e.isError)f.error("Request completion failed, attempting direct completion",{requestId:T,error:e.content[0].text})
2294
- else{try{await w.updateRequest(T,{status:"completed",completionSummary:R}),f.info("Request finalized to completed",{requestId:T})}catch(e){f.warn("Failed to finalize request to completed, may be stuck at ready_for_merge",{requestId:T,error:(0,d.getErrorMessage)(e)})}$=!0,f.info("Request completed successfully",{requestId:T})}}catch(e){f.error("Request completion threw exception, attempting direct completion",{requestId:T,error:e instanceof Error?e.message:e+""})}if(!$)try{f.info("Attempting direct request completion via API",{requestId:T}),await w.updateRequest(T,{status:"completed",completionSummary:R}),$=!0,f.info("Request completed successfully via direct API call",{requestId:T})}catch(e){return f.error("Direct request completion also failed",{requestId:T,error:e instanceof Error?e.message:e+""}),{content:[{type:"text",text:`\u26a0\ufe0f Quick change operation succeeded but request completion failed.\n\n**Request:** ${T}\n**Status:** Still in 'in_progress' - please complete manually\n\nThe file operation was successful, but we couldn't automatically complete the request. Please use the complete-request tool manually.`}],isError:!0}}const j=Date.now()-y
2295
- f.info("Quick fix completed",{requestId:T,duration:j,hasPartialFailure:P})
2304
+ else{try{await w.updateRequest(T,{status:"completed",completionSummary:P}),f.info("Request finalized to completed",{requestId:T})}catch(e){f.warn("Failed to finalize request to completed, may be stuck at ready_for_merge",{requestId:T,error:(0,d.getErrorMessage)(e)})}$=!0,f.info("Request completed successfully",{requestId:T})}}catch(e){f.error("Request completion threw exception, attempting direct completion",{requestId:T,error:e instanceof Error?e.message:e+""})}if(!$)try{f.info("Attempting direct request completion via API",{requestId:T}),await w.updateRequest(T,{status:"completed",completionSummary:P}),$=!0,f.info("Request completed successfully via direct API call",{requestId:T})}catch(e){return f.error("Direct request completion also failed",{requestId:T,error:e instanceof Error?e.message:e+""}),{content:[{type:"text",text:`\u26a0\ufe0f Quick change operation succeeded but request completion failed.\n\n**Request:** ${T}\n**Status:** Still in 'in_progress' - please complete manually\n\nThe file operation was successful, but we couldn't automatically complete the request. Please use the complete-request tool manually.`}],isError:!0}}const j=Date.now()-y
2305
+ f.info("Quick fix completed",{requestId:T,duration:j,hasPartialFailure:R})
2296
2306
  const O=(0,n.readAlchemyMeta)(C)?.toolRecordId
2297
2307
  let D
2298
- return D=P?`\u26a0\ufe0f Quick change completed with partial success\n\n**Request:** ${T}\n**Title:** ${v}\n**Operation:** ${t}\n**Duration:** ${j}ms\n**Status:** Some operations succeeded, some failed\n\nThe successful changes have been applied and automatically merged to main.\n**Active branch:** main\n\n**\u26a0\ufe0f Note:** This quick-fix had partial failures. See operation details below:\n\n`+q:`\u2705 Quick change completed successfully!\n\n**Request:** ${T}\n**Title:** ${v}\n**Operation:** ${t}\n**Duration:** ${j}ms\n\nThe change has been applied and automatically merged to main.\n**Active branch:** main`+(O?`\n[RECORD:${O}]`:""),S&&(D+="\n\n\u{1f4a1} **Recommendation:** You've created several quick-edits in a row. For better traceability and organization, consider creating a proper feature or bugfix request with multiple tasks for your next change."),{content:[{type:"text",text:D}],...(0,n.alchemyMeta)({kind:"quick-"+t,toolRecordId:O})}}catch(e){if(f.error("Quick change workflow failed after request creation, cleaning up",{requestId:T,error:(0,d.getErrorMessage)(e)}),x)try{await b.updateTaskStatus(x,"canceled"),f.info("Canceled task after workflow failure",{taskId:x})}catch(e){f.warn("Failed to cancel task during cleanup",{taskId:x,error:e instanceof Error?e.message:e+""})}try{await w.updateRequest(T,{status:"canceled"}),f.info("Canceled request after workflow failure",{requestId:T}),u.workspaceManager&&(await u.workspaceManager.cancelRequest(T),f.info("Cleaned up branch/worktree after workflow failure",{requestId:T}))}catch(e){f.warn("Failed to cancel request during cleanup",{requestId:T,error:e instanceof Error?e.message:e+""})}throw e}}catch(e){const t=Date.now()-y
2308
+ return D=R?`\u26a0\ufe0f Quick change completed with partial success\n\n**Request:** ${T}\n**Title:** ${v}\n**Operation:** ${t}\n**Duration:** ${j}ms\n**Status:** Some operations succeeded, some failed\n\nThe successful changes have been applied and automatically merged to main.\n**Active branch:** main\n\n**\u26a0\ufe0f Note:** This quick-fix had partial failures. See operation details below:\n\n`+q:`\u2705 Quick change completed successfully!\n\n**Request:** ${T}\n**Title:** ${v}\n**Operation:** ${t}\n**Duration:** ${j}ms\n\nThe change has been applied and automatically merged to main.\n**Active branch:** main`+(O?`\n[RECORD:${O}]`:""),S&&(D+="\n\n\u{1f4a1} **Recommendation:** You've created several quick-edits in a row. For better traceability and organization, consider creating a proper feature or bugfix request with multiple tasks for your next change."),{content:[{type:"text",text:D}],...(0,n.alchemyMeta)({kind:"quick-"+t,toolRecordId:O})}}catch(e){if(f.error("Quick change workflow failed after request creation, cleaning up",{requestId:T,error:(0,d.getErrorMessage)(e)}),x)try{await b.updateTaskStatus(x,"canceled"),f.info("Canceled task after workflow failure",{taskId:x})}catch(e){f.warn("Failed to cancel task during cleanup",{taskId:x,error:e instanceof Error?e.message:e+""})}try{await w.updateRequest(T,{status:"canceled"}),f.info("Canceled request after workflow failure",{requestId:T}),u.workspaceManager&&(await u.workspaceManager.cancelRequest(T),f.info("Cleaned up branch/worktree after workflow failure",{requestId:T}))}catch(e){f.warn("Failed to cancel request during cleanup",{requestId:T,error:e instanceof Error?e.message:e+""})}throw e}}catch(e){const t=Date.now()-y
2299
2309
  return f.error("Quick change failed",{error:(0,d.getErrorMessage)(e),duration:t}),e instanceof r.ValidationError?{content:[{type:"text",text:"\u274c "+e.message}],isError:!0}:{content:[{type:"text",text:"\u274c Quick change failed: "+(0,d.getErrorMessage)(e)}],isError:!0}}}
2300
2310
  const r=t(9860),n=t(2272),s=t(4079),o=t(9442),i=t(7684),a=t(2736),c=t(5715),l=t(7478),d=t(8824)},3807(module){"use strict"
2301
2311
  module.exports=require("simple-git")},3895(e,exports,t){"use strict"
@@ -2369,12 +2379,12 @@ Object.defineProperty(exports,"__esModule",{value:!0}),exports.handleWriteFile=a
2369
2379
  let v,C,_=d.FileOperationPhase.VALIDATION
2370
2380
  const E={toolName:"write_file",operationName:"write",fileOperationPhase:d.FileOperationPhase.FILE_WRITE,recordType:"write-file",metricsPrefix:"write_file",successMessage:"Successfully wrote content",failureMessage:"Failed to write content"}
2371
2381
  try{const n=e
2372
- let{path:g,documentId:S,content:q,format:T,append:x,comment:P}=n
2382
+ let{path:g,documentId:S,content:q,format:T,append:x,comment:R}=n
2373
2383
  Array.isArray(q)&&(q=q.join("\n"))
2374
- const{enforceActiveTask:R}=await Promise.resolve().then(t.bind(t,3451)),M=await R(r,s,f,e.taskId)
2384
+ const{enforceActiveTask:P}=await Promise.resolve().then(t.bind(t,3451)),M=await P(r,s,f,e.taskId)
2375
2385
  if("errorResult"in M)return M.errorResult
2376
2386
  const{taskId:$}=M,j=!!S,O=!!g
2377
- b.info("Writing content to "+(j?"document":"file"),{taskId:$,filePath:O?g:void 0,documentId:j?S:void 0,contentLength:"string"==typeof q?q.length:JSON.stringify(q).length,format:T,append:x,comment:P})
2387
+ b.info("Writing content to "+(j?"document":"file"),{taskId:$,filePath:O?g:void 0,documentId:j?S:void 0,contentLength:"string"==typeof q?q.length:JSON.stringify(q).length,format:T,append:x,comment:R})
2378
2388
  let D,A,F,N="",z=!1,L=!1
2379
2389
  const H=O?g:void 0
2380
2390
  if(j){if(r.apiClient)try{await(0,m.ensureDocumentNotLocked)(S,r.apiClient,b,y,"write_file-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
@@ -2382,18 +2392,18 @@ throw e}if(!r.documentFileManager)throw Error("Document file manager not availab
2382
2392
  N=await r.documentFileManager.getDocumentAsFile(S)
2383
2393
  const e=r.documentFileManager.getCachedDocumentInfo(S)
2384
2394
  F=e?.filename,L=!0,z=!1}_=d.FileOperationPhase.TASK_VALIDATION,y.incrementCounter("write_file_phase",1,{phase:_})
2385
- const B=O?H:"document:"+S,U=await d.validateTaskId($,B,s,b,y,E.metricsPrefix),G=U?.requestId
2386
- let W=null
2387
- O&&G&&(W=await d.validateWorkItemStates($,B,s,i,r,b,y,E.metricsPrefix))
2395
+ const B=O?H:"document:"+S,U=await d.validateTaskId($,B,s,b,y,E.metricsPrefix),W=U?.requestId
2396
+ let G=null
2397
+ O&&W&&(G=await d.validateWorkItemStates($,B,s,i,r,b,y,E.metricsPrefix))
2388
2398
  let V={taskPromoted:!1,requestPromoted:!1}
2389
- O&&G&&W&&(V=await d.autoPromoteTaskStatus($,U.status,G,W.request?.status,B,s,i,b,y,E.metricsPrefix),V.taskPromoted&&b.info("Auto-promoted task to in_progress for file operation",{taskId:$,requestId:G,previousStatus:U.status,newStatus:V.newTaskStatus,triggeringOperation:"write_file"}))
2390
- const Q=await d.ensureCorrectWorkspaceContext({taskPromoted:V.taskPromoted,requestId:G,context:r,operation:"write_file",logger:b,metrics:y,metricsPrefix:E.metricsPrefix,requireRequestContext:O})
2399
+ O&&W&&G&&(V=await d.autoPromoteTaskStatus($,U.status,W,G.request?.status,B,s,i,b,y,E.metricsPrefix),V.taskPromoted&&b.info("Auto-promoted task to in_progress for file operation",{taskId:$,requestId:W,previousStatus:U.status,newStatus:V.newTaskStatus,triggeringOperation:"write_file"}))
2400
+ const Q=await d.ensureCorrectWorkspaceContext({taskPromoted:V.taskPromoted,requestId:W,context:r,operation:"write_file",logger:b,metrics:y,metricsPrefix:E.metricsPrefix,requireRequestContext:O})
2391
2401
  if(!Q.success)throw Error(Q.error)
2392
- if(Q.switched&&b.info("Workspace context successfully established",{requestId:G,branchName:Q.branchName,operation:"write_file"}),O&&H){const e=d.validateAndNormalizePath(H,r)
2402
+ if(Q.switched&&b.info("Workspace context successfully established",{requestId:W,branchName:Q.branchName,operation:"write_file"}),O&&H){const e=d.validateAndNormalizePath(H,r)
2393
2403
  D=e.normalizedPath,A=e.fullPath,N=A
2394
- try{await c.default.access(A),L=!0}catch{L=!1,z=!0}b.debug("Path validated with correct workspace context",{rawPath:H,normalizedPath:D,fullPath:A,workspaceBasePath:r.workspaceManager?.getCurrentContext(r.currentSessionId).basePath})}if(j&&G)try{await(0,h.validateRequestStatusForDocumentOperation)(G,i,b,y,"write_file-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2404
+ try{await c.default.access(A),L=!0}catch{L=!1,z=!0}b.debug("Path validated with correct workspace context",{rawPath:H,normalizedPath:D,fullPath:A,workspaceBasePath:r.workspaceManager?.getCurrentContext(r.currentSessionId).basePath})}if(j&&W)try{await(0,h.validateRequestStatusForDocumentOperation)(W,i,b,y,"write_file-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2395
2405
  throw e}_=d.FileOperationPhase.RECORD_CREATION,y.incrementCounter("write_file_phase",1,{phase:_})
2396
- const{toolRecordId:K}=await d.createFileOperationRecords($,G,r.projectId,E.recordType,B,{operationType:j?"document":"file",documentId:j?S:void 0,documentFilename:F,filePath:O?D:void 0,contentLength:"string"==typeof q?q.length:JSON.stringify(q).length,format:T||"text",append:x||!1,wasFileCreated:!L,userComment:P},s,o,b,y,E.metricsPrefix,w)
2406
+ const{toolRecordId:K}=await d.createFileOperationRecords($,W,r.projectId,E.recordType,B,{operationType:j?"document":"file",documentId:j?S:void 0,documentFilename:F,filePath:O?D:void 0,contentLength:"string"==typeof q?q.length:JSON.stringify(q).length,format:T||"text",append:x||!1,wasFileCreated:!L,userComment:R},s,o,b,y,E.metricsPrefix,w)
2397
2407
  let J
2398
2408
  if(v=K,C=K,_=E.fileOperationPhase,y.incrementCounter("write_file_phase",1,{phase:_}),"json"===T)if("string"==typeof q)try{JSON.parse(q),J=q}catch(e){throw new u.ValidationError("Content is not valid JSON")}else J=JSON.stringify(q,null,2)
2399
2409
  else J="string"==typeof q?q:JSON.stringify(q,null,2)
@@ -2406,7 +2416,7 @@ if(await c.default.mkdir(Z,{recursive:!0}),await c.default.writeFile(N,Y,"utf8")
2406
2416
  try{await r.documentFileManager.syncDocument(S),b.info("Document synced successfully",{documentId:S})}catch(e){b.warn("Failed to sync document immediately",{documentId:S,error:e})}}let X,ee,te=null,re=!1
2407
2417
  if(O){if(_=d.FileOperationPhase.GIT_COMMIT,y.incrementCounter("write_file_phase",1,{phase:_}),r.workspaceManager){const e=r.workspaceManager.getCurrentContext(r.currentSessionId)
2408
2418
  ee=e.branchName,re=e.permanentBranch,b.debug("Retrieved branch name from workspace manager",{branchName:ee,requestId:e.requestId,mode:e.mode,isMainBranch:e.isMainBranch})}try{const e=`${z?"Create":x?"Append to":"Update"} ${D} (${C})`,t=await d.commitToGit($,D,C,C,e,r,b,y,E.metricsPrefix)
2409
- X=t.commitHash,te=t.previousCommitHash,b.info("Changes committed to git via shared utility",{path:D,commitMessage:e,commitHash:X?.substring(0,8),previousCommitHash:te?.substring(0,8),branchName:ee,toolRecordId:C})}catch(e){b.warn("Git operations failed via shared utility",{error:e})}}try{await o.updateToolRecord(C,{metadata:{path:O?D:"document:"+S,status:"completed",finalContentLength:Y.length,wasFileCreated:z,wasAppended:x&&L,operationType:j?"document":"file",processingTime:Date.now()-k,userComment:P,...O&&X&&{commitHash:X,previousCommitHash:te||void 0}},note:"Write operation completed successfully"+(j?" (document synced)":" (committed to git)")})}catch(e){b.warn("Failed to update tool record",{recordError:e})}let ne=`**${z?"Created":x?"Appended to":"Updated"} ${j?`document ${S}${F?` (${F})`:""}`:"file "+D}**\n`
2419
+ X=t.commitHash,te=t.previousCommitHash,b.info("Changes committed to git via shared utility",{path:D,commitMessage:e,commitHash:X?.substring(0,8),previousCommitHash:te?.substring(0,8),branchName:ee,toolRecordId:C})}catch(e){b.warn("Git operations failed via shared utility",{error:e})}}try{await o.updateToolRecord(C,{metadata:{path:O?D:"document:"+S,status:"completed",finalContentLength:Y.length,wasFileCreated:z,wasAppended:x&&L,operationType:j?"document":"file",processingTime:Date.now()-k,userComment:R,...O&&X&&{commitHash:X,previousCommitHash:te||void 0}},note:"Write operation completed successfully"+(j?" (document synced)":" (committed to git)")})}catch(e){b.warn("Failed to update tool record",{recordError:e})}let ne=`**${z?"Created":x?"Appended to":"Updated"} ${j?`document ${S}${F?` (${F})`:""}`:"file "+D}**\n`
2410
2420
  ne+=`**Content Length:** ${Y.length} characters\n`,O&&ee&&(re||(ne+=`**Branch:** ${ee}\n`)),O&&X&&(ne+=`**Commit Hash:** ${X.substring(0,8)}\n`,te&&(ne+=`**Previous Commit:** ${te.substring(0,8)}\n`)),j&&(ne+=`\n**Document Update:** The document content has been updated and synced back to the tracking system. You can continue editing using other file modification tools with documentId \`${S}\`.`)
2411
2421
  const se=Date.now()
2412
2422
  b.info("Write operation completed successfully",{duration:se-k,path:O?D:"document:"+S,contentLength:Y.length,wasCreated:z}),I({tool:"write_file",success:!0}),y.incrementCounter("write_file_total",1,{success:!0})
@@ -2539,9 +2549,9 @@ e.grep&&(C=`${C} 2>&1 | grep -i ${JSON.stringify(e.grep)}`)
2539
2549
  const _=t.workspaceManager?.getCurrentContext(t.currentSessionId)?.basePath||t.basePath,E=v.cwd?o.default.resolve(_,v.cwd):_,S=o.default.join(_,a.ALCHEMY_DIR_NAME,"command-logs"),q=`${v.name.replace(/[^a-zA-Z0-9._-]/g,"_")}-${Date.now()}`,T=o.default.join(S,q+".log")
2540
2550
  let x=null
2541
2551
  try{i.default.mkdirSync(S,{recursive:!0}),x=i.default.createWriteStream(T,{flags:"w"}),x.write(`# ${(new Date).toISOString()} starting: ${C}\n# cwd: ${E}\n# timeout: ${v.timeout||60}s\n\n`)}catch(e){h.warn("Failed to open command log file",{logPath:T,error:(0,l.getErrorMessage)(e)})}h.info("Running command",{name:v.name,command:C,cwd:E,configuredCwd:v.cwd,logPath:T})
2542
- const P=await(0,n.runTrackedShellWithHeartbeat)(C,{cwd:E,timeoutMs:1e3*(v.timeout||60),env:{...process.env,FORCE_COLOR:"0"},onChunk:x?(e,t)=>{x?.write(t)}:void 0},{id:q,name:v.name,sessionId:g?.sessionId,logPath:T},f)
2543
- x&&(x.write(`\n# exit: ${P.exitCode}${P.timedOut?" (timed out)":""}\n`),x.end())
2544
- const{stdout:R,stderr:M,exitCode:$,timedOut:j}=P,{output:O,truncatedNote:D,logFooter:A}=(0,s.formatCommandOutput)(R,M,{invocationId:q}),F=j?"TIMEOUT":null
2552
+ const R=await(0,n.runTrackedShellWithHeartbeat)(C,{cwd:E,timeoutMs:1e3*(v.timeout||60),env:{...process.env,FORCE_COLOR:"0"},onChunk:x?(e,t)=>{x?.write(t)}:void 0},{id:q,name:v.name,sessionId:g?.sessionId,logPath:T},f)
2553
+ x&&(x.write(`\n# exit: ${R.exitCode}${R.timedOut?" (timed out)":""}\n`),x.end())
2554
+ const{stdout:P,stderr:M,exitCode:$,timedOut:j}=R,{output:O,truncatedNote:D,logFooter:A}=(0,s.formatCommandOutput)(P,M,{invocationId:q}),F=j?"TIMEOUT":null
2545
2555
  let N
2546
2556
  if(m)try{const e=await m.createToolRecord({projectId:t.projectId,type:"run-command",metadata:{name:v.name,command:C,exitCode:$,timedOut:j,status:j?"timeout":0===$?"success":"failed",timestamp:(new Date).toISOString()}})
2547
2557
  N=e?.id}catch(e){h.debug("Failed to create tool record for command run",{error:(0,l.getErrorMessage)(e)})}return y({success:!0}),{content:[{type:"text",text:`## ${v.name}${F?` \u2014 ${F} (killed after ${v.timeout}s)`:""}\n\`\`\`\n$ ${C}\n${O}\n\`\`\`${D}\n\nExit code: ${$}\n${A} (pass to read_files or search)`}],...(0,c.alchemyMeta)({kind:"run-command",toolRecordId:N})}}catch(e){return y({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to run command: "+(0,l.getErrorMessage)(e)}],isError:!0}}}
@@ -2651,7 +2661,7 @@ const{operation:I}=w
2651
2661
  if("list"!==I&&"search"!==I&&!b){const e=await(0,a.resolveRequestIdOrError)(p,y,t.currentSessionId,`Error: requestId is required for '${I}' and could not be resolved from session`)
2652
2662
  if(!e.ok)return e.errorResult
2653
2663
  b=e.requestId}switch(y.info("Processing request operation",{requestId:b,operation:I}),I){case"complete":{y.info("Routing to complete-request handler")
2654
- const e={requestId:b,summary:w.complete.summary,skipTestsReason:w.complete.skipTestsReason,skipTests:w.complete.skipTests}
2664
+ const e={requestId:b,summary:w.complete.summary,skipTestsReason:w.complete.skipTestsReason,skipTests:w.complete.skipTests,criteriaComments:w.complete.criteriaComments}
2655
2665
  return(0,u.withAlchemyKind)(await(0,r.handleCompleteRequest)(e,t,p,m,g,f),h.complete)}case"merge":return y.info("Routing to merge handler"),(0,u.withAlchemyKind)(await(0,l.handleMergeRequest)({requestId:b,verifications:w.merge?.verifications||[]},t,p,m,g,f),h.merge)
2656
2666
  case"approve":{y.info("Routing to approve-request handler")
2657
2667
  const e={requestId:b}
@@ -3088,48 +3098,59 @@ return{isOffline:this.isInOfflineMode(),consecutiveFailures:e.consecutiveFailure
3088
3098
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.def=void 0
3089
3099
  const r=t(6183),n=t(2965)
3090
3100
  exports.def={name:"read_files",description:'Read the contents of multiple files and documents with flexible line selection.\n\nLINE SELECTION (string format):\n- Single line: "lines": "5"\n- Multiple lines: "lines": "1,3,7,10"\n- Range: "lines": "5-15"\n- Entire file: omit "lines" parameter\n\nEXAMPLES:\n- Read first 10 lines: {"path": "file.txt", "lines": "1-10"}\n- Read specific lines: {"path": "file.txt", "lines": "1,5,25"}\n- Read line 42 only: {"path": "file.txt", "lines": "42"}\n- Read entire file: {"path": "file.txt"}\n\nSupports both filesystem files (using \'path\') and tracked documents (using \'documentId\'). More efficient than reading files one by one. Failed reads won\'t stop the entire operation.',schema:r.ReadFilesSchema,annotations:{title:"Read Files/Documents",readOnlyHint:!0},readOnly:!0,handler(e,t){return(0,n.handleReadFiles)(e,t.context,t.logger,t.metrics)}}},5715(e,exports,t){"use strict"
3091
- Object.defineProperty(exports,"__esModule",{value:!0}),exports.handleCompleteRequest=async function(e,t,c,l,d,u,h){const p=l.child({tool:"complete_request"}),m=d.startTimer("tool_execution_time")
3092
- try{const{requestId:n,summary:s,skipTestsReason:l,skipTests:d}=e
3101
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.handleCompleteRequest=async function(e,t,l,d,u,h,p){const m=d.child({tool:"complete_request"}),g=u.startTimer("tool_execution_time")
3102
+ try{const{requestId:n,summary:s,skipTestsReason:d,skipTests:u,criteriaComments:h}=e
3093
3103
  if(!n)throw(0,r.createValidationError)("Request ID is required")
3094
3104
  if(!s)throw(0,r.createValidationError)("Summary is required")
3095
- if(l&&d&&d.length>0)throw(0,r.createValidationError)("Provide either skipTestsReason (skip all) or skipTests (per-command), not both.")
3096
- p.info("Starting request completion",{requestId:n,skipAllRequested:!!l,perCommandSkipCount:d?.length||0})
3097
- const u=h?.sessionId
3098
- let g
3099
- try{const e=await c.proxyPost(`/api/projects/${t.projectId}/requests/${n}/validate-completion`,{sessionId:u,skipTestsReason:l,skipTests:d})
3100
- g=e?.data||e}catch(e){const t=(0,o.getErrorMessage)(e)
3101
- return p.error("Server validation failed",{requestId:n,error:t}),m({success:!1,error:"validation_request_failed"}),{content:[{type:"text",text:"Failed to validate completion: "+t}],isError:!0}}if(!g.canComplete){let e=`Cannot complete request ${n}: ${g.reason}\n`
3102
- return g.blockedByTasks&&g.blockedByTasks.length>0&&(e+="\n**Tasks that must be completed or canceled first:**\n",g.blockedByTasks.forEach(((t,r)=>{e+=`${r+1}. **${t.taskId}** - ${t.title} (Status: ${t.status})\n`}))),g.lifoViolation&&(e+="\n**Requests that must be re-completed first (LIFO order):**\n",g.lifoViolation.blockingRequests.forEach(((t,r)=>{e+=`${r+1}. **${t.requestId}** - ${t.title} (Status: ${t.status})\n`}))),m({success:!1,reason:"server_blocked"}),{content:[{type:"text",text:e}],isError:!0}}if(g.testsSkipped&&(l||d&&d.length>0))try{const e=c.getToolRecordClient()
3103
- e&&await e.createToolRecord({projectId:t.projectId,requestId:n,type:"tests-skipped",metadata:{...l?{reason:l}:{},...d&&d.length>0?{skipTests:d}:{},completionMode:g.completionMode,timestamp:(new Date).toISOString()}})}catch(e){p.warn("Failed to persist tests-skipped tool_record",{error:(0,o.getErrorMessage)(e)})}const f=c.getRequestClient(),y="auto-merge"!==g.completionMode&&!g.testsSkipped&&!1===g.hasActiveTestProcesses&&("test-by-default"===g.completionMode||"always-test"===g.completionMode)
3104
- let w="auto-merge"!==g.completionMode&&!g.testsSkipped&&!y
3105
- const b="manual-review"===g.reviewMode
3106
- let I,k=null
3107
- if(w)try{const[e,r]=await Promise.all([c.proxyGet(`/api/projects/${t.projectId}/requests/${n}/test-runs`),fetch(`${(0,a.getActionServerBaseUrl)()}/api/branch-head?requestId=${encodeURIComponent(n)}`,{signal:AbortSignal.timeout(5e3)}).catch((e=>(p.debug("branch-head fetch failed; proceeding with ready_for_review",{error:(0,o.getErrorMessage)(e)}),null)))]),s=e?.data||e||[],i=Array.isArray(s)&&s.length>0?s[0]:null
3108
- if(i&&"passed"===i.status&&i.commitSha){let e=null
3109
- if(r&&r.ok){const t=await r.json()
3110
- e=t?.data?.sha??null}e&&e===i.commitSha&&(w=!1,k=`latest test run ${i.id} passed against current branch HEAD ${e.slice(0,7)}`,I=i.id,p.info("Skip-if-fresh: SHA match, bypassing ready_for_review",{requestId:n,runId:i.id,sha:e}))}}catch(e){p.debug("Skip-if-fresh lookup failed; proceeding with ready_for_review",{error:(0,o.getErrorMessage)(e)})}const v=w||b?"ready_for_review":"ready_for_merge"
3111
- try{await f.updateRequest(n,{status:v,completionSummary:s,...I?{skippedTestRunId:I}:{}})}catch(e){const t=(0,o.getErrorMessage)(e)
3112
- return m({success:!1,error:"status_transition_failed"}),{content:[{type:"text",text:"Failed to transition request: "+t}],isError:!0}}let C
3113
- try{C=await f.getRequest(n)}catch(e){const t=(0,o.getErrorMessage)(e)
3114
- return m({success:!1,error:"fetch_request_failed"}),{content:[{type:"text",text:"Failed to fetch request criteria: "+t}],isError:!0}}const _=C?.acceptanceCriteria||[]
3115
- if(m({success:!0}),w){const e=g.completionMode
3116
- return{content:[{type:"text",text:`Request ${n} moved to ready_for_review. ${"ask-me"===e?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip).":`Tests are running automatically in the background (${e} mode). When they pass and the project is set to auto-finalize, the request will be merged without further input; otherwise the user will click Finalize after reviewing.`} Do NOT call merge or any other tool. Your work is done. Stop here and wait.`}]}}if(b)return{content:[{type:"text",text:`Request ${n} submitted for human review.${g.testsSkipped&&l?`\n\n_Tests skipped: ${l}_`:""}\n\nThe project is set to manual-review \u2014 a person will approve and merge from the UI. Do NOT call merge yourself.`}]}
3117
- const E=k?`\n\n_Skipped re-running tests: ${k}._\n`:"",S=y?`\n\n_No test processes are configured for this project; ${g.completionMode} mode is being treated as auto-merge._\n`:""
3118
- return 0===_.length?{content:[{type:"text",text:`Request ${n} is ready. ${E}${S}No acceptance criteria defined \u2014 call merge directly.`}]}:{content:[{type:"text",text:`Request ${n} completion started (${v}).${E}${S}\n\n## Next Step: Verify & Merge\n\n${(0,i.formatVerifyInstructions)(_)}\n\nUse the merge operation with your verification evidence to merge to main.`}]}}catch(r){let o="An unexpected error occurred",i=""
3119
- r instanceof n.ZodError?(o="Validation error",i=r.errors.map((e=>`${e.path.join(".")}: ${e.message}`)).join(", ")):r instanceof Error?(o=r.message,i=r.stack||""):i=r+"",p.error("Complete request failed",{error:o,details:i})
3120
- try{await(0,s.createFailureToolRecord)("complete-request",r,{error:o,details:i,requestId:e?.requestId},c.getToolRecordClient(),p,d,{requestId:e?.requestId,projectId:t.projectId,note:"Failed to complete request"})}catch{}return d.startTimer("tool_execution_time")({success:!1,error:r instanceof Error?r.name:"unknown"}),{content:[{type:"text",text:"Error: "+o}],isError:!0}}}
3121
- const r=t(9860),n=t(1569),s=t(8616),o=t(8824),i=t(5454),a=t(9414)},5767(e,exports,t){"use strict"
3105
+ if(d&&u&&u.length>0)throw(0,r.createValidationError)("Provide either skipTestsReason (skip all) or skipTests (per-command), not both.")
3106
+ m.info("Starting request completion",{requestId:n,skipAllRequested:!!d,perCommandSkipCount:u?.length||0})
3107
+ const f=p?.sessionId??t.currentSessionId,y=p??(f?{providerId:"unknown",sessionId:f,createdAt:(new Date).toISOString()}:void 0)
3108
+ let w,b=null
3109
+ try{const e=await fetch(`${(0,a.getActionServerBaseUrl)()}/api/branch-head?requestId=${encodeURIComponent(n)}`,{signal:AbortSignal.timeout(5e3)})
3110
+ if(e.ok){const t=await e.json()
3111
+ b=t?.data?.sha??null}}catch(e){m.debug("branch-head fetch failed; server will fall back",{error:(0,o.getErrorMessage)(e)})}try{const e=await l.proxyPost(`/api/projects/${t.projectId}/requests/${n}/validate-completion`,{sessionId:f,skipTestsReason:d,skipTests:u,headSha:b})
3112
+ w=e?.data||e}catch(e){const t=(0,o.getErrorMessage)(e)
3113
+ return m.error("Server validation failed",{requestId:n,error:t}),g({success:!1,error:"validation_request_failed"}),{content:[{type:"text",text:"Failed to validate completion: "+t}],isError:!0}}if(!w.canComplete){let e=`Cannot complete request ${n}: ${w.reason}\n`
3114
+ return w.blockedByTasks&&w.blockedByTasks.length>0&&(e+="\n**Tasks that must be completed or canceled first:**\n",w.blockedByTasks.forEach(((t,r)=>{e+=`${r+1}. **${t.taskId}** - ${t.title} (Status: ${t.status})\n`}))),w.lifoViolation&&(e+="\n**Requests that must be re-completed first (LIFO order):**\n",w.lifoViolation.blockingRequests.forEach(((t,r)=>{e+=`${r+1}. **${t.requestId}** - ${t.title} (Status: ${t.status})\n`}))),g({success:!1,reason:"server_blocked"}),{content:[{type:"text",text:e}],isError:!0}}if(h&&h.length>0)try{const e=l.getRequestClient(),r=await e.getRequest(n),s=r?.acceptanceCriteria||[]
3115
+ if(s.length>0){const e=(0,i.buildCriteriaKeyMap)(s),r=[]
3116
+ for(const t of h){const n=e.get(t.key)
3117
+ n&&r.push({criterionId:n.id,evidence:t.comment})}r.length>0&&await l.proxyPost(`/api/projects/${t.projectId}/requests/${n}/verify-criteria`,{verifications:r,dimension:"coder"})}}catch(e){m.warn("Failed to persist coder criteria comments",{error:(0,o.getErrorMessage)(e)})}if((0,c.isAgentReviewMode)(w.reviewMode)&&"escalated"===w.reviewStatus)return g({success:!0}),{content:[{type:"text",text:`Request ${n}: agent review hit its pass cap and was escalated for human sign-off. No further action from you; a human finalizes or sends back must_fix items.`}]}
3118
+ if((0,c.isAgentReviewMode)(w.reviewMode)&&w.reviewFresh&&"pending"!==w.reviewStatus&&"completed"!==w.reviewStatus&&"escalated"!==w.reviewStatus)try{await l.getRequestClient().updateRequest(n,{reviewStatus:"completed",completionSummary:s})}catch(e){return g({success:!1,error:"review_mark_failed"}),{content:[{type:"text",text:"Failed to record review: "+(0,o.getErrorMessage)(e)}],isError:!0}}else if((0,c.isAgentReviewMode)(w.reviewMode)&&"pending"!==w.reviewStatus&&"completed"!==w.reviewStatus){const e=l.getRequestClient()
3119
+ try{await e.updateRequest(n,{reviewStatus:"pending",completionSummary:s,cliOrigin:y})}catch(e){return g({success:!1,error:"review_start_failed"}),{content:[{type:"text",text:"Failed to start review: "+(0,o.getErrorMessage)(e)}],isError:!0}}return g({success:!0}),{content:[{type:"text",text:`Request ${n}: review started. Read-only reviewers are reading your diff. STOP here and wait \u2014 do NOT poll, sleep, or call tools to pass the time; each reviewer's report is delivered to you automatically and wakes you, so just end your turn between reports. When their reports arrive (a detailed handoff follows with the specifics), act on the findings, finish your tasks, and call complete again. After review passes, the server runs any remaining gates and messages you the exact next step (run tests, await human sign-off, or merge) -- wait for that and don't merge until it tells you to.`}]}}if((0,c.isAgentReviewMode)(w.reviewMode)&&"pending"===w.reviewStatus){const e=l.getRequestClient()
3120
+ try{await e.updateRequest(n,{reviewStatus:"completed",completionSummary:s,cliOrigin:y})}catch(e){return g({success:!1,error:"review_finish_failed"}),{content:[{type:"text",text:"Failed to finish review: "+(0,o.getErrorMessage)(e)}],isError:!0}}return g({success:!0}),{content:[{type:"text",text:`Request ${n}: review submitted. The server is evaluating it and will message you the exact next step (run tests, await human sign-off, or merge) -- wait for that before acting. If a criterion is still unmet, the criteria reviewer takes another pass and reports back; address any must_fix and call complete again.`}]}}if((0,c.isAgentReviewMode)(w.reviewMode)&&"completed"===w.reviewStatus&&("auto-merge"===w.completionMode||w.testsSkipped||!0!==w.hasActiveTestProcesses))return g({success:!0}),{content:[{type:"text",text:`Request ${n}: review is complete and all gates are clear. Call merge to finalize (do not call complete again).`}]}
3121
+ if(w.testsSkipped&&(d||u&&u.length>0))try{const e=l.getToolRecordClient()
3122
+ e&&await e.createToolRecord({projectId:t.projectId,requestId:n,type:"tests-skipped",metadata:{...d?{reason:d}:{},...u&&u.length>0?{skipTests:u}:{},completionMode:w.completionMode,timestamp:(new Date).toISOString()}})}catch(e){m.warn("Failed to persist tests-skipped tool_record",{error:(0,o.getErrorMessage)(e)})}const I=l.getRequestClient(),k=!w.testsSkipped&&!1===w.hasActiveTestProcesses&&("test-by-default"===w.completionMode||"always-test"===w.completionMode)
3123
+ let v="auto-merge"!==w.completionMode&&!w.testsSkipped&&!k
3124
+ const C="manual-review"===w.reviewMode
3125
+ let _,E=null
3126
+ if(v)try{const e=await l.proxyGet(`/api/projects/${t.projectId}/requests/${n}/test-runs`),r=e?.data||e||[],s=Array.isArray(r)&&r.length>0?r[0]:null
3127
+ if(s&&"passed"===s.status&&s.commitSha){const e=b
3128
+ e&&e===s.commitSha&&(v=!1,E=`latest test run ${s.id} passed against current branch HEAD ${e.slice(0,7)}`,_=s.id,m.info("Skip-if-fresh: SHA match, bypassing ready_for_review",{requestId:n,runId:s.id,sha:e}))}}catch(e){m.debug("Skip-if-fresh lookup failed; proceeding with ready_for_review",{error:(0,o.getErrorMessage)(e)})}const S=v?"in_progress":C?"ready_for_review":"ready_for_merge",q=v?"running":void 0
3129
+ try{await I.updateRequest(n,{status:S,...q?{testStatus:q}:{},completionSummary:s,cliOrigin:y,..._?{skippedTestRunId:_}:{}})}catch(e){const t=(0,o.getErrorMessage)(e)
3130
+ return g({success:!1,error:"status_transition_failed"}),{content:[{type:"text",text:"Failed to transition request: "+t}],isError:!0}}let T
3131
+ try{T=await I.getRequest(n)}catch(e){const t=(0,o.getErrorMessage)(e)
3132
+ return g({success:!1,error:"fetch_request_failed"}),{content:[{type:"text",text:"Failed to fetch request criteria: "+t}],isError:!0}}const x=T?.acceptanceCriteria||[]
3133
+ if(g({success:!0}),v){const e=w.completionMode
3134
+ return{content:[{type:"text",text:`Request ${n}: tests are now running. ${"ask-me"===e?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip). Stop here; you will receive a report when testing finishes.":`Tests are running automatically in the background (${e} mode). Stop here; a tester subagent will run the test commands and post a report back to you when done.`}\n\n## When the report arrives\n- **Passed** \u2014 call \`merge\` with verification evidence for each acceptance criterion to finalize the request.\n- **Failed** \u2014 fix the issues and call \`complete\` again.\n\nDo NOT call merge, finalize, or any other tool BEFORE the report arrives \u2014 stop here and wait.`}]}}if(C)return{content:[{type:"text",text:`Request ${n} submitted for human review.${w.testsSkipped&&d?`\n\n_Tests skipped: ${d}_`:""}\n\nThe project is set to manual-review \u2014 a person will approve and merge from the UI. Do NOT call merge yourself.`}]}
3135
+ const R=E?`\n\n_Skipped re-running tests: ${E}._\n`:"",P=k?`\n\n_No test processes are configured for this project; ${w.completionMode} mode is being treated as auto-merge._\n`:""
3136
+ return 0===x.length?{content:[{type:"text",text:`Request ${n} is ready. ${R}${P}No acceptance criteria defined \u2014 call merge directly.`}]}:{content:[{type:"text",text:`Request ${n}: all gates are clear.${R}${P}\n\n## Next Step: Verify & Merge\n\n${(0,i.formatVerifyInstructions)(x)}\n\nUse the merge operation with your verification evidence to merge to main.`}]}}catch(r){let o="An unexpected error occurred",i=""
3137
+ r instanceof n.ZodError?(o="Validation error",i=r.errors.map((e=>`${e.path.join(".")}: ${e.message}`)).join(", ")):r instanceof Error?(o=r.message,i=r.stack||""):i=r+"",m.error("Complete request failed",{error:o,details:i})
3138
+ try{await(0,s.createFailureToolRecord)("complete-request",r,{error:o,details:i,requestId:e?.requestId},l.getToolRecordClient(),m,u,{requestId:e?.requestId,projectId:t.projectId,note:"Failed to complete request"})}catch{}return u.startTimer("tool_execution_time")({success:!1,error:r instanceof Error?r.name:"unknown"}),{content:[{type:"text",text:"Error: "+o}],isError:!0}}}
3139
+ const r=t(9860),n=t(1569),s=t(8616),o=t(8824),i=t(5454),a=t(9414),c=t(3580)},5767(e,exports,t){"use strict"
3122
3140
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.def=void 0
3123
3141
  const r=t(6183),n=t(6285)
3124
3142
  exports.def={name:"specialist_ops",description:"Manage your pool of up to 10 specialists. Each has a specialization describing their domain. Reuse specialists via follow-up before spawning new ones.\n\nAll params are flat (no nested objects). The operation field determines which params apply.\n\nOperations:\n\u2022 delegate \u2014 prompt + specialization required. Optional: description, specializationHeadline, requestId.\n\u2022 follow-up \u2014 prompt + sessionId required\n\u2022 check-status \u2014 sessionId required\n\u2022 list \u2014 all params optional: activeOnly, requestId (filter), limit\n\u2022 abort \u2014 sessionId required",schema:r.SpecialistOpsSchema,annotations:{title:"Specialist Operations",readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1},handler(e,t){return(0,n.handleSpecialistOps)(e,t.context,t.logger,t.metrics,t.apiClient??void 0,t.cliOrigin)}}},5802(module){"use strict"
3125
3143
  module.exports=require("@modelcontextprotocol/sdk/server/stdio.js")},5806(e,exports,t){"use strict"
3126
3144
  function r(){const e=(0,s.areTestsRequiredForCompletion)(),t=e?o:i
3127
3145
  if(t)return t
3128
- const r=n.z.object({requestId:n.z.string(),summary:n.z.string(),skipTestsReason:n.z.string().min(20).optional(),skipTests:n.z.array(n.z.object({commandName:n.z.string().min(1),reason:n.z.string().min(20)})).optional(),acceptanceEvidence:n.z.array(n.z.object({evidence:n.z.string()}))}),a=n.z.object({testRecords:n.z.array(n.z.string()),coverage:n.z.object({criteriaTestedCount:n.z.number(),totalTestCases:n.z.number()}),criterionCoverage:n.z.array(n.z.object({coverage:n.z.enum(["none","partial","full"]),testRecords:n.z.array(n.z.string())}))}),c=e?r.extend({testVerification:a}):r
3146
+ const r=n.z.object({requestId:n.z.string(),summary:n.z.string(),skipTestsReason:n.z.string().min(20).optional(),skipTests:n.z.array(n.z.object({commandName:n.z.string().min(1),reason:n.z.string().min(20)})).optional(),criteriaComments:n.z.array(n.z.object({key:n.z.string().min(1),comment:n.z.string().min(1)})).optional()}),a=n.z.object({testRecords:n.z.array(n.z.string()),coverage:n.z.object({criteriaTestedCount:n.z.number(),totalTestCases:n.z.number()}),criterionCoverage:n.z.array(n.z.object({coverage:n.z.enum(["none","partial","full"]),testRecords:n.z.array(n.z.string())}))}),c=e?r.extend({testVerification:a}):r
3129
3147
  return e?o=c:i=c,c}Object.defineProperty(exports,"__esModule",{value:!0}),exports.DynamicCompleteRequestSchema=void 0,exports.getDynamicCompleteRequestSchema=r
3130
3148
  const n=t(1569),s=t(2478)
3131
3149
  let o=null,i=null
3132
- exports.DynamicCompleteRequestSchema={get schema(){return r()}}},5964(e,exports){"use strict"
3150
+ exports.DynamicCompleteRequestSchema={get schema(){return r()}}},5837(e,exports,t){"use strict"
3151
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.def=void 0
3152
+ const r=t(1569),n=t(7648),s=r.z.object({requestId:r.z.string().describe("The request whose acceptance criteria are being recorded."),verifications:r.z.array(r.z.object({key:r.z.string().min(1).describe('Short criterion key (e.g. "1a") as shown next to the criterion.'),status:r.z.enum(["met","unmet"]).default("met").describe('Verdict for this criterion: "met" if the diff delivers it, "unmet" if missing or only partial.'),evidence:r.z.string().min(1).describe("For met: how the diff satisfies it (cite file:line). For unmet: what is missing and how to fix it.")})).min(1).describe("One entry per acceptance criterion you reviewed: record a verdict (met or unmet) for EVERY criterion, not only the satisfied ones.")})
3153
+ exports.def={name:"record_criteria_verification",description:"Record the per-criterion acceptance-criteria verdict (met or unmet + reason) for every criterion; record-only, does NOT merge. For the criteria reviewer to persist its full verdict.",schema:s,annotations:{title:"Record Criteria Verification",readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0},handler(e,t){return(0,n.handleRecordCriteriaVerification)(e,t.context,t.apiClient,t.logger,t.metrics)}}},5964(e,exports){"use strict"
3133
3154
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.ConflictDetectionError=void 0,exports.createConflictDetectionError=function(e,r){return new t(e,r)}
3134
3155
  class t extends Error{constructor(e,t){super(e),this.isConflictDetection=!0,this.preserveWorktree=!0,this.name="ConflictDetectionError",this.conflictInfo=t}static isConflictDetectionError(e){return e instanceof t||e instanceof Error&&(!0===e.isConflictDetection||void 0!==e.conflictInfo)}static shouldPreserveWorktree(e){return t.isConflictDetectionError(e)||e instanceof Error&&!0===e.preserveWorktree}}exports.ConflictDetectionError=t},5967(e,exports,t){"use strict"
3135
3156
  var r=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
@@ -3150,56 +3171,56 @@ const I={toolName:"delete-files",operationName:"delete",fileOperationPhase:c.Fil
3150
3171
  try{const d=n.getTaskClient(),k=n.getToolRecordClient(),v=n.getRequestClient(),C=e,{paths:_,operations:E,comment:S}=C,{enforceActiveTask:q}=await Promise.resolve().then(t.bind(t,3451)),T=await q(r,n,s,e.taskId)
3151
3172
  if("errorResult"in T)return T.errorResult
3152
3173
  const{taskId:x}=T
3153
- let P=[]
3154
- if(_)P=_.map((e=>({type:"file",target:e})))
3174
+ let R=[]
3175
+ if(_)R=_.map((e=>({type:"file",target:e})))
3155
3176
  else{if(!E)throw Error("Either paths or operations must be specified")
3156
- P=E.map((e=>{if(e.path)return{type:"file",target:e.path}
3177
+ R=E.map((e=>{if(e.path)return{type:"file",target:e.path}
3157
3178
  if(e.documentId)return{type:"document",target:e.documentId}
3158
- throw Error("Invalid operation: neither path nor documentId specified")}))}if(0===P.length)throw Error("At least one file or document must be specified for deletion")
3159
- const R=P.filter((e=>"file"===e.type)),M=P.filter((e=>"document"===e.type)),$=P.length
3160
- g.info("Starting mixed file and document deletion operation",{taskId:x,totalOperations:P.length,fileOperations:R.length,documentOperations:M.length,comment:S}),c.validateTaskIdFormat(x,g,o,I.metricsPrefix)
3179
+ throw Error("Invalid operation: neither path nor documentId specified")}))}if(0===R.length)throw Error("At least one file or document must be specified for deletion")
3180
+ const P=R.filter((e=>"file"===e.type)),M=R.filter((e=>"document"===e.type)),$=R.length
3181
+ g.info("Starting mixed file and document deletion operation",{taskId:x,totalOperations:R.length,fileOperations:P.length,documentOperations:M.length,comment:S}),c.validateTaskIdFormat(x,g,o,I.metricsPrefix)
3161
3182
  const j=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
3162
3183
  g.info("Initial branch context",{initialBranch:j.branch,initialRequestId:j.requestId,isMain:j.isMain})
3163
3184
  const O=[]
3164
- for(const e of R){const{normalizedPath:t,fullPath:n}=c.validateAndNormalizePath(e.target,r)
3185
+ for(const e of P){const{normalizedPath:t,fullPath:n}=c.validateAndNormalizePath(e.target,r)
3165
3186
  O.push({normalized:t,full:n})}b=c.FileOperationPhase.TASK_VALIDATION,o.incrementCounter("delete_files_phase",1,{phase:b})
3166
3187
  const D=O.length>0?O[0].normalized:"document_operations",A=await c.validateTaskId(x,D,d,g,o,I.metricsPrefix),F=A?.requestId,N=await c.validateWorkItemStates(x,D,d,v,r,g,o,I.metricsPrefix),z=await c.autoPromoteTaskStatus(x,A.status,F,N.request?.status,D,d,v,g,o,I.metricsPrefix)
3167
- z.taskPromoted&&g.info(`Auto-promoted task ${x} (${A.title||"Untitled"}) to in_progress for mixed operations`,{taskId:x,taskTitle:A.title,previousStatus:A.status,newStatus:z.newTaskStatus,totalOperations:P.length,fileOperations:R.length,documentOperations:M.length}),z.requestPromoted&&g.info(`Auto-promoted request ${F} to in_progress for file operations`,{requestId:F,previousStatus:N.request?.status,newStatus:z.newRequestStatus,triggeringTaskId:x})
3188
+ z.taskPromoted&&g.info(`Auto-promoted task ${x} (${A.title||"Untitled"}) to in_progress for mixed operations`,{taskId:x,taskTitle:A.title,previousStatus:A.status,newStatus:z.newTaskStatus,totalOperations:R.length,fileOperations:P.length,documentOperations:M.length}),z.requestPromoted&&g.info(`Auto-promoted request ${F} to in_progress for file operations`,{requestId:F,previousStatus:N.request?.status,newStatus:z.newRequestStatus,triggeringTaskId:x})
3168
3189
  const L=await c.ensureCorrectWorkspaceContext({taskPromoted:z.taskPromoted,requestId:F,context:r,operation:"delete-files",logger:g,metrics:o,metricsPrefix:I.metricsPrefix})
3169
3190
  if(!L.success)throw Error(L.error)
3170
3191
  let H={hadUserMods:!1,userModsCommitHash:void 0}
3171
3192
  if(r.git)try{g.debug("[DELETE-FILES] Checking for user changes before mixed delete operations")
3172
3193
  const e=await(0,u.commitUserChangesBeforeToolOperation)(r.git,"delete-files",{requestId:F,taskId:x,workspaceManager:r.workspaceManager},g,o)
3173
- e.userChangesCommitted&&(g.debug("[DELETE-FILES] User changes committed before mixed delete operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),g.info("User changes committed before mixed delete-files operation",{taskId:x,totalOperations:P.length,fileOperations:R.length,documentOperations:M.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}),H={hadUserMods:!0,userModsCommitHash:e.commitHash})}catch(e){g.debug("[DELETE-FILES] Pre-tool commit failed, continuing with mixed delete operations",{error:e instanceof Error?e.message:e+""}),g.warn("Pre-tool user changes commit failed, continuing with mixed delete operation",{taskId:x,totalOperations:P.length,fileOperations:R.length,documentOperations:M.length,error:e instanceof Error?e.message:e+""})}g.debug("[DELETE-FILES] Proceeding with mixed delete operations",{totalOperations:P.length,fileDeletes:R.length,documentDeletes:M.length}),b=c.FileOperationPhase.RECORD_CREATION,o.incrementCounter("delete_files_phase",1,{phase:b})
3174
- const{toolRecordId:B,localToolRecordId:U}=await c.createFileOperationRecords(x,F,r.projectId,I.recordType,D,{totalOperations:P.length,fileOperations:R.length,documentOperations:M.length,filePaths:O.map((e=>e.normalized)),documentIds:M.map((e=>e.target)),userComment:S,hadUserMods:H.hadUserMods,userModsCommitHash:H.userModsCommitHash},d,k,g,o,I.metricsPrefix,i)
3194
+ e.userChangesCommitted&&(g.debug("[DELETE-FILES] User changes committed before mixed delete operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),g.info("User changes committed before mixed delete-files operation",{taskId:x,totalOperations:R.length,fileOperations:P.length,documentOperations:M.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}),H={hadUserMods:!0,userModsCommitHash:e.commitHash})}catch(e){g.debug("[DELETE-FILES] Pre-tool commit failed, continuing with mixed delete operations",{error:e instanceof Error?e.message:e+""}),g.warn("Pre-tool user changes commit failed, continuing with mixed delete operation",{taskId:x,totalOperations:R.length,fileOperations:P.length,documentOperations:M.length,error:e instanceof Error?e.message:e+""})}g.debug("[DELETE-FILES] Proceeding with mixed delete operations",{totalOperations:R.length,fileDeletes:P.length,documentDeletes:M.length}),b=c.FileOperationPhase.RECORD_CREATION,o.incrementCounter("delete_files_phase",1,{phase:b})
3195
+ const{toolRecordId:B,localToolRecordId:U}=await c.createFileOperationRecords(x,F,r.projectId,I.recordType,D,{totalOperations:R.length,fileOperations:P.length,documentOperations:M.length,filePaths:O.map((e=>e.normalized)),documentIds:M.map((e=>e.target)),userComment:S,hadUserMods:H.hadUserMods,userModsCommitHash:H.userModsCommitHash},d,k,g,o,I.metricsPrefix,i)
3175
3196
  y=B,w=B,b=I.fileOperationPhase,o.incrementCounter("delete_files_phase",1,{phase:b})
3176
- const G=[]
3177
- let W=0
3197
+ const W=[]
3198
+ let G=0
3178
3199
  M.length>0&&n.setProjectId(r.projectId)
3179
3200
  for(let e=0;e<O.length;e++){const t=O[e],r={type:"file",path:t.normalized,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0}
3180
3201
  try{try{await a.default.access(t.full)}catch(e){throw Error("File not found: "+t.normalized)}if((await a.default.stat(t.full)).isDirectory())throw Error("Cannot 'delete' a directory: "+t.normalized)
3181
- await a.default.unlink(t.full),r.success=!0,W++,g.info("Successfully deleted file",{path:t.normalized})}catch(e){r.error=(0,m.getErrorMessage)(e),g.warn("Failed to delete file "+t.normalized,{error:r.error})}G.push(r)}const V=M.length>0?n.getDocumentClient():null
3202
+ await a.default.unlink(t.full),r.success=!0,G++,g.info("Successfully deleted file",{path:t.normalized})}catch(e){r.error=(0,m.getErrorMessage)(e),g.warn("Failed to delete file "+t.normalized,{error:r.error})}W.push(r)}const V=M.length>0?n.getDocumentClient():null
3182
3203
  for(const e of M){const t=e.target,r={type:"document",documentId:t,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0}
3183
3204
  try{let e
3184
3205
  try{if(e=await V.getDocument(t),r.filename=e.filename,g.info("Document found for archival",{documentId:e.id,filename:e.filename,type:e.type,requestId:e.requestId}),e.requestId)try{await(0,h.validateRequestStatusForDocumentOperation)(e.requestId,v,g,o,"delete-document")}catch(e){if(e instanceof l.ValidationError)throw Error(e.message)
3185
3206
  throw e}try{await(0,p.ensureDocumentNotLocked)(t,n,g,o,"delete-document-archive")}catch(e){if(e instanceof l.ValidationError)throw Error(e.message)
3186
3207
  throw e}}catch(e){throw Error(`Document not found or validation failed: ${t}. ${(0,m.getErrorMessage)(e)}`)}const s=await V.archiveDocument(t)
3187
- r.success=!0,r.filename=s.filename,W++,g.info("Document archived successfully",{documentId:s.id,filename:s.filename,archivedAt:s.archived_at})}catch(e){r.error=(0,m.getErrorMessage)(e),g.warn("Failed to delete document "+t,{error:r.error})}G.push(r)}const Q=Date.now()-f
3188
- o.recordValue("delete_files_time",Q),o.incrementCounter("delete_files_operations_total",$),o.incrementCounter("delete_files_operations_success",W),o.incrementCounter("delete_files_operations_failed",$-W),o.incrementCounter("delete_files_file_operations",R.length),o.incrementCounter("delete_files_document_operations",M.length),W===$?o.incrementCounter("delete_files_success",1):W>0?o.incrementCounter("delete_files_partial_success",1):o.incrementCounter("delete_files_total_failure",1)
3208
+ r.success=!0,r.filename=s.filename,G++,g.info("Document archived successfully",{documentId:s.id,filename:s.filename,archivedAt:s.archived_at})}catch(e){r.error=(0,m.getErrorMessage)(e),g.warn("Failed to delete document "+t,{error:r.error})}W.push(r)}const Q=Date.now()-f
3209
+ o.recordValue("delete_files_time",Q),o.incrementCounter("delete_files_operations_total",$),o.incrementCounter("delete_files_operations_success",G),o.incrementCounter("delete_files_operations_failed",$-G),o.incrementCounter("delete_files_file_operations",P.length),o.incrementCounter("delete_files_document_operations",M.length),G===$?o.incrementCounter("delete_files_success",1):G>0?o.incrementCounter("delete_files_partial_success",1):o.incrementCounter("delete_files_total_failure",1)
3189
3210
  let K=null
3190
- if(W>0){b=c.FileOperationPhase.GIT_COMMIT,o.incrementCounter("delete_files_phase",1,{phase:b})
3191
- const e=G.filter((e=>e.success)),t=e.filter((e=>"file"===e.type)).length,n=e.filter((e=>"document"===e.type)).length
3211
+ if(G>0){b=c.FileOperationPhase.GIT_COMMIT,o.incrementCounter("delete_files_phase",1,{phase:b})
3212
+ const e=W.filter((e=>e.success)),t=e.filter((e=>"file"===e.type)).length,n=e.filter((e=>"document"===e.type)).length
3192
3213
  let s
3193
3214
  s=t>0&&n>0?`Delete ${t} files and ${n} documents - ${S}`:t>0?1===t?"Delete file - "+S:`Delete ${t} files - ${S}`:1===n?"Delete document - "+S:`Delete ${n} documents - ${S}`,K=await c.commitToGit(x,D,B,U,s,r,g,o,I.metricsPrefix)}b=c.FileOperationPhase.RECORD_UPDATE_SUCCESS,o.incrementCounter("delete_files_phase",1,{phase:b})
3194
- const J=G.filter((e=>e.success)),Y=G.filter((e=>!e.success))
3195
- await c.updateFileOperationRecords(x,y,w,D,I.recordType,W===$?`Successfully deleted all ${$} operations`:`Deleted ${W}/${$} operations successfully`,{status:W===$?"completed":"partial_success",commitHash:K?.commitHash,previousCommitHash:K?.previousCommitHash,totalOperations:$,fileOperations:R.length,documentOperations:M.length,successCount:W,failureCount:$-W,successfulOperations:J.map((e=>({type:e.type,path:e.path,documentId:e.documentId,filename:e.filename}))),failedOperations:Y.map((e=>({type:e.type,path:e.path,documentId:e.documentId,filename:e.filename,error:e.error}))),userComment:S,hadUserMods:H.hadUserMods,userModsCommitHash:H.userModsCommitHash},W===$?`Successfully deleted all ${$} operations`:`Deleted ${W}/${$} operations successfully`,d,k,g,o,I.metricsPrefix)
3215
+ const J=W.filter((e=>e.success)),Y=W.filter((e=>!e.success))
3216
+ await c.updateFileOperationRecords(x,y,w,D,I.recordType,G===$?`Successfully deleted all ${$} operations`:`Deleted ${G}/${$} operations successfully`,{status:G===$?"completed":"partial_success",commitHash:K?.commitHash,previousCommitHash:K?.previousCommitHash,totalOperations:$,fileOperations:P.length,documentOperations:M.length,successCount:G,failureCount:$-G,successfulOperations:J.map((e=>({type:e.type,path:e.path,documentId:e.documentId,filename:e.filename}))),failedOperations:Y.map((e=>({type:e.type,path:e.path,documentId:e.documentId,filename:e.filename,error:e.error}))),userComment:S,hadUserMods:H.hadUserMods,userModsCommitHash:H.userModsCommitHash},G===$?`Successfully deleted all ${$} operations`:`Deleted ${G}/${$} operations successfully`,d,k,g,o,I.metricsPrefix)
3196
3217
  const Z=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
3197
3218
  let X=""
3198
- if(W===$){const e=J.filter((e=>"file"===e.type)).length,t=J.filter((e=>"document"===e.type)).length
3199
- X=e>0&&t>0?`Successfully deleted ${e} files and ${t} documents`:e>0?`Successfully deleted all ${e} ${1===e?"file":"files"}`:`Successfully archived all ${t} ${1===t?"document":"documents"}`}else X=W>0?`Successfully deleted ${W}/${$} operations.\n\nFailed operations:\n`+G.filter((e=>!e.success)).map((e=>{const t="file"===e.type?e.path:`${e.filename||e.documentId} (${e.documentId})`
3200
- return`\u2022 ${e.type}: ${t}: ${e.error}`})).join("\n"):"All delete operations failed:\n"+G.map((e=>{const t="file"===e.type?e.path:`${e.filename||e.documentId} (${e.documentId})`
3219
+ if(G===$){const e=J.filter((e=>"file"===e.type)).length,t=J.filter((e=>"document"===e.type)).length
3220
+ X=e>0&&t>0?`Successfully deleted ${e} files and ${t} documents`:e>0?`Successfully deleted all ${e} ${1===e?"file":"files"}`:`Successfully archived all ${t} ${1===t?"document":"documents"}`}else X=G>0?`Successfully deleted ${G}/${$} operations.\n\nFailed operations:\n`+W.filter((e=>!e.success)).map((e=>{const t="file"===e.type?e.path:`${e.filename||e.documentId} (${e.documentId})`
3221
+ return`\u2022 ${e.type}: ${t}: ${e.error}`})).join("\n"):"All delete operations failed:\n"+W.map((e=>{const t="file"===e.type?e.path:`${e.filename||e.documentId} (${e.documentId})`
3201
3222
  return`\u2022 ${e.type}: ${t}: ${e.error}`})).join("\n")
3202
- return K?.commitHash&&(X+="\nCommit: "+K.commitHash.substring(0,8)),Z.requestId&&(X+="\nBranch: "+Z.requestId),{content:[{type:"text",text:X}],isError:0===W}}catch(t){if(e.taskId&&n)try{const s=n.getToolRecordClient(),o=t instanceof l.NotFoundError||t instanceof l.ValidationError||t instanceof d.ZodError
3223
+ return K?.commitHash&&(X+="\nCommit: "+K.commitHash.substring(0,8)),Z.requestId&&(X+="\nBranch: "+Z.requestId),{content:[{type:"text",text:X}],isError:0===G}}catch(t){if(e.taskId&&n)try{const s=n.getToolRecordClient(),o=t instanceof l.NotFoundError||t instanceof l.ValidationError||t instanceof d.ZodError
3203
3224
  await s.createToolRecord({...o?{}:{taskId:e.taskId},projectId:r.projectId,type:"delete-files",metadata:{status:"failed",timestamp:(new Date).toISOString(),totalOperations:e.operations?.length||e.paths?.length||0,fileOperations:e.paths?.length||e.operations?.filter((e=>e.path))?.length||0,documentOperations:e.operations?.filter((e=>e.documentId))?.length||0,paths:e.paths||e.operations?.filter((e=>e.path))?.map((e=>e.path))||[],documentIds:e.operations?.filter((e=>e.documentId))?.map((e=>e.documentId))||[],userComment:e.comment,error:(0,m.getErrorMessage)(t),errorDetails:t instanceof Error?t.stack:t+"",phase:b,attemptedTaskId:e.taskId,taskIdValidationFailed:o},note:"Failed to delete files - "+(0,m.getErrorMessage)(t)})}catch(t){g.error("Failed to create failure record for delete-files operation",{error:t instanceof Error?t.message:t+"",taskId:e.taskId,totalOperations:e.operations?.length||e.paths?.length||0,fileOperations:e.paths?.length||e.operations?.filter((e=>e.path))?.length||0,documentOperations:e.operations?.filter((e=>e.documentId))?.length||0})}const s=Date.now()-f
3204
3225
  if(o.recordValue("delete_files_time",s),o.incrementCounter("delete_files_errors",1),g.error("Error in delete-files operation:",{error:(0,m.getErrorMessage)(t),time:s}),(y||w)&&e.taskId){b=c.FileOperationPhase.RECORD_UPDATE_FAILURE
3205
3226
  try{const r=n.getTaskClient(),s=n.getToolRecordClient()
@@ -3277,7 +3298,7 @@ if("create"===r){e.name||t.addIssue({code:"custom",message:"name is required for
3277
3298
  const r=o.QUEST_METADATA_KEYS.filter((t=>void 0!==e[t]))
3278
3299
  r.length>0&&t.addIssue({code:"custom",message:`Quest metadata fields (${r.join(", ")}) are not allowed on plan_write create. Quests are created via the UI flow at /quests/new. plan_write update still works on existing Quest documents.`})}else e.planId||t.addIssue({code:"custom",message:`planId is required for '${r}'.`})
3279
3300
  if("append"!==r||e.content||t.addIssue({code:"custom",message:'content is required for \'append\'. Example: { "operation": "append", "planId": "plan000001", "content": "..." }'}),"update"===r){const r=void 0!==e.content,n=void 0!==e.criteria||void 0!==e.tickIntervalSeconds||void 0!==e.maxInFlight||void 0!==e.maxPerDay||void 0!==e.minIterations||void 0!==e.status||void 0!==e.completionMode
3280
- r||n||t.addIssue({code:"custom",message:"update requires either 'content' (plan or quest body) or at least one metadata field (criteria, tickIntervalSeconds, maxInFlight, maxPerDay, minIterations, status, completionMode \u2014 quest only)."})}"replace"===r&&(e.old||t.addIssue({code:"custom",message:'old is required for replace. Example: { "operation": "replace", "planId": "plan000001", "old": "find this", "new": "replace with" }'}),void 0===e.new&&t.addIssue({code:"custom",message:"new is required for replace"})),"restore"!==r||e.versionNumber||t.addIssue({code:"custom",message:'versionNumber is required for restore. Example: { "operation": "restore", "planId": "plan000001", "versionNumber": 1 }'})})),exports.QuestSetCriteriaStatusesSchema=r.z.object({questId:r.z.string().min(1).describe("The quest documentId whose criteria to update."),updates:r.z.array(r.z.object({id:r.z.string().min(1).describe("Criterion id (must match an existing item in metadata.criteria)."),status:r.z.enum(["unverified","verified"]).describe("New status for this criterion."),evidence:r.z.string().optional().describe("Optional evidence note (file path, request id, test name, command output, etc.) describing why the status changed.")})).min(1).describe("One or more per-criterion updates. Each id must exist in the quest's metadata.criteria; unknown ids return an error listing the valid ids. Updates merge into the existing item (other fields preserved); only status and evidence change.")}),exports.QuestAuditCompleteSchema=r.z.object({questId:r.z.string().min(1).describe("The quest documentId to audit (the long uuid form returned by plan_write create, or the project-scoped doc000NN id)."),summary:r.z.string().min(1).describe("Short prose summary of what evidence the audit found. Stored on the quest if this call reaches the threshold and flips status \u2014 visible to the user when they review."),evidence:r.z.array(r.z.string()).optional().describe("Optional list of evidence references (file paths, request IDs, test names, command outputs) that support the audit conclusion. Stored on the quest alongside the summary if status flips.")}),exports.SwitchToMainBranchSchema=r.z.object({}),exports.SwitchToBranchSchema=r.z.object({branch:r.z.string().optional()}),exports.RevertRequestSchema=r.z.object({requestId:c,reason:r.z.string(),confirmDestructive:r.z.boolean().optional()}),exports.ModifyFileSchema=r.z.object({operations:r.z.array(r.z.object({path:r.z.string().optional(),documentId:l.optional(),operationType:r.z.enum(["replace-string","insert-lines","replace-lines","delete-string","delete-lines"]),replaceString:r.z.object({replacements:r.z.array(r.z.object({old_str:r.z.string(),new_str:r.z.string()})),mode:r.z.enum(["unique","all"]).optional()}).optional(),insertLines:r.z.object({insertions:r.z.array(r.z.object({type:r.z.enum(["before","after","between"]),line:r.z.number().optional(),afterLine:r.z.number().optional(),beforeLine:r.z.number().optional(),content:r.z.union([r.z.string(),r.z.array(r.z.string())])}).refine((e=>"between"===e.type?void 0!==e.afterLine&&void 0!==e.beforeLine&&void 0===e.line:void 0!==e.line&&void 0===e.afterLine&&void 0===e.beforeLine),{message:"Invalid line parameters"}))}).optional(),replaceLines:r.z.object({replacements:r.z.array(r.z.object({lines:r.z.string(),content:r.z.union([r.z.string(),r.z.array(r.z.string())])}))}).optional(),deleteString:r.z.object({patterns:r.z.array(r.z.string()),mode:r.z.enum(["all","unique"]).optional()}).optional(),deleteLines:r.z.object({lines:r.z.string()}).optional()}).transform(d).refine(u,{message:"path or documentId required"}).refine((e=>"replace-string"===e.operationType?e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteString&&!e.deleteLines:"insert-lines"===e.operationType?e.insertLines&&!e.replaceString&&!e.replaceLines&&!e.deleteString&&!e.deleteLines:"replace-lines"===e.operationType?e.replaceLines&&!e.replaceString&&!e.insertLines&&!e.deleteString&&!e.deleteLines:"delete-string"===e.operationType?e.deleteString&&!e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteLines:"delete-lines"===e.operationType&&e.deleteLines&&!e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteString),{message:"Invalid operation data"})),comment:r.z.string()}),exports.ManageFilesSchema=r.z.object({operations:r.z.array(r.z.object({operationType:r.z.enum(["create-directory","move-files","delete-files","get-file-info"]),createDirectory:r.z.object({path:r.z.string()}).optional(),moveFiles:r.z.object({moves:r.z.array(r.z.object({source:r.z.string(),destination:r.z.string()}))}).optional(),deleteFiles:r.z.object({targets:r.z.array(r.z.object({path:r.z.string().optional(),documentId:l.optional()}).transform(d).refine(u,{message:"path or documentId required"}))}).optional(),getFileInfo:r.z.object({path:r.z.string()}).optional()}).refine((e=>"create-directory"===e.operationType?e.createDirectory&&!e.moveFiles&&!e.deleteFiles&&!e.getFileInfo:"move-files"===e.operationType?e.moveFiles&&!e.createDirectory&&!e.deleteFiles&&!e.getFileInfo:"delete-files"===e.operationType?e.deleteFiles&&!e.createDirectory&&!e.moveFiles&&!e.getFileInfo:"get-file-info"===e.operationType&&e.getFileInfo&&!e.createDirectory&&!e.moveFiles&&!e.deleteFiles),{message:"Invalid operation data"})),comment:r.z.string()}),exports.RequestOperationsSchema=r.z.object({requestId:c.optional(),operation:r.z.enum(["complete","merge","approve","revert","get-info","list","search","delete-empty"]),complete:r.z.preprocess((e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e),r.z.object({summary:r.z.string(),skipTestsReason:exports.skipTestsReasonSchema,skipTests:exports.skipTestsSchema})).optional(),merge:r.z.preprocess((e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e),r.z.object({verifications:r.z.array(r.z.object({key:r.z.string().min(2).max(4),evidence:r.z.string().min(1)})).min(1)})).optional(),revert:r.z.object({reason:r.z.string(),confirmDestructive:r.z.boolean().optional()}).optional(),list:r.z.object({filters:r.z.object({type:r.z.enum(["feature","bugfix"]).optional(),status:r.z.enum(["pending_approval","open","in_progress","ready_for_review","ready_for_merge","resolving_conflicts","completed","canceled"]).optional(),planDocumentId:r.z.string().optional().describe("Narrow to requests linked to this Plan document (use the plan's id or local id)."),questDocumentId:r.z.string().optional().describe("Narrow to requests spawned under this Quest document (use the quest's id or local id)."),dateFrom:r.z.string().optional(),dateTo:r.z.string().optional(),limit:r.z.number().min(1).max(100).default(20),offset:r.z.number().min(0).default(0),sortBy:r.z.enum(["created","updated"]).default("updated"),sortDirection:r.z.enum(["asc","desc"]).default("desc")}).optional()}).optional(),search:r.z.object({query:r.z.string().min(1),searchIn:r.z.enum(["title","description","criteria","all"]).default("all"),filters:r.z.object({type:r.z.enum(["feature","bugfix"]).optional(),status:r.z.enum(["pending_approval","open","in_progress","ready_for_review","ready_for_merge","resolving_conflicts","completed","canceled"]).optional(),planDocumentId:r.z.string().optional().describe("Narrow to requests linked to this Plan document."),questDocumentId:r.z.string().optional().describe("Narrow to requests spawned under this Quest document."),dateFrom:r.z.string().optional(),dateTo:r.z.string().optional(),limit:r.z.number().min(1).max(100).default(20),offset:r.z.number().min(0).default(0)}).optional()}).optional(),approve:r.z.object({}).optional()}).superRefine(((e,t)=>{e.requestId
3301
+ r||n||t.addIssue({code:"custom",message:"update requires either 'content' (plan or quest body) or at least one metadata field (criteria, tickIntervalSeconds, maxInFlight, maxPerDay, minIterations, status, completionMode \u2014 quest only)."})}"replace"===r&&(e.old||t.addIssue({code:"custom",message:'old is required for replace. Example: { "operation": "replace", "planId": "plan000001", "old": "find this", "new": "replace with" }'}),void 0===e.new&&t.addIssue({code:"custom",message:"new is required for replace"})),"restore"!==r||e.versionNumber||t.addIssue({code:"custom",message:'versionNumber is required for restore. Example: { "operation": "restore", "planId": "plan000001", "versionNumber": 1 }'})})),exports.QuestSetCriteriaStatusesSchema=r.z.object({questId:r.z.string().min(1).describe("The quest documentId whose criteria to update."),updates:r.z.array(r.z.object({id:r.z.string().min(1).describe("Criterion id (must match an existing item in metadata.criteria)."),status:r.z.enum(["unverified","verified"]).describe("New status for this criterion."),evidence:r.z.string().optional().describe("Optional evidence note (file path, request id, test name, command output, etc.) describing why the status changed.")})).min(1).describe("One or more per-criterion updates. Each id must exist in the quest's metadata.criteria; unknown ids return an error listing the valid ids. Updates merge into the existing item (other fields preserved); only status and evidence change.")}),exports.QuestAuditCompleteSchema=r.z.object({questId:r.z.string().min(1).describe("The quest documentId to audit (the long uuid form returned by plan_write create, or the project-scoped doc000NN id)."),summary:r.z.string().min(1).describe("Short prose summary of what evidence the audit found. Stored on the quest if this call reaches the threshold and flips status \u2014 visible to the user when they review."),evidence:r.z.array(r.z.string()).optional().describe("Optional list of evidence references (file paths, request IDs, test names, command outputs) that support the audit conclusion. Stored on the quest alongside the summary if status flips.")}),exports.SwitchToMainBranchSchema=r.z.object({}),exports.SwitchToBranchSchema=r.z.object({branch:r.z.string().optional()}),exports.RevertRequestSchema=r.z.object({requestId:c,reason:r.z.string(),confirmDestructive:r.z.boolean().optional()}),exports.ModifyFileSchema=r.z.object({operations:r.z.array(r.z.object({path:r.z.string().optional(),documentId:l.optional(),operationType:r.z.enum(["replace-string","insert-lines","replace-lines","delete-string","delete-lines"]),replaceString:r.z.object({replacements:r.z.array(r.z.object({old_str:r.z.string(),new_str:r.z.string()})),mode:r.z.enum(["unique","all"]).optional()}).optional(),insertLines:r.z.object({insertions:r.z.array(r.z.object({type:r.z.enum(["before","after","between"]),line:r.z.number().optional(),afterLine:r.z.number().optional(),beforeLine:r.z.number().optional(),content:r.z.union([r.z.string(),r.z.array(r.z.string())])}).refine((e=>"between"===e.type?void 0!==e.afterLine&&void 0!==e.beforeLine&&void 0===e.line:void 0!==e.line&&void 0===e.afterLine&&void 0===e.beforeLine),{message:"Invalid line parameters"}))}).optional(),replaceLines:r.z.object({replacements:r.z.array(r.z.object({lines:r.z.string(),content:r.z.union([r.z.string(),r.z.array(r.z.string())])}))}).optional(),deleteString:r.z.object({patterns:r.z.array(r.z.string()),mode:r.z.enum(["all","unique"]).optional()}).optional(),deleteLines:r.z.object({lines:r.z.string()}).optional()}).transform(d).refine(u,{message:"path or documentId required"}).refine((e=>"replace-string"===e.operationType?e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteString&&!e.deleteLines:"insert-lines"===e.operationType?e.insertLines&&!e.replaceString&&!e.replaceLines&&!e.deleteString&&!e.deleteLines:"replace-lines"===e.operationType?e.replaceLines&&!e.replaceString&&!e.insertLines&&!e.deleteString&&!e.deleteLines:"delete-string"===e.operationType?e.deleteString&&!e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteLines:"delete-lines"===e.operationType&&e.deleteLines&&!e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteString),{message:"Invalid operation data"})),comment:r.z.string()}),exports.ManageFilesSchema=r.z.object({operations:r.z.array(r.z.object({operationType:r.z.enum(["create-directory","move-files","delete-files","get-file-info"]),createDirectory:r.z.object({path:r.z.string()}).optional(),moveFiles:r.z.object({moves:r.z.array(r.z.object({source:r.z.string(),destination:r.z.string()}))}).optional(),deleteFiles:r.z.object({targets:r.z.array(r.z.object({path:r.z.string().optional(),documentId:l.optional()}).transform(d).refine(u,{message:"path or documentId required"}))}).optional(),getFileInfo:r.z.object({path:r.z.string()}).optional()}).refine((e=>"create-directory"===e.operationType?e.createDirectory&&!e.moveFiles&&!e.deleteFiles&&!e.getFileInfo:"move-files"===e.operationType?e.moveFiles&&!e.createDirectory&&!e.deleteFiles&&!e.getFileInfo:"delete-files"===e.operationType?e.deleteFiles&&!e.createDirectory&&!e.moveFiles&&!e.getFileInfo:"get-file-info"===e.operationType&&e.getFileInfo&&!e.createDirectory&&!e.moveFiles&&!e.deleteFiles),{message:"Invalid operation data"})),comment:r.z.string()}),exports.RequestOperationsSchema=r.z.object({requestId:c.optional(),operation:r.z.enum(["complete","merge","approve","revert","get-info","list","search","delete-empty"]),complete:r.z.preprocess((e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e),r.z.object({summary:r.z.string(),skipTestsReason:exports.skipTestsReasonSchema,skipTests:exports.skipTestsSchema,criteriaComments:r.z.array(r.z.object({key:r.z.string().min(1),comment:r.z.string().min(1)})).optional()})).optional(),merge:r.z.preprocess((e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e),r.z.object({verifications:r.z.array(r.z.object({key:r.z.string().min(2).max(4),evidence:r.z.string().min(1)})).min(1)})).optional(),revert:r.z.object({reason:r.z.string(),confirmDestructive:r.z.boolean().optional()}).optional(),list:r.z.object({filters:r.z.object({type:r.z.enum(["feature","bugfix"]).optional(),status:r.z.enum(["pending_approval","open","in_progress","ready_for_review","ready_for_merge","resolving_conflicts","completed","canceled"]).optional(),planDocumentId:r.z.string().optional().describe("Narrow to requests linked to this Plan document (use the plan's id or local id)."),questDocumentId:r.z.string().optional().describe("Narrow to requests spawned under this Quest document (use the quest's id or local id)."),dateFrom:r.z.string().optional(),dateTo:r.z.string().optional(),limit:r.z.number().min(1).max(100).default(20),offset:r.z.number().min(0).default(0),sortBy:r.z.enum(["created","updated"]).default("updated"),sortDirection:r.z.enum(["asc","desc"]).default("desc")}).optional()}).optional(),search:r.z.object({query:r.z.string().min(1),searchIn:r.z.enum(["title","description","criteria","all"]).default("all"),filters:r.z.object({type:r.z.enum(["feature","bugfix"]).optional(),status:r.z.enum(["pending_approval","open","in_progress","ready_for_review","ready_for_merge","resolving_conflicts","completed","canceled"]).optional(),planDocumentId:r.z.string().optional().describe("Narrow to requests linked to this Plan document."),questDocumentId:r.z.string().optional().describe("Narrow to requests spawned under this Quest document."),dateFrom:r.z.string().optional(),dateTo:r.z.string().optional(),limit:r.z.number().min(1).max(100).default(20),offset:r.z.number().min(0).default(0)}).optional()}).optional(),approve:r.z.object({}).optional()}).superRefine(((e,t)=>{e.requestId
3281
3302
  const r=e.operation,n={complete:{field:"complete",hint:'Provide: { complete: { summary: "..." } }'},merge:{field:"merge",hint:'Provide: { merge: { verifications: [{key: "1a", evidence: "..."}] } }'},revert:{field:"revert",hint:'Provide: { revert: { reason: "..." } }'},search:{field:"search",hint:'Provide: { search: { query: "..." } }'}}[r]
3282
3303
  n&&!e[n.field]&&t.addIssue({code:"custom",message:`'${r}' operation requires '${n.field}' data. ${n.hint}`})})),exports.QuickWriteSchema=r.z.object({title:r.z.string().min(1,"Title is required"),description:r.z.string().min(1,"Description is required"),path:r.z.string().optional(),documentId:l.optional(),content:r.z.union([r.z.string(),r.z.array(r.z.string())]),format:r.z.enum(["text","json"]).optional(),append:r.z.boolean().optional()}).transform(d).refine(u,{message:"path or documentId required"}),exports.QuickReplaceSchema=r.z.object({title:r.z.string().min(1,"Title is required"),description:r.z.string().min(1,"Description is required"),operations:r.z.array(r.z.object({path:r.z.string().optional(),documentId:l.optional(),replacements:r.z.array(r.z.object({old:r.z.string().min(1),new:r.z.string(),match_mode:r.z.enum(["unique","all"]).optional()})).min(1),fuzzy_match:r.z.boolean().optional()}).transform(d).refine(u,{message:"path or documentId required"})).min(1),fuzzy_match:r.z.boolean().optional(),comment:r.z.string().min(1,"Comment describing the change is required")}),exports.QuickManageSchema=r.z.object({title:r.z.string().min(1,"Title is required"),description:r.z.string().min(1,"Description is required"),operations:r.z.array(r.z.object({operationType:r.z.enum(["create-directory","move-files","delete-files"]),createDirectory:r.z.object({path:r.z.string()}).optional(),moveFiles:r.z.object({moves:r.z.array(r.z.object({source:r.z.string(),destination:r.z.string()}))}).optional(),deleteFiles:r.z.object({targets:r.z.array(r.z.object({path:r.z.string().optional(),documentId:l.optional()}).transform(d).refine(u,{message:"path or documentId required"}))}).optional()})).min(1)}),exports.GenerateRequestJournalSchema=r.z.object({requestId:r.z.string().regex(/^req[_\d].+$/,"Invalid request ID format. Expected format: req_[26 chars] or req######")}),exports.MetaWorkflowListSchema=r.z.object({}),exports.MetaWorkflowGetSchema=r.z.object({workflowId:r.z.string().describe("Workflow ID to retrieve")}),exports.MetaWorkflowCreateSchema=r.z.object({name:r.z.string().min(1).describe("Unique name for the workflow"),shortName:r.z.string().min(1).max(10).describe("Short display name (required, max 10 chars)"),description:r.z.string().optional().describe("Description of what the workflow does"),documentation:r.z.string().optional().describe("Detailed documentation"),defaultAgent:r.z.string().optional().describe("Default agent template to use"),completionMode:r.z.enum(["auto-merge","ask-me","test-by-default","always-test"]).optional().describe("Testing axis: auto-merge (skip tests), ask-me (notify human on completion), test-by-default (tests run; opt-out allowed), always-test (tests required)"),reviewMode:r.z.enum(["auto-finalize","manual-review"]).optional().describe("Review axis: auto-finalize (server merges on pass/skip) or manual-review (human approves via UI)"),approvalMode:r.z.enum(["none","require-approval"]).optional().describe("Pre-work approval: none (default) or require-approval")}),exports.MetaWorkflowUpdateSchema=r.z.object({workflowId:r.z.string().describe("Workflow ID to update"),name:r.z.string().min(1).optional().describe("New name"),shortName:r.z.string().max(10).optional().describe("New short name (max 10 chars)"),description:r.z.string().optional().describe("New description"),documentation:r.z.string().optional().describe("New documentation"),defaultAgent:r.z.string().optional().describe("New default agent"),completionMode:r.z.enum(["auto-merge","ask-me","test-by-default","always-test"]).optional().describe("Testing axis"),reviewMode:r.z.enum(["auto-finalize","manual-review"]).optional().describe("Review axis"),approvalMode:r.z.enum(["none","require-approval"]).optional().describe("Pre-work approval: none (default) or require-approval")}),exports.MetaRecipeListSchema=r.z.object({}),exports.MetaRecipeGetSchema=r.z.object({recipeId:r.z.string().describe("Recipe ID to retrieve")}),exports.MetaRecipeCreateSchema=r.z.object({name:r.z.string().min(1).describe("Unique name for the recipe"),description:r.z.string().optional().describe("Description of what the recipe does"),documentation:r.z.string().optional().describe("Detailed documentation")}),exports.MetaRecipeAddHookSchema=r.z.object({recipeId:r.z.string().describe("Recipe ID to add the hook to"),hookId:r.z.string().describe("Hook template ID to add"),position:r.z.number().int().min(0).optional().describe("Position in the recipe (0-based, appended if omitted)")}),exports.MetaRecipeRemoveHookSchema=r.z.object({recipeId:r.z.string().describe("Recipe ID to remove the hook from"),hookId:r.z.string().describe("Hook template ID to remove")}),exports.MetaHookListSchema=r.z.object({}),exports.MetaHookCreateSchema=r.z.object({name:r.z.string().min(1).describe("Unique name for the hook"),description:r.z.string().optional().describe("Description of what the hook does"),eventType:r.z.string().describe("Event type that triggers this hook (e.g., session_idle, request_completed, custom:plan_ready)"),category:r.z.enum(["alchemy","session","message","editing","reading","file_management","documents","history","tool"]).default("session").describe("Hook category"),agent:r.z.string().describe("Agent template to execute when hook fires"),promptTemplate:r.z.string().describe("Prompt template with {{variable}} substitution"),condition:r.z.record(r.z.any()).optional().describe("Condition object for filtering when hook fires"),executionMode:r.z.enum(["same_session","sub_agent","background","notification","direct_report"]).default("background").describe("How to execute the hook"),timing:r.z.enum(["before","after"]).default("after").describe("When to fire relative to the event"),maxIterations:r.z.number().int().min(1).optional().describe("Maximum times to fire per session"),emitEvent:r.z.string().optional().describe("Custom event to emit on completion"),emitEventOnCondition:r.z.union([r.z.object({condition:r.z.object({field:r.z.string(),operator:r.z.enum(["contains","not_contains","equals","not_equals","matches","not_matches"]),value:r.z.string()}),event:r.z.string()}),r.z.array(r.z.object({condition:r.z.object({field:r.z.string(),operator:r.z.enum(["contains","not_contains","equals","not_equals","matches","not_matches"]),value:r.z.string()}),event:r.z.string()}))]).optional().describe("Conditional event emission based on output")}),exports.MetaWorkflowAddRecipeSchema=r.z.object({workflowId:r.z.string().describe("Workflow ID to add the recipe to"),recipeId:r.z.string().describe("Recipe ID to add"),position:r.z.number().int().min(0).optional().describe("Position in the workflow (0-based, appended if omitted)")}),exports.MetaWorkflowRemoveRecipeSchema=r.z.object({workflowId:r.z.string().describe("Workflow ID to remove the recipe from"),recipeId:r.z.string().describe("Recipe ID to remove")}),exports.MetaAgentListSchema=r.z.object({}),exports.MetaReferenceSchema=r.z.object({}),exports.TestingProcessListSchema=r.z.object({}),exports.TestingProcessGetSchema=r.z.object({processId:r.z.string().describe("Test process ID to retrieve")})
3283
3304
  const m=r.z.object({name:r.z.string().min(1).describe('Command name (e.g., "Build", "Unit Tests")'),command:r.z.string().min(1).describe('Shell command to run (e.g., "npm test")'),required:r.z.boolean().default(!0).describe("If true, failure blocks the request (default: true)"),timeout:r.z.number().int().min(10).max(3600).default(300).describe("Max execution time in seconds (default: 300)")})
@@ -3408,34 +3429,34 @@ try{const C=e,{operations:_,comment:E}=C,{enforceActiveTask:S}=await Promise.res
3408
3429
  if("errorResult"in q)return q.errorResult
3409
3430
  const{taskId:T}=q
3410
3431
  if(y.info("Inserting lines into files and documents",{taskId:T,operationCount:_.length,comment:E}),!_||0===_.length)throw new d.ValidationError("At least one operation is required")
3411
- const x=_.filter((e=>e.path)),P=_.filter((e=>e.documentId))
3412
- y.info("Operation breakdown",{fileOperations:x.length,documentOperations:P.length})
3413
- const R=[]
3432
+ const x=_.filter((e=>e.path)),R=_.filter((e=>e.documentId))
3433
+ y.info("Operation breakdown",{fileOperations:x.length,documentOperations:R.length})
3434
+ const P=[]
3414
3435
  for(const e of x){const{normalizedPath:t,fullPath:r}=l.validateAndNormalizePath(e.path,n)
3415
- R.push({type:"file",path:t,fullPath:r,insertions:e.insertions})}const M=[]
3416
- if(P.length>0&&!n.documentFileManager)throw Error("Document file manager not available - cannot process document operations")
3417
- for(const e of P)M.push({type:"document",documentId:e.documentId,insertions:e.insertions})
3436
+ P.push({type:"file",path:t,fullPath:r,insertions:e.insertions})}const M=[]
3437
+ if(R.length>0&&!n.documentFileManager)throw Error("Document file manager not available - cannot process document operations")
3438
+ for(const e of R)M.push({type:"document",documentId:e.documentId,insertions:e.insertions})
3418
3439
  if(M.length>0&&n.apiClient){const e=M.map((e=>e.documentId))
3419
3440
  try{await(0,p.ensureDocumentsNotLocked)(e,n.apiClient,y,g,"insert-lines-documents")}catch(e){if(e instanceof d.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3420
3441
  throw e}}k=l.FileOperationPhase.TASK_VALIDATION,g.incrementCounter("insert_lines_phase",1,{phase:k})
3421
- const $=R.length>0?R[0].path:"document-operation",j=await l.validateTaskId(T,$,s,y,g,v.metricsPrefix),O=j?.requestId
3442
+ const $=P.length>0?P[0].path:"document-operation",j=await l.validateTaskId(T,$,s,y,g,v.metricsPrefix),O=j?.requestId
3422
3443
  let D=null
3423
- R.length>0&&O&&(D=await l.validateWorkItemStates(T,R[0].path,s,i,n,y,g,v.metricsPrefix))
3444
+ P.length>0&&O&&(D=await l.validateWorkItemStates(T,P[0].path,s,i,n,y,g,v.metricsPrefix))
3424
3445
  let A={taskPromoted:!1,requestPromoted:!1}
3425
- R.length>0&&O&&D&&(A=await l.autoPromoteTaskStatus(T,j.status,O,D.request?.status,R[0].path,s,i,y,g,v.metricsPrefix),A.taskPromoted&&y.info("Auto-promoted task to in_progress for insert-lines operation",{taskId:T,requestId:O,previousStatus:j.status,newStatus:A.newTaskStatus,triggeringOperation:"insert-lines"}))
3446
+ P.length>0&&O&&D&&(A=await l.autoPromoteTaskStatus(T,j.status,O,D.request?.status,P[0].path,s,i,y,g,v.metricsPrefix),A.taskPromoted&&y.info("Auto-promoted task to in_progress for insert-lines operation",{taskId:T,requestId:O,previousStatus:j.status,newStatus:A.newTaskStatus,triggeringOperation:"insert-lines"}))
3426
3447
  const F=await l.ensureCorrectWorkspaceContext({taskPromoted:A.taskPromoted,requestId:O,context:n,operation:"insert-lines",logger:y,metrics:g,metricsPrefix:v.metricsPrefix})
3427
3448
  if(!F.success)throw Error(F.error)
3428
- if(R.length>0){y.debug("Re-validating file paths with correct workspace context",{operationCount:R.length,workspaceBasePath:n.workspaceManager?.getCurrentContext(n.currentSessionId).basePath})
3429
- for(let e=0;e<R.length;e++){const t=R[e],r=x[e],{normalizedPath:s,fullPath:o}=l.validateAndNormalizePath(r.path,n)
3430
- R[e]={...t,path:s,fullPath:o}}}if(M.length>0&&O)try{await(0,u.validateRequestStatusForDocumentOperation)(O,i,y,g,"insert-lines-document")}catch(e){if(e instanceof d.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3449
+ if(P.length>0){y.debug("Re-validating file paths with correct workspace context",{operationCount:P.length,workspaceBasePath:n.workspaceManager?.getCurrentContext(n.currentSessionId).basePath})
3450
+ for(let e=0;e<P.length;e++){const t=P[e],r=x[e],{normalizedPath:s,fullPath:o}=l.validateAndNormalizePath(r.path,n)
3451
+ P[e]={...t,path:s,fullPath:o}}}if(M.length>0&&O)try{await(0,u.validateRequestStatusForDocumentOperation)(O,i,y,g,"insert-lines-document")}catch(e){if(e instanceof d.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3431
3452
  throw e}k=l.FileOperationPhase.RECORD_CREATION,g.incrementCounter("insert_lines_phase",1,{phase:k})
3432
- const N=[...R.map((e=>({type:"file",path:e.path,insertions:e.insertions}))),...M.map((e=>({type:"document",documentId:e.documentId,insertions:e.insertions})))],{toolRecordId:z}=await l.createFileOperationRecords(T,O,n.projectId,v.recordType,$,{operationCount:_.length,fileOperations:R.length,documentOperations:M.length,operations:N,userComment:E},s,o,y,g,v.metricsPrefix,f)
3433
- if(b=z,I=z,k=v.fileOperationPhase,g.incrementCounter("insert_lines_phase",1,{phase:k}),R.length>0&&n.git)try{y.debug("[INSERT-LINES] Checking for user changes before insert operations")
3453
+ const N=[...P.map((e=>({type:"file",path:e.path,insertions:e.insertions}))),...M.map((e=>({type:"document",documentId:e.documentId,insertions:e.insertions})))],{toolRecordId:z}=await l.createFileOperationRecords(T,O,n.projectId,v.recordType,$,{operationCount:_.length,fileOperations:P.length,documentOperations:M.length,operations:N,userComment:E},s,o,y,g,v.metricsPrefix,f)
3454
+ if(b=z,I=z,k=v.fileOperationPhase,g.incrementCounter("insert_lines_phase",1,{phase:k}),P.length>0&&n.git)try{y.debug("[INSERT-LINES] Checking for user changes before insert operations")
3434
3455
  const e=await(0,h.commitUserChangesBeforeToolOperation)(n.git,"insert-lines",{requestId:O,taskId:T,workspaceManager:n.workspaceManager},y,g)
3435
- e.userChangesCommitted&&(y.debug("[INSERT-LINES] User changes committed before insert operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),y.info("User changes committed before insert-lines operation",{taskId:T,fileOperationsCount:R.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){y.debug("[INSERT-LINES] Pre-tool commit failed, continuing with insertions",{error:e instanceof Error?e.message:e+""}),y.warn("Pre-tool user changes commit failed, continuing with insert operation",{taskId:T,fileOperationsCount:R.length,error:e instanceof Error?e.message:e+""})}y.debug("[INSERT-LINES] Proceeding with file operations",{fileCount:R.length})
3456
+ e.userChangesCommitted&&(y.debug("[INSERT-LINES] User changes committed before insert operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),y.info("User changes committed before insert-lines operation",{taskId:T,fileOperationsCount:P.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){y.debug("[INSERT-LINES] Pre-tool commit failed, continuing with insertions",{error:e instanceof Error?e.message:e+""}),y.warn("Pre-tool user changes commit failed, continuing with insert operation",{taskId:T,fileOperationsCount:P.length,error:e instanceof Error?e.message:e+""})}y.debug("[INSERT-LINES] Proceeding with file operations",{fileCount:P.length})
3436
3457
  const L=[]
3437
3458
  let H=0,B=0,U=0
3438
- for(const e of R){const t={type:"file",path:e.path,success:!1,insertions:[],successfulInsertions:0,failedInsertions:0,totalLinesAdded:0}
3459
+ for(const e of P){const t={type:"file",path:e.path,success:!1,insertions:[],successfulInsertions:0,failedInsertions:0,totalLinesAdded:0}
3439
3460
  try{if(await c.default.access(e.fullPath),!(await c.default.stat(e.fullPath)).isFile())throw Error("Path is not a file: "+e.path)
3440
3461
  const n=await c.default.readFile(e.fullPath,"utf8"),{newContent:s,results:o}=await r(n,e.insertions)
3441
3462
  t.insertions=o,t.successfulInsertions=o.filter((e=>e.success)).length,t.failedInsertions=o.filter((e=>!e.success)).length,t.totalLinesAdded=o.filter((e=>e.success)).reduce(((e,t)=>e+(t.linesAdded||0)),0),s!==n&&t.successfulInsertions>0?(await c.default.writeFile(e.fullPath,s,"utf8"),t.success=!0,U++,y.info("File updated successfully",{path:e.path,successfulInsertions:t.successfulInsertions,failedInsertions:t.failedInsertions,linesAdded:t.totalLinesAdded})):0===t.failedInsertions&&(t.success=!0),H+=t.failedInsertions,B+=t.totalLinesAdded}catch(r){t.error=(0,m.getErrorMessage)(r),t.failedInsertions=e.insertions.length,H+=t.failedInsertions,y.error("File operation failed",{path:e.path,error:t.error})}L.push(t)}for(const e of M){const t={type:"document",documentId:e.documentId,success:!1,insertions:[],successfulInsertions:0,failedInsertions:0,totalLinesAdded:0}
@@ -3443,10 +3464,10 @@ try{const s=await n.documentFileManager.getDocumentAsFile(e.documentId),o=n.docu
3443
3464
  t.filename=o?.filename
3444
3465
  const i=await c.default.readFile(s,"utf8"),{newContent:a,results:l}=await r(i,e.insertions)
3445
3466
  t.insertions=l,t.successfulInsertions=l.filter((e=>e.success)).length,t.failedInsertions=l.filter((e=>!e.success)).length,t.totalLinesAdded=l.filter((e=>e.success)).reduce(((e,t)=>e+(t.linesAdded||0)),0),a!==i&&t.successfulInsertions>0?(await c.default.writeFile(s,a,"utf8"),n.documentFileManager.markForSync(e.documentId),t.success=!0,U++,y.info("Document updated successfully",{documentId:e.documentId,filename:t.filename,successfulInsertions:t.successfulInsertions,failedInsertions:t.failedInsertions,linesAdded:t.totalLinesAdded})):0===t.failedInsertions&&(t.success=!0),H+=t.failedInsertions,B+=t.totalLinesAdded}catch(r){t.error=(0,m.getErrorMessage)(r),t.failedInsertions=e.insertions.length,H+=t.failedInsertions,y.error("Document operation failed",{documentId:e.documentId,error:t.error})}L.push(t)}if(M.length>0)try{for(const e of M){const t=L.find((t=>t.documentId===e.documentId))
3446
- t?.success&&await n.documentFileManager.syncDocument(e.documentId)}}catch(e){y.warn("Some documents may not have synced properly",{error:e})}const G=await l.handleMultiFileGitCommit(T,R,L,U,{operationType:"Insert lines",toolRecordId:I,successField:"successfulInsertions",logger:y,metrics:g,metricsPrefix:"insert_lines"},n),W=l.processMultiFileOperationResults(L,"successfulInsertions"),{successfulOperations:V,failedOperations:Q,totalSuccessfulChanges:K,overallSuccess:J,successfulFiles:Y,failedFiles:Z}=W
3447
- try{await o.updateToolRecord(I,{metadata:{path:R.length>0?R[0].path:"document:"+M[0]?.documentId,status:J?"completed":"failed",error:J?void 0:Q+" operations failed",totalOperations:L.length,successfulFiles:Y,failedFiles:Z,operations:N,totalSuccessfulInsertions:K,totalFailedInsertions:H,totalLinesAdded:B,operationsWithChanges:U,processingTime:Date.now()-w,userComment:E,...R.length>0&&G.success&&G.commitHash&&{commitHash:G.commitHash,previousCommitHash:G.previousCommitHash||void 0}},note:J?`Line insertion completed: ${V}/${L.length} operations successful${R.length>0?" (committed to git)":""}`:`Line insertion partially failed: ${Q}/${L.length} operations failed`})}catch(e){y.warn("Failed to update tool record",{recordError:e})}let X="## Line Insertion Results\n\n"
3467
+ t?.success&&await n.documentFileManager.syncDocument(e.documentId)}}catch(e){y.warn("Some documents may not have synced properly",{error:e})}const W=await l.handleMultiFileGitCommit(T,P,L,U,{operationType:"Insert lines",toolRecordId:I,successField:"successfulInsertions",logger:y,metrics:g,metricsPrefix:"insert_lines"},n),G=l.processMultiFileOperationResults(L,"successfulInsertions"),{successfulOperations:V,failedOperations:Q,totalSuccessfulChanges:K,overallSuccess:J,successfulFiles:Y,failedFiles:Z}=G
3468
+ try{await o.updateToolRecord(I,{metadata:{path:P.length>0?P[0].path:"document:"+M[0]?.documentId,status:J?"completed":"failed",error:J?void 0:Q+" operations failed",totalOperations:L.length,successfulFiles:Y,failedFiles:Z,operations:N,totalSuccessfulInsertions:K,totalFailedInsertions:H,totalLinesAdded:B,operationsWithChanges:U,processingTime:Date.now()-w,userComment:E,...P.length>0&&W.success&&W.commitHash&&{commitHash:W.commitHash,previousCommitHash:W.previousCommitHash||void 0}},note:J?`Line insertion completed: ${V}/${L.length} operations successful${P.length>0?" (committed to git)":""}`:`Line insertion partially failed: ${Q}/${L.length} operations failed`})}catch(e){y.warn("Failed to update tool record",{recordError:e})}let X="## Line Insertion Results\n\n"
3448
3469
  if(n.workspaceManager){const e=n.workspaceManager.getCurrentContext(n.currentSessionId)
3449
- e.permanentBranch||(X+=`**Branch:** \`${e.branchName}\`\n\n`)}if(X+="**Summary:**\n",X+=`- **Files processed:** ${V+Q}\n`,X+=`- **Successful operations:** ${V}\n`,X+=`- **Failed operations:** ${Q}\n`,X+=`- **Total insertions:** ${K} successful, ${H} failed\n`,X+=`- **Total Lines Added:** ${B}\n`,X+="\n",G.success&&G.commitHash&&(X+="**Git Commit:**\n",X+=`- **Commit Hash:** ${G.commitHash.substring(0,8)}\n`,X+=`- **Files Committed:** ${G.filesCommitted.length}\n`,G.previousCommitHash&&(X+=`- **Previous Commit:** ${G.previousCommitHash.substring(0,8)}\n`),X+="\n"),1===L.length){const e=L[0]
3470
+ e.permanentBranch||(X+=`**Branch:** \`${e.branchName}\`\n\n`)}if(X+="**Summary:**\n",X+=`- **Files processed:** ${V+Q}\n`,X+=`- **Successful operations:** ${V}\n`,X+=`- **Failed operations:** ${Q}\n`,X+=`- **Total insertions:** ${K} successful, ${H} failed\n`,X+=`- **Total Lines Added:** ${B}\n`,X+="\n",W.success&&W.commitHash&&(X+="**Git Commit:**\n",X+=`- **Commit Hash:** ${W.commitHash.substring(0,8)}\n`,X+=`- **Files Committed:** ${W.filesCommitted.length}\n`,W.previousCommitHash&&(X+=`- **Previous Commit:** ${W.previousCommitHash.substring(0,8)}\n`),X+="\n"),1===L.length){const e=L[0]
3450
3471
  if(X+=`**Operation:** ${e.success?"\u2705 Success":"\u274c Failed"}\n`,"file"===e.type?X+=`**File:** ${e.path}\n`:(X+="**Document:** "+e.documentId,e.filename&&(X+=` (${e.filename})`),X+="\n"),e.error?X+=`**Error:** ${e.error}\n`:(X+=`**Insertions:** ${e.successfulInsertions} successful`,e.failedInsertions>0&&(X+=`, ${e.failedInsertions} failed`),X+="\n",X+=`**Lines Added:** ${e.totalLinesAdded}\n`),e.insertions.some((e=>!e.success))){X+="**Failed Insertion Details:**\n"
3451
3472
  for(const t of e.insertions.filter((e=>!e.success))){const e="between"===t.type?`between lines ${t.afterLine} and ${t.beforeLine}`:`${t.type} line ${t.line}`
3452
3473
  X+=`- ${t.type} insertion ${e}: ${t.error}\n`}}}else{X+="**Summary:**\n",X+=`- **Total Operations:** ${L.length}\n`,X+=`- **Successful:** ${V}\n`,X+=`- **Failed:** ${Q}\n`,X+=`- **Total Insertions:** ${K} successful, ${H} failed\n`,X+=`- **Total Lines Added:** ${B}\n\n`,X+="**Detailed Results:**\n\n"
@@ -3474,17 +3495,17 @@ const T=new p.DocumentClient(e,f,y,_,v||void 0,C,{timeout:w.timeout,retryAttempt
3474
3495
  I.registerClient(T)
3475
3496
  const x=new g.ToolRecordClient(e,f,y,_,v||void 0,C,{timeout:w.timeout,retryAttempts:w.retryAttempts,retryDelay:w.retryDelay,circuitBreakerThreshold:w.circuitBreakerThreshold,circuitBreakerResetTime:w.circuitBreakerResetTime})
3476
3497
  I.registerClient(x)
3477
- const P=new d.ProxyClient(e,f,y,_,v||void 0,C,{timeout:w.timeout,retryAttempts:w.retryAttempts,retryDelay:w.retryDelay,circuitBreakerThreshold:w.circuitBreakerThreshold,circuitBreakerResetTime:w.circuitBreakerResetTime})
3478
- if(I.registerClient(P),!w.alchemyPath)throw Error("alchemyPath is required for ProjectSynchronizer creation. Cannot create API client without project synchronization capabilities.")
3498
+ const R=new d.ProxyClient(e,f,y,_,v||void 0,C,{timeout:w.timeout,retryAttempts:w.retryAttempts,retryDelay:w.retryDelay,circuitBreakerThreshold:w.circuitBreakerThreshold,circuitBreakerResetTime:w.circuitBreakerResetTime})
3499
+ if(I.registerClient(R),!w.alchemyPath)throw Error("alchemyPath is required for ProjectSynchronizer creation. Cannot create API client without project synchronization capabilities.")
3479
3500
  try{f.info("Creating ProjectSynchronizer components")
3480
3501
  const{ProjectRegistry,ProjectFileSystem,ProjectSynchronizer}=await t.e(478).then(t.bind(t,5478)),e=new ProjectRegistry(f),r=new ProjectFileSystem(f),n=new ProjectSynchronizer(f,e,new l.ProjectClientAdapter(_,f),r,{createRemoteProjects:!0})
3481
3502
  _.setProjectSynchronizer(n),f.info("ProjectSynchronizer created and connected to ProjectClient")}catch(e){const t="Failed to create required ProjectSynchronizer components: "+(0,h.getErrorMessage)(e)
3482
- throw f.error(t,{error:e instanceof Error?e.stack:e+""}),Error(t)}const R=new s.ApiClient(k,_,E,S,q,T,x,P,f)
3483
- f.info("API client initialized with specialized clients"),v?(R.setAuthToken(v),f.info("Auth token set on ApiClient during creation",{hasToken:!0,tokenLength:v.length})):f.warn("No auth token available during ApiClient creation",{info:"Client will need to authenticate before making requests"})
3503
+ throw f.error(t,{error:e instanceof Error?e.stack:e+""}),Error(t)}const P=new s.ApiClient(k,_,E,S,q,T,x,R,f)
3504
+ f.info("API client initialized with specialized clients"),v?(P.setAuthToken(v),f.info("Auth token set on ApiClient during creation",{hasToken:!0,tokenLength:v.length})):f.warn("No auth token available during ApiClient creation",{info:"Client will need to authenticate before making requests"})
3484
3505
  const M=I.verifyAllClients()
3485
3506
  M.success?f.info("Token consistency verified across all clients"):f.error(`Token inconsistency detected in ${M.failedClients.length} clients: ${M.failedClients.join(", ")}`)
3486
- const $=R.getAuthToken()
3487
- return v&&!$?(f.error("CRITICAL: ApiClient token was not set properly!"),R.setAuthToken(v)):$&&f.info("ApiClient token verified",{tokenLength:$.length,matches:$===v}),f.info("API client creation completed successfully"),R}}},6540(e,exports){"use strict"
3507
+ const $=P.getAuthToken()
3508
+ return v&&!$?(f.error("CRITICAL: ApiClient token was not set properly!"),P.setAuthToken(v)):$&&f.info("ApiClient token verified",{tokenLength:$.length,matches:$===v}),f.info("API client creation completed successfully"),P}}},6540(e,exports){"use strict"
3488
3509
  var t
3489
3510
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.LogLevel=void 0,function(e){e.ERROR="error",e.WARN="warn",e.INFO="info",e.DEBUG="debug"}(t||(exports.LogLevel=t={}))},6552(e,exports,t){"use strict"
3490
3511
  async function r(){const e=new s.StdioServerTransport,t=(0,l.setupParentProcessDetection)((()=>{b.info("Parent process gone or orphan detected. Shutting down."),process.exit(0)}))
@@ -3562,13 +3583,13 @@ try{const _=e,{operations:E,comment:S}=_,{enforceActiveTask:q}=await Promise.res
3562
3583
  if("errorResult"in T)return T.errorResult
3563
3584
  const{taskId:x}=T
3564
3585
  if(w.info("Replacing lines in files and documents",{taskId:x,operationCount:E.length,comment:S}),!E||0===E.length)throw new d.ValidationError("At least one operation is required")
3565
- const P=E.filter((e=>e.path)),R=E.filter((e=>e.documentId))
3566
- w.info("Operation breakdown",{fileOperations:P.length,documentOperations:R.length})
3586
+ const R=E.filter((e=>e.path)),P=E.filter((e=>e.documentId))
3587
+ w.info("Operation breakdown",{fileOperations:R.length,documentOperations:P.length})
3567
3588
  const M=[]
3568
- for(const e of P){const{normalizedPath:t,fullPath:r}=l.validateAndNormalizePath(e.path,n)
3589
+ for(const e of R){const{normalizedPath:t,fullPath:r}=l.validateAndNormalizePath(e.path,n)
3569
3590
  M.push({type:"file",path:t,fullPath:r,replacements:e.replacements.map((e=>({lines:(0,f.parseLineSpec)(e.lines),content:e.content})))})}const $=[]
3570
- if(R.length>0&&!n.documentFileManager)throw Error("Document file manager not available - cannot process document operations")
3571
- for(const e of R)$.push({type:"document",documentId:e.documentId,replacements:e.replacements.map((e=>({lines:(0,f.parseLineSpec)(e.lines),content:e.content})))})
3591
+ if(P.length>0&&!n.documentFileManager)throw Error("Document file manager not available - cannot process document operations")
3592
+ for(const e of P)$.push({type:"document",documentId:e.documentId,replacements:e.replacements.map((e=>({lines:(0,f.parseLineSpec)(e.lines),content:e.content})))})
3572
3593
  if($.length>0&&n.apiClient){const e=$.map((e=>e.documentId))
3573
3594
  try{await(0,p.ensureDocumentsNotLocked)(e,n.apiClient,w,g,"replace-lines-documents")}catch(e){if(e instanceof d.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3574
3595
  throw e}}v=l.FileOperationPhase.TASK_VALIDATION,g.incrementCounter("replace_lines_phase",1,{phase:v})
@@ -3580,7 +3601,7 @@ M.length>0&&D&&A&&(F=await l.autoPromoteTaskStatus(x,O.status,D,A.request?.statu
3580
3601
  const N=await l.ensureCorrectWorkspaceContext({taskPromoted:F.taskPromoted,requestId:D,context:n,operation:"replace-lines",logger:w,metrics:g,metricsPrefix:C.metricsPrefix})
3581
3602
  if(!N.success)throw Error(N.error)
3582
3603
  if(M.length>0){w.debug("Re-validating file paths with correct workspace context",{operationCount:M.length,workspaceBasePath:n.workspaceManager?.getCurrentContext(n.currentSessionId).basePath})
3583
- for(let e=0;e<M.length;e++){const t=M[e],r=P[e],{normalizedPath:s,fullPath:o}=l.validateAndNormalizePath(r.path,n)
3604
+ for(let e=0;e<M.length;e++){const t=M[e],r=R[e],{normalizedPath:s,fullPath:o}=l.validateAndNormalizePath(r.path,n)
3584
3605
  M[e]={...t,path:s,fullPath:o}}}if($.length>0&&D)try{await(0,u.validateRequestStatusForDocumentOperation)(D,i,w,g,"replace-lines-document")}catch(e){if(e instanceof d.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3585
3606
  throw e}v=l.FileOperationPhase.RECORD_CREATION,g.incrementCounter("replace_lines_phase",1,{phase:v})
3586
3607
  const z=[...M.map((e=>({type:"file",path:e.path,replacements:e.replacements}))),...$.map((e=>({type:"document",documentId:e.documentId,replacements:e.replacements})))],{toolRecordId:L}=await l.createFileOperationRecords(x,D,n.projectId,C.recordType,j,{operationCount:E.length,fileOperations:M.length,documentOperations:$.length,operations:z,userComment:S},s,o,w,g,C.metricsPrefix,y)
@@ -3588,21 +3609,21 @@ if(I=L,k=L,v=C.fileOperationPhase,g.incrementCounter("replace_lines_phase",1,{ph
3588
3609
  const e=await(0,h.commitUserChangesBeforeToolOperation)(n.git,"replace-lines",{requestId:D,taskId:x,workspaceManager:n.workspaceManager},w,g)
3589
3610
  e.userChangesCommitted&&(w.debug("[REPLACE-LINES] User changes committed before replace operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),w.info("User changes committed before replace-lines operation",{taskId:x,fileOperationsCount:M.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){w.debug("[REPLACE-LINES] Pre-tool commit failed, continuing with replacements",{error:e instanceof Error?e.message:e+""}),w.warn("Pre-tool user changes commit failed, continuing with replace operation",{taskId:x,fileOperationsCount:M.length,error:e instanceof Error?e.message:e+""})}w.debug("[REPLACE-LINES] Proceeding with file operations",{fileCount:M.length})
3590
3611
  const H=[]
3591
- let B=0,U=0,G=0,W=0
3612
+ let B=0,U=0,W=0,G=0
3592
3613
  for(const e of M){const t={type:"file",path:e.path,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0,totalLinesReplaced:0,totalLinesAdded:0}
3593
3614
  try{if(await c.default.access(e.fullPath),!(await c.default.stat(e.fullPath)).isFile())throw Error("Path is not a file: "+e.path)
3594
3615
  const n=await c.default.readFile(e.fullPath,"utf8"),{newContent:s,results:o}=await r(n,e.replacements)
3595
- t.replacements=o,t.successfulReplacements=o.filter((e=>e.success)).length,t.failedReplacements=o.filter((e=>!e.success)).length,t.totalLinesReplaced=o.filter((e=>e.success)).reduce(((e,t)=>e+(t.linesReplaced||0)),0),t.totalLinesAdded=o.filter((e=>e.success)).reduce(((e,t)=>e+(t.linesAdded||0)),0),s!==n&&t.successfulReplacements>0?(await c.default.writeFile(e.fullPath,s,"utf8"),t.success=!0,W++,w.info("File updated successfully",{path:e.path,successfulReplacements:t.successfulReplacements,failedReplacements:t.failedReplacements,linesReplaced:t.totalLinesReplaced,linesAdded:t.totalLinesAdded})):0===t.failedReplacements&&(t.success=!0),B+=t.failedReplacements,U+=t.totalLinesReplaced,G+=t.totalLinesAdded}catch(r){t.error=(0,m.getErrorMessage)(r),t.failedReplacements=e.replacements.length,B+=t.failedReplacements,w.error("File operation failed",{path:e.path,error:t.error})}H.push(t)}for(const e of $){const t={type:"document",documentId:e.documentId,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0,totalLinesReplaced:0,totalLinesAdded:0}
3616
+ t.replacements=o,t.successfulReplacements=o.filter((e=>e.success)).length,t.failedReplacements=o.filter((e=>!e.success)).length,t.totalLinesReplaced=o.filter((e=>e.success)).reduce(((e,t)=>e+(t.linesReplaced||0)),0),t.totalLinesAdded=o.filter((e=>e.success)).reduce(((e,t)=>e+(t.linesAdded||0)),0),s!==n&&t.successfulReplacements>0?(await c.default.writeFile(e.fullPath,s,"utf8"),t.success=!0,G++,w.info("File updated successfully",{path:e.path,successfulReplacements:t.successfulReplacements,failedReplacements:t.failedReplacements,linesReplaced:t.totalLinesReplaced,linesAdded:t.totalLinesAdded})):0===t.failedReplacements&&(t.success=!0),B+=t.failedReplacements,U+=t.totalLinesReplaced,W+=t.totalLinesAdded}catch(r){t.error=(0,m.getErrorMessage)(r),t.failedReplacements=e.replacements.length,B+=t.failedReplacements,w.error("File operation failed",{path:e.path,error:t.error})}H.push(t)}for(const e of $){const t={type:"document",documentId:e.documentId,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0,totalLinesReplaced:0,totalLinesAdded:0}
3596
3617
  try{const s=await n.documentFileManager.getDocumentAsFile(e.documentId),o=n.documentFileManager.getCachedDocumentInfo(e.documentId)
3597
3618
  t.filename=o?.filename
3598
3619
  const i=await c.default.readFile(s,"utf8"),{newContent:a,results:l}=await r(i,e.replacements)
3599
- t.replacements=l,t.successfulReplacements=l.filter((e=>e.success)).length,t.failedReplacements=l.filter((e=>!e.success)).length,t.totalLinesReplaced=l.filter((e=>e.success)).reduce(((e,t)=>e+(t.linesReplaced||0)),0),t.totalLinesAdded=l.filter((e=>e.success)).reduce(((e,t)=>e+(t.linesAdded||0)),0),a!==i&&t.successfulReplacements>0?(await c.default.writeFile(s,a,"utf8"),n.documentFileManager.markForSync(e.documentId),t.success=!0,W++,w.info("Document updated successfully",{documentId:e.documentId,filename:t.filename,successfulReplacements:t.successfulReplacements,failedReplacements:t.failedReplacements,linesReplaced:t.totalLinesReplaced,linesAdded:t.totalLinesAdded})):0===t.failedReplacements&&(t.success=!0),B+=t.failedReplacements,U+=t.totalLinesReplaced,G+=t.totalLinesAdded}catch(r){t.error=(0,m.getErrorMessage)(r),t.failedReplacements=e.replacements.length,B+=t.failedReplacements,w.error("Document operation failed",{documentId:e.documentId,error:t.error})}H.push(t)}if($.length>0)try{for(const e of $){const t=H.find((t=>t.documentId===e.documentId))
3600
- t?.success&&await n.documentFileManager.syncDocument(e.documentId)}}catch(e){w.warn("Some documents may not have synced properly",{error:e})}const V=await l.handleMultiFileGitCommit(x,M,H,W,{operationType:"Replace lines",toolRecordId:k,successField:"successfulReplacements",logger:w,metrics:g,metricsPrefix:"replace_lines"},n),Q=l.processMultiFileOperationResults(H,"successfulReplacements"),{successfulOperations:K,failedOperations:J,totalSuccessfulChanges:Y,overallSuccess:Z,successfulFiles:X,failedFiles:ee}=Q
3601
- try{await o.updateToolRecord(k,{metadata:{path:M.length>0?M[0].path:"document:"+$[0]?.documentId,status:Z?"completed":"failed",error:Z?void 0:J+" operations failed",totalOperations:H.length,successfulFiles:X,failedFiles:ee,operations:z,totalSuccessfulReplacements:Y,totalFailedReplacements:B,totalLinesReplaced:U,totalLinesAdded:G,operationsWithChanges:W,processingTime:Date.now()-b,userComment:S,...M.length>0&&V.success&&V.commitHash&&{commitHash:V.commitHash,previousCommitHash:V.previousCommitHash||void 0}},note:Z?`Line replacement completed: ${K}/${H.length} operations successful${M.length>0?" (committed to git)":""}`:`Line replacement partially failed: ${J}/${H.length} operations failed`})}catch(e){w.warn("Failed to update tool record",{recordError:e})}let te="## Line Replacement Results\n\n"
3620
+ t.replacements=l,t.successfulReplacements=l.filter((e=>e.success)).length,t.failedReplacements=l.filter((e=>!e.success)).length,t.totalLinesReplaced=l.filter((e=>e.success)).reduce(((e,t)=>e+(t.linesReplaced||0)),0),t.totalLinesAdded=l.filter((e=>e.success)).reduce(((e,t)=>e+(t.linesAdded||0)),0),a!==i&&t.successfulReplacements>0?(await c.default.writeFile(s,a,"utf8"),n.documentFileManager.markForSync(e.documentId),t.success=!0,G++,w.info("Document updated successfully",{documentId:e.documentId,filename:t.filename,successfulReplacements:t.successfulReplacements,failedReplacements:t.failedReplacements,linesReplaced:t.totalLinesReplaced,linesAdded:t.totalLinesAdded})):0===t.failedReplacements&&(t.success=!0),B+=t.failedReplacements,U+=t.totalLinesReplaced,W+=t.totalLinesAdded}catch(r){t.error=(0,m.getErrorMessage)(r),t.failedReplacements=e.replacements.length,B+=t.failedReplacements,w.error("Document operation failed",{documentId:e.documentId,error:t.error})}H.push(t)}if($.length>0)try{for(const e of $){const t=H.find((t=>t.documentId===e.documentId))
3621
+ t?.success&&await n.documentFileManager.syncDocument(e.documentId)}}catch(e){w.warn("Some documents may not have synced properly",{error:e})}const V=await l.handleMultiFileGitCommit(x,M,H,G,{operationType:"Replace lines",toolRecordId:k,successField:"successfulReplacements",logger:w,metrics:g,metricsPrefix:"replace_lines"},n),Q=l.processMultiFileOperationResults(H,"successfulReplacements"),{successfulOperations:K,failedOperations:J,totalSuccessfulChanges:Y,overallSuccess:Z,successfulFiles:X,failedFiles:ee}=Q
3622
+ try{await o.updateToolRecord(k,{metadata:{path:M.length>0?M[0].path:"document:"+$[0]?.documentId,status:Z?"completed":"failed",error:Z?void 0:J+" operations failed",totalOperations:H.length,successfulFiles:X,failedFiles:ee,operations:z,totalSuccessfulReplacements:Y,totalFailedReplacements:B,totalLinesReplaced:U,totalLinesAdded:W,operationsWithChanges:G,processingTime:Date.now()-b,userComment:S,...M.length>0&&V.success&&V.commitHash&&{commitHash:V.commitHash,previousCommitHash:V.previousCommitHash||void 0}},note:Z?`Line replacement completed: ${K}/${H.length} operations successful${M.length>0?" (committed to git)":""}`:`Line replacement partially failed: ${J}/${H.length} operations failed`})}catch(e){w.warn("Failed to update tool record",{recordError:e})}let te="## Line Replacement Results\n\n"
3602
3623
  if(n.workspaceManager){const e=n.workspaceManager.getCurrentContext(n.currentSessionId)
3603
- e.permanentBranch||(te+=`**Branch:** \`${e.branchName}\`\n\n`)}if(te+="**Summary:**\n",te+=`- **Files processed:** ${K+J}\n`,te+=`- **Successful operations:** ${K}\n`,te+=`- **Failed operations:** ${J}\n`,te+=`- **Total replacements:** ${Y} successful, ${B} failed\n`,te+=`- **Total Lines Replaced:** ${U}\n`,G>0&&(te+=`- **Total Lines Added:** ${G}\n`),te+="\n",V.success&&V.commitHash&&(te+="**Git Commit:**\n",te+=`- **Commit Hash:** ${V.commitHash.substring(0,8)}\n`,te+=`- **Files Committed:** ${V.filesCommitted.length}\n`,V.previousCommitHash&&(te+=`- **Previous Commit:** ${V.previousCommitHash.substring(0,8)}\n`),te+="\n"),1===H.length){const e=H[0]
3624
+ e.permanentBranch||(te+=`**Branch:** \`${e.branchName}\`\n\n`)}if(te+="**Summary:**\n",te+=`- **Files processed:** ${K+J}\n`,te+=`- **Successful operations:** ${K}\n`,te+=`- **Failed operations:** ${J}\n`,te+=`- **Total replacements:** ${Y} successful, ${B} failed\n`,te+=`- **Total Lines Replaced:** ${U}\n`,W>0&&(te+=`- **Total Lines Added:** ${W}\n`),te+="\n",V.success&&V.commitHash&&(te+="**Git Commit:**\n",te+=`- **Commit Hash:** ${V.commitHash.substring(0,8)}\n`,te+=`- **Files Committed:** ${V.filesCommitted.length}\n`,V.previousCommitHash&&(te+=`- **Previous Commit:** ${V.previousCommitHash.substring(0,8)}\n`),te+="\n"),1===H.length){const e=H[0]
3604
3625
  if(te+=`**Operation:** ${e.success?"\u2705 Success":"\u274c Failed"}\n`,"file"===e.type?te+=`**File:** ${e.path}\n`:(te+="**Document:** "+e.documentId,e.filename&&(te+=` (${e.filename})`),te+="\n"),e.error?te+=`**Error:** ${e.error}\n`:(te+=`**Replacements:** ${e.successfulReplacements} successful`,e.failedReplacements>0&&(te+=`, ${e.failedReplacements} failed`),te+="\n",te+=`**Lines Replaced:** ${e.totalLinesReplaced}\n`,e.totalLinesAdded>0&&(te+=`**Lines Added:** ${e.totalLinesAdded}\n`)),e.replacements.some((e=>!e.success))){te+="**Failed Replacement Details:**\n"
3605
- for(const t of e.replacements.filter((e=>!e.success)))te+=`- Replace ${"number"==typeof t.lines?"line "+t.lines:Array.isArray(t.lines)?`lines [${t.lines.join(", ")}]`:`lines ${t.lines.start}-${t.lines.end}`}: ${t.error}\n`}}else{te+="**Summary:**\n",te+=`- **Total Operations:** ${H.length}\n`,te+=`- **Successful:** ${K}\n`,te+=`- **Failed:** ${J}\n`,te+=`- **Total Replacements:** ${Y} successful, ${B} failed\n`,te+=`- **Total Lines Replaced:** ${U}\n`,G>0&&(te+=`- **Total Lines Added:** ${G}\n`),te+="\n",te+="**Detailed Results:**\n\n"
3626
+ for(const t of e.replacements.filter((e=>!e.success)))te+=`- Replace ${"number"==typeof t.lines?"line "+t.lines:Array.isArray(t.lines)?`lines [${t.lines.join(", ")}]`:`lines ${t.lines.start}-${t.lines.end}`}: ${t.error}\n`}}else{te+="**Summary:**\n",te+=`- **Total Operations:** ${H.length}\n`,te+=`- **Successful:** ${K}\n`,te+=`- **Failed:** ${J}\n`,te+=`- **Total Replacements:** ${Y} successful, ${B} failed\n`,te+=`- **Total Lines Replaced:** ${U}\n`,W>0&&(te+=`- **Total Lines Added:** ${W}\n`),te+="\n",te+="**Detailed Results:**\n\n"
3606
3627
  for(const e of H){if("file"===e.type?te+=`### File: ${e.path}\n`:(te+="### Document: "+e.documentId,e.filename&&(te+=` (${e.filename})`),te+="\n"),te+=`- **Status:** ${e.success?"\u2705 Success":"\u274c Failed"}\n`,e.error&&(te+=`- **Error:** ${e.error}\n`),te+=`- **Replacements:** ${e.successfulReplacements} successful`,e.failedReplacements>0&&(te+=`, ${e.failedReplacements} failed`),te+="\n",te+=`- **Lines Replaced:** ${e.totalLinesReplaced}\n`,e.totalLinesAdded>0&&(te+=`- **Lines Added:** ${e.totalLinesAdded}\n`),e.replacements.some((e=>!e.success))){te+="- **Failed Replacement Details:**\n"
3607
3628
  for(const t of e.replacements.filter((e=>!e.success)))te+=` - Replace ${"number"==typeof t.lines?"line "+t.lines:Array.isArray(t.lines)?`lines [${t.lines.join(", ")}]`:`lines ${t.lines.start}-${t.lines.end}`}: ${t.error}\n`}te+="\n"}}$.length>0&&(te+="\u{1f4c4} **Document Changes:** Modified documents have been automatically synced back to the tracking system.\n\n")
3608
3629
  const re=Date.now()-b
@@ -3680,8 +3701,8 @@ o.info("Getting file changes for task "+m,{showDiff:g})
3680
3701
  const f=r.getTaskClient(),y=r.getToolRecordClient(),w=t.projectId
3681
3702
  let b
3682
3703
  r.setProjectId(w)
3683
- try{const P=await f.getTask(m)
3684
- o.info("Raw task response data",{responseDataType:typeof P,isArray:Array.isArray(P),hasData:null!=P,properties:P&&"object"==typeof P?Object.keys(P):[]}),b=(0,l.extractDataFromResponse)(P,{logger:o,operationName:"getTask",defaultValue:{id:m,title:"Unknown Task",status:"unknown",description:"No description available"}}),o.info("Found task: "+b.title)}catch(R){o.warn("Could not fetch task information: "+(0,u.getErrorMessage)(R)),b={id:m,title:"Unknown Task",status:"unknown",description:"No description available"}}let I=[]
3704
+ try{const R=await f.getTask(m)
3705
+ o.info("Raw task response data",{responseDataType:typeof R,isArray:Array.isArray(R),hasData:null!=R,properties:R&&"object"==typeof R?Object.keys(R):[]}),b=(0,l.extractDataFromResponse)(R,{logger:o,operationName:"getTask",defaultValue:{id:m,title:"Unknown Task",status:"unknown",description:"No description available"}}),o.info("Found task: "+b.title)}catch(P){o.warn("Could not fetch task information: "+(0,u.getErrorMessage)(P)),b={id:m,title:"Unknown Task",status:"unknown",description:"No description available"}}let I=[]
3685
3706
  try{const M=await y.getToolRecordsByTaskId(m)
3686
3707
  if(o.info("Raw records response data",{responseDataType:typeof M,isArray:Array.isArray(M),hasData:null!=M,properties:M&&"object"==typeof M?Object.keys(M):[]}),I=(0,l.extractArrayFromResponse)(M,{logger:o,operationName:"searchRecords",defaultValue:[]}),I.length>0&&o.info("First record summary:",{id:I[0].id,type:I[0].type,hasMetadata:!!I[0].metadata,hasCommitHash:!!I[0].metadata?.commitHash}),o.info(`Extracted ${I.length} records for task ${m}`),I.length>0){const $={}
3687
3708
  I.forEach((e=>{$[e.type]=($[e.type]||0)+1})),o.info("Record type distribution:",$)}}catch(j){o.warn("Error fetching records for task "+m,{error:(0,u.getErrorMessage)(j)}),I=[]}if(0===I.length)return p({success:!0,recordCount:0}),{content:[{type:"text",text:`No records found for task ${m}.`}]}
@@ -3750,22 +3771,22 @@ ne&&ne.trim().length>0?(te=ne.split("\n").map((e=>"+"+e)).join("\n"),E.set(F,{fi
3750
3771
  te=await t.git.diff(oe),E.set(F,{firstChange:Z,lastChange:X,hasDiff:!(!te||0>=te.trim().length),diffText:te||"No changes detected in git diff"})}}catch(ie){o.warn("Error generating diff for "+F,{error:ie instanceof Error?ie.message:ie+""}),E.set(F,{firstChange:Z,lastChange:X,hasDiff:!0,diffText:"Error generating diff, but git history is available"})}continue}}else o.info("No git history found for "+F)}}catch(ae){o.warn("Error getting git history for "+F,{error:(0,u.getErrorMessage)(ae)})}E.set(F,{firstChange:N[0],lastChange:N[N.length-1],hasDiff:!1,diffText:"No commit hashes available for this file"})
3751
3772
  continue}const H=L[0],B=L[L.length-1]
3752
3773
  o.info(`First commit: ${H.commitHash?H.commitHash:"unknown"}, Last commit: ${B.commitHash?B.commitHash:"unknown"}`)
3753
- let U=null,G=!1
3754
- if(t.git&&H.commitHash)try{U=await(0,c.findPreviousCommit)(t.git,F,H.commitHash),U?(G=!0,o.info(`Found previous commit: ${U} for ${F}`)):o.info(`No previous commit found for ${F}, likely a new file`)}catch(ce){o.warn("Error finding previous commit for "+F,{error:(0,u.getErrorMessage)(ce)})}const W=G&&U?{...H,commitHash:U,status:"pre-task"}:H
3755
- if(o.info(`Using ${G?"pre-task":"first task"} commit as baseline for ${F}: ${W.commitHash}`),o.info(`Last commit for ${F}: ${B.commitHash}`),o.info("Commits are "+(W.commitHash===B.commitHash?"identical":"different")),H.commitHash===B.commitHash&&!G){if(g&&!G&&t.git&&B.commitHash)try{const le=[`${B.commitHash}:${F}`]
3774
+ let U=null,W=!1
3775
+ if(t.git&&H.commitHash)try{U=await(0,c.findPreviousCommit)(t.git,F,H.commitHash),U?(W=!0,o.info(`Found previous commit: ${U} for ${F}`)):o.info(`No previous commit found for ${F}, likely a new file`)}catch(ce){o.warn("Error finding previous commit for "+F,{error:(0,u.getErrorMessage)(ce)})}const G=W&&U?{...H,commitHash:U,status:"pre-task"}:H
3776
+ if(o.info(`Using ${W?"pre-task":"first task"} commit as baseline for ${F}: ${G.commitHash}`),o.info(`Last commit for ${F}: ${B.commitHash}`),o.info("Commits are "+(G.commitHash===B.commitHash?"identical":"different")),H.commitHash===B.commitHash&&!W){if(g&&!W&&t.git&&B.commitHash)try{const le=[`${B.commitHash}:${F}`]
3756
3777
  o.info(`Getting new file content using git show: ${B.commitHash?B.commitHash.substring(0,8):"unknown"}:${F}`)
3757
3778
  const de=await t.git.show(le)
3758
3779
  if(de&&de.trim().length>0){let ue=""
3759
3780
  const he=de.split("\n")
3760
3781
  for(const pe of he)ue+=`+${pe}\n`
3761
- E.set(F,{firstChange:W,lastChange:B,hasDiff:!0,diffText:ue}),o.info(`Formatted new file content as diff, ${he.length} lines`)
3762
- continue}}catch(me){o.warn("Error getting new file content for "+F,{error:(0,u.getErrorMessage)(me)})}E.set(F,{firstChange:W,lastChange:B,hasDiff:!1,diffText:"Only one commit available for this file"})
3763
- continue}if(H.commitHash===B.commitHash&&G){if(U===H.commitHash){E.set(F,{firstChange:W,lastChange:B,hasDiff:!1,diffText:"No changes detected"})
3782
+ E.set(F,{firstChange:G,lastChange:B,hasDiff:!0,diffText:ue}),o.info(`Formatted new file content as diff, ${he.length} lines`)
3783
+ continue}}catch(me){o.warn("Error getting new file content for "+F,{error:(0,u.getErrorMessage)(me)})}E.set(F,{firstChange:G,lastChange:B,hasDiff:!1,diffText:"Only one commit available for this file"})
3784
+ continue}if(H.commitHash===B.commitHash&&W){if(U===H.commitHash){E.set(F,{firstChange:G,lastChange:B,hasDiff:!1,diffText:"No changes detected"})
3764
3785
  continue}o.info("Special case: First and last task commits are the same, but pre-task commit is different")}let V="",Q=!1
3765
- if(g||"pre-task"!==W.status){try{if(t.git){try{await t.git.show([`${B.commitHash}:${F}`])}catch(fe){o.warn(`File ${F} does not exist in commit ${B.commitHash}, might be deleted or moved`),V="File was deleted or moved from this location during the task",Q=!0,E.set(F,{firstChange:W,lastChange:B,hasDiff:Q,diffText:V})
3786
+ if(g||"pre-task"!==G.status){try{if(t.git){try{await t.git.show([`${B.commitHash}:${F}`])}catch(fe){o.warn(`File ${F} does not exist in commit ${B.commitHash}, might be deleted or moved`),V="File was deleted or moved from this location during the task",Q=!0,E.set(F,{firstChange:G,lastChange:B,hasDiff:Q,diffText:V})
3766
3787
  continue}let ge
3767
- if("pre-task"===W.status?(ge=[`${W.commitHash}..${B.commitHash}`,"--",F],o.info(`Comparing pre-task commit with final commit: ${W.commitHash?W.commitHash.substring(0,8):"unknown"}..${B.commitHash?B.commitHash.substring(0,8):"unknown"} for ${F}`)):(ge=["4b825dc642cb6eb9a060e54bf8d69288fbee4904.."+B.commitHash,"--",F],o.info(`File created during task, showing full file diff using empty tree object: ${B.commitHash?B.commitHash.substring(0,8):"unknown"} for ${F}`)),V=await t.git.diff(ge),Q=!!V&&V.trim().length>0,!Q&&W.commitHash!==B.commitHash){o.info("No diff found between commits but commits are different, trying direct file content comparison")
3768
- try{const ye=await t.git.show([`${W.commitHash}:${F}`]),we=await t.git.show([`${B.commitHash}:${F}`])
3788
+ if("pre-task"===G.status?(ge=[`${G.commitHash}..${B.commitHash}`,"--",F],o.info(`Comparing pre-task commit with final commit: ${G.commitHash?G.commitHash.substring(0,8):"unknown"}..${B.commitHash?B.commitHash.substring(0,8):"unknown"} for ${F}`)):(ge=["4b825dc642cb6eb9a060e54bf8d69288fbee4904.."+B.commitHash,"--",F],o.info(`File created during task, showing full file diff using empty tree object: ${B.commitHash?B.commitHash.substring(0,8):"unknown"} for ${F}`)),V=await t.git.diff(ge),Q=!!V&&V.trim().length>0,!Q&&G.commitHash!==B.commitHash){o.info("No diff found between commits but commits are different, trying direct file content comparison")
3789
+ try{const ye=await t.git.show([`${G.commitHash}:${F}`]),we=await t.git.show([`${B.commitHash}:${F}`])
3769
3790
  if(ye!==we&&(Q=!0,V="Changes detected through direct content comparison (not visible in standard diff)",g)){const be=ye.split("\n"),Ie=we.split("\n")
3770
3791
  Math.abs(be.length-Ie.length)>0&&(V+=`\n\nLine count changed: ${be.length} \u2192 ${Ie.length}`),ye.includes("\0")||we.includes("\0")?V+="\n\nBinary content detected - changes not displayed":ye.replace(/\s+/g,"")===we.replace(/\s+/g,"")&&(V+="\n\nWhitespace-only changes detected")}}catch(ke){o.warn("Error in direct file comparison: "+(ke instanceof Error?ke.message:ke+""))}}o.info(`Diff generation result for ${F}: hasDiff=${Q}, length=${V.length}`)}}catch(ve){if(o.warn("Error getting diff for "+F,{error:(0,u.getErrorMessage)(ve),firstCommit:H.commitHash||"unknown",lastCommit:B.commitHash||"unknown"}),V="Error getting diff: "+(0,u.getErrorMessage)(ve),"pre-task"!==H.status&&t.git)try{const Ce=[`${B.commitHash}:${F}`]
3771
3792
  o.info(`Trying fallback to show file content using git show: ${B.commitHash?B.commitHash.substring(0,8):"unknown"}:${F}`)
@@ -3774,19 +3795,19 @@ if(_e&&_e.trim().length>0){if(g){let Ee=""
3774
3795
  const Se=_e.split("\n")
3775
3796
  for(const qe of Se)Ee+=`+${qe}\n`
3776
3797
  V=Ee}else V="File created during this task. Content:\n"+_e
3777
- Q=!0,o.info("Fallback succeeded, got file content of length "+_e.length)}}catch(Te){o.warn("Fallback also failed for "+F,{error:Te instanceof Error?Te.message:Te+""})}}E.set(F,{firstChange:W,lastChange:B,hasDiff:Q,diffText:V||"No changes detected between commits"})}else Q=W.commitHash!==B.commitHash,V=Q?"File has changes":"No changes detected between commits",E.set(F,{firstChange:W,lastChange:B,hasDiff:Q,diffText:V})}let S=`# File Changes for Task: ${m}\n\n`
3798
+ Q=!0,o.info("Fallback succeeded, got file content of length "+_e.length)}}catch(Te){o.warn("Fallback also failed for "+F,{error:Te instanceof Error?Te.message:Te+""})}}E.set(F,{firstChange:G,lastChange:B,hasDiff:Q,diffText:V||"No changes detected between commits"})}else Q=G.commitHash!==B.commitHash,V=Q?"File has changes":"No changes detected between commits",E.set(F,{firstChange:G,lastChange:B,hasDiff:Q,diffText:V})}let S=`# File Changes for Task: ${m}\n\n`
3778
3799
  b&&"object"==typeof b&&(S+="## Task Information\n",S+=`- **Title**: ${b.title||"Unknown"}\n`,S+=`- **Status**: ${b.status||"Unknown"}\n`,S+=`- **Description**: ${b.description||"No description"}\n\n`)
3779
3800
  const q=3e3
3780
3801
  let T=0,x=!1
3781
3802
  if(g){for(const xe of E.values())xe.hasDiff&&xe.diffText&&(T+=xe.diffText.split("\n").length)
3782
3803
  x=T>q,o.info(`Total diff size: ${T} lines (limit: ${q} lines)`),o.info(`Diffs ${x?"will be limited":"will be shown"} based on size`)}if(S+="## Summary\n",S+=`- **Files Modified**: ${_.size}\n`,S+=`- **Total File Operations**: ${C.length}\n`,S+="- **What's Shown**: For existing files, comparing state before task started with final state.\n",S+=" For files created during task, showing the entire file as created.\n",x?(S+=`- **Diff Display**: Limited (total diff size of ${T} lines exceeds limit of ${q} lines)\n`,S+=" Use file-history tool with individual files to see detailed changes\n\n"):S+=`- **Diff Display**: ${g?"Enabled":"Disabled"} (use showDiff=${!g} to ${g?"hide":"show"} diffs)\n\n`,v.allMoves.length>0){S+="## Move Operations\n\n",S+=`Detected ${v.allMoves.length} file move operation(s):\n\n`
3783
- for(const Pe of v.allMoves)S+=`- **${Pe.source}** \u2192 **${Pe.destination}**\n`,S+=` - Operation: ${Pe.type}\n`,S+=` - Timestamp: ${new Date(Pe.timestamp).toLocaleString()}\n`,S+=` - Record ID: ${Pe.recordId}\n\n`}S+="## Modified Files\n\n"
3784
- for(const[Re,Me]of E.entries()){const{normalizedPath:$e,fullPath:je}=d.validateAndNormalizePath(Re,t)
3804
+ for(const Re of v.allMoves)S+=`- **${Re.source}** \u2192 **${Re.destination}**\n`,S+=` - Operation: ${Re.type}\n`,S+=` - Timestamp: ${new Date(Re.timestamp).toLocaleString()}\n`,S+=` - Record ID: ${Re.recordId}\n\n`}S+="## Modified Files\n\n"
3805
+ for(const[Pe,Me]of E.entries()){const{normalizedPath:$e,fullPath:je}=d.validateAndNormalizePath(Pe,t)
3785
3806
  let Oe=!1
3786
- try{await a.access(je),Oe=!0}catch{}S+=`### ${Re} ${Oe?"":"(Deleted)"}\n\n`
3807
+ try{await a.access(je),Oe=!0}catch{}S+=`### ${Pe} ${Oe?"":"(Deleted)"}\n\n`
3787
3808
  const De=new Date(Me.firstChange.timestamp).toLocaleString(),Ae=new Date(Me.lastChange.timestamp).toLocaleString()
3788
3809
  S+=`**First Change**: ${De}\n`,S+=`**Last Change**: ${Ae}\n`,"pre-task"===Me.firstChange.status&&Me.firstChange.commitHash?S+=`**Pre-Task Commit**: ${Me.firstChange.commitHash.substring(0,8)}\n`:Me.firstChange.commitHash&&(S+=`**File Created During Task**: ${Me.firstChange.commitHash.substring(0,8)}\n`),Me.lastChange.commitHash&&(S+=`**Final Commit**: ${Me.lastChange.commitHash.substring(0,8)}\n`)
3789
- const Fe=v.sourceToMove.get(Re),Ne=v.destToMove.get(Re)
3810
+ const Fe=v.sourceToMove.get(Pe),Ne=v.destToMove.get(Pe)
3790
3811
  Fe?S+=`**\u2139\ufe0f Move Operation**: This file was moved TO **${Fe.destination}**\n`:Ne&&(S+=`**\u2139\ufe0f Move Operation**: This file was moved FROM **${Ne.source}**\n`),g&&!x?Me.hasDiff?(S+="\n**Changes**:\n",S+="```diff\n",S+=Me.diffText,S+="\n```\n\n"):S+=`\n**Note**: ${Me.diffText}\n\n`:x&&Me.hasDiff?(S+=`\n**Note**: File has changes (${Me.diffText?Me.diffText.split("\n").length:0} lines). `,S+=`Compare ${Me.firstChange.commitHash?Me.firstChange.commitHash.substring(0,8):"unknown"}..${Me.lastChange.commitHash?Me.lastChange.commitHash.substring(0,8):"unknown"} to see changes.\n\n`):Me.hasDiff?S+="\n**Note**: File has changes. Use showDiff=true to see the diff.\n\n":S+=`\n**Note**: ${Me.diffText}\n\n`,S+="---\n\n"}return p({success:!0,fileCount:_.size}),{content:[{type:"text",text:S}]}}catch(ze){return o.error("Error in task file history tool",{error:ze instanceof Error?ze.stack:ze+""}),p({success:!1,error:ze instanceof Error?ze.name:"unknown"}),{content:[{type:"text",text:"Error: "+(0,u.getErrorMessage)(ze)}],isError:!0}}}
3791
3812
  const i=t(9860),a=o(t(1943)),c=t(9671),l=t(2960),d=o(t(5967)),u=t(8824),h=t(4466)},6928(module){"use strict"
3792
3813
  module.exports=require("path")},6975(e,exports,t){"use strict"
@@ -4143,7 +4164,9 @@ let r=`\n\n\u26a0\ufe0f **Performance Warning**: Large untracked files detected
4143
4164
  for(const t of e.slice(0,5))r+=`- \`${t.path}\` (${t.sizeMB} MB)\n`
4144
4165
  return e.length>5&&(r+=`- ... and ${e.length-5} more large files\n`),r+="\nConsider adding these to `.gitignore` or moving them outside the repository.",r}
4145
4166
  const h=t(3444),p=t(9860),m=t(3922),g=t(8824),f=u(t(9896)),y=u(t(6928))
4146
- t(857)},7575(e,exports){"use strict"
4167
+ t(857)},7499(e,exports){"use strict"
4168
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.TEST_MAX_ROUNDS=void 0,exports.decideTestRoundCap=function(e,t,r=exports.TEST_MAX_ROUNDS){const n=e.filter((e=>e.id!==t&&("failed"===e.status||"error"===e.status))).length+1
4169
+ return{escalate:n>=r,failedRounds:n}},exports.TEST_MAX_ROUNDS=3},7575(e,exports){"use strict"
4147
4170
  var t
4148
4171
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.FileOperationPhase=void 0,function(e){e.VALIDATION="validation",e.TASK_VALIDATION="task_validation",e.RECORD_CREATION="record_creation",e.FILE_WRITE="file_write",e.STRING_REPLACEMENT="string_replacement",e.GIT_COMMIT="git_commit",e.RECORD_UPDATE_SUCCESS="record_update_success",e.RECORD_UPDATE_FAILURE="record_update_failure"}(t||(exports.FileOperationPhase=t={}))},7609(e,exports,t){"use strict"
4149
4172
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.handleUpdatePlan=async function(e,t,s,o){const i=o.child({tool:"plan_operations",operation:"update"})
@@ -4344,7 +4367,26 @@ return!1}async cleanup(){this.logger.info("Cleaning up multi-agent workspace man
4344
4367
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.ConnectionAwareClient=void 0
4345
4368
  const r=t(4192),n=t(7163)
4346
4369
  class s extends r.BaseApiClient{constructor(e,t,r,s,o,i){t.debug("ConnectionAwareClient constructor parameters:",{hasAuthToken:!!s,hasOptions:!!o,optionsType:o?typeof o:"undefined",options:o?JSON.stringify(o):"undefined",hasConnectionManager:!!i}),super(e,t,r,s,o),this.isGettingAuthToken=!1,this.connectionStatusManager=i||{isInOfflineMode(){return!1},isOffline(){return!1},setOfflineMode(){},async checkConnectivity(){return!0},getHealthCheckStats(){return{isOffline:!1,consecutiveFailures:0,currentBackoffMs:0,lastCheckTime:0}},cleanup(){}},s&&this.logger.debug("Client initialized with auth token",{clientType:this.constructor.name,tokenPrefix:s.substring(0,10)+"..."})
4347
- try{(0,n.debugTokenAccess)(this,"ConnectionAwareClient constructor")}catch(e){this.logger.debug("Error accessing token details during init",{error:e instanceof Error?e.message:e+""})}}setConnectionStatusManager(e){this.logger.debug("Setting connection status manager in ConnectionAwareClient"),this.connectionStatusManager=e}}exports.ConnectionAwareClient=s},7660(e,exports,t){"use strict"
4370
+ try{(0,n.debugTokenAccess)(this,"ConnectionAwareClient constructor")}catch(e){this.logger.debug("Error accessing token details during init",{error:e instanceof Error?e.message:e+""})}}setConnectionStatusManager(e){this.logger.debug("Setting connection status manager in ConnectionAwareClient"),this.connectionStatusManager=e}}exports.ConnectionAwareClient=s},7648(e,exports,t){"use strict"
4371
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.handleRecordCriteriaVerification=async function(e,t,i,a,c){const l=a.child({tool:"record_criteria_verification"}),d=c.startTimer("tool_execution_time")
4372
+ try{const{requestId:a,verifications:c}=e
4373
+ if(!a)throw(0,r.createValidationError)("requestId is required")
4374
+ if(!Array.isArray(c)||0===c.length)throw(0,r.createValidationError)("verifications array is required and must be non-empty")
4375
+ const u=i.getRequestClient()
4376
+ let h
4377
+ try{h=await u.getRequest(a)}catch(e){throw(0,r.createValidationError)(`Failed to fetch request ${a}: ${(0,n.getErrorMessage)(e)}`)}const p=h?.acceptanceCriteria||[]
4378
+ if(0===p.length)return d({success:!1,reason:"no_criteria"}),{content:[{type:"text",text:`Request ${a} has no acceptance criteria to record.`}],isError:!0}
4379
+ const m=(0,o.buildCriteriaKeyMap)(p),g=new Set(m.keys()),f=c.filter((e=>!g.has(e.key))).map((e=>e.key))
4380
+ if(f.length>0)return d({success:!1,reason:"unknown_keys"}),{content:[{type:"text",text:`Unknown criterion key(s): ${f.join(", ")}\n\nValid criteria:\n${(0,o.formatCriteriaWithKeys)(p)}`}],isError:!0}
4381
+ const y=c.map((e=>({criterionId:m.get(e.key).id,evidence:e.evidence,status:"unmet"===e.status?"unmet":"met"})))
4382
+ let w,b=null
4383
+ try{const e=await fetch(`${(0,s.getActionServerBaseUrl)()}/api/branch-head?requestId=${encodeURIComponent(a)}`,{signal:AbortSignal.timeout(5e3)})
4384
+ e.ok&&(b=(await e.json())?.data?.sha??null)}catch(e){l.debug("branch-head fetch failed; verdicts recorded without sha",{error:(0,n.getErrorMessage)(e)})}try{const e=await i.proxyPost(`/api/projects/${t.projectId}/requests/${a}/verify-criteria`,{verifications:y,dimension:"review",headSha:b})
4385
+ w=e?.data||e}catch(e){return d({success:!1,error:"record_failed"}),{content:[{type:"text",text:"Failed to record criteria verification: "+(0,n.getErrorMessage)(e)}],isError:!0}}l.info("Recorded criteria verification",{requestId:a,verified:w.verified,remaining:w.remainingUnverified})
4386
+ const I=y.filter((e=>"met"===e.status)).length,k=y.length-I
4387
+ return d({success:!0}),{content:[{type:"text",text:`Recorded verdicts for ${y.length} criterion/criteria on ${a} (${I} met, ${k} unmet). ${w.remainingUnverified} remain unmet overall; the server opens a rework task for the coder when any are unmet. This does NOT merge; the coder finalizes after review.`}]}}catch(e){const t=(0,n.getErrorMessage)(e)
4388
+ return l.error("record_criteria_verification failed",{error:t}),d({success:!1,error:"unexpected"}),{content:[{type:"text",text:"Error: "+t}],isError:!0}}}
4389
+ const r=t(9860),n=t(8824),s=t(9414),o=t(5454)},7660(e,exports,t){"use strict"
4348
4390
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.projectContextMiddleware=exports.ProjectContext=exports.ProjectIDFactory=exports.ProjectID=void 0
4349
4391
  const r=t(4055)
4350
4392
  Object.defineProperty(exports,"ProjectID",{enumerable:!0,get(){return r.ProjectID}}),Object.defineProperty(exports,"ProjectIDFactory",{enumerable:!0,get(){return r.ProjectIDFactory}})
@@ -4372,10 +4414,10 @@ const e=await(0,i.handleDeleteFiles)({taskId:k,operations:_,comment:w+" [via man
4372
4414
  S.push({type:"delete-files",result:e})}for(const e of E){f.info("Routing to get-file-info handler",{path:e.path})
4373
4415
  const t=await(0,s.handleGetFileInfo)({path:e.path},c,f,m)
4374
4416
  S.push({type:"get-file-info",result:t})}const q=S.some((e=>e.result.isError)),T=S.filter((e=>!e.result.isError)).length,x=S.filter((e=>e.result.isError)).length
4375
- let P="## Manage Files Results\n\n"
4376
- P+="**Summary:**\n",P+=`- **Total operation types:** ${S.length}\n`,P+=`- **Successful:** ${T}\n`,P+=`- **Failed:** ${x}\n\n`
4377
- for(const{type:e,result:t}of S)P+=`### ${e} operations\n`,P+=t.content[0].text+"\n\n"
4378
- return f.info("Manage-files operations completed",{totalOperationTypes:S.length,successCount:T,errorCount:x}),m.incrementCounter("manage_files_total",1,{success:!q}),{content:[{type:"text",text:P}],...(0,o.alchemyMeta)({kind:"manage-files"}),isError:q}}catch(e){return f.error("Manage-files operation failed",{error:e instanceof Error?e.stack:e+""}),m.incrementCounter("manage_files_errors",1),{content:[{type:"text",text:"\u274c **Manage Files Failed:** "+(0,a.getErrorMessage)(e)}],isError:!0}}}
4417
+ let R="## Manage Files Results\n\n"
4418
+ R+="**Summary:**\n",R+=`- **Total operation types:** ${S.length}\n`,R+=`- **Successful:** ${T}\n`,R+=`- **Failed:** ${x}\n\n`
4419
+ for(const{type:e,result:t}of S)R+=`### ${e} operations\n`,R+=t.content[0].text+"\n\n"
4420
+ return f.info("Manage-files operations completed",{totalOperationTypes:S.length,successCount:T,errorCount:x}),m.incrementCounter("manage_files_total",1,{success:!q}),{content:[{type:"text",text:R}],...(0,o.alchemyMeta)({kind:"manage-files"}),isError:q}}catch(e){return f.error("Manage-files operation failed",{error:e instanceof Error?e.stack:e+""}),m.incrementCounter("manage_files_errors",1),{content:[{type:"text",text:"\u274c **Manage Files Failed:** "+(0,a.getErrorMessage)(e)}],isError:!0}}}
4379
4421
  const r=t(8309),n=t(2414),s=t(3628),o=t(2272),i=t(5992),a=t(8824)},7713(e,exports,t){"use strict"
4380
4422
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.def=void 0
4381
4423
  const r=t(6183),n=t(5303)
@@ -4543,21 +4585,21 @@ const{normalizedPath:_,fullPath:E}=l.validateAndNormalizePath(u,r)
4543
4585
  b=l.FileOperationPhase.TASK_VALIDATION,p.incrementCounter("create_directory_phase",1,{phase:b})
4544
4586
  const S=await l.validateTaskId(C,_,n,g,p,I.metricsPrefix),q=S?.requestId,T=await l.validateWorkItemStates(C,_,n,o,r,g,p,I.metricsPrefix),x=await l.autoPromoteTaskStatus(C,S.status,q,T.request?.status,_,n,o,g,p,I.metricsPrefix)
4545
4587
  x.taskPromoted&&g.info(`Auto-promoted task ${C} (${S.title||"Untitled"}) to in_progress for file operation`,{taskId:C,taskTitle:S.title,previousStatus:S.status,newStatus:x.newTaskStatus,path:_}),x.requestPromoted&&g.info(`Auto-promoted request ${q} to in_progress for file operation`,{requestId:q,previousStatus:T.request?.status,newStatus:x.newRequestStatus,triggeringTaskId:C})
4546
- const P=await l.ensureCorrectWorkspaceContext({taskPromoted:x.taskPromoted,requestId:q,context:r,operation:"create-directory",logger:g,metrics:p,metricsPrefix:I.metricsPrefix})
4547
- if(!P.success)throw Error(P.error)
4548
- let R=!1
4549
- try{R=(await a.default.stat(E)).isDirectory()}catch{R=!1}b=l.FileOperationPhase.RECORD_CREATION,p.incrementCounter("create_directory_phase",1,{phase:b})
4550
- const{toolRecordId:M,localToolRecordId:$}=await l.createFileOperationRecords(C,q,r.projectId,I.recordType,_,{directoryExists:R,userComment:h},n,s,g,p,I.metricsPrefix,m)
4588
+ const R=await l.ensureCorrectWorkspaceContext({taskPromoted:x.taskPromoted,requestId:q,context:r,operation:"create-directory",logger:g,metrics:p,metricsPrefix:I.metricsPrefix})
4589
+ if(!R.success)throw Error(R.error)
4590
+ let P=!1
4591
+ try{P=(await a.default.stat(E)).isDirectory()}catch{P=!1}b=l.FileOperationPhase.RECORD_CREATION,p.incrementCounter("create_directory_phase",1,{phase:b})
4592
+ const{toolRecordId:M,localToolRecordId:$}=await l.createFileOperationRecords(C,q,r.projectId,I.recordType,_,{directoryExists:P,userComment:h},n,s,g,p,I.metricsPrefix,m)
4551
4593
  y=M,w=M,b=I.fileOperationPhase,p.incrementCounter("create_directory_phase",1,{phase:b})
4552
- let j=R
4553
- if(!R){await a.default.mkdir(E,{recursive:!0}),g.info("Successfully created directory "+_)
4594
+ let j=P
4595
+ if(!P){await a.default.mkdir(E,{recursive:!0}),g.info("Successfully created directory "+_)
4554
4596
  try{const e=c.default.join(E,".gitkeep")
4555
4597
  await a.default.writeFile(e,"# This file makes the directory trackable by Git\n"),j=!0,g.info("Created .gitkeep file for Git tracking")}catch(e){g.warn("Failed to create .gitkeep file",{error:e instanceof Error?e.message:e+""}),j=!1}}const O=Date.now()-f
4556
4598
  p.recordValue("create_directory_time",O),p.incrementCounter("create_directory_success",1),b=l.FileOperationPhase.GIT_COMMIT,p.incrementCounter("create_directory_phase",1,{phase:b})
4557
- const D=`Create directory: ${_} - ${h||"Create directory"}`,A=!R&&j?_+"/.gitkeep":_,F=await l.commitToGit(C,A,M,$,D,r,g,p,I.metricsPrefix)
4558
- b=l.FileOperationPhase.RECORD_UPDATE_SUCCESS,p.incrementCounter("create_directory_phase",1,{phase:b}),await l.updateFileOperationRecords(C,y,w,_,I.recordType,`Successfully ${R?"verified":"created"} directory: ${_}`,{status:"completed",commitHash:F.commitHash,previousCommitHash:F.previousCommitHash,directoryExists:R,isDirectory:!0,userComment:h},`Successfully ${R?"verified":"created"} directory: ${_}`,n,s,g,p,I.metricsPrefix)
4599
+ const D=`Create directory: ${_} - ${h||"Create directory"}`,A=!P&&j?_+"/.gitkeep":_,F=await l.commitToGit(C,A,M,$,D,r,g,p,I.metricsPrefix)
4600
+ b=l.FileOperationPhase.RECORD_UPDATE_SUCCESS,p.incrementCounter("create_directory_phase",1,{phase:b}),await l.updateFileOperationRecords(C,y,w,_,I.recordType,`Successfully ${P?"verified":"created"} directory: ${_}`,{status:"completed",commitHash:F.commitHash,previousCommitHash:F.previousCommitHash,directoryExists:P,isDirectory:!0,userComment:h},`Successfully ${P?"verified":"created"} directory: ${_}`,n,s,g,p,I.metricsPrefix)
4559
4601
  const N=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
4560
- return{content:[{type:"text",text:R?"Directory already exists":`Successfully created directory${F.commitHash?"\nCommit: "+F.commitHash.substring(0,8):""}${N.requestId&&!N.permanentBranch?"\nBranch: "+N.requestId:""}`}]}}catch(t){if(e.taskId&&s)try{const n=t instanceof d.NotFoundError||t instanceof d.ValidationError||t instanceof u.ZodError
4602
+ return{content:[{type:"text",text:P?"Directory already exists":`Successfully created directory${F.commitHash?"\nCommit: "+F.commitHash.substring(0,8):""}${N.requestId&&!N.permanentBranch?"\nBranch: "+N.requestId:""}`}]}}catch(t){if(e.taskId&&s)try{const n=t instanceof d.NotFoundError||t instanceof d.ValidationError||t instanceof u.ZodError
4561
4603
  await s.createToolRecord({...n?{}:{taskId:e.taskId},projectId:r.projectId,type:"create-directory",metadata:{status:"failed",timestamp:(new Date).toISOString(),path:e.path,userComment:e.comment,error:(0,h.getErrorMessage)(t),errorDetails:t instanceof Error?t.stack:t+"",phase:b,attemptedTaskId:e.taskId,taskIdValidationFailed:n},note:`Failed to create directory ${e.path} - ${(0,h.getErrorMessage)(t)}`})}catch(t){g.error("Failed to create failure record for create directory operation",{error:t instanceof Error?t.message:t+"",taskId:e.taskId,path:e.path})}const o=Date.now()-f
4562
4604
  if(p.recordValue("create_directory_time",o),p.incrementCounter("create_directory_errors",1),g.error("Error creating directory:",{error:(0,h.getErrorMessage)(t),time:o}),(y||w)&&e.taskId){b=l.FileOperationPhase.RECORD_UPDATE_FAILURE
4563
4605
  try{await l.updateFileOperationRecords(e.taskId,y,w,e.path,I.recordType,"Failed to create directory "+e.path,{status:"failed",error:(0,h.getErrorMessage)(t),userComment:e.comment},"Failed to create directory "+e.path,n,s,g,p,I.metricsPrefix)}catch(t){g.error("Failed to update record with failure status",{taskId:e.taskId,recordId:y,error:t instanceof Error?t.message:t+""})}}return l.handleFileOperationError(t,b,g,p,e,I)}}
@@ -5168,8 +5210,8 @@ Object.defineProperty(exports,"__esModule",{value:!0}),exports.handleReplaceInFi
5168
5210
  let C,_=u.FileOperationPhase.VALIDATION
5169
5211
  try{const E=e,{enforceActiveTask:S}=await Promise.resolve().then(t.bind(t,3451)),q=await S(r,s,a,e.taskId)
5170
5212
  if("errorResult"in q)return q.errorResult
5171
- const{taskId:T}=q,{operations:x,fuzzy_match:P=!0,comment:R}=E
5172
- k.info("Replace in files batch operation",{taskId:T,operationCount:x.length,totalReplacements:x.reduce(((e,t)=>e+t.replacements.length),0),globalFuzzyMatch:P,comment:R})
5213
+ const{taskId:T}=q,{operations:x,fuzzy_match:R=!0,comment:P}=E
5214
+ k.info("Replace in files batch operation",{taskId:T,operationCount:x.length,totalReplacements:x.reduce(((e,t)=>e+t.replacements.length),0),globalFuzzyMatch:R,comment:P})
5173
5215
  const M=x.filter((e=>e.documentId)).map((e=>e.documentId))
5174
5216
  if(M.length>0&&r.apiClient)try{await(0,f.ensureDocumentsNotLocked)(M,r.apiClient,k,c,"replace_in_files-documents")}catch(e){if(e instanceof p.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
5175
5217
  throw e}_=u.FileOperationPhase.TASK_VALIDATION,c.incrementCounter("replace_in_files_phase",1,{phase:_})
@@ -5189,7 +5231,7 @@ if(!n.success)throw Error(n.error)
5189
5231
  Date.now(),N=!0}if(M.length>0&&A)try{await(0,m.validateRequestStatusForDocumentOperation)(A,i,k,c,"replace_in_files-documents")}catch(e){if(e instanceof p.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
5190
5232
  throw e}O=Date.now()
5191
5233
  const z=new Map
5192
- if(k.info("\u{1f50d} Starting external edit detection",{hasFileOperations:F,hasGit:!!r.git,operationCount:x.length}),F&&r.git)for(const e of x)if(e.path&&!e.documentId)try{const t=u.validateAndNormalizePath(e.path,r),n=await l.default.readFile(t.fullPath,"utf8"),s=void 0!==e.fuzzy_match?e.fuzzy_match:P,o=[]
5234
+ if(k.info("\u{1f50d} Starting external edit detection",{hasFileOperations:F,hasGit:!!r.git,operationCount:x.length}),F&&r.git)for(const e of x)if(e.path&&!e.documentId)try{const t=u.validateAndNormalizePath(e.path,r),n=await l.default.readFile(t.fullPath,"utf8"),s=void 0!==e.fuzzy_match?e.fuzzy_match:R,o=[]
5193
5235
  for(const t of e.replacements){const r=(0,h.findMatches)(n,t.old,s,100,e.path)
5194
5236
  o.push(...r)}if(o.length>0){const s=(0,y.calculateReplacementRegion)(n,o,t.fullPath)
5195
5237
  k.info("\u{1f50d} Checking for external edits",{path:t.normalizedPath,affectedLines:s.lineRanges.map((e=>`${e.start}-${e.end}`)).join(", "),matchCount:o.length})
@@ -5197,15 +5239,15 @@ const i=await(0,w.detectExternalEdits)(r.git,s,k)
5197
5239
  k.info("\u{1f50d} External edit detection result",{path:t.normalizedPath,hasExternalEdits:i.hasExternalEdits,conflictingLines:i.conflictingLines,hasMessage:!!i.message}),i.hasExternalEdits&&i.message?(z.set(e.path,{message:i.message,debugInfo:i.debugInfo}),k.warn("\u26a0\ufe0f External edits detected before auto-commit",{path:t.normalizedPath,conflictingLines:i.conflictingLines})):(i.debugInfo&&z.set(e.path,{message:"",debugInfo:i.debugInfo}),k.info("\u2705 No external edit conflicts detected",{path:t.normalizedPath}))}else k.info("\u2139\ufe0f No matches found for external edit detection",{path:t.normalizedPath}),z.set(e.path,{message:"",debugInfo:{detectionRan:!1,reason:"No matches found - patterns not found in file",affectedRegion:"none",uncommittedChanges:"not checked",overlapDetected:!1}})}catch(t){k.warn("Failed to check for external edits before auto-commit",{path:e.path,error:(0,b.getErrorMessage)(t)})}if(Date.now(),O=Date.now(),F&&r.git)try{k.debug("[REPLACE-IN-FILES] Checking for user changes before batch operation")
5198
5240
  const e=await(0,g.commitUserChangesBeforeToolOperation)(r.git,"replace_in_files",{requestId:A,taskId:T,workspaceManager:r.workspaceManager},k,c)
5199
5241
  e.userChangesCommitted&&(k.debug("[REPLACE-IN-FILES] User changes committed",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),k.info("User changes committed before batch operation",{taskId:T,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){k.warn("Pre-tool user changes commit failed",{taskId:T,error:e instanceof Error?e.message:e+""})}Date.now(),O=Date.now(),_=u.FileOperationPhase.RECORD_CREATION,c.incrementCounter("replace_in_files_phase",1,{phase:_})
5200
- const{toolRecordId:L}=await u.createFileOperationRecords(T,A,r.projectId,"replace-in-files",j,{operationCount:x.length,totalReplacements:x.reduce(((e,t)=>e+t.replacements.length),0),globalFuzzyMatch:P,userComment:R},s,o,k,c,"replace_in_files",I)
5242
+ const{toolRecordId:L}=await u.createFileOperationRecords(T,A,r.projectId,"replace-in-files",j,{operationCount:x.length,totalReplacements:x.reduce(((e,t)=>e+t.replacements.length),0),globalFuzzyMatch:R,userComment:P},s,o,k,c,"replace_in_files",I)
5201
5243
  C=L,Date.now(),O=Date.now(),_=u.FileOperationPhase.STRING_REPLACEMENT,c.incrementCounter("replace_in_files_phase",1,{phase:_})
5202
5244
  const H=[],B=[]
5203
- for(const e of x){const t=e.path?z.get(e.path):void 0,s=await n(e,P,r,0,0,t?.message,t?.debugInfo)
5245
+ for(const e of x){const t=e.path?z.get(e.path):void 0,s=await n(e,R,r,0,0,t?.message,t?.debugInfo)
5204
5246
  H.push(s),s.successfulReplacements>0&&"file"===s.type&&s.path&&B.push(s.path)}Date.now(),O=Date.now()
5205
- const U=x.filter((e=>e.path&&!e.documentId)).map((e=>({path:e.path}))),G=await u.handleMultiFileGitCommit(T,U,H,B.length,{operationType:"Replace in files",toolRecordId:L||C||"unknown",successField:"successfulReplacements",logger:k,metrics:c,metricsPrefix:"replace_in_files"},r),W=G.commitHash
5247
+ const U=x.filter((e=>e.path&&!e.documentId)).map((e=>({path:e.path}))),W=await u.handleMultiFileGitCommit(T,U,H,B.length,{operationType:"Replace in files",toolRecordId:L||C||"unknown",successField:"successfulReplacements",logger:k,metrics:c,metricsPrefix:"replace_in_files"},r),G=W.commitHash
5206
5248
  Date.now(),Date.now()
5207
5249
  const V=H.filter((e=>e.success)).length,Q=H.length-V,K=H.reduce(((e,t)=>e+t.successfulReplacements),0),J=H.reduce(((e,t)=>e+t.failedReplacements),0),Y=H.map((e=>({type:e.type,path:e.path,documentId:e.documentId,filename:e.filename,replacements:e.replacements.map((e=>({old_str:e.old,new_str:e.new,success:e.success,error:e.error,matchesFound:e.matchesFound,matchType:e.matchType,lines:e.lines})))}))),Z=H.filter((e=>e.success)).map((e=>({path:e.path,documentId:e.documentId,filename:e.filename,successfulReplacements:e.successfulReplacements,failedReplacements:e.failedReplacements}))),X=H.filter((e=>!e.success)).map((e=>({path:e.path,documentId:e.documentId,filename:e.filename,error:e.error,successfulReplacements:e.successfulReplacements,failedReplacements:e.failedReplacements})))
5208
- await o.updateToolRecord(C,{metadata:{path:j,status:0===Q?"completed":"partial",operationCount:x.length,operations:Y,successfulFiles:Z,failedFiles:X,successfulReplacements:K,failedReplacements:J,processingTime:Date.now()-v,userComment:R,...G.success&&G.commitHash&&{commitHash:G.commitHash,previousCommitHash:G.previousCommitHash||void 0}}})
5250
+ await o.updateToolRecord(C,{metadata:{path:j,status:0===Q?"completed":"partial",operationCount:x.length,operations:Y,successfulFiles:Z,failedFiles:X,successfulReplacements:K,failedReplacements:J,processingTime:Date.now()-v,userComment:P,...W.success&&W.commitHash&&{commitHash:W.commitHash,previousCommitHash:W.previousCommitHash||void 0}}})
5209
5251
  const ee=await async function(e,t,r,n,s){const o=e.filter((e=>e.success)).length,i=e.length-o,a=e.filter((e=>!e.success&&!e.error&&e.successfulReplacements>0)).length
5210
5252
  let c="## Replace In Files - Batch Results\n\n"
5211
5253
  if(s.workspaceManager)try{const e=s.workspaceManager.getCurrentContext(s.currentSessionId)
@@ -5219,7 +5261,7 @@ if(o.length>0){c+="\n**Failed Replacement Details:**\n"
5219
5261
  for(const e of o)c+=`- \u274c \`${e.old.substring(0,40)}${e.old.length>40?"...":""}\` \u2192 \`${e.new.substring(0,40)}${e.new.length>40?"...":""}\`: ${e.error}\n`,e.details&&e.details.length>0&&(c+=" **Candidates found:**\n",c+=e.details.slice(0,5).map((e=>` - Line ${e.line}: \`${e.actually_matched.substring(0,40)}${e.actually_matched.length>40?"...":""}\` (${e.match_type})`)).join("\n")+"\n",e.details.length>5&&(c+=` ... and ${e.details.length-5} more matches\n`)),e.similarMatches&&e.similarMatches.length>0&&(c+=" **Did you mean? (Similar matches found):**\n",c+=e.similarMatches.map((e=>` - Line ${e.line}: \`${e.text.substring(0,60)}${e.text.length>60?"...":""}\` (${e.reason}, similarity: ${(100*e.similarity).toFixed(0)}%)`)).join("\n")+"\n")}c+="\n"}const l=e.filter((e=>"document"===e.type&&(e.success||e.successfulReplacements>0)))
5220
5262
  l.length>0&&(c+=`\n**Document Changes:** ${l.length} modified document(s) synced back to tracking system.\n`)
5221
5263
  const d=s.workspaceManager?.consumeLargeFileWarning(s.currentSessionId)
5222
- return d&&(c+=d),c}(H,W,K,J,r)
5264
+ return d&&(c+=d),c}(H,G,K,J,r)
5223
5265
  return{content:[{type:"text",text:ee}],isError:0===K,...(0,d.alchemyMeta)({kind:"replace-in-files",toolRecordId:C,failed:J>0})}}catch(e){const t=Date.now()-v
5224
5266
  if(k.error("Replace in files batch operation failed",{error:e instanceof Error?e.stack:e+"",duration:t,phase:_}),C)try{await o.updateToolRecord(C,{metadata:{status:"failed",error:(0,b.getErrorMessage)(e),phase:_,duration:t}})}catch(e){}return c.incrementCounter("replace_in_files_errors",1,{phase:_}),{content:[{type:"text",text:"\u274c **Replace In Files Failed:** "+(0,b.getErrorMessage)(e)}],isError:!0}}},c(t(857))
5225
5267
  const l=c(t(1943)),d=(a(t(9896)),a(t(6928)),c(t(6982)),t(2272)),u=a(t(5967)),h=t(3626),p=t(9860),m=t(5003),g=t(7478),f=t(9949),y=t(9947),w=t(1318),b=t(8824)},9470(e,exports){"use strict"