alchemylab 1.0.0

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/LICENSE.txt ADDED
@@ -0,0 +1,33 @@
1
+ Alchemy MCP Server Software License
2
+
3
+ Copyright (c) 2025 Testfire Software. All rights reserved.
4
+
5
+ GRANT OF LICENSE
6
+ Permission is hereby granted to use this software solely for its intended
7
+ purpose as a Model Context Protocol server in connection with intended
8
+ services.
9
+
10
+ RESTRICTIONS
11
+ This license does not grant any rights to sublicense or distribute this
12
+ software. No rights are granted beyond the specific use permission stated
13
+ above.
14
+
15
+ OWNERSHIP
16
+ This software and all intellectual property rights therein remain the
17
+ exclusive property of Testfire Software. No title or ownership rights
18
+ are transferred under this license.
19
+
20
+ DISCLAIMER OF WARRANTIES
21
+ This software is provided "AS IS" without warranty of any kind, either
22
+ express or implied, including but not limited to the implied warranties
23
+ of merchantability, fitness for a particular purpose, or non-infringement.
24
+
25
+ LIMITATION OF LIABILITY
26
+ In no event shall Testfire Software be liable for any damages whatsoever
27
+ arising out of the use of or inability to use this software.
28
+
29
+ TERMINATION
30
+ This license is effective until terminated. Your rights under this license
31
+ will terminate automatically if you fail to comply with any of its terms.
32
+
33
+ END OF LICENSE
package/dist/478.js ADDED
@@ -0,0 +1,109 @@
1
+ "use strict"
2
+ exports.id=478,exports.ids=[478],exports.modules={2096(e,exports,t){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
3
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.ProjectConfigService=void 0
4
+ const o=r(t(1943)),i=r(t(6928)),s=r(t(857)),a=t(4139),n=t(8824)
5
+ exports.ProjectConfigService=class{constructor(e){this.logger=e.child({component:"project-config"})}async readProjectId(e){try{const t=i.default.join(e,a.ALCHEMY_DIR_NAME,"project.json"),r=await o.default.readFile(t,"utf-8"),s=JSON.parse(r)
6
+ return s.id?s.id+"":null}catch(e){return this.logger.debug("Could not read project ID",{error:(0,n.getErrorMessage)(e)}),null}}async readProjectConfig(e){try{const t=i.default.join(e,a.ALCHEMY_DIR_NAME,"config.json"),r=await o.default.readFile(t,"utf-8")
7
+ return JSON.parse(r)}catch(e){return this.logger.debug("Could not read project config",{error:(0,n.getErrorMessage)(e)}),{}}}async saveMultiAgentConfig(e,t,r){try{const s=i.default.join(e,a.ALCHEMY_DIR_NAME),n=i.default.join(s,"config.json")
8
+ await o.default.mkdir(s,{recursive:!0})
9
+ let c={}
10
+ try{const e=await o.default.readFile(n,"utf-8")
11
+ c=JSON.parse(e)}catch(e){this.logger.debug("No existing config.json, creating new one")}c.multiAgent=!1!==t,void 0!==r&&(c.autoJournal=r),c.lockTimeout||(c.lockTimeout=3600),c.worktreeCleanupDelay||(c.worktreeCleanupDelay=900),c.maxWorktreeAge||(c.maxWorktreeAge=24),c.cleanupInterval||(c.cleanupInterval=15),void 0===c.preserveBranchesOnCleanup&&(c.preserveBranchesOnCleanup=!0),c.maxConcurrentSessions||(c.maxConcurrentSessions=10),c.sessionTimeoutWarning||(c.sessionTimeoutWarning=45),await o.default.writeFile(n,JSON.stringify(c,null,2),"utf-8"),this.logger.info("Saved multiAgent config",{configPath:n,multiAgent:c.multiAgent})}catch(e){this.logger.error("Failed to save multiAgent config",{error:(0,n.getErrorMessage)(e)})}}getToolPreferencesPath(){const e=s.default.homedir()
12
+ return i.default.join(e,".alchemy_lab","tool-preferences.json")}async loadToolPreferences(e){const t=this.getToolPreferencesPath()
13
+ try{const r=await o.default.readFile(t,"utf-8"),i=JSON.parse(r)
14
+ return e&&i[e]?i[e]:e?null:i}catch(t){return this.logger.debug("No user preferences found",{error:(0,n.getErrorMessage)(t)}),e?null:{}}}async saveToolPreferences(e,t,r,s){const a=this.getToolPreferencesPath(),n=i.default.dirname(a)
15
+ this.logger.info("Saving user tool preferences",{clientType:e,preset:t,disabledToolsCount:r?.length||0,allowedToolsCount:s?.length||0}),await o.default.mkdir(n,{recursive:!0})
16
+ let c={}
17
+ try{const e=await o.default.readFile(a,"utf-8")
18
+ c=JSON.parse(e)}catch(e){}c[e]={preset:t,disabledTools:r||[],allowedAlchemyTools:s||[],updatedAt:(new Date).toISOString()},await o.default.writeFile(a,JSON.stringify(c,null,2),"utf-8"),this.logger.info("User tool preferences saved",{clientType:e,prefsFile:a})}}},2568(e,exports,t){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
19
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.ProjectSynchronizer=void 0
20
+ const o=r(t(6928)),i=t(8029),s=t(8824),a=t(2096)
21
+ exports.ProjectSynchronizer=class{constructor(e,t,r,o,i={}){this.logger=e.child({component:"project-synchronizer"}),this.registry=t,this.remoteApi=r,this.fileSystem=o,this.options={createRemoteProjects:i.createRemoteProjects??!0,maxRetryAttempts:i.maxRetryAttempts??3,retryDelayMs:i.retryDelayMs??1e3},this.logger.info("ProjectSynchronizer initialized",{options:this.options})}async ensureProjectExists(e){const t=Math.random().toString(36).substring(2,8)
22
+ this.logger.info("\u{1f4de} SYNC-TRACE: ensureProjectExists called",{callId:t,projectId:e,stackTrace:Error().stack?.split("\n").slice(1,4).map((e=>e.trim())).join(" -> ")||"unknown"})
23
+ try{if(!this.remoteApi.isOnline())return this.logger.info("\u{1f4de} SYNC-TRACE: System offline, returning original ID",{callId:t,projectId:e}),e
24
+ if(this.logger.info("\u{1f4de} SYNC-TRACE: System online, proceeding",{callId:t,projectId:e}),this.registry.isVerified(e))return this.logger.info("\u{1f4de} SYNC-TRACE: Cache hit - already verified",{callId:t,projectId:e}),e
25
+ this.logger.info("\u{1f4de} SYNC-TRACE: Cache miss - checking remote server",{callId:t,projectId:e})
26
+ const r=await this.remoteApi.fetchProject(e)
27
+ if(this.logger.info("\u{1f4de} SYNC-TRACE: Remote fetch completed",{callId:t,projectId:e,found:!!r,remoteProject:r?{id:r.id,name:r.name}:null}),r)return this.logger.info("Project exists on remote server",{projectId:e}),this.registry.register(r),r.id
28
+ if(this.logger.info("\u{1f4de} SYNC-TRACE: Project not found, will create",{callId:t,projectId:e}),!this.options.createRemoteProjects)throw this.logger.info("Project does not exist on remote and creation is disabled",{projectId:e}),Error(`Project ${e} does not exist on remote server and creation is disabled`)
29
+ {this.logger.info("\u{1f4de} SYNC-TRACE: Creating project on remote server",{callId:t,projectId:e})
30
+ let r={id:e,name:"Remote Synchronized Project",description:"Automatically created during synchronization",status:"active"}
31
+ const o=this.registry.getProject(e)
32
+ o&&(this.logger.info("\u{1f4de} SYNC-TRACE: Using local project data",{callId:t,projectId:e,projectName:o.name}),r={...o})
33
+ try{this.logger.info("\u{1f4de} SYNC-TRACE: Calling remoteApi.createProject",{callId:t,projectId:e,projectName:r.name})
34
+ const o=await this.remoteApi.createProject(r)
35
+ return this.logger.info("Create project API call succeeded",{returnedId:o?.id,returnedName:o?.name}),this.registry.register(o),this.logger.info("Successfully created project on remote server",{projectId:o.id,projectName:o.name}),o.id}catch(t){if(t&&"object"==typeof t&&"status"in t&&409===t.status)return this.logger.info("Project already exists on remote (409 conflict)",{projectId:e}),this.registry.markVerified(e),e
36
+ throw this.logger.error("Failed to create project on remote server",{projectId:e,error:t instanceof Error?t.stack:t+"",status:t?.status,message:t instanceof Error?t.message:t+""}),t}}}catch(t){throw this.logger.error("Error verifying project existence",{projectId:e,error:t instanceof Error?t.stack:t+"",message:(0,s.getErrorMessage)(t)}),t}}async createProject(e,t){try{if(e.id){if(!i.ProjectIDFactory.isValid(e.id)){this.logger.warn("Invalid project ID format, generating new ID",{originalId:e.id})
37
+ const t=i.ProjectIDFactory.create().toString()
38
+ e.id=t}}else{const t=i.ProjectIDFactory.create().toString()
39
+ e.id=t,this.logger.info("Generated new project ID",{projectId:t})}const r=(new Date).toISOString(),o={id:e.id,name:e.name||"Unnamed Project",description:e.description||"No description provided",status:e.status||"active",createdAt:e.createdAt||r,updatedAt:e.updatedAt||r,metadata:e.metadata||{}}
40
+ if(this.registry.register(o),t&&await this.fileSystem.writeProjectFile(o,t),this.remoteApi.isOnline())try{this.logger.info("Syncing new project to remote server",{projectId:o.id}),await this.ensureProjectExists(o.id)}catch(e){this.logger.warn("Failed to sync new project to remote, will retry later",{projectId:o.id,error:e instanceof Error?e.message:e+""})}return o}catch(t){throw this.logger.error("Failed to create project",{projectData:e,error:t instanceof Error?t.stack:t+""}),t}}async syncAllProjects(e){try{if(!this.remoteApi.isOnline())return void this.logger.info("Skipping project synchronization - system is offline")
41
+ this.logger.info("Starting project synchronization from directory",{basePath:e})
42
+ const t=await this.fileSystem.readProjectFile(e)
43
+ if(!t||!t.id)return void this.logger.info("No valid local project found, skipping synchronization",{basePath:e})
44
+ if(this.logger.info("Found local project",{projectId:t.id,projectName:t.name}),this.logger.info("Registering project in registry before synchronization",{projectId:t.id,projectName:t.name}),this.registry.register(t),this.logger.info("Ensuring project exists on remote server",{projectId:t.id}),await this.ensureProjectExists(t.id)){this.logger.info("Project exists on remote, checking metadata sync",{projectId:t.id,projectName:t.name,basePath:e}),t.metadata&&Object.keys(t.metadata).length>0&&(this.logger.info("Syncing project metadata to remote (async)",{projectId:t.id,metadataKeys:Object.keys(t.metadata)}),this.remoteApi.updateProject(t.id,{metadata:t.metadata}).then((()=>{this.logger.info("Project metadata synced successfully",{projectId:t.id})})).catch((e=>{this.logger.warn("Failed to sync project metadata",{projectId:t.id,error:e instanceof Error?e.message:e+""})})))
45
+ try{const r=await this.remoteApi.fetchProject(t.id)
46
+ if(r?.metadata){const{autoJournal:o}=r.metadata
47
+ if(void 0!==o){const r=new a.ProjectConfigService(this.logger)
48
+ await r.saveMultiAgentConfig(e,void 0,o),this.logger.info("Synced remote settings to local config",{projectId:t.id,autoJournal:o})}}}catch(e){this.logger.warn("Failed to sync remote settings to local config",{projectId:t.id,error:e instanceof Error?e.message:e+""})}this.logger.info("Successfully synchronized project",{projectId:t.id,projectName:t.name,basePath:e})}else this.logger.warn("Failed to verify/create project on remote server",{projectId:t.id,basePath:e})}catch(t){this.logger.error("Error during project synchronization",{basePath:e,error:t instanceof Error?t.stack:t+""})}}async loadLocalProject(e){try{this.logger.info("Loading local project from directory",{basePath:e})
49
+ const t=await this.fileSystem.readProjectFile(e)
50
+ return t&&t.id?(this.registry.register(t),this.logger.info("Successfully loaded local project",{projectId:t.id,basePath:e}),t):(this.logger.info("No valid local project found",{basePath:e}),null)}catch(t){return this.logger.error("Error loading local project",{basePath:e,error:t instanceof Error?t.stack:t+""}),null}}async getOrCreateProject(e,t={}){this.logger.info("\u{1f680} getOrCreateProject called",{basePath:e,hasProjectData:!!Object.keys(t).length,projectData:Object.keys(t)})
51
+ try{this.logger.info("Attempting to load existing local project",{basePath:e})
52
+ const r=await this.loadLocalProject(e)
53
+ if(r){this.logger.info("Found existing local project",{projectId:r.id,projectName:r.name,basePath:e})
54
+ const t=this.remoteApi.isOnline()
55
+ if(this.logger.info("Checking online status for verification",{isOnline:t,projectId:r.id}),!t)return this.logger.info("Using existing project (offline, skipping server verification)",{projectId:r.id,basePath:e}),r
56
+ {this.logger.info("System is online - starting project verification",{projectId:r.id,basePath:e})
57
+ const t=await this.ensureProjectExists(r.id)
58
+ if(this.logger.info("Project verification completed",{projectId:r.id,exists:t,basePath:e}),t)return this.logger.info("Using existing project (verified on server)",{projectId:r.id,basePath:e}),r
59
+ this.logger.warn("Local project not found on server, creating new project",{invalidProjectId:r.id,basePath:e})}}this.logger.info("No existing project found, creating new one",{basePath:e}),t.name||(t.name=o.default.basename(e))
60
+ const i=await this.createProject(t,e)
61
+ return this.logger.info("Created new project for directory",{projectId:i.id,basePath:e}),i}catch(t){this.logger.error("Error getting or creating project",{basePath:e,error:t instanceof Error?t.stack:t+""})
62
+ const r=await this.createProject({name:"Fallback Project for "+o.default.basename(e),description:"Created as fallback due to error"},e)
63
+ return this.logger.info("Created fallback project due to error",{projectId:r.id,basePath:e}),r}}async verifyAndFixProjectName(e){try{if(!this.remoteApi.isOnline())return this.logger.info("Skipping project name verification - system is offline"),!0
64
+ if(this.registry.isVerifiedWithName&&this.registry.isVerifiedWithName(e.id,e.name))return this.logger.info("Project name already verified, skipping verification",{projectId:e.id,projectName:e.name}),!0
65
+ const t=await this.remoteApi.fetchProject(e.id)
66
+ if(!t)return this.logger.warn("Cannot verify project name - project not found on remote",{projectId:e.id}),!1
67
+ if(t.name===e.name)return this.logger.info("Project name matches remote, marking as verified",{projectId:e.id,projectName:e.name}),this.registry.markVerifiedWithName&&this.registry.markVerifiedWithName(e.id,e.name),!0
68
+ this.logger.info("Project name mismatch, updating remote name",{projectId:e.id,localName:e.name,remoteName:t.name})
69
+ const r=this.options.maxRetryAttempts,o=this.options.retryDelayMs
70
+ for(let t=1;r>=t;t++)try{return await this.remoteApi.updateProject(e.id,{name:e.name}),this.logger.info("Project name updated successfully",{projectId:e.id,newName:e.name}),this.registry.markVerifiedWithName&&this.registry.markVerifiedWithName(e.id,e.name),!0}catch(i){if(t>=r)throw i
71
+ this.logger.warn(`Failed to update project name, retrying (${t}/${r})`,{projectId:e.id,error:i instanceof Error?i.message:i+""}),await new Promise((e=>setTimeout(e,o)))}return!1}catch(t){return this.logger.error("Failed to verify/fix project name",{projectId:e.id,projectName:e.name,error:t instanceof Error?t.stack:t+""}),!1}}async syncProject(e,t){try{if(!this.remoteApi.isOnline())return this.logger.info("Skipping project synchronization - system is offline",{projectId:e}),!1
72
+ let r=null
73
+ if(t&&(r=await this.loadLocalProject(t),r&&r.id!==e&&(this.logger.warn("Project ID mismatch between request and loaded project",{requestedId:e,loadedId:r.id}),r=null)),!r){const t=this.registry.getProject(e)
74
+ t&&(r=t)}if(!r)return this.logger.info("Project not found locally, attempting to fetch from remote",{projectId:e}),r=await this.remoteApi.fetchProject(e),r?(this.registry.register(r),t&&await this.fileSystem.writeProjectFile(r,t),!0):(this.logger.warn("Project not found locally or remotely",{projectId:e}),!1)
75
+ if(!await this.ensureProjectExists(e))return!1
76
+ if(await this.verifyAndFixProjectName(r)||this.logger.warn("Failed to verify/fix project name",{projectId:r.id,projectName:r.name}),r.metadata&&Object.keys(r.metadata).length>0)try{this.logger.info("Syncing project metadata to remote",{projectId:r.id,metadataKeys:Object.keys(r.metadata)}),await this.remoteApi.updateProject(r.id,{metadata:r.metadata}),this.logger.info("Project metadata synced successfully",{projectId:r.id})}catch(e){this.logger.warn("Failed to sync project metadata",{projectId:r.id,error:e instanceof Error?e.message:e+""})}return this.logger.info("Project synchronization completed successfully",{projectId:e}),!0}catch(r){return this.logger.error("Error synchronizing project",{projectId:e,basePath:t,error:r instanceof Error?r.stack:r+""}),!1}}}},3102(e,exports,t){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
77
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.DefaultProjectFileSystem=void 0
78
+ const o=r(t(9896)),i=r(t(6928)),s=t(4139)
79
+ exports.DefaultProjectFileSystem=class{constructor(e){this.logger=e.child({component:"project-file-system"})}async readProjectFile(e){try{const t=i.default.join(e,"project.json"),r=i.default.join(e,s.ALCHEMY_DIR_NAME,"project.json")
80
+ let a=r
81
+ if(o.default.existsSync(t))a=t,this.logger.info("Found project file in base directory",{path:a})
82
+ else{if(!o.default.existsSync(r))return this.logger.info("Project file does not exist in either location",{directPath:t,nestedPath:r}),null
83
+ this.logger.info("Found project file in alchemy_lab subdirectory",{path:a})}const n=await o.default.promises.readFile(a,"utf8"),c=JSON.parse(n)
84
+ return c.id?(this.logger.info("Read project file successfully",{projectId:c.id,path:a}),c):(this.logger.warn("Project file has no ID",{path:a}),null)}catch(t){return this.logger.error("Failed to read project file",{basePath:e,error:t instanceof Error?t.stack:t+""}),null}}async writeProjectFile(e,t){try{const r=i.default.join(t,"project.json"),a=i.default.join(t,s.ALCHEMY_DIR_NAME,"project.json")
85
+ let n=r
86
+ !o.default.existsSync(r)&&o.default.existsSync(a)?(n=a,this.logger.info("Using existing nested path for project file",{path:n})):this.logger.info("Using direct path for project file",{path:n}),await this.ensureDirectoryExists(i.default.dirname(n)),await o.default.promises.writeFile(n,JSON.stringify(e,null,2),"utf8"),this.logger.info("Wrote project file successfully",{projectId:e.id,path:n})}catch(r){throw this.logger.error("Failed to write project file",{projectId:e.id,basePath:t,error:r instanceof Error?r.stack:r+""}),r}}async ensureDirectoryExists(e){try{o.default.existsSync(e)||(await o.default.promises.mkdir(e,{recursive:!0}),this.logger.info("Created directory",{path:e}))}catch(t){throw this.logger.error("Failed to create directory",{path:e,error:t instanceof Error?t.stack:t+""}),t}}}},5478(e,exports,t){exports.ProjectSynchronizer=exports.ProjectFileSystem=exports.ProjectRegistry=void 0
87
+ var r=t(9955)
88
+ Object.defineProperty(exports,"ProjectRegistry",{enumerable:!0,get:()=>r.ProjectRegistry})
89
+ var o=t(3102)
90
+ Object.defineProperty(exports,"ProjectFileSystem",{enumerable:!0,get:()=>o.DefaultProjectFileSystem})
91
+ var i=t(2568)
92
+ Object.defineProperty(exports,"ProjectSynchronizer",{enumerable:!0,get:()=>i.ProjectSynchronizer}),t(6975)},8029(e,exports,t){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
93
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.ProjectIDBackwardCompat=exports.ProjectIDFactory=exports.ProjectID=void 0
94
+ const o=r(t(6982))
95
+ class i{static create(){return exports.ProjectIDFactory.create()}static fromString(e){return exports.ProjectIDFactory.fromString(e)}static isValid(e){return exports.ProjectIDFactory.isValid(e)}constructor(e){this.id=e}toString(){return this.id}equals(e){return this.id===e.toString()}isStandardFormat(){return this.id.includes("_")&&this.id.startsWith("prj_")}}exports.ProjectID=i,exports.ProjectIDFactory={create(){const e=Date.now().toString().substring(5),t=o.default.randomBytes(4).toString("hex")
96
+ return i.fromString(`prj_${e}_${t}`)},fromString(e){return this.isValid(e)?new i(e):null},isValid(e){if(!e||"string"!=typeof e||5>e.length||!e.startsWith("prj"))return!1
97
+ if(e.includes("_")){const t=e.split("_")
98
+ return t.length>=3&&"prj"===t[0]}return!1}},exports.ProjectIDBackwardCompat={create:exports.ProjectIDFactory.create,fromString:exports.ProjectIDFactory.fromString,isValid:exports.ProjectIDFactory.isValid},Object.assign(i,exports.ProjectIDBackwardCompat)},9955(e,exports,t){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
99
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.ProjectRegistry=void 0
100
+ const o=r(t(9896)),i=r(t(6928))
101
+ exports.ProjectRegistry=class{constructor(e,t={}){this.projects=new Map,this.verifiedIds=new Set,this.verifiedNames=new Map,this.logger=e.child({component:"project-registry"}),this.options={persistToDisk:t.persistToDisk??!1,storageDirectory:t.storageDirectory??"./temp-projects"},this.options.persistToDisk?this.logger.warn("Project persistence to disk is enabled - this may be legacy functionality"):this.logger.info("Project persistence to disk is disabled - this is the recommended configuration"),this.logger.info("ProjectRegistry initialized",{options:this.options,persistenceEnabled:this.options.persistToDisk})}register(e,t={}){if(!e.id)return void this.logger.warn("Attempted to register project without ID")
102
+ const r=t.markVerified??!1,o=t.saveToFile??this.options.persistToDisk
103
+ this.projects.set(e.id,e),r&&(this.verifiedIds.add(e.id),e.name&&this.verifiedNames.set(e.id,e.name)),this.logger.info("Registered project",{projectId:e.id,projectName:e.name,markVerified:r,saveToFile:o}),o&&(this.options.persistToDisk?this.saveProjectToFile(e):this.logger.debug("Skipping project file persistence (disabled in configuration)",{projectId:e.id}))}hasProject(e){return this.projects.has(e)}markVerified(e){this.verifiedIds.add(e),this.logger.info("Marked project as verified",{projectId:e})}isVerified(e){return this.verifiedIds.has(e)}markVerifiedWithName(e,t){this.verifiedIds.add(e),this.verifiedNames.set(e,t),this.logger.info("Marked project as verified with name",{projectId:e,projectName:t})}isVerifiedWithName(e,t){return this.verifiedIds.has(e)&&this.verifiedNames.get(e)===t}getVerifiedName(e){return this.verifiedNames.get(e)}getProject(e){return this.projects.get(e)}getAllProjects(){return Array.from(this.projects.values())}clearVerificationCache(e){e?(this.verifiedIds.delete(e),this.verifiedNames.delete(e),this.logger.info("Cleared verification for project",{projectId:e})):(this.verifiedIds.clear(),this.verifiedNames.clear(),this.logger.info("Cleared all project verifications"))}saveProjectToFile(e){try{if(!o.default.existsSync(this.options.storageDirectory))try{this.logger.info("Creating storage directory",{directory:this.options.storageDirectory,absolutePath:i.default.resolve(this.options.storageDirectory)}),o.default.mkdirSync(this.options.storageDirectory,{recursive:!0}),this.logger.info("Storage directory created successfully",{directory:this.options.storageDirectory,absolutePath:i.default.resolve(this.options.storageDirectory)})}catch(e){return void this.logger.error("Failed to create storage directory",{directory:this.options.storageDirectory,absolutePath:i.default.resolve(this.options.storageDirectory),error:e instanceof Error?e.stack:e+""})}const t=i.default.join(this.options.storageDirectory,`project-${e.id}.json`)
104
+ o.default.writeFileSync(t,JSON.stringify(e,null,2),"utf8"),this.logger.info("Saved project to file",{projectId:e.id,filePath:t})}catch(t){this.logger.error("Failed to save project to file",{projectId:e.id,error:t instanceof Error?t.stack:t+""})}}async loadFromDisk(){try{if(!o.default.existsSync(this.options.storageDirectory))try{return this.logger.info("Storage directory does not exist, creating it",{directory:this.options.storageDirectory,absolutePath:i.default.resolve(this.options.storageDirectory)}),o.default.mkdirSync(this.options.storageDirectory,{recursive:!0}),void this.logger.info("Storage directory created successfully",{directory:this.options.storageDirectory,absolutePath:i.default.resolve(this.options.storageDirectory)})}catch(e){return void this.logger.error("Failed to create storage directory",{directory:this.options.storageDirectory,absolutePath:i.default.resolve(this.options.storageDirectory),error:e instanceof Error?e.stack:e+""})}const e=o.default.readdirSync(this.options.storageDirectory).filter((e=>e.startsWith("project-")&&e.endsWith(".json")))
105
+ this.logger.info("Loading projects from disk",{directory:this.options.storageDirectory,fileCount:e.length})
106
+ let t=0
107
+ for(const r of e)try{const e=i.default.join(this.options.storageDirectory,r),s=o.default.readFileSync(e,"utf8"),a=JSON.parse(s)
108
+ if(!a.id){this.logger.warn("Skipping project file with missing ID",{filePath:e})
109
+ continue}this.register(a,{saveToFile:!1}),t++}catch(e){this.logger.error("Error loading project file",{file:r,error:e instanceof Error?e.stack:e+""})}this.logger.info("Finished loading projects from disk",{totalLoaded:t,totalFiles:e.length})}catch(e){this.logger.error("Failed to load projects from disk",{error:e instanceof Error?e.stack:e+""})}}setStorageDirectory(e){this.options.storageDirectory=e,this.logger.info("Set storage directory",{directory:e})}setPersistToDisk(e){this.options.persistToDisk=e,this.logger.info("Set persist to disk",{persistToDisk:e})}}}}
package/dist/60.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict"
2
+ exports.id=60,exports.ids=[60],exports.modules={9060(e,exports,t){var i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
3
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.ConfigManager=void 0,exports.createConfigManager=function(e){return new c(e)}
4
+ const r=i(t(1943)),a=i(t(6928)),n=i(t(857)),o=t(4139),s=t(8824),l={multiAgent:!1,lockOverride:{enabled:!0,passwordValidityMinutes:5}},d={remoteServerUrl:"https://api.alchemylabcode.com",nodePath:"node"}
5
+ class c{constructor(e){this.logger=e.child({component:"config-manager"}),this.installationConfigDir=this.getInstallationConfigDir()}getInstallationConfigDir(){const e=__dirname||process.cwd(),t=n.default.homedir()
6
+ return e.includes("node_modules")?a.default.join(t,".alchemy-mcp"):a.default.join(t,".alchemy-mcp-local")}async ensureDirectory(e){try{await r.default.access(e)}catch(t){await r.default.mkdir(e,{recursive:!0}),this.logger.debug("Created directory",{dirPath:e})}}async readConfig(e,t){try{const i=await r.default.readFile(e,"utf8"),a=JSON.parse(i)
7
+ return{...t,...a}}catch(i){return"ENOENT"===i.code||this.logger.warn("Error reading config file, using defaults",{filePath:e,error:(0,s.getErrorMessage)(i)}),t}}async writeConfig(e,t){await this.ensureDirectory(a.default.dirname(e)),await r.default.writeFile(e,JSON.stringify(t,null,2),"utf8"),this.logger.debug("Wrote config file",{filePath:e})}async getProjectConfig(e){const t=a.default.join(e,o.ALCHEMY_DIR_NAME,"config.json")
8
+ return this.readConfig(t,l)}async updateProjectConfig(e,t){const i=a.default.join(e,o.ALCHEMY_DIR_NAME,"config.json"),r={...await this.getProjectConfig(e),...t}
9
+ await this.writeConfig(i,r),this.logger.info("Updated project config",{projectPath:e,updates:t})}async getProjectMetadata(e){const t=a.default.join(e,o.ALCHEMY_DIR_NAME,"project.json")
10
+ try{const e=await r.default.readFile(t,"utf8"),i=JSON.parse(e)
11
+ return{id:i.id,name:i.name,createdAt:i.createdAt,status:i.status}}catch(e){return"ENOENT"===e.code||this.logger.warn("Error reading project metadata",{projectJsonPath:t,error:(0,s.getErrorMessage)(e)}),null}}async getInstallationConfig(){const e=a.default.join(this.installationConfigDir,"config.json")
12
+ return this.readConfig(e,d)}async updateInstallationConfig(e){const t=a.default.join(this.installationConfigDir,"config.json"),i={...await this.getInstallationConfig(),...e}
13
+ await this.writeConfig(t,i),this.logger.info("Updated installation config",{updates:e})}async getEffectiveConfig(e){const[t,i,r]=await Promise.all([this.getProjectConfig(e),this.getProjectMetadata(e),this.getInstallationConfig()])
14
+ return{remoteServerUrl:r.remoteServerUrl||d.remoteServerUrl,nodePath:r.nodePath||d.nodePath,projectId:i?.id,projectName:i?.name,multiAgent:t.multiAgent||!1,preferredClient:t.preferredClient,lockOverride:{enabled:t.lockOverride?.enabled??l.lockOverride.enabled,passwordValidityMinutes:t.lockOverride?.passwordValidityMinutes??l.lockOverride.passwordValidityMinutes}}}getInstallationConfigPath(){return this.installationConfigDir}}exports.ConfigManager=c}}
package/dist/800.js ADDED
@@ -0,0 +1,23 @@
1
+ "use strict"
2
+ exports.id=800,exports.ids=[800],exports.modules={3800(e,exports,t){var r,o=this&&this.__createBinding||(Object.create?function(e,t,r,o){void 0===o&&(o=r)
3
+ var i=Object.getOwnPropertyDescriptor(t,r)
4
+ i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:()=>t[r]}),Object.defineProperty(e,o,i)}:function(e,t,r,o){void 0===o&&(o=r),e[o]=t[r]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),a=this&&this.__importStar||(r=function(e){return r=Object.getOwnPropertyNames||function(e){var t=[]
5
+ for(var r in e)({}).hasOwnProperty.call(e,r)&&(t[t.length]=r)
6
+ return t},r(e)},function(e){if(e&&e.__esModule)return e
7
+ var t={}
8
+ if(null!=e)for(var a=r(e),c=0;c<a.length;c++)"default"!==a[c]&&o(t,e,a[c])
9
+ return i(t,e),t})
10
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.SimpleProjectCreationLock=void 0
11
+ const c=a(t(1943)),s=a(t(6928)),n=t(5218),l=t(4139)
12
+ exports.SimpleProjectCreationLock=class{constructor(e,t){this.maxWaitMs=3e4,this.checkIntervalMs=500,this.lockFilePath=s.join(e,".alchemy-project-creation.lock"),this.projectFilePath=s.join(e,l.ALCHEMY_DIR_NAME,"project.json"),this.logger=t.child({component:"simple-project-creation-lock"})}async acquireLock(){if(!(0,n.isMultiAgentModeEnabled)())return this.logger.debug("Single-agent mode, skipping lock coordination"),{acquired:!0,shouldCreate:!0}
13
+ this.logger.info("Multi-agent mode: attempting to acquire project creation lock",{processId:process.pid,lockFile:this.lockFilePath})
14
+ const e=await this.loadExistingProject()
15
+ if(e)return this.logger.info("Project already exists, no creation needed",{projectId:e.id}),{acquired:!1,shouldCreate:!1,projectData:e}
16
+ try{const e={processId:process.pid,timestamp:Date.now(),lockFile:this.lockFilePath}
17
+ return await c.writeFile(this.lockFilePath,JSON.stringify(e,null,2),{flag:"wx"}),this.logger.info("Successfully acquired project creation lock",{processId:process.pid,lockFile:this.lockFilePath}),{acquired:!0,shouldCreate:!0}}catch(e){return"EEXIST"===e.code?(this.logger.info("Lock already held by another process, will wait",{processId:process.pid}),await this.waitForProjectCreation()):(this.logger.error("Error acquiring project creation lock",{error:e.message}),{acquired:!0,shouldCreate:!0})}}async releaseLock(){try{await c.unlink(this.lockFilePath),this.logger.info("Released project creation lock",{processId:process.pid})}catch(e){"ENOENT"!==e.code&&this.logger.warn("Failed to release project creation lock",{error:e.message})}}async waitForProjectCreation(){const e=Math.floor(this.maxWaitMs/this.checkIntervalMs)
18
+ this.logger.info("Waiting for project creation by another process",{maxAttempts:e,processId:process.pid})
19
+ for(let t=1;e>=t;t++){await this.sleep(this.checkIntervalMs)
20
+ const r=await this.loadExistingProject()
21
+ if(r)return this.logger.info("Project creation completed by another process",{projectId:r.id,attempt:t,processId:process.pid}),{acquired:!1,shouldCreate:!1,projectData:r}
22
+ if(!await this.lockFileExists()&&(this.logger.warn("Lock disappeared but no project found, creation may have failed",{attempt:t,processId:process.pid}),t>e/2))return this.logger.info("Attempting to acquire lock after apparent creation failure"),{acquired:!0,shouldCreate:!0}}return this.logger.error("Timeout waiting for project creation",{maxWaitMs:this.maxWaitMs,processId:process.pid}),{acquired:!0,shouldCreate:!0}}async loadExistingProject(){try{const e=await c.readFile(this.projectFilePath,"utf8"),t=JSON.parse(e)
23
+ if(t&&t.id)return t}catch(e){"ENOENT"!==e.code&&this.logger.debug("Failed to load existing project",{error:e.message})}return null}async lockFileExists(){try{return await c.access(this.lockFilePath),!0}catch{return!1}}sleep(e){return new Promise((t=>setTimeout(t,e)))}}}}
package/dist/939.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict"
2
+ exports.id=939,exports.ids=[939],exports.modules={9939(e,exports,s){function t(e){try{const s=r.default.readFileSync(e)
3
+ return u.default.createHash("md5").update(s).digest("hex")}catch{return null}}var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
4
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.syncPlugins=async function(e,s,o,i){const d={synced:[],skipped:[],errors:[]},l=i||function(e){const s=process.argv[1],t=n.default.dirname(s)
5
+ return e?t:n.default.dirname(t)}(s),c=n.default.join(e,".opencode","plugin")
6
+ try{await r.default.promises.mkdir(c,{recursive:!0})}catch(e){return o.error("Failed to create plugin directory",{destDir:c,error:e instanceof Error?e.message:"Unknown error"}),d}for(const e of a){const s=n.default.join(l,e.sourceName),a=n.default.join(c,e.destName)
7
+ try{if(!r.default.existsSync(s)){o.warn("Plugin source not found: "+e.sourceName,{sourcePath:s}),d.errors.push(e.destName)
8
+ continue}const i=await r.default.promises.readFile(s,"utf8").catch((()=>null))
9
+ if(null===i){o.warn("Could not read plugin source: "+e.sourceName),d.errors.push(e.destName)
10
+ continue}const l=e.destName.startsWith("lib/")?i:["const __plugin = (function() {\n const module = { exports: {} };\n const exports = module.exports;\n (function() {",i," })();\n return module.exports.default || module.exports;\n})();\nexport default __plugin;"].join("\n"),p=u.default.createHash("md5").update(l).digest("hex"),m=t(a)
11
+ if(null===m||p!==m){const s=n.default.dirname(a)
12
+ s!==c&&await r.default.promises.mkdir(s,{recursive:!0}),await r.default.promises.writeFile(a,l,"utf8"),o.info("Synced plugin: "+e.destName,{reason:null===m?"not installed":"updated"}),d.synced.push(e.destName)}else d.skipped.push(e.destName)}catch(s){o.error("Failed to sync plugin: "+e.destName,{error:s instanceof Error?s.message:"Unknown error"}),d.errors.push(e.destName)}}return d}
13
+ const r=o(s(9896)),n=o(s(6928)),u=o(s(6982)),a=[{sourceName:"plugins/hooks/plugin.js",destName:"event-hooks.js"},{sourceName:"plugins/hooks/lib/condition-evaluator.js",destName:"lib/condition-evaluator.js"},{sourceName:"plugins/hooks/lib/hook-utils.js",destName:"lib/hook-utils.js"},{sourceName:"plugins/hooks/lib/dedup-utils.js",destName:"lib/dedup-utils.js"},{sourceName:"plugins/inject-session.js",destName:"inject-session.js"},{sourceName:"plugins/anthropic-auth.js",destName:"anthropic-auth.js"},{sourceName:"plugins/system-logger.js",destName:"system-logger.js"}]}}
package/dist/994.js ADDED
@@ -0,0 +1,126 @@
1
+ "use strict"
2
+ exports.id=994,exports.ids=[994],exports.modules={5994(t,exports,e){var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}}
3
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.InteractiveShell=void 0
4
+ const s=r(e(3785)),a=e(5317),i=e(3807),n=r(e(6928)),o=r(e(9896)),l=r(e(6895)),c=e(4139),u=e(4192),h=e(1152)
5
+ exports.InteractiveShell=class{constructor(t){if(this.currentBranch="main",this.currentStatus=null,this.history=[],this.statusCache={map:new Map,ts:0},this.pathExecutableCache=null,this.projectPath=t.projectPath,this.currentSymlink=n.default.join(t.projectPath,c.ALCHEMY_DIR_NAME,"current"),this.currentDir=t.projectPath,this.logger=t.logger,this.historyFile=n.default.join(t.projectPath,c.ALCHEMY_DIR_NAME,"shell-history.txt"),this.projectId=t.projectId,t.remoteServerUrl){const e=(0,h.createMetricsCollector)(!1)
6
+ this.apiClient=new u.BaseApiClient(t.remoteServerUrl,t.logger,e,t.authToken)}}async start(t){return this.shutdownCallback=t,this.currentBranch="main",this.updateCurrentSymlink(),this.loadHistory(),this.rl=s.default.createInterface({input:process.stdin,output:process.stdout,prompt:this.buildPrompt(),historySize:500,removeHistoryDuplicates:!0,completer:t=>this.completer(t)}),this.history.length>0&&(this.rl.history=[...this.history].reverse()),this.printHelp(!0),this.rl.prompt(),new Promise((t=>{this.rl.on("line",(async e=>{const r=e.trim()
7
+ if(r){if(this.appendHistory(r),await this.processCommand(r))return this.rl.close(),void t()
8
+ this.rl.prompt()}else this.rl.prompt()}))
9
+ let e,r=!1
10
+ this.rl.on("SIGINT",(()=>{r?(e&&clearTimeout(e),this.rl.close()):(r=!0,console.log(""),console.log(l.default.gray("Press Ctrl+C again to exit, or continue typing.")),this.rl.prompt(),e=setTimeout((()=>{r=!1}),2e3))})),this.rl.on("close",(async()=>{this.shutdownCallback&&await this.shutdownCallback(),t()}))}))}buildPrompt(){const t=l.default.green(this.currentBranch),e=this.currentStatus&&"main"!==this.currentBranch?` ${l.default.gray("|")} ${this.colorStatus(this.currentStatus)}`:""
11
+ return`${l.default.cyan("[")}${t}${e}${l.default.cyan("]")} ${l.default.yellow("alchemy")}${l.default.gray(">")} `}colorStatus(t){switch(t){case"completed":return l.default.green(t)
12
+ case"in_progress":return l.default.yellow(t)
13
+ case"open":return l.default.blue(t)
14
+ case"ready_for_review":return l.default.magenta("review")
15
+ case"canceled":default:return l.default.gray(t)
16
+ case"reverted":return l.default.red(t)}}async fetchRequestStatus(t){if(!this.apiClient||!this.projectId)return null
17
+ try{const e=await this.apiClient.get(`/api/projects/${this.projectId}/requests/${t}`),r=e?.data||e
18
+ return r?.status||null}catch{return null}}async fetchBulkStatuses(){if(1e4>Date.now()-this.statusCache.ts&&this.statusCache.map.size>0)return this.statusCache.map
19
+ if(!this.apiClient||!this.projectId)return new Map
20
+ try{const t=await this.apiClient.get(`/api/projects/${this.projectId}/requests?limit=100&sortBy=updated&sortDirection=desc`),e=t?.data||t||[],r=new Map
21
+ for(const t of Array.isArray(e)?e:[])t.localId&&t.status&&r.set(t.localId,t.status)
22
+ return this.statusCache={map:r,ts:Date.now()},r}catch{return this.statusCache.map}}formatRequestWithStatus(t,e,r){return`${r?l.default.green(t):t}${e?" "+this.colorStatus(e):""}`}updatePrompt(){this.rl.setPrompt(this.buildPrompt())}getPathExecutables(){if(this.pathExecutableCache)return this.pathExecutableCache
23
+ const t=new Set,e=(process.env.PATH||"").split(n.default.delimiter)
24
+ for(const r of e)try{if(!o.default.existsSync(r))continue
25
+ for(const e of o.default.readdirSync(r))t.add(e)}catch{}return this.pathExecutableCache=Array.from(t).sort(),this.pathExecutableCache}completer(t){const e=["br","branch","logs","pwd","cd ","help","exit","quit"],r=t.includes(" "),s=t.indexOf(" "),a=r?t.slice(0,s).toLowerCase():""
26
+ if(r&&("br"===a||"branch"===a))return setImmediate((()=>this.rl.write("\n"))),[[],""]
27
+ if(!r){const r=e.filter((e=>e.startsWith(t))),s=t?this.getPathExecutables().filter((e=>e.startsWith(t))):[],a=[...new Set([...r,...s])]
28
+ if(a.length>0)return[a,t]
29
+ if(!t)return[e,t]}const i=t.lastIndexOf(" "),l=0>i?t:t.slice(i+1),c=0>i?"":t.slice(0,i+1)
30
+ try{const e=l.includes(n.default.sep)||l.includes("/"),r=e?n.default.resolve(this.currentDir,n.default.dirname(l)):this.currentDir,s=e?n.default.basename(l):l,a=e?n.default.dirname(l)+"/":""
31
+ if(!o.default.existsSync(r))return[[],t]
32
+ const i=o.default.readdirSync(r,{withFileTypes:!0}).filter((t=>t.name.startsWith(s)&&!t.name.startsWith("."))).map((t=>{const e=t.isDirectory()?t.name+"/":t.name
33
+ return c+a+e}))
34
+ if(i.length>0)return[i,t]}catch{}return[[],t]}async detectCurrentBranch(){try{const t=(0,i.simpleGit)(this.currentDir),e=(await t.branch()).current||"main"
35
+ this.currentBranch=this.extractRequestId(e)||e}catch{this.currentBranch="main"}}async processCommand(t){const e=t.split(/\s+/),r=e[0].toLowerCase(),s=e.slice(1)
36
+ switch(r){case"exit":case"quit":return this.shutdownCallback&&await this.shutdownCallback(),!0
37
+ case"help":return this.printHelp(!1),!1
38
+ case"br":case"branch":return await this.listBranches(s.length>0?s.join(" "):void 0),!1
39
+ case"logs":return await this.tailLogs(s),!1
40
+ case"pwd":return console.log(this.getVirtualCwd()),!1
41
+ case"cd":return this.changeDirectory(s[0]||"~"),!1
42
+ default:return this.executeCommand(t),!1}}changeDirectory(t){try{let e
43
+ if(e="~"===t||""===t?this.currentSymlink:n.default.isAbsolute(t)?t:n.default.resolve(this.currentDir,t),!o.default.existsSync(e)||!o.default.statSync(e).isDirectory())return void console.log(l.default.red("cd: no such directory: "+t))
44
+ this.currentDir=e}catch(t){console.log(l.default.red("cd: "+t.message))}}async tailLogs(t){const r=n.default.join(this.projectPath,c.ALCHEMY_DIR_NAME,"server.log")
45
+ if(!o.default.existsSync(r))return void console.log(l.default.gray("No log file found yet. Logs will appear once the server processes requests."))
46
+ const s=t[0]&&/^\d+$/.test(t[0])?parseInt(t[0],10):50
47
+ console.log(l.default.gray(`Tailing ${r} (last ${s} lines, Ctrl+C to stop)`))
48
+ const{spawn:a}=await Promise.resolve().then(e.t.bind(e,5317,23)),i=a("tail",["-n",s+"","-f",r],{stdio:["ignore","inherit","inherit"]})
49
+ return new Promise((t=>{const e=process.stdin,r=e.isRaw
50
+ this.rl.pause(),e.setRawMode(!0),e.resume()
51
+ const s=()=>{e.removeListener("data",a)
52
+ try{i.kill("SIGTERM")}catch{}try{e.setRawMode(r??!1)}catch{}this.rl.resume()},a=t=>{3!==t[0]&&"q"!==t.toString()||i.kill("SIGTERM")}
53
+ e.on("data",a),i.on("close",(()=>{s(),t()}))}))}updateCurrentSymlink(){try{let t
54
+ if("main"===this.currentBranch)t=this.projectPath
55
+ else{const e=n.default.join(this.projectPath,c.ALCHEMY_DIR_NAME,"worktrees",this.currentBranch)
56
+ t=o.default.existsSync(e)?e:this.projectPath}try{o.default.unlinkSync(this.currentSymlink)}catch{}o.default.symlinkSync(t,this.currentSymlink),this.currentDir=this.currentSymlink}catch(t){this.logger.warn("Failed to update current symlink",{error:t.message})}}getVirtualCwd(){return this.currentDir}executeCommand(t){try{(0,a.execSync)(t,{cwd:this.currentDir,stdio:"inherit",env:{...process.env,PWD:this.currentDir,GIT_DIR:void 0,GIT_WORK_TREE:void 0}})}catch(t){void 0!==t.status&&null!==t.status||console.log(l.default.red("Error: "+t.message))}}getWorktreeRequestIds(){const t=n.default.join(this.projectPath,c.ALCHEMY_DIR_NAME,"worktrees"),e=new Set
57
+ if(o.default.existsSync(t))for(const r of o.default.readdirSync(t,{withFileTypes:!0}))r.isDirectory()&&e.add(r.name)
58
+ return e}extractRequestId(t){const e=t.match(/^(?:requests\/)?(req\d+)/)
59
+ return e?e[1]:null}async listBranches(t){try{const e=(0,i.simpleGit)(this.projectPath),r=await e.branch(),s=this.getWorktreeRequestIds(),a=await this.fetchBulkStatuses(),n=new Set,o=[],c=[]
60
+ for(const t of r.all){if(t.startsWith("remotes/"))continue
61
+ if("main"===t)continue
62
+ const e=this.extractRequestId(t)
63
+ e&&!n.has(e)&&(n.add(e),o.push(e))}for(const t of s)n.has(t)||(n.add(t),o.push(t))
64
+ o.sort(((t,e)=>t.localeCompare(e)))
65
+ for(const t of o){const e=this.currentBranch===t||this.currentBranch==="requests/"+t
66
+ c.push(this.formatRequestWithStatus(t,a.get(t),e))}if(o.push("main"),c.push("main"===this.currentBranch?l.default.green("main"):"main"),0===o.length)return void console.log(l.default.gray("No branches found."))
67
+ if(t&&o.includes(t))return void(t!==this.currentBranch&&await this.switchBranch(t))
68
+ let u=o.indexOf(this.currentBranch)
69
+ 0>u&&(u=o.length-1)
70
+ const h=await this.selectFromList(o,"Select branch:",c,t?0:u,!0,t)
71
+ this.rl.pause(),h&&h!==this.currentBranch?await this.switchBranch(h):h||console.log(l.default.gray("Cancelled.")),this.rl.resume()}catch(t){console.log(l.default.red("Failed to list branches: "+t.message))}}async ensureWorktree(t,e){const r=n.default.join(this.projectPath,c.ALCHEMY_DIR_NAME,"worktrees"),s=n.default.join(r,t)
72
+ if(o.default.existsSync(s)&&o.default.statSync(s).isDirectory())return s
73
+ console.log(l.default.gray(`Creating worktree for ${t}...`)),o.default.mkdirSync(r,{recursive:!0})
74
+ const a=(0,i.simpleGit)(this.projectPath)
75
+ return await a.raw(["worktree","add",s,e]),console.log(l.default.gray("Worktree created at "+s)),s}async selectFromList(t,e,r,s,a,i){const n=t,o=r||t
76
+ return new Promise((t=>{let r=0
77
+ const c=process.stdin,u=c.isRaw
78
+ let h=!1,d=i||"",f=n.map(((t,e)=>e))
79
+ null!=s&&s>=0&&s<n.length&&(r=s)
80
+ const p=()=>{if(!d)return void(f=n.map(((t,e)=>e)))
81
+ const t=d.toLowerCase()
82
+ let e=n.map(((t,e)=>({item:t,i:e}))).filter((({item:e})=>e.toLowerCase().startsWith(t)))
83
+ 0===e.length&&/^\d+$/.test(t)&&(e=n.map(((t,e)=>({item:t,i:e}))).filter((({item:e})=>e.replace(/\D/g,"").endsWith(t)))),0===e.length&&(e=n.map(((t,e)=>({item:t,i:e}))).filter((({item:e})=>e.toLowerCase().includes(t)))),f=e.map((t=>t.i))},y=process.stdout.rows||24,g=Math.max(3,y-4)
84
+ let m=0,w=0,S=0
85
+ this.rl.pause()
86
+ const C=()=>{const t=f.length,s=t>g
87
+ s?m>r?m=r:m+g>r||(m=r-g+1):m=0
88
+ const i=(()=>{const t=f.length
89
+ if(0===t)return 1
90
+ const e=t>g
91
+ let r=e?Math.min(g,t-m):t
92
+ return e&&m>0&&r++,e&&t>m+g&&r++,r})(),n=i+1
93
+ $&&S>1&&process.stdout.write(`\r\x1b[${S-1}A\r`),n>w&&(w=n),S=w
94
+ const c=w-n
95
+ for(let t=0;c>t;t++)process.stdout.write("\x1b[2K\n")
96
+ if(0===t)process.stdout.write(`\x1b[2K ${l.default.gray("no matches")}\n`)
97
+ else{const e=s&&m>0,a=s&&t>m+g,i=s?Math.min(m+g,t):t,n=s?m:0
98
+ e&&process.stdout.write(`\x1b[2K ${l.default.gray(`\u25b2 ${m} more`)}\n`)
99
+ for(let t=n;i>t;t++){const e=f[t],s=t===r?l.default.cyan("\u276f "):" ",a=t===r?l.default.cyan(o[e]):o[e]
100
+ process.stdout.write(`\x1b[2K${s}${a}\n`)}a&&process.stdout.write(`\x1b[2K ${l.default.gray(`\u25bc ${t-i} more`)}\n`)}a&&d?process.stdout.write(`\x1b[2K${l.default.gray(">")} ${l.default.yellow(d)}${l.default.gray("_")}`):a?process.stdout.write(`\x1b[2K${l.default.gray(">")} ${l.default.gray("type to filter...")}`):process.stdout.write("\x1b[2K"+l.default.gray(e)),$=!0}
101
+ d&&(p(),r=0)
102
+ let $=!1
103
+ C(),c.setRawMode(!0),c.resume()
104
+ const b=()=>{if(!h){h=!0,c.removeListener("data",v)
105
+ try{c.setRawMode(u??!1)}catch{}$&&S>1&&process.stdout.write(`\r\x1b[${S-1}A\r`),process.stdout.write("\x1b[J"),this.rl.resume()}},v=e=>{if(!h)try{const s=e.toString()
106
+ "\x1b[A"===s?f.length>0&&(r=Math.max(0,r-1),C()):"\x1b[B"===s?f.length>0&&(r=Math.min(f.length-1,r+1),C()):"\r"===s||"\n"===s?f.length>0&&(b(),t(n[f[r]])):"\x1b"===s||"\x03"===s?(b(),t(null)):a&&"\x7f"===s?d.length>0&&(d=d.slice(0,-1),p(),r=0,m=0,C()):!a||1!==s.length||" ">s||s>"~"||(d+=s,p(),r=0,m=0,C())}catch{b(),t(null)}}
107
+ c.on("data",v)}))}findMatchingBranches(t,e,r){const s=new Set
108
+ for(const t of e){const e=this.extractRequestId(t)
109
+ e&&s.add(e)}for(const t of r)s.add(t)
110
+ const a=Array.from(s)
111
+ if(s.has(t))return[t]
112
+ const i=a.filter((e=>e.startsWith(t)))
113
+ if(i.length>0)return i.sort()
114
+ if(/^\d+$/.test(t)){const e=a.filter((e=>e.replace(/\D/g,"").endsWith(t)))
115
+ if(e.length>0)return e.sort()}return[]}async switchBranch(t){try{if("main"===t)return this.currentBranch="main",this.currentStatus=null,this.updateCurrentSymlink(),this.updatePrompt(),console.log(l.default.green("Switched to main")),void console.log(l.default.gray(" "+this.currentDir))
116
+ const e=(0,i.simpleGit)(this.projectPath),r=await e.branch(),s=this.getWorktreeRequestIds(),a=this.findMatchingBranches(t,r.all,s)
117
+ if(0===a.length)return console.log(l.default.red("No branch matching: "+t)),void console.log(l.default.gray(' Use "branches" to see available branches'))
118
+ let n
119
+ if(1===a.length)n=a[0]
120
+ else{const e=await this.fetchBulkStatuses(),r=a.map((t=>this.formatRequestWithStatus(t,e.get(t),!1))),s=await this.selectFromList(a,`Multiple matches for "${t}" \u2014 select one:`,r,void 0,!0)
121
+ if(!s)return void console.log(l.default.gray("Cancelled."))
122
+ n=s}const o=r.all.includes("requests/"+n)?"requests/"+n:n
123
+ await this.ensureWorktree(n,o),this.currentBranch=n,this.updateCurrentSymlink(),this.currentStatus=await this.fetchRequestStatus(n),this.updatePrompt()
124
+ const c=this.currentStatus?` ${l.default.gray("|")} ${this.colorStatus(this.currentStatus)}`:""
125
+ console.log(l.default.green("Switched to "+n)+c),console.log(l.default.gray(" "+this.getVirtualCwd()))}catch(t){console.log(l.default.red("Failed to switch: "+t.message))}}printHelp(t){t?(console.log(""),console.log(l.default.gray('Type "help" for available commands. Commands run in the current branch directory.')),console.log("")):(console.log(""),console.log(l.default.bold("Interactive Shell Commands:")),console.log(` ${l.default.yellow("branch")} / ${l.default.yellow("br")} Browse and switch branches`),console.log(` ${l.default.yellow("logs")} ${l.default.gray("[N]")} Tail action server log (Ctrl+C to stop, N = lines of history)`),console.log(` ${l.default.yellow("cd")} ${l.default.gray("<dir>")} Change directory within current branch`),console.log(` ${l.default.yellow("pwd")} Show current working directory`),console.log(` ${l.default.yellow("help")} Show this help`),console.log(` ${l.default.yellow("exit")} / ${l.default.yellow("quit")} Stop the server and exit`),console.log(""),console.log(l.default.gray(" Any other input is executed as a shell command in the current directory.")),console.log(""))}loadHistory(){try{if(o.default.existsSync(this.historyFile)){const t=o.default.readFileSync(this.historyFile,"utf-8")
126
+ this.history=t.split("\n").filter((t=>""!==t.trim())),this.history.length>500&&(this.history=this.history.slice(-500))}}catch{}}appendHistory(t){try{this.history.push(t),o.default.appendFileSync(this.historyFile,t+"\n")}catch{}}}}}