alchemylab 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -96,9 +96,9 @@ if(this.TOKEN_CACHE.hasValidToken&&e<this.TOKEN_CACHE.hasValidToken.expiresAt){c
96
96
  return this.logger.debug("Using cached hasValidToken result",{ageSecs:Math.round((e-t.timestamp)/1e3),hasToken:t.value}),t.value}this.logger.debug("Checking if valid token exists (cache miss or expired)")
97
97
  const t=null!==await this.getToken()
98
98
  return this.TOKEN_CACHE.hasValidToken={value:t,timestamp:e,expiresAt:e+this.CACHE_TTL_MS,lastCheck:e,exists:t},t}getTokenDirectoryPath(){return this.tokenDirPath}getManualTokenFilePath(){return r.default.join(this.tokenDirPath,"manual-token.json")}logTokenLocationInstructions(){const e=this.getManualTokenFilePath()
99
- console.log("========================================"),console.log("To use MCP server, you need to authenticate."),console.log("Token file location: "+e),console.log("You can either:"),console.log('\n1. Use the authenticate tool (recommended)\n2. Manually place a token file at the above location\n3. Set up automatic authentication flow\n\nFor manual token placement, create a JSON file with:\n{\n "token": "your_token_here",\n "userId": "your_user_id",\n "username": "your_username", \n "role": "user",\n "expiresAt": "2025-12-31T23:59:59.000Z"\n}\n'),console.log("For more information, see the authentication documentation."),console.log("========================================")}async startAuthenticationFlow(){this.pendingAuthCheck=!0
99
+ console.log("========================================"),console.log("To use the alchemy CLI, you need to authenticate."),console.log("Token file location: "+e),console.log("You can either:"),console.log('\n1. Use the authenticate tool (recommended)\n2. Manually place a token file at the above location\n3. Set up automatic authentication flow\n\nFor manual token placement, create a JSON file with:\n{\n "token": "your_token_here",\n "userId": "your_user_id",\n "username": "your_username", \n "role": "user",\n "expiresAt": "2025-12-31T23:59:59.000Z"\n}\n'),console.log("For more information, see the authentication documentation."),console.log("========================================")}async startAuthenticationFlow(){this.pendingAuthCheck=!0
100
100
  try{const{tempCode:e,authUrl:t}=await this.authFlow.startAuthFlow()
101
- return this.tempAuthCode=e,this.logger.info("Started external authentication flow",{tempCode:e,authUrl:t}),this.authFlow.startPolling(e,(async t=>{this.logger.info("Authentication flow completed",{tempCode:e.substring(0,4)+"***",username:t.username}),await this.storeToken(t),this.pendingAuthCheck=!1,this.tempAuthCode=null,this.invalidateCache(),console.log("Authentication successful!"),console.log(`Welcome, ${t.username}!`),console.log("You can now use all MCP tools and features."),console.log("========================================")}),(()=>{this.logger.info("Authentication flow timed out",{tempCode:e.substring(0,4)+"***"}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow timed out."),console.log("Please try again or manually place a token file."),console.log("Token file location:"),console.log(""+this.getManualTokenFilePath()),console.log("========================================")}),(t=>{this.logger.error("Authentication flow error",{tempCode:e.substring(0,4)+"***",error:t}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow error."),console.log("Error: "+t),console.log("Please try again or manually place a token file."),console.log(""+this.getManualTokenFilePath()),console.log("========================================")})),{tempCode:e,authUrl:t}}catch(e){throw this.logger.error("Error starting authentication flow",{error:(0,c.getErrorMessage)(e)}),this.pendingAuthCheck=!1,this.tempAuthCode=null,e}}hasPendingAuth(){return this.pendingAuthCheck||!!this.tempAuthCode}getAuthStatus(){return this.hasPendingAuth()?{hasToken:!1,isPendingAuth:!0,tempCode:this.tempAuthCode,authUrl:this.authFlow.getAuthUrl(this.tempAuthCode)}:{hasToken:!1,isPendingAuth:!1}}async checkAuthStatus(e){if(!e)return null
101
+ return this.tempAuthCode=e,this.logger.info("Started external authentication flow",{tempCode:e,authUrl:t}),this.authFlow.startPolling(e,(async t=>{this.logger.info("Authentication flow completed",{tempCode:e.substring(0,4)+"***",username:t.username}),await this.storeToken(t),this.pendingAuthCheck=!1,this.tempAuthCode=null,this.invalidateCache(),console.log("Authentication successful!"),console.log(`Welcome, ${t.username}!`),console.log("You can now use the alchemy CLI."),console.log("========================================")}),(()=>{this.logger.info("Authentication flow timed out",{tempCode:e.substring(0,4)+"***"}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow timed out."),console.log("Please try again or manually place a token file."),console.log("Token file location:"),console.log(""+this.getManualTokenFilePath()),console.log("========================================")}),(t=>{this.logger.error("Authentication flow error",{tempCode:e.substring(0,4)+"***",error:t}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow error."),console.log("Error: "+t),console.log("Please try again or manually place a token file."),console.log(""+this.getManualTokenFilePath()),console.log("========================================")})),{tempCode:e,authUrl:t}}catch(e){throw this.logger.error("Error starting authentication flow",{error:(0,c.getErrorMessage)(e)}),this.pendingAuthCheck=!1,this.tempAuthCode=null,e}}hasPendingAuth(){return this.pendingAuthCheck||!!this.tempAuthCode}getAuthStatus(){return this.hasPendingAuth()?{hasToken:!1,isPendingAuth:!0,tempCode:this.tempAuthCode,authUrl:this.authFlow.getAuthUrl(this.tempAuthCode)}:{hasToken:!1,isPendingAuth:!1}}async checkAuthStatus(e){if(!e)return null
102
102
  try{const t=this.authFlow.getPollingStatus()
103
103
  if(t.status===a.PollingStatus.AUTHENTICATED&&t.tokenInfo)return this.logger.info("Authentication polling has token available",{tempCode:e.substring(0,4)+"***",username:t.tokenInfo.username}),t.tokenInfo
104
104
  if(t.status===a.PollingStatus.ERROR||t.status===a.PollingStatus.TIMEOUT)return this.pendingAuthCheck=!1,this.tempAuthCode=null,null
@@ -177,7 +177,7 @@ const r=s(t(7252)),o=s(t(8577)),n=t(4192),i=t(1152),a=s(t(6928)),c=s(t(9896)),l=
177
177
  class I{updateAuthToken(e){this.options.authToken=e,this.apiClient.authToken=e,this.configurer.authToken=e}constructor(e,t){this.directReportDedup=new Map,this.activeMcpCalls=new Map,this.pendingAgentResync=!1,this.settingsSyncCounter=0,this.versionWarnings=[],this.updateBlocked=!1,this._pendingUpdateBlock=!1,this.isPolling=!1,this.isProcessingAction=!1,this.openCodeUrlCache=null,this.openCodePort=null,this.proxyAbortControllers=new Map,this.trackedChildPids=new Set,this.sseEventBuffer=[],this.hasRemoteEventConsumers=!1,this.cachedProjectConfig=null,this.logger=e,this.options=t,this.port=t.port||3456,this.startTime=new Date
178
178
  const s=(0,i.createMetricsCollector)(!1)
179
179
  this.apiClient=new n.BaseApiClient(t.remoteServerUrl,e,s,t.authToken,{timeout:35e3}),this.configurer=new u.MCPClientConfigurer(e,t.remoteServerUrl,t.authToken),this.cliBridge=new h.CLIBridgeWebSocket(e),(0,h.setCLIBridge)(this.cliBridge),this.hookExecutor=new f.HookExecutor(e,"",t.projectPath,this.apiClient,{cachedDefaultModel:this.cachedDefaultModel,trackChildPid:e=>this.trackedChildPids.add(e)}),this.app=this.createApp()}createApp(){const e=(0,r.default)()
180
- return e.use((0,o.default)()),e.use(r.default.json({limit:"10mb"})),e.get("/health",this.handleHealth.bind(this)),e.get("/status",this.handleStatus.bind(this)),e.get("/opencode",this.handleOpenCodeConfig.bind(this)),e.post("/sync-agents",this.handleSyncAgents.bind(this)),e.post("/api/generate-journal",this.handleGenerateJournal.bind(this)),e.get("/api/event-hooks/by-event/:eventType",this.handleEventHooksProxy.bind(this)),e.post("/api/hook-triggers",this.handleHookTriggersProxy.bind(this)),e.get("/api/hook-iterations/:sessionId/:hookId",this.handleGetHookIteration.bind(this)),e.post("/api/hook-iterations/:sessionId/:hookId/increment",this.handleIncrementHookIteration.bind(this)),e.get("/api/project-settings",((e,t)=>{t.json({success:!0,data:{defaultModel:this.cachedDefaultModel||null}})})),e.post("/api/sync-settings",(async(e,t)=>{await this.syncProjectSettings(),t.json({success:!0,data:{defaultModel:this.cachedDefaultModel||null}})})),e.get("/api/agents/by-name/:agentName",this.handleGetAgentByName.bind(this)),e.get("/api/sessions/:sessionId/agent-type",this.handleGetSessionAgentType.bind(this)),e.get("/api/sessions/:sessionId/parent",this.handleGetSessionParent.bind(this)),e.get("/api/sessions/:sessionId/ancestors",(async(e,t)=>{try{const{sessionId:s}=e.params,r=this.projectId
180
+ return e.use(((e,t,s)=>{t.setHeader("Access-Control-Allow-Private-Network","true"),s()})),e.use((0,o.default)()),e.use(r.default.json({limit:"10mb"})),e.get("/health",this.handleHealth.bind(this)),e.get("/status",this.handleStatus.bind(this)),e.get("/opencode",this.handleOpenCodeConfig.bind(this)),e.post("/sync-agents",this.handleSyncAgents.bind(this)),e.post("/api/generate-journal",this.handleGenerateJournal.bind(this)),e.get("/api/event-hooks/by-event/:eventType",this.handleEventHooksProxy.bind(this)),e.post("/api/hook-triggers",this.handleHookTriggersProxy.bind(this)),e.get("/api/hook-iterations/:sessionId/:hookId",this.handleGetHookIteration.bind(this)),e.post("/api/hook-iterations/:sessionId/:hookId/increment",this.handleIncrementHookIteration.bind(this)),e.get("/api/project-settings",((e,t)=>{t.json({success:!0,data:{defaultModel:this.cachedDefaultModel||null}})})),e.post("/api/sync-settings",(async(e,t)=>{await this.syncProjectSettings(),t.json({success:!0,data:{defaultModel:this.cachedDefaultModel||null}})})),e.get("/api/agents/by-name/:agentName",this.handleGetAgentByName.bind(this)),e.get("/api/sessions/:sessionId/agent-type",this.handleGetSessionAgentType.bind(this)),e.get("/api/sessions/:sessionId/parent",this.handleGetSessionParent.bind(this)),e.get("/api/sessions/:sessionId/ancestors",(async(e,t)=>{try{const{sessionId:s}=e.params,r=this.projectId
181
181
  if(!r)return void t.status(400).json({success:!1,error:"No project"})
182
182
  const o=await this.apiClient.get(`/api/projects/${r}/cli-sessions/external/opencode/${encodeURIComponent(s)}/ancestors`),n=(o?.data||o||[]).map((e=>({externalSessionId:e.externalSessionId,agentType:e.agentType,title:e.title})))
183
183
  t.json({success:!0,ancestors:n})}catch(e){t.status(500).json({success:!1,error:(0,g.getErrorMessage)(e)})}})),e.get("/api/registry/projects",(async(e,s)=>{try{const{listLive:e}=await t.e(640).then(t.bind(t,2640))
@@ -1158,7 +1158,7 @@ if(this.logger.debug("Polling response",{data:r}),r.authenticated&&r.token){this
1158
1158
  const s=this.parseTokenResponse(r)
1159
1159
  if(!s)throw Error("Invalid token response from server")
1160
1160
  this.pollingStatus=n.AUTHENTICATED,this.tokenResult=s,this.stopPolling(),t&&t(s)}else this.logger.debug("Not authenticated yet, continuing to poll",{tempCode:e.substring(0,4)+"***"})}catch(e){const t=(0,o.getErrorMessage)(e)
1161
- throw Error("Error during polling: "+t)}}catch(t){const s=(0,o.getErrorMessage)(t)
1161
+ throw Error(`Error during polling: ${t}${/fetch failed|ECONNREFUSED|ENOTFOUND|ETIMEDOUT|network/i.test(t)?" (remote may be unreachable \u2014 check your connection and try again)":""}`)}}catch(t){const s=(0,o.getErrorMessage)(t)
1162
1162
  this.logger.error("Error polling for authentication",{tempCode:e.substring(0,4)+"***",error:s}),this.pollingStatus=n.ERROR,this.pollingError=s,this.stopPolling(),r&&r(s)}}
1163
1163
  return i(),this.pollingIntervalId=setInterval(i,this.pollingIntervalMs),()=>this.stopPolling()}stopPolling(){this.pollingIntervalId&&(clearInterval(this.pollingIntervalId),this.pollingIntervalId=null,this.logger.debug("Stopped polling for authentication",{status:this.pollingStatus}))}getPollingStatus(){const e={status:this.pollingStatus}
1164
1164
  return this.pollingStatus===n.AUTHENTICATED&&this.tokenResult?e.tokenInfo=this.tokenResult:this.pollingStatus===n.ERROR&&this.pollingError&&(e.error=this.pollingError),this.pollingStartTime>0&&(e.elapsedTimeMs=Date.now()-this.pollingStartTime),e}resetPollingState(){this.stopPolling(),this.pollingStatus=n.NOT_STARTED,this.pollingStartTime=0,this.tokenResult=null,this.pollingError=null}async startGoogleOAuthFlow(){this.logger.info("Starting Google OAuth authentication flow")
@@ -1289,11 +1289,12 @@ let l=!1,u=null
1289
1289
  const g=async()=>{l||(l=!0,u&&clearInterval(u),console.log(""),console.log("Shutting down..."),await $.stop(),process.exit(0))}
1290
1290
  process.on("SIGTERM",g),process.on("SIGINT",g)
1291
1291
  const{InteractiveShell:p}=await e.e(994).then(e.t.bind(e,5994,23)),f=new p({projectPath:i,logger:b,remoteServerUrl:E,authToken:P,projectId:_})
1292
- u=setInterval((async()=>{try{if(await T.hasValidToken())return
1293
- console.log(""),console.log("\u26a0\ufe0f Auth token expired. Opening browser to re-authenticate...")
1292
+ let y=!1
1293
+ u=setInterval((async()=>{if(!y)try{if(await T.hasValidToken())return
1294
+ y=!0,console.log(""),console.log("\u26a0\ufe0f Auth token expired. Opening browser to re-authenticate...")
1294
1295
  const e=await T.startAuthenticationFlow()
1295
1296
  if(console.log("\u{1f310} "+e.authUrl),o(e.authUrl),console.log("\u23f1\ufe0f Waiting for re-authentication..."),await n(T)){const e=await T.getToken()
1296
- e?.token&&(P=e.token,$.updateAuthToken(P)),console.log("\u2705 Re-authenticated successfully.")}else console.log("\u274c Re-authentication timed out. Some features may not work until you restart.")}catch(e){b.warn("Token watchdog check failed",{error:(0,I.getErrorMessage)(e)})}}),3e5),await f.start(g)}catch(e){b.error("Failed to start server",{error:(0,I.getErrorMessage)(e)}),console.error("\u274c Failed to start: "+(0,I.getErrorMessage)(e)),process.exit(1)}}({port:C})
1297
+ e?.token&&(P=e.token,$.updateAuthToken(P)),console.log("\u2705 Re-authenticated successfully.")}else console.log("\u274c Re-authentication timed out. Some features may not work until you restart.")}catch(e){b.warn("Token watchdog check failed",{error:(0,I.getErrorMessage)(e)})}finally{y=!1}}),3e5),await f.start(g)}catch(e){b.error("Failed to start server",{error:(0,I.getErrorMessage)(e)}),console.error("\u274c Failed to start: "+(0,I.getErrorMessage)(e)),process.exit(1)}}({port:C})
1297
1298
  const E=b[0].toLowerCase()
1298
1299
  switch("--help"!==E&&"-h"!==E||(s(),process.exit(0)),"--version"!==E&&"-v"!==E||(console.log("alchemy v"+t()),process.exit(0)),E){case"serve":await async function(e={}){const s=process.cwd()
1299
1300
  r(s)||(console.log("\u{1f4c1} Current directory is not an AlchemyLab project."),console.log(""),console.log("\u{1f4a1} Run `alchemy` to initialize this project."),console.log(""),process.exit(1))
@@ -587,9 +587,9 @@ if(this.TOKEN_CACHE.hasValidToken&&e<this.TOKEN_CACHE.hasValidToken.expiresAt){c
587
587
  return this.logger.debug("Using cached hasValidToken result",{ageSecs:Math.round((e-t.timestamp)/1e3),hasToken:t.value}),t.value}this.logger.debug("Checking if valid token exists (cache miss or expired)")
588
588
  const t=null!==await this.getToken()
589
589
  return this.TOKEN_CACHE.hasValidToken={value:t,timestamp:e,expiresAt:e+this.CACHE_TTL_MS,lastCheck:e,exists:t},t}getTokenDirectoryPath(){return this.tokenDirPath}getManualTokenFilePath(){return n.default.join(this.tokenDirPath,"manual-token.json")}logTokenLocationInstructions(){const e=this.getManualTokenFilePath()
590
- console.log("========================================"),console.log("To use MCP server, you need to authenticate."),console.log("Token file location: "+e),console.log("You can either:"),console.log('\n1. Use the authenticate tool (recommended)\n2. Manually place a token file at the above location\n3. Set up automatic authentication flow\n\nFor manual token placement, create a JSON file with:\n{\n "token": "your_token_here",\n "userId": "your_user_id",\n "username": "your_username", \n "role": "user",\n "expiresAt": "2025-12-31T23:59:59.000Z"\n}\n'),console.log("For more information, see the authentication documentation."),console.log("========================================")}async startAuthenticationFlow(){this.pendingAuthCheck=!0
590
+ console.log("========================================"),console.log("To use the alchemy CLI, you need to authenticate."),console.log("Token file location: "+e),console.log("You can either:"),console.log('\n1. Use the authenticate tool (recommended)\n2. Manually place a token file at the above location\n3. Set up automatic authentication flow\n\nFor manual token placement, create a JSON file with:\n{\n "token": "your_token_here",\n "userId": "your_user_id",\n "username": "your_username", \n "role": "user",\n "expiresAt": "2025-12-31T23:59:59.000Z"\n}\n'),console.log("For more information, see the authentication documentation."),console.log("========================================")}async startAuthenticationFlow(){this.pendingAuthCheck=!0
591
591
  try{const{tempCode:e,authUrl:t}=await this.authFlow.startAuthFlow()
592
- return this.tempAuthCode=e,this.logger.info("Started external authentication flow",{tempCode:e,authUrl:t}),this.authFlow.startPolling(e,(async t=>{this.logger.info("Authentication flow completed",{tempCode:e.substring(0,4)+"***",username:t.username}),await this.storeToken(t),this.pendingAuthCheck=!1,this.tempAuthCode=null,this.invalidateCache(),console.log("Authentication successful!"),console.log(`Welcome, ${t.username}!`),console.log("You can now use all MCP tools and features."),console.log("========================================")}),(()=>{this.logger.info("Authentication flow timed out",{tempCode:e.substring(0,4)+"***"}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow timed out."),console.log("Please try again or manually place a token file."),console.log("Token file location:"),console.log(""+this.getManualTokenFilePath()),console.log("========================================")}),(t=>{this.logger.error("Authentication flow error",{tempCode:e.substring(0,4)+"***",error:t}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow error."),console.log("Error: "+t),console.log("Please try again or manually place a token file."),console.log(""+this.getManualTokenFilePath()),console.log("========================================")})),{tempCode:e,authUrl:t}}catch(e){throw this.logger.error("Error starting authentication flow",{error:(0,c.getErrorMessage)(e)}),this.pendingAuthCheck=!1,this.tempAuthCode=null,e}}hasPendingAuth(){return this.pendingAuthCheck||!!this.tempAuthCode}getAuthStatus(){return this.hasPendingAuth()?{hasToken:!1,isPendingAuth:!0,tempCode:this.tempAuthCode,authUrl:this.authFlow.getAuthUrl(this.tempAuthCode)}:{hasToken:!1,isPendingAuth:!1}}async checkAuthStatus(e){if(!e)return null
592
+ return this.tempAuthCode=e,this.logger.info("Started external authentication flow",{tempCode:e,authUrl:t}),this.authFlow.startPolling(e,(async t=>{this.logger.info("Authentication flow completed",{tempCode:e.substring(0,4)+"***",username:t.username}),await this.storeToken(t),this.pendingAuthCheck=!1,this.tempAuthCode=null,this.invalidateCache(),console.log("Authentication successful!"),console.log(`Welcome, ${t.username}!`),console.log("You can now use the alchemy CLI."),console.log("========================================")}),(()=>{this.logger.info("Authentication flow timed out",{tempCode:e.substring(0,4)+"***"}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow timed out."),console.log("Please try again or manually place a token file."),console.log("Token file location:"),console.log(""+this.getManualTokenFilePath()),console.log("========================================")}),(t=>{this.logger.error("Authentication flow error",{tempCode:e.substring(0,4)+"***",error:t}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow error."),console.log("Error: "+t),console.log("Please try again or manually place a token file."),console.log(""+this.getManualTokenFilePath()),console.log("========================================")})),{tempCode:e,authUrl:t}}catch(e){throw this.logger.error("Error starting authentication flow",{error:(0,c.getErrorMessage)(e)}),this.pendingAuthCheck=!1,this.tempAuthCode=null,e}}hasPendingAuth(){return this.pendingAuthCheck||!!this.tempAuthCode}getAuthStatus(){return this.hasPendingAuth()?{hasToken:!1,isPendingAuth:!0,tempCode:this.tempAuthCode,authUrl:this.authFlow.getAuthUrl(this.tempAuthCode)}:{hasToken:!1,isPendingAuth:!1}}async checkAuthStatus(e){if(!e)return null
593
593
  try{const t=this.authFlow.getPollingStatus()
594
594
  if(t.status===a.PollingStatus.AUTHENTICATED&&t.tokenInfo)return this.logger.info("Authentication polling has token available",{tempCode:e.substring(0,4)+"***",username:t.tokenInfo.username}),t.tokenInfo
595
595
  if(t.status===a.PollingStatus.ERROR||t.status===a.PollingStatus.TIMEOUT)return this.pendingAuthCheck=!1,this.tempAuthCode=null,null
@@ -5192,7 +5192,7 @@ if(this.logger.debug("Polling response",{data:n}),n.authenticated&&n.token){this
5192
5192
  const r=this.parseTokenResponse(n)
5193
5193
  if(!r)throw Error("Invalid token response from server")
5194
5194
  this.pollingStatus=s.AUTHENTICATED,this.tokenResult=r,this.stopPolling(),t&&t(r)}else this.logger.debug("Not authenticated yet, continuing to poll",{tempCode:e.substring(0,4)+"***"})}catch(e){const t=(0,o.getErrorMessage)(e)
5195
- throw Error("Error during polling: "+t)}}catch(t){const r=(0,o.getErrorMessage)(t)
5195
+ throw Error(`Error during polling: ${t}${/fetch failed|ECONNREFUSED|ENOTFOUND|ETIMEDOUT|network/i.test(t)?" (remote may be unreachable \u2014 check your connection and try again)":""}`)}}catch(t){const r=(0,o.getErrorMessage)(t)
5196
5196
  this.logger.error("Error polling for authentication",{tempCode:e.substring(0,4)+"***",error:r}),this.pollingStatus=s.ERROR,this.pollingError=r,this.stopPolling(),n&&n(r)}}
5197
5197
  return i(),this.pollingIntervalId=setInterval(i,this.pollingIntervalMs),()=>this.stopPolling()}stopPolling(){this.pollingIntervalId&&(clearInterval(this.pollingIntervalId),this.pollingIntervalId=null,this.logger.debug("Stopped polling for authentication",{status:this.pollingStatus}))}getPollingStatus(){const e={status:this.pollingStatus}
5198
5198
  return this.pollingStatus===s.AUTHENTICATED&&this.tokenResult?e.tokenInfo=this.tokenResult:this.pollingStatus===s.ERROR&&this.pollingError&&(e.error=this.pollingError),this.pollingStartTime>0&&(e.elapsedTimeMs=Date.now()-this.pollingStartTime),e}resetPollingState(){this.stopPolling(),this.pollingStatus=s.NOT_STARTED,this.pollingStartTime=0,this.tokenResult=null,this.pollingError=null}async startGoogleOAuthFlow(){this.logger.info("Starting Google OAuth authentication flow")
package/dist/index.js CHANGED
@@ -455,17 +455,17 @@ const x=new k.ConnectionStatusManager(T,n.child({component:"connection-status-ma
455
455
  j.registerClient(M)
456
456
  const O=new I.TaskClient(T,n.child({component:"task-client"}),o,M,x,R)
457
457
  j.registerClient(O)
458
- const $=new v.FileOperationsClient(T,n.child({component:"file-client"}),o,M,R,x)
459
- j.registerClient($)
460
- const D=new C.ProxyClient(T,n.child({component:"proxy-client"}),o,M,R,x)
458
+ const D=new v.FileOperationsClient(T,n.child({component:"file-client"}),o,M,R,x)
461
459
  j.registerClient(D)
460
+ const $=new C.ProxyClient(T,n.child({component:"proxy-client"}),o,M,R,x)
461
+ j.registerClient($)
462
462
  const A=new _.RequestClient(T,n.child({component:"request-client"}),o,M,R,x)
463
463
  A.setAuthToken(R),(0,d.isDebugToolsEnabled)()&&n.debug("Explicitly set token on RequestClient",{tokenPresent:!!R}),j.registerClient(A)
464
464
  const F=new E.DocumentClient(T,n.child({component:"document-client"}),o,M,R,x)
465
465
  j.registerClient(F)
466
466
  const N=new q.ToolRecordClient(T,n.child({component:"tool-record-client"}),o,M,R,x)
467
467
  j.registerClient(N)
468
- const L=new S.ApiClient(P,M,O,$,A,F,N,D,n.child({component:"api-client"})),z=a.default.Router();(0,h.registerAuthRoutes)(z,{projectClient:M,taskClient:O,fileClient:$,authManager:P,apiClient:L},i,n)
468
+ const L=new S.ApiClient(P,M,O,D,A,F,N,$,n.child({component:"api-client"})),z=a.default.Router();(0,h.registerAuthRoutes)(z,{projectClient:M,taskClient:O,fileClient:D,authManager:P,apiClient:L},i,n)
469
469
  const H=r.getContext();(0,g.registerConfigRoutes)(z,n,H.basePath),e.use("/api",z)
470
470
  const B=e=>{const t=o.startTimer(e)
471
471
  return e=>t(e)},U=(e,t,n)=>{const o=e.query.path||e.body.path
@@ -500,7 +500,7 @@ return r({endpoint:"files/content",method:"GET",success:!0,encoding:"binary"}),t
500
500
  r({endpoint:"files/content",method:"GET",success:!0,encoding:o}),t.json({success:!0,data:{path:e.relativePath,content:s,size:n.size,modified:n.mtime}})}catch(t){throw"ENOENT"===t.code?(r({endpoint:"files/content",method:"GET",success:!1,error:"not_found"}),(0,u.createNotFoundError)("File not found: "+e.relativePath)):t}}catch(e){r(e)}})),e.post("/api/files/write",U,G,(async(e,t,s)=>{try{o.incrementCounter("api_requests_total",1,{endpoint:"files/write",method:"POST"})
501
501
  const s=B("api_request_duration"),{content:i,taskId:a,format:c="text"}=e.body
502
502
  if(void 0===i)throw(0,u.createValidationError)("Content parameter is required")
503
- const l=await(0,f.handleWriteFile)({taskId:a,path:e.relativePath,content:i,format:c},r.getContext(),$,O,N,A,n,o)
503
+ const l=await(0,f.handleWriteFile)({taskId:a,path:e.relativePath,content:i,format:c},r.getContext(),D,O,N,A,n,o)
504
504
  s({endpoint:"files/write",method:"POST",success:!0}),t.json({success:!0,data:l})}catch(e){s(e)}})),e.post("/api/files/replace",U,G,(async(e,t,s)=>{try{o.incrementCounter("api_requests_total",1,{endpoint:"files/replace",method:"POST"})
505
505
  const s=B("api_request_duration"),{replacements:i,mode:a="unique",taskId:c}=e.body
506
506
  if(!i||!Array.isArray(i))throw(0,u.createValidationError)("Replacements array is required")
@@ -588,9 +588,9 @@ if(this.TOKEN_CACHE.hasValidToken&&e<this.TOKEN_CACHE.hasValidToken.expiresAt){c
588
588
  return this.logger.debug("Using cached hasValidToken result",{ageSecs:Math.round((e-t.timestamp)/1e3),hasToken:t.value}),t.value}this.logger.debug("Checking if valid token exists (cache miss or expired)")
589
589
  const t=null!==await this.getToken()
590
590
  return this.TOKEN_CACHE.hasValidToken={value:t,timestamp:e,expiresAt:e+this.CACHE_TTL_MS,lastCheck:e,exists:t},t}getTokenDirectoryPath(){return this.tokenDirPath}getManualTokenFilePath(){return n.default.join(this.tokenDirPath,"manual-token.json")}logTokenLocationInstructions(){const e=this.getManualTokenFilePath()
591
- console.log("========================================"),console.log("To use MCP server, you need to authenticate."),console.log("Token file location: "+e),console.log("You can either:"),console.log('\n1. Use the authenticate tool (recommended)\n2. Manually place a token file at the above location\n3. Set up automatic authentication flow\n\nFor manual token placement, create a JSON file with:\n{\n "token": "your_token_here",\n "userId": "your_user_id",\n "username": "your_username", \n "role": "user",\n "expiresAt": "2025-12-31T23:59:59.000Z"\n}\n'),console.log("For more information, see the authentication documentation."),console.log("========================================")}async startAuthenticationFlow(){this.pendingAuthCheck=!0
591
+ console.log("========================================"),console.log("To use the alchemy CLI, you need to authenticate."),console.log("Token file location: "+e),console.log("You can either:"),console.log('\n1. Use the authenticate tool (recommended)\n2. Manually place a token file at the above location\n3. Set up automatic authentication flow\n\nFor manual token placement, create a JSON file with:\n{\n "token": "your_token_here",\n "userId": "your_user_id",\n "username": "your_username", \n "role": "user",\n "expiresAt": "2025-12-31T23:59:59.000Z"\n}\n'),console.log("For more information, see the authentication documentation."),console.log("========================================")}async startAuthenticationFlow(){this.pendingAuthCheck=!0
592
592
  try{const{tempCode:e,authUrl:t}=await this.authFlow.startAuthFlow()
593
- return this.tempAuthCode=e,this.logger.info("Started external authentication flow",{tempCode:e,authUrl:t}),this.authFlow.startPolling(e,(async t=>{this.logger.info("Authentication flow completed",{tempCode:e.substring(0,4)+"***",username:t.username}),await this.storeToken(t),this.pendingAuthCheck=!1,this.tempAuthCode=null,this.invalidateCache(),console.log("Authentication successful!"),console.log(`Welcome, ${t.username}!`),console.log("You can now use all MCP tools and features."),console.log("========================================")}),(()=>{this.logger.info("Authentication flow timed out",{tempCode:e.substring(0,4)+"***"}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow timed out."),console.log("Please try again or manually place a token file."),console.log("Token file location:"),console.log(""+this.getManualTokenFilePath()),console.log("========================================")}),(t=>{this.logger.error("Authentication flow error",{tempCode:e.substring(0,4)+"***",error:t}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow error."),console.log("Error: "+t),console.log("Please try again or manually place a token file."),console.log(""+this.getManualTokenFilePath()),console.log("========================================")})),{tempCode:e,authUrl:t}}catch(e){throw this.logger.error("Error starting authentication flow",{error:(0,c.getErrorMessage)(e)}),this.pendingAuthCheck=!1,this.tempAuthCode=null,e}}hasPendingAuth(){return this.pendingAuthCheck||!!this.tempAuthCode}getAuthStatus(){return this.hasPendingAuth()?{hasToken:!1,isPendingAuth:!0,tempCode:this.tempAuthCode,authUrl:this.authFlow.getAuthUrl(this.tempAuthCode)}:{hasToken:!1,isPendingAuth:!1}}async checkAuthStatus(e){if(!e)return null
593
+ return this.tempAuthCode=e,this.logger.info("Started external authentication flow",{tempCode:e,authUrl:t}),this.authFlow.startPolling(e,(async t=>{this.logger.info("Authentication flow completed",{tempCode:e.substring(0,4)+"***",username:t.username}),await this.storeToken(t),this.pendingAuthCheck=!1,this.tempAuthCode=null,this.invalidateCache(),console.log("Authentication successful!"),console.log(`Welcome, ${t.username}!`),console.log("You can now use the alchemy CLI."),console.log("========================================")}),(()=>{this.logger.info("Authentication flow timed out",{tempCode:e.substring(0,4)+"***"}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow timed out."),console.log("Please try again or manually place a token file."),console.log("Token file location:"),console.log(""+this.getManualTokenFilePath()),console.log("========================================")}),(t=>{this.logger.error("Authentication flow error",{tempCode:e.substring(0,4)+"***",error:t}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow error."),console.log("Error: "+t),console.log("Please try again or manually place a token file."),console.log(""+this.getManualTokenFilePath()),console.log("========================================")})),{tempCode:e,authUrl:t}}catch(e){throw this.logger.error("Error starting authentication flow",{error:(0,c.getErrorMessage)(e)}),this.pendingAuthCheck=!1,this.tempAuthCode=null,e}}hasPendingAuth(){return this.pendingAuthCheck||!!this.tempAuthCode}getAuthStatus(){return this.hasPendingAuth()?{hasToken:!1,isPendingAuth:!0,tempCode:this.tempAuthCode,authUrl:this.authFlow.getAuthUrl(this.tempAuthCode)}:{hasToken:!1,isPendingAuth:!1}}async checkAuthStatus(e){if(!e)return null
594
594
  try{const t=this.authFlow.getPollingStatus()
595
595
  if(t.status===a.PollingStatus.AUTHENTICATED&&t.tokenInfo)return this.logger.info("Authentication polling has token available",{tempCode:e.substring(0,4)+"***",username:t.tokenInfo.username}),t.tokenInfo
596
596
  if(t.status===a.PollingStatus.ERROR||t.status===a.PollingStatus.TIMEOUT)return this.pendingAuthCheck=!1,this.tempAuthCode=null,null
@@ -681,7 +681,7 @@ I.initialScan={totalEntries:t.length,directories:r,files:n,firstFewFiles:n.slice
681
681
  I.errors.push(t),l.error(t)}const M=_?"file":"directory"
682
682
  l.info(`Searching for "${n}" in ${M} ${C} (mode: ${P})`,{needle:n,searchTarget:M,path:C,options:{maxResults:E,caseSensitive:q,fileExtension:x,searchIn:P}}),b=Date.now(),I.phases.initializationTime=b-u
683
683
  const O=Date.now()
684
- let $=[],D=0,A=0
684
+ let D=[],$=0,A=0
685
685
  try{const e=await async function(e,t,n,o,s,i){const{maxResults:a,fileExtension:c,searchIn:l,isFile:d,contextLines:u}=n,p=[]
686
686
  if(s.info("performLocalSearch started",{searchPath:e,pattern:t.toString(),options:n}),d)return await async function(e,t,r,n,o,s=0){const i=[],a=h.default.basename(e)
687
687
  let c
@@ -698,16 +698,16 @@ const f={path:e,filesProcessed:0,filesMatched:0,subdirectories:0,errors:[]}
698
698
  try{const{filesCount:n,fileMatchesCount:c,subdirCount:d,subdirStats:h}=await r(e,t,p,a,o,s,0,f,l,u)
699
699
  return f.filesProcessed=n,f.filesMatched=c,f.subdirectories=d,i.directoryStats.push(f),h&&h.length>0&&i.directoryStats.push(...h),s.info("performLocalSearch completed",{totalFiles:n,matchesFound:p.length,directories:d+1}),{matches:p,totalFiles:n}}catch(t){const r="Error in performLocalSearch: "+(0,k.getErrorMessage)(t)
700
700
  return f.errors.push(r),i.directoryStats.push(f),i.errors.push(r),s.error(r,{error:t instanceof Error?t.stack:t+"",searchPath:e}),{matches:p,totalFiles:f.filesProcessed}}}(C,R,{maxResults:E,fileExtension:x,searchIn:P,isFile:_,contextLines:j},x,l,I)
701
- $=e.matches,D=e.totalFiles
701
+ D=e.matches,$=e.totalFiles
702
702
  const t=1e3
703
- $.length>0&&$.length<=t?($.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 ${$.length} matches by modification time (newest first)`)):$.length>t&&l.info(`Skipped sorting ${$.length} matches (exceeds hard cap of ${t} for performance)`),A=$.length,$.length>E&&($=$.slice(0,E),l.info(`Limited results to ${E} (from ${A} total matches)`)),$.forEach((e=>{e.relativePath=function(e,t){const r=h.default.relative(e,t)
704
- return r?r===h.default.basename(t)?r:r.startsWith("./")?r.substring(2):r:h.default.basename(t)}(C,e.file)})),l.info(`Local search completed: found ${A||$.length} total matches in ${D} files, returning ${$.length} results`),I.phases.searchTime=Date.now()-O}catch(e){const t="Error during search: "+(0,k.getErrorMessage)(e)
705
- I.errors.push(t),l.error(t),I.phases.searchTime=Date.now()-O}I.totalFiles=D,I.totalMatches=$.length,I.endTime=Date.now()
703
+ 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)`),A=D.length,D.length>E&&(D=D.slice(0,E),l.info(`Limited results to ${E} (from ${A} total matches)`)),D.forEach((e=>{e.relativePath=function(e,t){const r=h.default.relative(e,t)
704
+ return r?r===h.default.basename(t)?r:r.startsWith("./")?r.substring(2):r:h.default.basename(t)}(C,e.file)})),l.info(`Local search completed: found ${A||D.length} total matches in ${$} files, returning ${D.length} results`),I.phases.searchTime=Date.now()-O}catch(e){const t="Error during search: "+(0,k.getErrorMessage)(e)
705
+ I.errors.push(t),l.error(t),I.phases.searchTime=Date.now()-O}I.totalFiles=$,I.totalMatches=D.length,I.endTime=Date.now()
706
706
  let F,N=""
707
707
  try{if(t.workspaceManager){const e=t.workspaceManager.getCurrentContext(t.currentSessionId)
708
708
  e.branchName&&!e.permanentBranch&&(N=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}),N=" (branch context unavailable)"}l.debug("Search diagnostic information",{diagnostic:I})
709
709
  const L="content"===P?"content":"filename"===P?"filenames":"content and filenames"
710
- if(A>$.length?(F=`Found ${A} results for "${n}" (searching ${L})`,p&&(F+=" in "+p),T&&(F+=" with extension "+T),F+=`${N}. Showing first ${$.length}:\n\n`):(F=`Found ${$.length} results for "${n}" (searching ${L})`,p&&(F+=" in "+p),T&&(F+=" with extension "+T),F+=N+":\n\n"),$.length>0)if(j>0){const{filenameMatches:e,mergedGroups:t}=function(e,t){const r=e.filter((e=>"filename"===e.matchType)),n=e.filter((e=>"content"===e.matchType))
710
+ if(A>D.length?(F=`Found ${A} results for "${n}" (searching ${L})`,p&&(F+=" in "+p),T&&(F+=" with extension "+T),F+=`${N}. Showing first ${D.length}:\n\n`):(F=`Found ${D.length} results for "${n}" (searching ${L})`,p&&(F+=" in "+p),T&&(F+=" with extension "+T),F+=N+":\n\n"),D.length>0)if(j>0){const{filenameMatches:e,mergedGroups:t}=function(e,t){const r=e.filter((e=>"filename"===e.matchType)),n=e.filter((e=>"content"===e.matchType))
711
711
  if(0===n.length)return{filenameMatches:r,mergedGroups:[]}
712
712
  const o=new Map
713
713
  for(const e of n){const t=o.get(e.file)||[]
@@ -715,7 +715,7 @@ t.push(e),o.set(e.file,t)}const i=[]
715
715
  for(const[e,r]of o.entries()){r.sort(((e,t)=>e.line-t.line))
716
716
  let e=[r[0]]
717
717
  for(let n=1;n<r.length;n++){const o=e[e.length-1],a=r[n],c=o.line+t
718
- a.line-t>c+1?(i.push(s(e,t)),e=[a]):e.push(a)}e.length>0&&i.push(s(e,t))}return{filenameMatches:r,mergedGroups:i}}($,j),r=[]
718
+ a.line-t>c+1?(i.push(s(e,t)),e=[a]):e.push(a)}e.length>0&&i.push(s(e,t))}return{filenameMatches:r,mergedGroups:i}}(D,j),r=[]
719
719
  e.forEach((e=>{r.push(e.relativePath+" [filename match]")})),t.forEach((e=>{const t=[]
720
720
  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")}`)})),F+=r.join("\n\n")}else F+=await async function(e){const t=e.filter((e=>"filename"===e.matchType)),r=e.filter((e=>"content"===e.matchType)),n=[]
721
721
  t.length>0&&t.forEach((e=>{n.push(e.relativePath+" [filename match]")}))
@@ -726,7 +726,7 @@ const r=t[0].relativePath||e,o=t.length,s=await i(e)
726
726
  let a=r
727
727
  void 0!==s&&(a+=` (${s} lines)`),a+=` - ${o} ${1===o?"match":"matches"}:`
728
728
  const c=t.map((e=>` :${e.line} - ${e.text}`))
729
- n.push(a+"\n"+c.join("\n"))}return n.join("\n\n")}($)
729
+ n.push(a+"\n"+c.join("\n"))}return n.join("\n\n")}(D)
730
730
  else F+="No matches found."
731
731
  return d({success:!0}),{content:[{type:"text",text:F}]}}catch(t){l.error("Search failed",{args:e,error:t instanceof Error?t.stack:t+""}),I.errors.push((0,k.getErrorMessage)(t)),I.endTime=Date.now(),l.debug("Search diagnostic information on error",{diagnostic:I})
732
732
  let r="Search failed: "+(0,k.getErrorMessage)(t)
@@ -1735,27 +1735,27 @@ throw Error(x.error)}let M={hadUserMods:!1,userModsCommitHash:void 0}
1735
1735
  if(r.git)try{y.debug("[MOVE-FILES] Checking for user changes before move operations")
1736
1736
  const e=await(0,g.commitUserChangesBeforeToolOperation)(r.git,"move-files",{requestId:P,taskId:E,workspaceManager:r.workspaceManager},y,f)
1737
1737
  e.userChangesCommitted&&(y.debug("[MOVE-FILES] User changes committed before move operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),y.info("User changes committed before move-files operation",{taskId:E,moveOperationsCount:S.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}),M={hadUserMods:!0,userModsCommitHash:e.commitHash})}catch(e){y.debug("[MOVE-FILES] Pre-tool commit failed, continuing with move operations",{error:e instanceof Error?e.message:e+""}),y.warn("Pre-tool user changes commit failed, continuing with move operation",{taskId:E,moveOperationsCount:S.length,error:e instanceof Error?e.message:e+""})}y.debug("[MOVE-FILES] Proceeding with move operations",{operationCount:S.length}),I=d.FileOperationPhase.RECORD_CREATION,f.incrementCounter("move_files_phase",1,{phase:I})
1738
- const{toolRecordId:O,localToolRecordId:$}=await d.createFileOperationRecords(E,P,r.projectId,v.recordType,S[0].source,{operationCount:h.length,operations:S.map((e=>({source:e.source,destination:e.destination}))),userComment:C,hadUserMods:M.hadUserMods,userModsCommitHash:M.userModsCommitHash},n,o,y,f,v.metricsPrefix,m)
1738
+ const{toolRecordId:O,localToolRecordId:D}=await d.createFileOperationRecords(E,P,r.projectId,v.recordType,S[0].source,{operationCount:h.length,operations:S.map((e=>({source:e.source,destination:e.destination}))),userComment:C,hadUserMods:M.hadUserMods,userModsCommitHash:M.userModsCommitHash},n,o,y,f,v.metricsPrefix,m)
1739
1739
  k=O,b=O,I=v.fileOperationPhase,f.incrementCounter("move_files_phase",1,{phase:I})
1740
- const D=[]
1740
+ const $=[]
1741
1741
  let A=0
1742
1742
  for(const e of S){const t={operation:{source:e.source,destination:e.destination},success:!1}
1743
1743
  try{try{await a.default.access(e.fullSource)}catch(t){throw Error("Source path not accessible: "+e.source)}const r=(await a.default.stat(e.fullSource)).isDirectory()
1744
1744
  t.isDirectory=r
1745
1745
  const n=c.default.dirname(e.fullDestination)
1746
- try{await a.default.mkdir(n,{recursive:!0})}catch(e){throw Error("Failed to create destination directory: "+n)}try{throw await a.default.access(e.fullDestination),Error("Destination already exists: "+e.destination)}catch(e){if(!(e instanceof Error&&e.message.includes("ENOENT")))throw e}await a.default.rename(e.fullSource,e.fullDestination),t.success=!0,A++,y.info("Successfully moved "+(r?"directory":"file"),{source:e.source,destination:e.destination,isDirectory:r})}catch(r){t.error=(0,p.getErrorMessage)(r),y.warn(`Failed to move ${e.source} to ${e.destination}`,{error:t.error})}D.push(t)}const F=Date.now()-w
1746
+ try{await a.default.mkdir(n,{recursive:!0})}catch(e){throw Error("Failed to create destination directory: "+n)}try{throw await a.default.access(e.fullDestination),Error("Destination already exists: "+e.destination)}catch(e){if(!(e instanceof Error&&e.message.includes("ENOENT")))throw e}await a.default.rename(e.fullSource,e.fullDestination),t.success=!0,A++,y.info("Successfully moved "+(r?"directory":"file"),{source:e.source,destination:e.destination,isDirectory:r})}catch(r){t.error=(0,p.getErrorMessage)(r),y.warn(`Failed to move ${e.source} to ${e.destination}`,{error:t.error})}$.push(t)}const F=Date.now()-w
1747
1747
  f.recordValue("move_files_time",F),f.incrementCounter("move_files_operations_total",h.length),f.incrementCounter("move_files_operations_success",A),f.incrementCounter("move_files_operations_failed",h.length-A),A===h.length?f.incrementCounter("move_files_success",1):A>0?f.incrementCounter("move_files_partial_success",1):f.incrementCounter("move_files_total_failure",1)
1748
1748
  let N=null
1749
1749
  if(A>0){I=d.FileOperationPhase.GIT_COMMIT,f.incrementCounter("move_files_phase",1,{phase:I})
1750
- const e=D.filter((e=>e.success)),t=1===e.length?`Move ${e[0].isDirectory?"directory":"file"} from ${e[0].operation.source} to ${e[0].operation.destination} - ${C}`:`Move ${e.length} ${1===e.length?"item":"items"} - ${C}`
1751
- N=await d.commitToGit(E,S[0].destination,O,$,t,r,y,f,v.metricsPrefix)}I=d.FileOperationPhase.RECORD_UPDATE_SUCCESS,f.incrementCounter("move_files_phase",1,{phase:I})
1752
- const L=D.filter((e=>e.success)),z=D.filter((e=>!e.success))
1750
+ const e=$.filter((e=>e.success)),t=1===e.length?`Move ${e[0].isDirectory?"directory":"file"} from ${e[0].operation.source} to ${e[0].operation.destination} - ${C}`:`Move ${e.length} ${1===e.length?"item":"items"} - ${C}`
1751
+ N=await d.commitToGit(E,S[0].destination,O,D,t,r,y,f,v.metricsPrefix)}I=d.FileOperationPhase.RECORD_UPDATE_SUCCESS,f.incrementCounter("move_files_phase",1,{phase:I})
1752
+ const L=$.filter((e=>e.success)),z=$.filter((e=>!e.success))
1753
1753
  await d.updateFileOperationRecords(E,k,b,S[0].source,v.recordType,A===h.length?`Successfully moved all ${h.length} items`:`Moved ${A}/${h.length} items successfully`,{status:A===h.length?"completed":"partial_success",commitHash:N?.commitHash,previousCommitHash:N?.previousCommitHash,operationCount:h.length,successCount:A,failureCount:h.length-A,successfulOperations:L.map((e=>({source:e.operation.source,destination:e.operation.destination,isDirectory:e.isDirectory}))),failedOperations:z.map((e=>({source:e.operation.source,destination:e.operation.destination,error:e.error}))),userComment:C,hadUserMods:M.hadUserMods,userModsCommitHash:M.userModsCommitHash},A===h.length?`Successfully moved all ${h.length} items`:`Moved ${A}/${h.length} items successfully`,n,o,y,f,v.metricsPrefix)
1754
1754
  const H=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
1755
1755
  let B=""
1756
1756
  if(A===h.length)B=`Successfully moved all ${h.length} ${1===h.length?"item":"items"}`
1757
- else if(A>0){const e=D.filter((e=>!e.success))
1758
- B=`Successfully moved ${A}/${h.length} items.\n\nFailed operations:\n`+e.map((e=>`\u2022 ${e.operation.source} \u2192 ${e.operation.destination}: ${e.error}`)).join("\n")}else B="All move operations failed:\n"+D.map((e=>`\u2022 ${e.operation.source} \u2192 ${e.operation.destination}: ${e.error}`)).join("\n")
1757
+ else if(A>0){const e=$.filter((e=>!e.success))
1758
+ B=`Successfully moved ${A}/${h.length} items.\n\nFailed operations:\n`+e.map((e=>`\u2022 ${e.operation.source} \u2192 ${e.operation.destination}: ${e.error}`)).join("\n")}else B="All move operations failed:\n"+$.map((e=>`\u2022 ${e.operation.source} \u2192 ${e.operation.destination}: ${e.error}`)).join("\n")
1759
1759
  if(N?.commitHash&&(B+="\nCommit: "+N.commitHash.substring(0,8)),H.requestId&&(B+="\nBranch: "+H.requestId),x.lockAcquired&&x.lockedRequestId){const e=r.workspaceManager?.getCurrentContext(r.currentSessionId)
1760
1760
  e?.permanentBranch||(B+="\n\u{1f512} **Locked request:** "+x.lockedRequestId)}return{content:[{type:"text",text:B}],isError:0===A}}catch(t){if(e.taskId&&o)try{const n=t instanceof u.NotFoundError||t instanceof u.ValidationError||t instanceof h.ZodError
1761
1761
  await o.createToolRecord({...n?{}:{taskId:e.taskId},projectId:r.projectId,type:"move-files",metadata:{status:"failed",timestamp:(new Date).toISOString(),operationCount:e.operations?.length||0,operations:e.operations||[],userComment:e.comment,error:(0,p.getErrorMessage)(t),errorDetails:t instanceof Error?t.stack:t+"",phase:I,attemptedTaskId:e.taskId,taskIdValidationFailed:n},note:"Failed to move files - "+(0,p.getErrorMessage)(t)})}catch(t){y.error("Failed to create failure record for move-files operation",{error:t instanceof Error?t.message:t+"",taskId:e.taskId,operationCount:e.operations?.length||0})}const s=Date.now()-w
@@ -1767,7 +1767,7 @@ Object.defineProperty(exports,"__esModule",{value:!0}),exports.def=void 0
1767
1767
  const r=t(6183),n=t(3707)
1768
1768
  exports.def={name:"quick_manage",description:"WHEN TO USE: trivial single-file edits only. For multi-file or feature work, spawn a coder via subagent_operations.\n\nMove, delete, or create directories. Wraps the change in a request/task workflow that auto-completes.\n\nProvide an array of operations, each with operationType and corresponding data:\n\u2022 create-directory: { createDirectory: { path } }\n\u2022 move-files: { moveFiles: { moves: [{ source, destination }] } }\n\u2022 delete-files: { deleteFiles: { targets: [{ path }] } }\n\nFor read-only operations like get-file-info, use manage_files instead.\n\nRequires: title, description, operations.",schema:r.QuickManageSchema,annotations:{title:"Quick Manage",readOnlyHint:!1,destructiveHint:!0,idempotentHint:!1},handler(e,t){return(0,n.handleQuickChange)(e,"manage",t.context,t.apiClient,t.logger,t.metrics,t.mcpServer)}}},2462(e,exports,t){"use strict"
1769
1769
  Object.defineProperty(exports,"__esModule",{value:!0})
1770
- const r=t(2245),n=t(9080),o=t(5692),s=t(9030),i=t(2903),a=t(4607),c=t(9499),l=t(6770),d=t(8045),u=t(9697),h=t(9196),g=t(5459),p=t(4805),f=t(260),m=t(2283),y=t(4165),w=t(7834),k=t(9373),b=t(6111),I=t(700),v=t(2783),C=t(2601),_=t(1722),E=t(7257),q=t(9230),S=t(6064),T=t(5216),P=t(6473),j=t(4921),R=t(8850),x=t(3556),M=t(1391),O=t(6315),$=t(7713),D=t(6252),A=t(213),F=t(7250),N=t(2425),L=t(1540),z=t(5767),H=t(4973),B=t(509),U=t(7613),G=t(8456),W=t(3322),V=t(5247),J=t(8849),K=t(542);(0,r.registerTool)(n.def),(0,r.registerTool)(o.def),(0,r.registerTool)(s.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)(g.def),(0,r.registerTool)(p.def),(0,r.registerTool)(f.def),(0,r.registerTool)(m.def),(0,r.registerTool)(y.def),(0,r.registerTool)(w.def),(0,r.registerTool)(k.def),(0,r.registerTool)(b.def),(0,r.registerTool)(I.def),(0,r.registerTool)(v.def),(0,r.registerTool)(S.def),(0,r.registerTool)(C.def),(0,r.registerTool)(_.def),(0,r.registerTool)(E.def),(0,r.registerTool)(q.def),(0,r.registerTool)(T.def),(0,r.registerTool)(P.def),(0,r.registerTool)(j.def),(0,r.registerTool)(R.def),(0,r.registerTool)(x.def),(0,r.registerTool)(M.def),(0,r.registerTool)(O.def),(0,r.registerTool)($.def),(0,r.registerTool)(D.def),(0,r.registerTool)(A.def),(0,r.registerTool)(F.def),(0,r.registerTool)(N.def),(0,r.registerTool)(L.def),(0,r.registerTool)(z.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)(J.checkingDefs),(0,r.registerTools)(K.debugDefs),(0,t(2245).freezeRegistry)()},2478(e,exports){"use strict"
1770
+ const r=t(2245),n=t(9080),o=t(5692),s=t(9030),i=t(2903),a=t(4607),c=t(9499),l=t(6770),d=t(8045),u=t(9697),h=t(9196),g=t(5459),p=t(4805),f=t(260),m=t(2283),y=t(4165),w=t(7834),k=t(9373),b=t(6111),I=t(700),v=t(2783),C=t(2601),_=t(1722),E=t(7257),q=t(9230),S=t(6064),T=t(5216),P=t(6473),j=t(4921),R=t(8850),x=t(3556),M=t(1391),O=t(6315),D=t(7713),$=t(6252),A=t(213),F=t(7250),N=t(2425),L=t(1540),z=t(5767),H=t(4973),B=t(509),U=t(7613),G=t(8456),W=t(3322),V=t(5247),J=t(8849),K=t(542);(0,r.registerTool)(n.def),(0,r.registerTool)(o.def),(0,r.registerTool)(s.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)(g.def),(0,r.registerTool)(p.def),(0,r.registerTool)(f.def),(0,r.registerTool)(m.def),(0,r.registerTool)(y.def),(0,r.registerTool)(w.def),(0,r.registerTool)(k.def),(0,r.registerTool)(b.def),(0,r.registerTool)(I.def),(0,r.registerTool)(v.def),(0,r.registerTool)(S.def),(0,r.registerTool)(C.def),(0,r.registerTool)(_.def),(0,r.registerTool)(E.def),(0,r.registerTool)(q.def),(0,r.registerTool)(T.def),(0,r.registerTool)(P.def),(0,r.registerTool)(j.def),(0,r.registerTool)(R.def),(0,r.registerTool)(x.def),(0,r.registerTool)(M.def),(0,r.registerTool)(O.def),(0,r.registerTool)(D.def),(0,r.registerTool)($.def),(0,r.registerTool)(A.def),(0,r.registerTool)(F.def),(0,r.registerTool)(N.def),(0,r.registerTool)(L.def),(0,r.registerTool)(z.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)(J.checkingDefs),(0,r.registerTools)(K.debugDefs),(0,t(2245).freezeRegistry)()},2478(e,exports){"use strict"
1771
1771
  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","auto-test-then-merge","manual-review"].includes(e)?e:"auto-merge"},exports.getApprovalMode=function(e){return e&&["none","require-approval"].includes(e)?e:"none"},exports.requestConfig={requireTestsForCompletion:!1}},2537(e,exports,t){"use strict"
1772
1772
  async function r(e,t,r){if(C.has(r)&&_>=t){if(0===t)return 0
1773
1773
  try{return(await y.default.readFile(e,"utf-8")).split("\n").length}catch{return}}}function n(e,t,r){const n="depth"in e,o=n?e:r,s=n?e.isDirectory:e.isDirectory(),a=e.name,c=s?"[\u{1f4c1} DIR]":"[\u{1f4c4} FILE]"
@@ -2296,20 +2296,20 @@ for(const e of j)x.push({type:"document",documentId:e.documentId,replacements:e.
2296
2296
  if(x.length>0&&r.apiClient){const e=x.map((e=>e.documentId))
2297
2297
  try{await(0,f.ensureDocumentsNotLocked)(e,r.apiClient,w,c,"replace-strings-documents")}catch(e){if(e instanceof h.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2298
2298
  throw e}}v=u.FileOperationPhase.TASK_VALIDATION,c.incrementCounter("replace_strings_phase",1,{phase:v})
2299
- const M=R.length>0?R[0].path:"document-operation",O=await u.validateTaskId(T,M,o,w,c,C.metricsPrefix),$=O?.requestId
2300
- let D=null
2301
- R.length>0&&$&&(D=await u.validateWorkItemStates(T,R[0].path,o,i,r,w,c,C.metricsPrefix))
2299
+ const M=R.length>0?R[0].path:"document-operation",O=await u.validateTaskId(T,M,o,w,c,C.metricsPrefix),D=O?.requestId
2300
+ let $=null
2301
+ R.length>0&&D&&($=await u.validateWorkItemStates(T,R[0].path,o,i,r,w,c,C.metricsPrefix))
2302
2302
  let A={taskPromoted:!1,requestPromoted:!1}
2303
- R.length>0&&$&&D&&(A=await u.autoPromoteTaskStatus(T,O.status,$,D.request?.status,R[0].path,o,i,w,c,C.metricsPrefix),A.taskPromoted&&w.info("Auto-promoted task to in_progress for replace-strings operation",{taskId:T,requestId:$,previousStatus:O.status,newStatus:A.newTaskStatus,triggeringOperation:"replace-strings"}))
2304
- const F=await u.ensureCorrectWorkspaceContext({taskPromoted:A.taskPromoted,requestId:$,context:r,operation:"replace-strings",logger:w,metrics:c,metricsPrefix:C.metricsPrefix})
2303
+ R.length>0&&D&&$&&(A=await u.autoPromoteTaskStatus(T,O.status,D,$.request?.status,R[0].path,o,i,w,c,C.metricsPrefix),A.taskPromoted&&w.info("Auto-promoted task to in_progress for replace-strings operation",{taskId:T,requestId:D,previousStatus:O.status,newStatus:A.newTaskStatus,triggeringOperation:"replace-strings"}))
2304
+ const F=await u.ensureCorrectWorkspaceContext({taskPromoted:A.taskPromoted,requestId:D,context:r,operation:"replace-strings",logger:w,metrics:c,metricsPrefix:C.metricsPrefix})
2305
2305
  if(!F.success){if(F.isLockConflict)return{content:[{type:"text",text:"\u274c "+F.error}],isError:!0}
2306
2306
  throw Error(F.error)}if(R.length>0){w.debug("Re-validating file paths with correct workspace context",{operationCount:R.length,workspaceBasePath:r.workspaceManager?.getCurrentContext(r.currentSessionId).basePath})
2307
2307
  for(let e=0;e<R.length;e++){const t=R[e],n=P[e],{normalizedPath:o,fullPath:s}=u.validateAndNormalizePath(n.path,r)
2308
- R[e]={...t,path:o,fullPath:s}}}if(x.length>0&&$)try{await(0,g.validateRequestStatusForDocumentOperation)($,i,w,c,"replace-strings-document")}catch(e){if(e instanceof h.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2308
+ R[e]={...t,path:o,fullPath:s}}}if(x.length>0&&D)try{await(0,g.validateRequestStatusForDocumentOperation)(D,i,w,c,"replace-strings-document")}catch(e){if(e instanceof h.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2309
2309
  throw e}v=u.FileOperationPhase.RECORD_CREATION,c.incrementCounter("replace_strings_phase",1,{phase:v})
2310
- const N=[...R.map((e=>({type:"file",path:e.path,replacements:e.replacements,mode:e.mode}))),...x.map((e=>({type:"document",documentId:e.documentId,replacements:e.replacements,mode:e.mode})))],{toolRecordId:L}=await u.createFileOperationRecords(T,$,r.projectId,C.recordType,M,{operationCount:E.length,fileOperations:R.length,documentOperations:x.length,operations:N,userComment:q},o,s,w,c,C.metricsPrefix,y)
2310
+ const N=[...R.map((e=>({type:"file",path:e.path,replacements:e.replacements,mode:e.mode}))),...x.map((e=>({type:"document",documentId:e.documentId,replacements:e.replacements,mode:e.mode})))],{toolRecordId:L}=await u.createFileOperationRecords(T,D,r.projectId,C.recordType,M,{operationCount:E.length,fileOperations:R.length,documentOperations:x.length,operations:N,userComment:q},o,s,w,c,C.metricsPrefix,y)
2311
2311
  if(b=L,I=L,v=C.fileOperationPhase,c.incrementCounter("replace_strings_phase",1,{phase:v}),R.length>0&&r.git)try{w.debug("[REPLACE-STRINGS] Checking for user changes before replace operations")
2312
- const e=await(0,p.commitUserChangesBeforeToolOperation)(r.git,"replace-strings",{requestId:$,taskId:T,workspaceManager:r.workspaceManager},w,c)
2312
+ const e=await(0,p.commitUserChangesBeforeToolOperation)(r.git,"replace-strings",{requestId:D,taskId:T,workspaceManager:r.workspaceManager},w,c)
2313
2313
  e.userChangesCommitted&&(w.debug("[REPLACE-STRINGS] User changes committed before replace operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),w.info("User changes committed before replace-strings operation",{taskId:T,fileOperationsCount:R.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){w.debug("[REPLACE-STRINGS] 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:T,fileOperationsCount:R.length,error:e instanceof Error?e.message:e+""})}w.debug("[REPLACE-STRINGS] Proceeding with file operations",{fileCount:R.length})
2314
2314
  const z=[]
2315
2315
  let H=0,B=0
@@ -2673,7 +2673,7 @@ let v,C,_=d.FileOperationPhase.VALIDATION
2673
2673
  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"}
2674
2674
  try{const n=d.validateArgs(e,l.WriteFileSchema),{path:f,documentId:q,content:S,format:T,append:P,comment:j}=n,{resolveActiveTaskId:R}=await Promise.resolve().then(t.bind(t,3451)),x=e.taskId||await R(r,o,m)||"untracked",M=!!q,O=!!f
2675
2675
  k.info("Writing content to "+(M?"document":"file"),{taskId:x,filePath:O?f:void 0,documentId:M?q:void 0,contentLength:"string"==typeof S?S.length:JSON.stringify(S).length,format:T,append:P,comment:j})
2676
- let $,D,A,F="",N=!1,L=!1
2676
+ let D,$,A,F="",N=!1,L=!1
2677
2677
  const z=O?f:void 0
2678
2678
  if(M){if(r.apiClient)try{await(0,p.ensureDocumentNotLocked)(q,r.apiClient,k,y,"write_file-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2679
2679
  throw e}if(!r.documentFileManager)throw Error("Document file manager not available")
@@ -2688,26 +2688,26 @@ O&&U&&G&&(W=await d.autoPromoteTaskStatus(x,B.status,U,G.request?.status,H,o,i,k
2688
2688
  const V=await d.ensureCorrectWorkspaceContext({taskPromoted:W.taskPromoted,requestId:U,context:r,operation:"write_file",logger:k,metrics:y,metricsPrefix:E.metricsPrefix,requireRequestContext:O})
2689
2689
  if(!V.success){if(V.isLockConflict)return{content:[{type:"text",text:"\u274c "+V.error}],isError:!0}
2690
2690
  throw Error(V.error)}if(V.switched&&k.info("Workspace context successfully established",{requestId:U,branchName:V.branchName,operation:"write_file"}),O&&z){const e=d.validateAndNormalizePath(z,r)
2691
- $=e.normalizedPath,D=e.fullPath,F=D
2692
- try{await c.default.access(D),L=!0}catch{L=!1,N=!0}k.debug("Path validated with correct workspace context",{rawPath:z,normalizedPath:$,fullPath:D,workspaceBasePath:r.workspaceManager?.getCurrentContext(r.currentSessionId).basePath})}if(M&&U)try{await(0,h.validateRequestStatusForDocumentOperation)(U,i,k,y,"write_file-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2691
+ D=e.normalizedPath,$=e.fullPath,F=$
2692
+ try{await c.default.access($),L=!0}catch{L=!1,N=!0}k.debug("Path validated with correct workspace context",{rawPath:z,normalizedPath:D,fullPath:$,workspaceBasePath:r.workspaceManager?.getCurrentContext(r.currentSessionId).basePath})}if(M&&U)try{await(0,h.validateRequestStatusForDocumentOperation)(U,i,k,y,"write_file-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2693
2693
  throw e}_=d.FileOperationPhase.RECORD_CREATION,y.incrementCounter("write_file_phase",1,{phase:_})
2694
- const{toolRecordId:J}=await d.createFileOperationRecords(x,U,r.projectId,E.recordType,H,{operationType:M?"document":"file",documentId:M?q:void 0,documentFilename:A,filePath:O?$:void 0,contentLength:"string"==typeof S?S.length:JSON.stringify(S).length,format:T||"text",append:P||!1,wasFileCreated:!L,userComment:j},o,s,k,y,E.metricsPrefix,w)
2694
+ const{toolRecordId:J}=await d.createFileOperationRecords(x,U,r.projectId,E.recordType,H,{operationType:M?"document":"file",documentId:M?q:void 0,documentFilename:A,filePath:O?D:void 0,contentLength:"string"==typeof S?S.length:JSON.stringify(S).length,format:T||"text",append:P||!1,wasFileCreated:!L,userComment:j},o,s,k,y,E.metricsPrefix,w)
2695
2695
  let K
2696
2696
  if(v=J,C=J,_=E.fileOperationPhase,y.incrementCounter("write_file_phase",1,{phase:_}),"json"===T)if("string"==typeof S)try{JSON.parse(S),K=S}catch(e){throw new u.ValidationError("Content is not valid JSON")}else K=JSON.stringify(S,null,2)
2697
2697
  else K="string"==typeof S?S:JSON.stringify(S,null,2)
2698
2698
  let Y=K
2699
2699
  if(O&&r.git)try{k.debug("[WRITE-FILE] Checking for user changes before write operation")
2700
2700
  const e=await(0,g.commitUserChangesBeforeToolOperation)(r.git,"write_file",{requestId:r.workspaceManager?.getCurrentContext(r.currentSessionId)?.requestId,taskId:x},k,y)
2701
- e.userChangesCommitted&&(k.debug("[WRITE-FILE] User changes committed before write operation",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),k.info("User changes committed before write-file operation",{taskId:x,path:$,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){k.debug("[WRITE-FILE] Pre-tool commit failed, continuing with write",{error:e instanceof Error?e.message:e+""}),k.warn("Pre-tool user changes commit failed, continuing with write operation",{taskId:x,path:$,error:e instanceof Error?e.message:e+""})}if(!F)throw Error("Target path not properly initialized")
2701
+ e.userChangesCommitted&&(k.debug("[WRITE-FILE] User changes committed before write operation",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),k.info("User changes committed before write-file operation",{taskId:x,path:D,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){k.debug("[WRITE-FILE] Pre-tool commit failed, continuing with write",{error:e instanceof Error?e.message:e+""}),k.warn("Pre-tool user changes commit failed, continuing with write operation",{taskId:x,path:D,error:e instanceof Error?e.message:e+""})}if(!F)throw Error("Target path not properly initialized")
2702
2702
  if(k.debug("[WRITE-FILE] Proceeding with file write operation",{targetPath:F}),P&&L)try{Y=await c.default.readFile(F,"utf8")+K}catch(e){k.warn("Failed to read existing content for append",{error:e})}const Q=a.default.dirname(F)
2703
- if(await c.default.mkdir(Q,{recursive:!0}),await c.default.writeFile(F,Y,"utf8"),k.info("Content written successfully",{path:O?$:"document:"+q,finalLength:Y.length,append:P,wasCreated:N}),M){r.documentFileManager.markForSync(q)
2703
+ if(await c.default.mkdir(Q,{recursive:!0}),await c.default.writeFile(F,Y,"utf8"),k.info("Content written successfully",{path:O?D:"document:"+q,finalLength:Y.length,append:P,wasCreated:N}),M){r.documentFileManager.markForSync(q)
2704
2704
  try{await r.documentFileManager.syncDocument(q),k.info("Document synced successfully",{documentId:q})}catch(e){k.warn("Failed to sync document immediately",{documentId:q,error:e})}}let Z,X,ee=null,te=!1
2705
2705
  if(O){if(_=d.FileOperationPhase.GIT_COMMIT,y.incrementCounter("write_file_phase",1,{phase:_}),r.workspaceManager){const e=r.workspaceManager.getCurrentContext(r.currentSessionId)
2706
- X=e.branchName,te=e.permanentBranch,k.debug("Retrieved branch name from workspace manager",{branchName:X,requestId:e.requestId,mode:e.mode,isMainBranch:e.isMainBranch})}try{const e=`${N?"Create":P?"Append to":"Update"} ${$} (${C})`,t=await d.commitToGit(x,$,C,C,e,r,k,y,E.metricsPrefix)
2707
- Z=t.commitHash,ee=t.previousCommitHash,k.info("Changes committed to git via shared utility",{path:$,commitMessage:e,commitHash:Z?.substring(0,8),previousCommitHash:ee?.substring(0,8),branchName:X,toolRecordId:C})}catch(e){k.warn("Git operations failed via shared utility",{error:e})}}try{await s.updateToolRecord(C,{metadata:{path:O?$:"document:"+q,status:"completed",finalContentLength:Y.length,wasFileCreated:N,wasAppended:P&&L,operationType:M?"document":"file",processingTime:Date.now()-I,userComment:j,...O&&Z&&{commitHash:Z,previousCommitHash:ee||void 0}},note:"Write operation completed successfully"+(M?" (document synced)":" (committed to git)")})}catch(e){k.warn("Failed to update tool record",{recordError:e})}let re=`**${N?"Created":P?"Appended to":"Updated"} ${M?`document ${q}${A?` (${A})`:""}`:"file "+$}**\n`
2706
+ X=e.branchName,te=e.permanentBranch,k.debug("Retrieved branch name from workspace manager",{branchName:X,requestId:e.requestId,mode:e.mode,isMainBranch:e.isMainBranch})}try{const e=`${N?"Create":P?"Append to":"Update"} ${D} (${C})`,t=await d.commitToGit(x,D,C,C,e,r,k,y,E.metricsPrefix)
2707
+ Z=t.commitHash,ee=t.previousCommitHash,k.info("Changes committed to git via shared utility",{path:D,commitMessage:e,commitHash:Z?.substring(0,8),previousCommitHash:ee?.substring(0,8),branchName:X,toolRecordId:C})}catch(e){k.warn("Git operations failed via shared utility",{error:e})}}try{await s.updateToolRecord(C,{metadata:{path:O?D:"document:"+q,status:"completed",finalContentLength:Y.length,wasFileCreated:N,wasAppended:P&&L,operationType:M?"document":"file",processingTime:Date.now()-I,userComment:j,...O&&Z&&{commitHash:Z,previousCommitHash:ee||void 0}},note:"Write operation completed successfully"+(M?" (document synced)":" (committed to git)")})}catch(e){k.warn("Failed to update tool record",{recordError:e})}let re=`**${N?"Created":P?"Appended to":"Updated"} ${M?`document ${q}${A?` (${A})`:""}`:"file "+D}**\n`
2708
2708
  re+=`**Content Length:** ${Y.length} characters\n`,O&&X&&(te||(re+=`**Branch:** ${X}\n`)),V.lockAcquired&&V.lockedRequestId&&!te&&(re+=`**Locked request:** ${V.lockedRequestId}\n`),O&&Z&&(re+=`**Commit Hash:** ${Z.substring(0,8)}\n`,ee&&(re+=`**Previous Commit:** ${ee.substring(0,8)}\n`)),C&&(re+=`[RECORD:${C}]\n`),M&&(re+=`\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 \`${q}\`.`)
2709
2709
  const ne=Date.now()
2710
- return k.info("Write operation completed successfully",{duration:ne-I,path:O?$:"document:"+q,contentLength:Y.length,wasCreated:N}),b({tool:"write_file",success:!0}),y.incrementCounter("write_file_total",1,{success:!0}),r.workspaceManager?.largeFileWarning&&(re+=r.workspaceManager.largeFileWarning,r.workspaceManager.largeFileWarning=""),{content:[{type:"text",text:re}]}}catch(t){const r=Date.now()-I
2710
+ return k.info("Write operation completed successfully",{duration:ne-I,path:O?D:"document:"+q,contentLength:Y.length,wasCreated:N}),b({tool:"write_file",success:!0}),y.incrementCounter("write_file_total",1,{success:!0}),r.workspaceManager?.largeFileWarning&&(re+=r.workspaceManager.largeFileWarning,r.workspaceManager.largeFileWarning=""),{content:[{type:"text",text:re}]}}catch(t){const r=Date.now()-I
2711
2711
  if(k.error("Write operation failed",{error:t instanceof Error?t.stack:t+"",duration:r,phase:_}),C)try{await s.updateToolRecord(C,{metadata:{path:e?.path,status:"failed",error:(0,f.getErrorMessage)(t),phase:_,duration:r,userComment:e?.comment},note:"Write operation failed: "+(0,f.getErrorMessage)(t)})}catch(e){}return b({tool:"write_file",success:!1}),y.incrementCounter("write_file_errors",1,{phase:_}),{content:[{type:"text",text:"\u274c **Write Operation Failed:** "+(0,f.getErrorMessage)(t)}],isError:!0}}}
2712
2712
  const a=i(t(6928)),c=i(t(1943)),l=t(6183),d=s(t(5967)),u=t(9860),h=t(5003),g=t(7478),p=t(9949),f=t(8824)},4118(e,exports){"use strict"
2713
2713
  Object.defineProperty(exports,"__esModule",{value:!0})},4139(e,exports){"use strict"
@@ -3467,10 +3467,10 @@ const R=j.filter((e=>"file"===e.type)),x=j.filter((e=>"document"===e.type)),M=j.
3467
3467
  m.info("Starting mixed file and document deletion operation",{taskId:P,totalOperations:j.length,fileOperations:R.length,documentOperations:x.length,comment:S}),l.validateTaskIdFormat(P,m,s,I.metricsPrefix)
3468
3468
  const O=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
3469
3469
  m.info("Initial branch context",{initialBranch:O.branch,initialRequestId:O.requestId,isMain:O.isMain})
3470
- const $=[]
3470
+ const D=[]
3471
3471
  for(const e of R){const{normalizedPath:t,fullPath:n}=l.validateAndNormalizePath(e.target,r)
3472
- $.push({normalized:t,full:n})}b=l.FileOperationPhase.TASK_VALIDATION,s.incrementCounter("delete_files_phase",1,{phase:b})
3473
- const D=$.length>0?$[0].normalized:"document_operations",A=await l.validateTaskId(P,D,u,m,s,I.metricsPrefix),F=A?.requestId,N=await l.validateWorkItemStates(P,D,u,C,r,m,s,I.metricsPrefix),L=await l.autoPromoteTaskStatus(P,A.status,F,N.request?.status,D,u,C,m,s,I.metricsPrefix)
3472
+ D.push({normalized:t,full:n})}b=l.FileOperationPhase.TASK_VALIDATION,s.incrementCounter("delete_files_phase",1,{phase:b})
3473
+ const $=D.length>0?D[0].normalized:"document_operations",A=await l.validateTaskId(P,$,u,m,s,I.metricsPrefix),F=A?.requestId,N=await l.validateWorkItemStates(P,$,u,C,r,m,s,I.metricsPrefix),L=await l.autoPromoteTaskStatus(P,A.status,F,N.request?.status,$,u,C,m,s,I.metricsPrefix)
3474
3474
  L.taskPromoted&&m.info(`Auto-promoted task ${P} (${A.title||"Untitled"}) to in_progress for mixed operations`,{taskId:P,taskTitle:A.title,previousStatus:A.status,newStatus:L.newTaskStatus,totalOperations:j.length,fileOperations:R.length,documentOperations:x.length}),L.requestPromoted&&m.info(`Auto-promoted request ${F} to in_progress for file operations`,{requestId:F,previousStatus:N.request?.status,newStatus:L.newRequestStatus,triggeringTaskId:P})
3475
3475
  const z=await l.ensureCorrectWorkspaceContext({taskPromoted:L.taskPromoted,requestId:F,context:r,operation:"delete-files",logger:m,metrics:s,metricsPrefix:I.metricsPrefix})
3476
3476
  if(!z.success){if(z.isLockConflict)return{content:[{type:"text",text:"\u274c "+z.error}],isError:!0}
@@ -3478,12 +3478,12 @@ throw Error(z.error)}let H={hadUserMods:!1,userModsCommitHash:void 0}
3478
3478
  if(r.git)try{m.debug("[DELETE-FILES] Checking for user changes before mixed delete operations")
3479
3479
  const e=await(0,h.commitUserChangesBeforeToolOperation)(r.git,"delete-files",{requestId:F,taskId:P,workspaceManager:r.workspaceManager},m,s)
3480
3480
  e.userChangesCommitted&&(m.debug("[DELETE-FILES] User changes committed before mixed delete operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),m.info("User changes committed before mixed delete-files operation",{taskId:P,totalOperations:j.length,fileOperations:R.length,documentOperations:x.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}),H={hadUserMods:!0,userModsCommitHash:e.commitHash})}catch(e){m.debug("[DELETE-FILES] Pre-tool commit failed, continuing with mixed delete operations",{error:e instanceof Error?e.message:e+""}),m.warn("Pre-tool user changes commit failed, continuing with mixed delete operation",{taskId:P,totalOperations:j.length,fileOperations:R.length,documentOperations:x.length,error:e instanceof Error?e.message:e+""})}m.debug("[DELETE-FILES] Proceeding with mixed delete operations",{totalOperations:j.length,fileDeletes:R.length,documentDeletes:x.length}),b=l.FileOperationPhase.RECORD_CREATION,s.incrementCounter("delete_files_phase",1,{phase:b})
3481
- const{toolRecordId:B,localToolRecordId:U}=await l.createFileOperationRecords(P,F,r.projectId,I.recordType,D,{totalOperations:j.length,fileOperations:R.length,documentOperations:x.length,filePaths:$.map((e=>e.normalized)),documentIds:x.map((e=>e.target)),userComment:S,hadUserMods:H.hadUserMods,userModsCommitHash:H.userModsCommitHash},u,v,m,s,I.metricsPrefix,i)
3481
+ const{toolRecordId:B,localToolRecordId:U}=await l.createFileOperationRecords(P,F,r.projectId,I.recordType,$,{totalOperations:j.length,fileOperations:R.length,documentOperations:x.length,filePaths:D.map((e=>e.normalized)),documentIds:x.map((e=>e.target)),userComment:S,hadUserMods:H.hadUserMods,userModsCommitHash:H.userModsCommitHash},u,v,m,s,I.metricsPrefix,i)
3482
3482
  w=B,k=B,b=I.fileOperationPhase,s.incrementCounter("delete_files_phase",1,{phase:b})
3483
3483
  const G=[]
3484
3484
  let W=0
3485
3485
  x.length>0&&n.setProjectId(r.projectId)
3486
- for(let e=0;e<$.length;e++){const t=$[e],r={type:"file",path:t.normalized,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0}
3486
+ for(let e=0;e<D.length;e++){const t=D[e],r={type:"file",path:t.normalized,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0}
3487
3487
  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)
3488
3488
  await a.default.unlink(t.full),r.success=!0,W++,m.info("Successfully deleted file",{path:t.normalized})}catch(e){r.error=(0,f.getErrorMessage)(e),m.warn("Failed to delete file "+t.normalized,{error:r.error})}G.push(r)}const V=x.length>0?n.getDocumentClient():null
3489
3489
  for(const e of x){const t=e.target,r={type:"document",documentId:t,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0}
@@ -3497,9 +3497,9 @@ let K=null
3497
3497
  if(W>0){b=l.FileOperationPhase.GIT_COMMIT,s.incrementCounter("delete_files_phase",1,{phase:b})
3498
3498
  const e=G.filter((e=>e.success)),t=e.filter((e=>"file"===e.type)).length,n=e.filter((e=>"document"===e.type)).length
3499
3499
  let o
3500
- o=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 l.commitToGit(P,D,B,U,o,r,m,s,I.metricsPrefix)}b=l.FileOperationPhase.RECORD_UPDATE_SUCCESS,s.incrementCounter("delete_files_phase",1,{phase:b})
3500
+ o=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 l.commitToGit(P,$,B,U,o,r,m,s,I.metricsPrefix)}b=l.FileOperationPhase.RECORD_UPDATE_SUCCESS,s.incrementCounter("delete_files_phase",1,{phase:b})
3501
3501
  const Y=G.filter((e=>e.success)),Q=G.filter((e=>!e.success))
3502
- await l.updateFileOperationRecords(P,w,k,D,I.recordType,W===M?`Successfully deleted all ${M} operations`:`Deleted ${W}/${M} operations successfully`,{status:W===M?"completed":"partial_success",commitHash:K?.commitHash,previousCommitHash:K?.previousCommitHash,totalOperations:M,fileOperations:R.length,documentOperations:x.length,successCount:W,failureCount:M-W,successfulOperations:Y.map((e=>({type:e.type,path:e.path,documentId:e.documentId,filename:e.filename}))),failedOperations:Q.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===M?`Successfully deleted all ${M} operations`:`Deleted ${W}/${M} operations successfully`,u,v,m,s,I.metricsPrefix)
3502
+ await l.updateFileOperationRecords(P,w,k,$,I.recordType,W===M?`Successfully deleted all ${M} operations`:`Deleted ${W}/${M} operations successfully`,{status:W===M?"completed":"partial_success",commitHash:K?.commitHash,previousCommitHash:K?.previousCommitHash,totalOperations:M,fileOperations:R.length,documentOperations:x.length,successCount:W,failureCount:M-W,successfulOperations:Y.map((e=>({type:e.type,path:e.path,documentId:e.documentId,filename:e.filename}))),failedOperations:Q.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===M?`Successfully deleted all ${M} operations`:`Deleted ${W}/${M} operations successfully`,u,v,m,s,I.metricsPrefix)
3503
3503
  const Z=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
3504
3504
  let X=""
3505
3505
  if(W===M){const e=Y.filter((e=>"file"===e.type)).length,t=Y.filter((e=>"document"===e.type)).length
@@ -3741,20 +3741,20 @@ for(const e of j)x.push({type:"document",documentId:e.documentId,insertions:e.in
3741
3741
  if(x.length>0&&n.apiClient){const e=x.map((e=>e.documentId))
3742
3742
  try{await(0,p.ensureDocumentsNotLocked)(e,n.apiClient,w,m,"insert-lines-documents")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3743
3743
  throw e}}v=d.FileOperationPhase.TASK_VALIDATION,m.incrementCounter("insert_lines_phase",1,{phase:v})
3744
- const M=R.length>0?R[0].path:"document-operation",O=await d.validateTaskId(T,M,o,w,m,C.metricsPrefix),$=O?.requestId
3745
- let D=null
3746
- R.length>0&&$&&(D=await d.validateWorkItemStates(T,R[0].path,o,i,n,w,m,C.metricsPrefix))
3744
+ const M=R.length>0?R[0].path:"document-operation",O=await d.validateTaskId(T,M,o,w,m,C.metricsPrefix),D=O?.requestId
3745
+ let $=null
3746
+ R.length>0&&D&&($=await d.validateWorkItemStates(T,R[0].path,o,i,n,w,m,C.metricsPrefix))
3747
3747
  let A={taskPromoted:!1,requestPromoted:!1}
3748
- R.length>0&&$&&D&&(A=await d.autoPromoteTaskStatus(T,O.status,$,D.request?.status,R[0].path,o,i,w,m,C.metricsPrefix),A.taskPromoted&&w.info("Auto-promoted task to in_progress for insert-lines operation",{taskId:T,requestId:$,previousStatus:O.status,newStatus:A.newTaskStatus,triggeringOperation:"insert-lines"}))
3749
- const F=await d.ensureCorrectWorkspaceContext({taskPromoted:A.taskPromoted,requestId:$,context:n,operation:"insert-lines",logger:w,metrics:m,metricsPrefix:C.metricsPrefix})
3748
+ R.length>0&&D&&$&&(A=await d.autoPromoteTaskStatus(T,O.status,D,$.request?.status,R[0].path,o,i,w,m,C.metricsPrefix),A.taskPromoted&&w.info("Auto-promoted task to in_progress for insert-lines operation",{taskId:T,requestId:D,previousStatus:O.status,newStatus:A.newTaskStatus,triggeringOperation:"insert-lines"}))
3749
+ const F=await d.ensureCorrectWorkspaceContext({taskPromoted:A.taskPromoted,requestId:D,context:n,operation:"insert-lines",logger:w,metrics:m,metricsPrefix:C.metricsPrefix})
3750
3750
  if(!F.success){if(F.isLockConflict)return{content:[{type:"text",text:"\u274c "+F.error}],isError:!0}
3751
3751
  throw Error(F.error)}if(R.length>0){w.debug("Re-validating file paths with correct workspace context",{operationCount:R.length,workspaceBasePath:n.workspaceManager?.getCurrentContext(n.currentSessionId).basePath})
3752
3752
  for(let e=0;e<R.length;e++){const t=R[e],r=P[e],{normalizedPath:o,fullPath:s}=d.validateAndNormalizePath(r.path,n)
3753
- R[e]={...t,path:o,fullPath:s}}}if(x.length>0&&$)try{await(0,h.validateRequestStatusForDocumentOperation)($,i,w,m,"insert-lines-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3753
+ R[e]={...t,path:o,fullPath:s}}}if(x.length>0&&D)try{await(0,h.validateRequestStatusForDocumentOperation)(D,i,w,m,"insert-lines-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3754
3754
  throw e}v=d.FileOperationPhase.RECORD_CREATION,m.incrementCounter("insert_lines_phase",1,{phase:v})
3755
- const N=[...R.map((e=>({type:"file",path:e.path,insertions:e.insertions}))),...x.map((e=>({type:"document",documentId:e.documentId,insertions:e.insertions})))],{toolRecordId:L}=await d.createFileOperationRecords(T,$,n.projectId,C.recordType,M,{operationCount:E.length,fileOperations:R.length,documentOperations:x.length,operations:N,userComment:q},o,s,w,m,C.metricsPrefix,y)
3755
+ const N=[...R.map((e=>({type:"file",path:e.path,insertions:e.insertions}))),...x.map((e=>({type:"document",documentId:e.documentId,insertions:e.insertions})))],{toolRecordId:L}=await d.createFileOperationRecords(T,D,n.projectId,C.recordType,M,{operationCount:E.length,fileOperations:R.length,documentOperations:x.length,operations:N,userComment:q},o,s,w,m,C.metricsPrefix,y)
3756
3756
  if(b=L,I=L,v=C.fileOperationPhase,m.incrementCounter("insert_lines_phase",1,{phase:v}),R.length>0&&n.git)try{w.debug("[INSERT-LINES] Checking for user changes before insert operations")
3757
- const e=await(0,g.commitUserChangesBeforeToolOperation)(n.git,"insert-lines",{requestId:$,taskId:T,workspaceManager:n.workspaceManager},w,m)
3757
+ const e=await(0,g.commitUserChangesBeforeToolOperation)(n.git,"insert-lines",{requestId:D,taskId:T,workspaceManager:n.workspaceManager},w,m)
3758
3758
  e.userChangesCommitted&&(w.debug("[INSERT-LINES] User changes committed before insert operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),w.info("User changes committed before insert-lines operation",{taskId:T,fileOperationsCount:R.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){w.debug("[INSERT-LINES] Pre-tool commit failed, continuing with insertions",{error:e instanceof Error?e.message:e+""}),w.warn("Pre-tool user changes commit failed, continuing with insert operation",{taskId:T,fileOperationsCount:R.length,error:e instanceof Error?e.message:e+""})}w.debug("[INSERT-LINES] Proceeding with file operations",{fileCount:R.length})
3759
3759
  const z=[]
3760
3760
  let H=0,B=0,U=0
@@ -3894,20 +3894,20 @@ for(const e of R)M.push({type:"document",documentId:e.documentId,replacements:e.
3894
3894
  if(M.length>0&&n.apiClient){const e=M.map((e=>e.documentId))
3895
3895
  try{await(0,p.ensureDocumentsNotLocked)(e,n.apiClient,k,m,"replace-lines-documents")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3896
3896
  throw e}}C=d.FileOperationPhase.TASK_VALIDATION,m.incrementCounter("replace_lines_phase",1,{phase:C})
3897
- const O=x.length>0?x[0].path:"document-operation",$=await d.validateTaskId(P,O,o,k,m,_.metricsPrefix),D=$?.requestId
3897
+ const O=x.length>0?x[0].path:"document-operation",D=await d.validateTaskId(P,O,o,k,m,_.metricsPrefix),$=D?.requestId
3898
3898
  let A=null
3899
- x.length>0&&D&&(A=await d.validateWorkItemStates(P,x[0].path,o,i,n,k,m,_.metricsPrefix))
3899
+ x.length>0&&$&&(A=await d.validateWorkItemStates(P,x[0].path,o,i,n,k,m,_.metricsPrefix))
3900
3900
  let F={taskPromoted:!1,requestPromoted:!1}
3901
- x.length>0&&D&&A&&(F=await d.autoPromoteTaskStatus(P,$.status,D,A.request?.status,x[0].path,o,i,k,m,_.metricsPrefix),F.taskPromoted&&k.info("Auto-promoted task to in_progress for replace-lines operation",{taskId:P,requestId:D,previousStatus:$.status,newStatus:F.newTaskStatus,triggeringOperation:"replace-lines"}))
3902
- const N=await d.ensureCorrectWorkspaceContext({taskPromoted:F.taskPromoted,requestId:D,context:n,operation:"replace-lines",logger:k,metrics:m,metricsPrefix:_.metricsPrefix})
3901
+ x.length>0&&$&&A&&(F=await d.autoPromoteTaskStatus(P,D.status,$,A.request?.status,x[0].path,o,i,k,m,_.metricsPrefix),F.taskPromoted&&k.info("Auto-promoted task to in_progress for replace-lines operation",{taskId:P,requestId:$,previousStatus:D.status,newStatus:F.newTaskStatus,triggeringOperation:"replace-lines"}))
3902
+ const N=await d.ensureCorrectWorkspaceContext({taskPromoted:F.taskPromoted,requestId:$,context:n,operation:"replace-lines",logger:k,metrics:m,metricsPrefix:_.metricsPrefix})
3903
3903
  if(!N.success){if(N.isLockConflict)return{content:[{type:"text",text:"\u274c "+N.error}],isError:!0}
3904
3904
  throw Error(N.error)}if(x.length>0){k.debug("Re-validating file paths with correct workspace context",{operationCount:x.length,workspaceBasePath:n.workspaceManager?.getCurrentContext(n.currentSessionId).basePath})
3905
3905
  for(let e=0;e<x.length;e++){const t=x[e],r=j[e],{normalizedPath:o,fullPath:s}=d.validateAndNormalizePath(r.path,n)
3906
- x[e]={...t,path:o,fullPath:s}}}if(M.length>0&&D)try{await(0,h.validateRequestStatusForDocumentOperation)(D,i,k,m,"replace-lines-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3906
+ x[e]={...t,path:o,fullPath:s}}}if(M.length>0&&$)try{await(0,h.validateRequestStatusForDocumentOperation)($,i,k,m,"replace-lines-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
3907
3907
  throw e}C=d.FileOperationPhase.RECORD_CREATION,m.incrementCounter("replace_lines_phase",1,{phase:C})
3908
- const L=[...x.map((e=>({type:"file",path:e.path,replacements:e.replacements}))),...M.map((e=>({type:"document",documentId:e.documentId,replacements:e.replacements})))],{toolRecordId:z}=await d.createFileOperationRecords(P,D,n.projectId,_.recordType,O,{operationCount:q.length,fileOperations:x.length,documentOperations:M.length,operations:L,userComment:S},o,s,k,m,_.metricsPrefix,w)
3908
+ const L=[...x.map((e=>({type:"file",path:e.path,replacements:e.replacements}))),...M.map((e=>({type:"document",documentId:e.documentId,replacements:e.replacements})))],{toolRecordId:z}=await d.createFileOperationRecords(P,$,n.projectId,_.recordType,O,{operationCount:q.length,fileOperations:x.length,documentOperations:M.length,operations:L,userComment:S},o,s,k,m,_.metricsPrefix,w)
3909
3909
  if(I=z,v=z,C=_.fileOperationPhase,m.incrementCounter("replace_lines_phase",1,{phase:C}),x.length>0&&n.git)try{k.debug("[REPLACE-LINES] Checking for user changes before replace operations")
3910
- const e=await(0,g.commitUserChangesBeforeToolOperation)(n.git,"replace-lines",{requestId:D,taskId:P,workspaceManager:n.workspaceManager},k,m)
3910
+ const e=await(0,g.commitUserChangesBeforeToolOperation)(n.git,"replace-lines",{requestId:$,taskId:P,workspaceManager:n.workspaceManager},k,m)
3911
3911
  e.userChangesCommitted&&(k.debug("[REPLACE-LINES] User changes committed before replace operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),k.info("User changes committed before replace-lines operation",{taskId:P,fileOperationsCount:x.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){k.debug("[REPLACE-LINES] Pre-tool commit failed, continuing with replacements",{error:e instanceof Error?e.message:e+""}),k.warn("Pre-tool user changes commit failed, continuing with replace operation",{taskId:P,fileOperationsCount:x.length,error:e instanceof Error?e.message:e+""})}k.debug("[REPLACE-LINES] Proceeding with file operations",{fileCount:x.length})
3912
3912
  const H=[]
3913
3913
  let B=0,U=0,G=0,W=0
@@ -4066,7 +4066,7 @@ n&&n.push({filePath:r,recordId:e.id,type:"replace-in-files",timestamp:e.createdA
4066
4066
  C.has(t)||C.set(t,[])
4067
4067
  const r=C.get(t)
4068
4068
  r&&r.push({filePath:t,recordId:e.id,type:e.type,timestamp:e.createdAt,commitHash:e.metadata.commitHash,status:e.metadata.status||"",record:e})})),s.info(`Grouped records by file path. Found ${C.size} unique files.`)
4069
- for(const[$,D]of C.entries())D.sort(((e,t)=>new Date(e.timestamp).getTime()-new Date(t.timestamp).getTime())),s.info(`File ${$} has ${D.length} records.`),s.info("Records with commit hashes: "+D.filter((e=>e.commitHash)).length)
4069
+ for(const[D,$]of C.entries())$.sort(((e,t)=>new Date(e.timestamp).getTime()-new Date(t.timestamp).getTime())),s.info(`File ${D} has ${$.length} records.`),s.info("Records with commit hashes: "+$.filter((e=>e.commitHash)).length)
4070
4070
  const _=new Map
4071
4071
  for(const[A,F]of C.entries()){s.info(`Processing file: ${A} (${F.length} records)`)
4072
4072
  const N=new Map
@@ -4118,8 +4118,8 @@ for(const Pe of I.allMoves)E+=`- **${Pe.source}** \u2192 **${Pe.destination}**\n
4118
4118
  for(const[je,Re]of _.entries()){const{normalizedPath:xe,fullPath:Me}=d.validateAndNormalizePath(je,t)
4119
4119
  let Oe=!1
4120
4120
  try{await a.access(Me),Oe=!0}catch{}E+=`### ${je} ${Oe?"":"(Deleted)"}\n\n`
4121
- const $e=new Date(Re.firstChange.timestamp).toLocaleString(),De=new Date(Re.lastChange.timestamp).toLocaleString()
4122
- E+=`**First Change**: ${$e}\n`,E+=`**Last Change**: ${De}\n`,"pre-task"===Re.firstChange.status&&Re.firstChange.commitHash?E+=`**Pre-Task Commit**: ${Re.firstChange.commitHash.substring(0,8)}\n`:Re.firstChange.commitHash&&(E+=`**File Created During Task**: ${Re.firstChange.commitHash.substring(0,8)}\n`),Re.lastChange.commitHash&&(E+=`**Final Commit**: ${Re.lastChange.commitHash.substring(0,8)}\n`)
4121
+ const De=new Date(Re.firstChange.timestamp).toLocaleString(),$e=new Date(Re.lastChange.timestamp).toLocaleString()
4122
+ E+=`**First Change**: ${De}\n`,E+=`**Last Change**: ${$e}\n`,"pre-task"===Re.firstChange.status&&Re.firstChange.commitHash?E+=`**Pre-Task Commit**: ${Re.firstChange.commitHash.substring(0,8)}\n`:Re.firstChange.commitHash&&(E+=`**File Created During Task**: ${Re.firstChange.commitHash.substring(0,8)}\n`),Re.lastChange.commitHash&&(E+=`**Final Commit**: ${Re.lastChange.commitHash.substring(0,8)}\n`)
4123
4123
  const Ae=I.sourceToMove.get(je),Fe=I.destToMove.get(je)
4124
4124
  Ae?E+=`**\u2139\ufe0f Move Operation**: This file was moved TO **${Ae.destination}**\n`:Fe&&(E+=`**\u2139\ufe0f Move Operation**: This file was moved FROM **${Fe.source}**\n`),p&&!T?Re.hasDiff?(E+="\n**Changes**:\n",E+="```diff\n",E+=Re.diffText,E+="\n```\n\n"):E+=`\n**Note**: ${Re.diffText}\n\n`:T&&Re.hasDiff?(E+=`\n**Note**: File has changes (${Re.diffText?Re.diffText.split("\n").length:0} lines). `,E+=`Compare ${Re.firstChange.commitHash?Re.firstChange.commitHash.substring(0,8):"unknown"}..${Re.lastChange.commitHash?Re.lastChange.commitHash.substring(0,8):"unknown"} to see changes.\n\n`):Re.hasDiff?E+="\n**Note**: File has changes. Use showDiff=true to see the diff.\n\n":E+=`\n**Note**: ${Re.diffText}\n\n`,E+="---\n\n"}return h({success:!0,fileCount:C.size}),{content:[{type:"text",text:E}]}}catch(Ne){return s.error("Error in task file history tool",{error:Ne instanceof Error?Ne.stack:Ne+""}),h({success:!1,error:Ne instanceof Error?Ne.name:"unknown"}),{content:[{type:"text",text:"Error: "+(0,u.getErrorMessage)(Ne)}],isError:!0}}}
4125
4125
  const i=t(9860),a=s(t(1943)),c=t(9671),l=t(2960),d=s(t(5967)),u=t(8824)},6928(module){"use strict"
@@ -4937,9 +4937,9 @@ w=x,k=x,b=I.fileOperationPhase,p.incrementCounter("create_directory_phase",1,{ph
4937
4937
  let O=R
4938
4938
  if(!R){await a.default.mkdir(E,{recursive:!0}),m.info("Successfully created directory "+_)
4939
4939
  try{const e=c.default.join(E,".gitkeep")
4940
- await a.default.writeFile(e,"# This file makes the directory trackable by Git\n"),O=!0,m.info("Created .gitkeep file for Git tracking")}catch(e){m.warn("Failed to create .gitkeep file",{error:e instanceof Error?e.message:e+""}),O=!1}}const $=Date.now()-y
4941
- p.recordValue("create_directory_time",$),p.incrementCounter("create_directory_success",1),b=d.FileOperationPhase.GIT_COMMIT,p.incrementCounter("create_directory_phase",1,{phase:b})
4942
- const D=`Create directory: ${_} - ${g||"Create directory"}`,A=!R&&O?_+"/.gitkeep":_,F=await d.commitToGit(C,A,x,M,D,r,m,p,I.metricsPrefix)
4940
+ await a.default.writeFile(e,"# This file makes the directory trackable by Git\n"),O=!0,m.info("Created .gitkeep file for Git tracking")}catch(e){m.warn("Failed to create .gitkeep file",{error:e instanceof Error?e.message:e+""}),O=!1}}const D=Date.now()-y
4941
+ p.recordValue("create_directory_time",D),p.incrementCounter("create_directory_success",1),b=d.FileOperationPhase.GIT_COMMIT,p.incrementCounter("create_directory_phase",1,{phase:b})
4942
+ const $=`Create directory: ${_} - ${g||"Create directory"}`,A=!R&&O?_+"/.gitkeep":_,F=await d.commitToGit(C,A,x,M,$,r,m,p,I.metricsPrefix)
4943
4943
  b=d.FileOperationPhase.RECORD_UPDATE_SUCCESS,p.incrementCounter("create_directory_phase",1,{phase:b}),await d.updateFileOperationRecords(C,w,k,_,I.recordType,`Successfully ${R?"verified":"created"} directory: ${_}`,{status:"completed",commitHash:F.commitHash,previousCommitHash:F.previousCommitHash,directoryExists:R,isDirectory:!0,userComment:g},`Successfully ${R?"verified":"created"} directory: ${_}`,n,o,m,p,I.metricsPrefix)
4944
4944
  const N=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
4945
4945
  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:""}${j.lockAcquired&&j.lockedRequestId&&!N.permanentBranch?"\n\u{1f512} **Locked request:** "+j.lockedRequestId:""}`}]}}catch(t){if(e.taskId&&o)try{const n=t instanceof u.NotFoundError||t instanceof u.ValidationError||t instanceof h.ZodError
@@ -5280,7 +5280,7 @@ if(this.logger.debug("Polling response",{data:n}),n.authenticated&&n.token){this
5280
5280
  const r=this.parseTokenResponse(n)
5281
5281
  if(!r)throw Error("Invalid token response from server")
5282
5282
  this.pollingStatus=s.AUTHENTICATED,this.tokenResult=r,this.stopPolling(),t&&t(r)}else this.logger.debug("Not authenticated yet, continuing to poll",{tempCode:e.substring(0,4)+"***"})}catch(e){const t=(0,o.getErrorMessage)(e)
5283
- throw Error("Error during polling: "+t)}}catch(t){const r=(0,o.getErrorMessage)(t)
5283
+ throw Error(`Error during polling: ${t}${/fetch failed|ECONNREFUSED|ENOTFOUND|ETIMEDOUT|network/i.test(t)?" (remote may be unreachable \u2014 check your connection and try again)":""}`)}}catch(t){const r=(0,o.getErrorMessage)(t)
5284
5284
  this.logger.error("Error polling for authentication",{tempCode:e.substring(0,4)+"***",error:r}),this.pollingStatus=s.ERROR,this.pollingError=r,this.stopPolling(),n&&n(r)}}
5285
5285
  return i(),this.pollingIntervalId=setInterval(i,this.pollingIntervalMs),()=>this.stopPolling()}stopPolling(){this.pollingIntervalId&&(clearInterval(this.pollingIntervalId),this.pollingIntervalId=null,this.logger.debug("Stopped polling for authentication",{status:this.pollingStatus}))}getPollingStatus(){const e={status:this.pollingStatus}
5286
5286
  return this.pollingStatus===s.AUTHENTICATED&&this.tokenResult?e.tokenInfo=this.tokenResult:this.pollingStatus===s.ERROR&&this.pollingError&&(e.error=this.pollingError),this.pollingStartTime>0&&(e.elapsedTimeMs=Date.now()-this.pollingStartTime),e}resetPollingState(){this.stopPolling(),this.pollingStatus=s.NOT_STARTED,this.pollingStartTime=0,this.tokenResult=null,this.pollingError=null}async startGoogleOAuthFlow(){this.logger.info("Starting Google OAuth authentication flow")
@@ -5520,18 +5520,18 @@ if(R.length>0&&r.apiClient)try{await(0,m.ensureDocumentsNotLocked)(R,r.apiClient
5520
5520
  throw e}_=u.FileOperationPhase.TASK_VALIDATION,c.incrementCounter("replace_in_files_phase",1,{phase:_})
5521
5521
  const x=T[0],M=x.documentId?"document:"+x.documentId:x.path
5522
5522
  let O=Date.now()
5523
- const $=await u.validateTaskId(S,M,o,I,c,"replace_in_files")
5523
+ const D=await u.validateTaskId(S,M,o,I,c,"replace_in_files")
5524
5524
  Date.now()
5525
- const D=$?.requestId,A=T.some((e=>e.path))
5525
+ const $=D?.requestId,A=T.some((e=>e.path))
5526
5526
  let F=!1
5527
- if(A&&D){O=Date.now()
5527
+ if(A&&$){O=Date.now()
5528
5528
  const e=await u.validateWorkItemStates(S,M,o,i,r,I,c,"replace_in_files")
5529
5529
  Date.now(),O=Date.now()
5530
- const t=await u.autoPromoteTaskStatus(S,$.status,D,e.request?.status,M,o,i,I,c,"replace_in_files")
5531
- t.taskPromoted&&I.info("Auto-promoted task to in_progress",{taskId:S,requestId:D,previousStatus:$.status,newStatus:t.newTaskStatus}),Date.now(),O=Date.now()
5532
- const n=await u.ensureCorrectWorkspaceContext({taskPromoted:t.taskPromoted,requestId:D,context:r,operation:"replace_in_files",logger:I,metrics:c,metricsPrefix:"replace_in_files"})
5530
+ const t=await u.autoPromoteTaskStatus(S,D.status,$,e.request?.status,M,o,i,I,c,"replace_in_files")
5531
+ t.taskPromoted&&I.info("Auto-promoted task to in_progress",{taskId:S,requestId:$,previousStatus:D.status,newStatus:t.newTaskStatus}),Date.now(),O=Date.now()
5532
+ const n=await u.ensureCorrectWorkspaceContext({taskPromoted:t.taskPromoted,requestId:$,context:r,operation:"replace_in_files",logger:I,metrics:c,metricsPrefix:"replace_in_files"})
5533
5533
  if(!n.success){if(n.isLockConflict)return{content:[{type:"text",text:"\u274c "+n.error}],isError:!0}
5534
- throw Error(n.error)}Date.now(),F=!0}if(R.length>0&&D)try{await(0,p.validateRequestStatusForDocumentOperation)(D,i,I,c,"replace_in_files-documents")}catch(e){if(e instanceof g.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
5534
+ throw Error(n.error)}Date.now(),F=!0}if(R.length>0&&$)try{await(0,p.validateRequestStatusForDocumentOperation)($,i,I,c,"replace_in_files-documents")}catch(e){if(e instanceof g.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
5535
5535
  throw e}O=Date.now()
5536
5536
  const N=new Map
5537
5537
  if(I.info("\u{1f50d} Starting external edit detection",{hasFileOperations:A,hasGit:!!r.git,operationCount:T.length}),A&&r.git)for(const e of T)if(e.path&&!e.documentId)try{const t=u.validateAndNormalizePath(e.path,r),n=await l.default.readFile(t.fullPath,"utf8"),o=void 0!==e.fuzzy_match?e.fuzzy_match:P,s=[]
@@ -5540,9 +5540,9 @@ s.push(...r)}if(s.length>0){const o=(0,y.calculateReplacementRegion)(n,s,t.fullP
5540
5540
  I.info("\u{1f50d} Checking for external edits",{path:t.normalizedPath,affectedLines:o.lineRanges.map((e=>`${e.start}-${e.end}`)).join(", "),matchCount:s.length})
5541
5541
  const i=await(0,w.detectExternalEdits)(r.git,o,I)
5542
5542
  I.info("\u{1f50d} External edit detection result",{path:t.normalizedPath,hasExternalEdits:i.hasExternalEdits,conflictingLines:i.conflictingLines,hasMessage:!!i.message}),i.hasExternalEdits&&i.message?(N.set(e.path,{message:i.message,debugInfo:i.debugInfo}),I.warn("\u26a0\ufe0f External edits detected before auto-commit",{path:t.normalizedPath,conflictingLines:i.conflictingLines})):(i.debugInfo&&N.set(e.path,{message:"",debugInfo:i.debugInfo}),I.info("\u2705 No external edit conflicts detected",{path:t.normalizedPath}))}else I.info("\u2139\ufe0f No matches found for external edit detection",{path:t.normalizedPath}),N.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){I.warn("Failed to check for external edits before auto-commit",{path:e.path,error:(0,k.getErrorMessage)(t)})}if(Date.now(),O=Date.now(),A&&r.git)try{I.debug("[REPLACE-IN-FILES] Checking for user changes before batch operation")
5543
- const e=await(0,f.commitUserChangesBeforeToolOperation)(r.git,"replace_in_files",{requestId:D,taskId:S,workspaceManager:r.workspaceManager},I,c)
5543
+ const e=await(0,f.commitUserChangesBeforeToolOperation)(r.git,"replace_in_files",{requestId:$,taskId:S,workspaceManager:r.workspaceManager},I,c)
5544
5544
  e.userChangesCommitted&&(I.debug("[REPLACE-IN-FILES] User changes committed",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),I.info("User changes committed before batch operation",{taskId:S,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){I.warn("Pre-tool user changes commit failed",{taskId:S,error:e instanceof Error?e.message:e+""})}Date.now(),O=Date.now(),_=u.FileOperationPhase.RECORD_CREATION,c.incrementCounter("replace_in_files_phase",1,{phase:_})
5545
- const{toolRecordId:L}=await u.createFileOperationRecords(S,D,r.projectId,"replace-in-files",M,{operationCount:T.length,totalReplacements:T.reduce(((e,t)=>e+t.replacements.length),0),globalFuzzyMatch:P,userComment:j},o,s,I,c,"replace_in_files",b)
5545
+ const{toolRecordId:L}=await u.createFileOperationRecords(S,$,r.projectId,"replace-in-files",M,{operationCount:T.length,totalReplacements:T.reduce(((e,t)=>e+t.replacements.length),0),globalFuzzyMatch:P,userComment:j},o,s,I,c,"replace_in_files",b)
5546
5546
  C=L,Date.now(),O=Date.now(),_=u.FileOperationPhase.STRING_REPLACEMENT,c.incrementCounter("replace_in_files_phase",1,{phase:_})
5547
5547
  const z=[],H=[]
5548
5548
  for(const e of T){const t=e.path?N.get(e.path):void 0,o=await n(e,P,r,0,0,t?.message,t?.debugInfo)
@@ -486,9 +486,9 @@ if(this.TOKEN_CACHE.hasValidToken&&e<this.TOKEN_CACHE.hasValidToken.expiresAt){c
486
486
  return this.logger.debug("Using cached hasValidToken result",{ageSecs:Math.round((e-t.timestamp)/1e3),hasToken:t.value}),t.value}this.logger.debug("Checking if valid token exists (cache miss or expired)")
487
487
  const t=null!==await this.getToken()
488
488
  return this.TOKEN_CACHE.hasValidToken={value:t,timestamp:e,expiresAt:e+this.CACHE_TTL_MS,lastCheck:e,exists:t},t}getTokenDirectoryPath(){return this.tokenDirPath}getManualTokenFilePath(){return n.default.join(this.tokenDirPath,"manual-token.json")}logTokenLocationInstructions(){const e=this.getManualTokenFilePath()
489
- console.log("========================================"),console.log("To use MCP server, you need to authenticate."),console.log("Token file location: "+e),console.log("You can either:"),console.log('\n1. Use the authenticate tool (recommended)\n2. Manually place a token file at the above location\n3. Set up automatic authentication flow\n\nFor manual token placement, create a JSON file with:\n{\n "token": "your_token_here",\n "userId": "your_user_id",\n "username": "your_username", \n "role": "user",\n "expiresAt": "2025-12-31T23:59:59.000Z"\n}\n'),console.log("For more information, see the authentication documentation."),console.log("========================================")}async startAuthenticationFlow(){this.pendingAuthCheck=!0
489
+ console.log("========================================"),console.log("To use the alchemy CLI, you need to authenticate."),console.log("Token file location: "+e),console.log("You can either:"),console.log('\n1. Use the authenticate tool (recommended)\n2. Manually place a token file at the above location\n3. Set up automatic authentication flow\n\nFor manual token placement, create a JSON file with:\n{\n "token": "your_token_here",\n "userId": "your_user_id",\n "username": "your_username", \n "role": "user",\n "expiresAt": "2025-12-31T23:59:59.000Z"\n}\n'),console.log("For more information, see the authentication documentation."),console.log("========================================")}async startAuthenticationFlow(){this.pendingAuthCheck=!0
490
490
  try{const{tempCode:e,authUrl:t}=await this.authFlow.startAuthFlow()
491
- return this.tempAuthCode=e,this.logger.info("Started external authentication flow",{tempCode:e,authUrl:t}),this.authFlow.startPolling(e,(async t=>{this.logger.info("Authentication flow completed",{tempCode:e.substring(0,4)+"***",username:t.username}),await this.storeToken(t),this.pendingAuthCheck=!1,this.tempAuthCode=null,this.invalidateCache(),console.log("Authentication successful!"),console.log(`Welcome, ${t.username}!`),console.log("You can now use all MCP tools and features."),console.log("========================================")}),(()=>{this.logger.info("Authentication flow timed out",{tempCode:e.substring(0,4)+"***"}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow timed out."),console.log("Please try again or manually place a token file."),console.log("Token file location:"),console.log(""+this.getManualTokenFilePath()),console.log("========================================")}),(t=>{this.logger.error("Authentication flow error",{tempCode:e.substring(0,4)+"***",error:t}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow error."),console.log("Error: "+t),console.log("Please try again or manually place a token file."),console.log(""+this.getManualTokenFilePath()),console.log("========================================")})),{tempCode:e,authUrl:t}}catch(e){throw this.logger.error("Error starting authentication flow",{error:(0,c.getErrorMessage)(e)}),this.pendingAuthCheck=!1,this.tempAuthCode=null,e}}hasPendingAuth(){return this.pendingAuthCheck||!!this.tempAuthCode}getAuthStatus(){return this.hasPendingAuth()?{hasToken:!1,isPendingAuth:!0,tempCode:this.tempAuthCode,authUrl:this.authFlow.getAuthUrl(this.tempAuthCode)}:{hasToken:!1,isPendingAuth:!1}}async checkAuthStatus(e){if(!e)return null
491
+ return this.tempAuthCode=e,this.logger.info("Started external authentication flow",{tempCode:e,authUrl:t}),this.authFlow.startPolling(e,(async t=>{this.logger.info("Authentication flow completed",{tempCode:e.substring(0,4)+"***",username:t.username}),await this.storeToken(t),this.pendingAuthCheck=!1,this.tempAuthCode=null,this.invalidateCache(),console.log("Authentication successful!"),console.log(`Welcome, ${t.username}!`),console.log("You can now use the alchemy CLI."),console.log("========================================")}),(()=>{this.logger.info("Authentication flow timed out",{tempCode:e.substring(0,4)+"***"}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow timed out."),console.log("Please try again or manually place a token file."),console.log("Token file location:"),console.log(""+this.getManualTokenFilePath()),console.log("========================================")}),(t=>{this.logger.error("Authentication flow error",{tempCode:e.substring(0,4)+"***",error:t}),this.pendingAuthCheck=!1,this.tempAuthCode=null,console.log("Authentication flow error."),console.log("Error: "+t),console.log("Please try again or manually place a token file."),console.log(""+this.getManualTokenFilePath()),console.log("========================================")})),{tempCode:e,authUrl:t}}catch(e){throw this.logger.error("Error starting authentication flow",{error:(0,c.getErrorMessage)(e)}),this.pendingAuthCheck=!1,this.tempAuthCode=null,e}}hasPendingAuth(){return this.pendingAuthCheck||!!this.tempAuthCode}getAuthStatus(){return this.hasPendingAuth()?{hasToken:!1,isPendingAuth:!0,tempCode:this.tempAuthCode,authUrl:this.authFlow.getAuthUrl(this.tempAuthCode)}:{hasToken:!1,isPendingAuth:!1}}async checkAuthStatus(e){if(!e)return null
492
492
  try{const t=this.authFlow.getPollingStatus()
493
493
  if(t.status===a.PollingStatus.AUTHENTICATED&&t.tokenInfo)return this.logger.info("Authentication polling has token available",{tempCode:e.substring(0,4)+"***",username:t.tokenInfo.username}),t.tokenInfo
494
494
  if(t.status===a.PollingStatus.ERROR||t.status===a.PollingStatus.TIMEOUT)return this.pendingAuthCheck=!1,this.tempAuthCode=null,null
@@ -4976,7 +4976,7 @@ if(this.logger.debug("Polling response",{data:n}),n.authenticated&&n.token){this
4976
4976
  const r=this.parseTokenResponse(n)
4977
4977
  if(!r)throw Error("Invalid token response from server")
4978
4978
  this.pollingStatus=s.AUTHENTICATED,this.tokenResult=r,this.stopPolling(),t&&t(r)}else this.logger.debug("Not authenticated yet, continuing to poll",{tempCode:e.substring(0,4)+"***"})}catch(e){const t=(0,o.getErrorMessage)(e)
4979
- throw Error("Error during polling: "+t)}}catch(t){const r=(0,o.getErrorMessage)(t)
4979
+ throw Error(`Error during polling: ${t}${/fetch failed|ECONNREFUSED|ENOTFOUND|ETIMEDOUT|network/i.test(t)?" (remote may be unreachable \u2014 check your connection and try again)":""}`)}}catch(t){const r=(0,o.getErrorMessage)(t)
4980
4980
  this.logger.error("Error polling for authentication",{tempCode:e.substring(0,4)+"***",error:r}),this.pollingStatus=s.ERROR,this.pollingError=r,this.stopPolling(),n&&n(r)}}
4981
4981
  return i(),this.pollingIntervalId=setInterval(i,this.pollingIntervalMs),()=>this.stopPolling()}stopPolling(){this.pollingIntervalId&&(clearInterval(this.pollingIntervalId),this.pollingIntervalId=null,this.logger.debug("Stopped polling for authentication",{status:this.pollingStatus}))}getPollingStatus(){const e={status:this.pollingStatus}
4982
4982
  return this.pollingStatus===s.AUTHENTICATED&&this.tokenResult?e.tokenInfo=this.tokenResult:this.pollingStatus===s.ERROR&&this.pollingError&&(e.error=this.pollingError),this.pollingStartTime>0&&(e.elapsedTimeMs=Date.now()-this.pollingStartTime),e}resetPollingState(){this.stopPolling(),this.pollingStatus=s.NOT_STARTED,this.pollingStartTime=0,this.tokenResult=null,this.pollingError=null}async startGoogleOAuthFlow(){this.logger.info("Starting Google OAuth authentication flow")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alchemylab",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "private": false,
5
5
  "description": "AlchemyLab - agentic coding IDEm",
6
6
  "author": "Testfire Software",