alchemylab 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +21 -29
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -176,8 +176,8 @@ const s=this.timerHookScheduler.resumeHook(e.params.hookId)
176
176
  t.json({success:s})})),e.post("/api/timer-hooks/:hookId/stop",((e,t)=>{if(!this.timerHookScheduler)return void t.status(503).json({success:!1,error:"Scheduler not running"})
177
177
  const s=this.timerHookScheduler.stopHook(e.params.hookId)
178
178
  t.json({success:s})})),e.get("/api/stuck-sessions",this.handleGetStuckSessions.bind(this)),e.post("/api/stuck-sessions/test-inject",this.handleTestInjectStuckSession.bind(this)),e.post("/api/stuck-sessions/:sessionId/retry",this.handleRetryStuckSession.bind(this)),e.get("/api/version-warnings",((e,t)=>{t.json({success:!0,data:this.versionWarnings})})),e.post("/api/self-update",(async(e,s)=>{try{const{execSync:e}=await Promise.resolve().then(t.t.bind(t,5317,23)),r=e("npm root -g",{encoding:"utf8"}).trim()
179
- try{c.default.accessSync(r,c.default.constants.W_OK)}catch{return void s.json({success:!1,error:"Permission denied. Run manually: sudo npm update -g alchemylab"})}const{exec:o}=await Promise.resolve().then(t.t.bind(t,5317,23))
180
- s.json({success:!0,message:"Update started. The CLI will restart when complete."}),o("npm update -g alchemylab",{timeout:12e4},((e,t,s)=>{e?this.logger.error("Self-update failed",{error:e.message,stderr:s}):(this.logger.info("Self-update complete, shutting down for restart",{stdout:t.trim()}),setTimeout((()=>{console.log("\n\x1b[32mUpdate complete. Please restart alchemylab.\x1b[0m\n"),process.exit(0)}),1e3))}))}catch(e){s.json({success:!1,error:(0,g.getErrorMessage)(e)})}})),e.use("/api/opencode",((e,t)=>this.handleOpenCodeProxy(e,t))),e}handleHealth(e,t){t.json({status:"healthy",uptime:Math.floor((Date.now()-this.startTime.getTime())/1e3),timestamp:(new Date).toISOString()})}handleStatus(e,t){t.json({status:"running",uptime:Math.floor((Date.now()-this.startTime.getTime())/1e3),startTime:this.startTime.toISOString(),projectId:this.projectId,serverId:this.serverId,isPolling:this.isPolling,port:this.port,timestamp:(new Date).toISOString()})}handleOpenCodeConfig(e,t){const s=a.default.join(this.options.projectPath,".alchemy_lab","opencode.json")
179
+ try{c.default.accessSync(r,c.default.constants.W_OK)}catch{return void s.json({success:!1,error:"Permission denied. Run manually: sudo npm install -g alchemylab@latest"})}const{exec:o}=await Promise.resolve().then(t.t.bind(t,5317,23))
180
+ s.json({success:!0,message:"Update started. The CLI will restart when complete."}),o("npm install -g alchemylab@latest",{timeout:12e4},((e,t,s)=>{e?this.logger.error("Self-update failed",{error:e.message,stderr:s}):(this.logger.info("Self-update complete, shutting down for restart",{stdout:t.trim()}),setTimeout((()=>{console.log("\n\x1b[32mUpdate complete. Please restart alchemylab.\x1b[0m\n"),process.exit(0)}),1e3))}))}catch(e){s.json({success:!1,error:(0,g.getErrorMessage)(e)})}})),e.use("/api/opencode",((e,t)=>this.handleOpenCodeProxy(e,t))),e}handleHealth(e,t){t.json({status:"healthy",uptime:Math.floor((Date.now()-this.startTime.getTime())/1e3),timestamp:(new Date).toISOString()})}handleStatus(e,t){t.json({status:"running",uptime:Math.floor((Date.now()-this.startTime.getTime())/1e3),startTime:this.startTime.toISOString(),projectId:this.projectId,serverId:this.serverId,isPolling:this.isPolling,port:this.port,timestamp:(new Date).toISOString()})}handleOpenCodeConfig(e,t){const s=a.default.join(this.options.projectPath,".alchemy_lab","opencode.json")
181
181
  try{if(!c.default.existsSync(s))return void t.status(404).json({error:"OpenCode config not found",message:"OpenCode serve may not be running"})
182
182
  const e=c.default.readFileSync(s,"utf-8"),r=JSON.parse(e)
183
183
  t.json({port:r.port,pid:r.pid,startedAt:r.startedAt,baseUrl:"http://localhost:"+r.port,directory:this.options.projectPath,proxyEnabled:!0})}catch(e){this.logger.error("Failed to read OpenCode config",{error:(0,g.getErrorMessage)(e)}),t.status(500).json({error:"Failed to read OpenCode config",message:(0,g.getErrorMessage)(e)})}}updateDefaultModel(e){void 0!==e&&e!==this.cachedDefaultModel&&(this.cachedDefaultModel=e,this.hookExecutor.setDefaultModel(e||""),e&&this.projectId&&this.resyncAgentMarkdowns().catch((e=>this.logger.debug("Background agent markdown re-sync failed",{error:(0,g.getErrorMessage)(e)}))))}async resyncAgentMarkdowns(){if(!this.projectId)return
@@ -190,34 +190,26 @@ for(const t of e){if(!t.enabled)continue
190
190
  const e=this.configurer.generateAgentMarkdown(t,"alchemy",o,s)
191
191
  await c.default.promises.writeFile(a.default.join(r,t.name+".md"),e,"utf8")}this.logger.info("Re-synced agent markdowns after model change",{model:o,count:e.length})
192
192
  try{const e=new v.SessionSpawnService({apiClient:this.apiClient,logger:this.logger,projectId:this.projectId,getDefaultModel:()=>this.cachedDefaultModel||void 0}).getOpenCodeServerUrl(this.options.projectPath)
193
- e&&(await fetch(e+"/config/reload",{method:"POST",signal:AbortSignal.timeout(5e3)})).ok&&this.logger.info("Triggered OpenCode config reload")}catch(e){this.logger.debug("Failed to trigger OpenCode config reload",{error:(0,g.getErrorMessage)(e)})}}async handleSyncAgents(e,s){try{const e=this.readProjectConfig()
194
- if(!e?.id)return void s.status(400).json({success:!1,error:"No project configuration found"})
193
+ e&&(await fetch(e+"/config/reload",{method:"POST",signal:AbortSignal.timeout(5e3)})).ok&&this.logger.info("Triggered OpenCode config reload")}catch(e){this.logger.debug("Failed to trigger OpenCode config reload",{error:(0,g.getErrorMessage)(e)})}}async handleSyncAgents(e,t){try{const e=this.readProjectConfig()
194
+ if(!e?.id)return void t.status(400).json({success:!1,error:"No project configuration found"})
195
195
  this.logger.info("Syncing agents from remote",{projectId:e.id})
196
- const r=await this.configurer.fetchAgentsFromRemote(e.id)
197
- if(!r||0===r.length)return void s.json({success:!0,message:"No agents to sync",count:0})
198
- const o=await this.configurer.fetchProjectFromRemote(e.id)
199
- this.logger.debug("Fetched project for global prompt",{projectId:e.id,hasProject:!!o,hasGlobalSystemPrompt:!!o?.metadata?.globalSystemPrompt})
200
- const n=o?.metadata?.globalSystemPrompt
201
- n?this.logger.info("Using global system prompt from project metadata",{projectId:e.id,promptLength:n.length}):this.logger.debug("No global system prompt found in project metadata")
202
- const i=a.default.join(this.options.projectPath,".opencode","agent")
203
- await c.default.promises.mkdir(i,{recursive:!0})
204
- let l=0
205
- for(const e of r){if(!e.enabled)continue
206
- const t="alchemy",s=this.cachedDefaultModel||"anthropic/claude-opus-4-5",r=this.configurer.generateAgentMarkdown(e,t,s,n),o=a.default.join(i,e.name+".md")
207
- await c.default.promises.writeFile(o,r,"utf8"),l++,this.logger.info("Synced agent file",{name:e.name,path:o,mode:e.mode})}try{const e=a.default.join(this.options.projectPath,"opencode.json")
208
- if(c.default.existsSync(e)){const t=c.default.readFileSync(e,"utf-8"),s=JSON.parse(t),n=o?.metadata?.bashToolAgents||{}
209
- if(s.agent){for(const e of r)e.enabled&&s.agent[e.name]&&e.name in n&&(s.agent[e.name].tools.bash=!!n[e.name])
210
- c.default.writeFileSync(e,JSON.stringify(s,null,2),"utf-8"),this.logger.info("Updated opencode.json agent tools",{bashOverrides:Object.keys(n).length})}}}catch(e){this.logger.warn("Failed to update opencode.json agent tools",{error:(0,g.getErrorMessage)(e)})}let d=!1
211
- try{const e=a.default.join(this.options.projectPath,".alchemy_lab","opencode.json")
212
- if(c.default.existsSync(e)){const s=c.default.readFileSync(e,"utf-8"),r=JSON.parse(s)
213
- if(r.pid)try{process.kill(r.pid,"SIGTERM"),this.logger.info("Killed existing OpenCode process",{pid:r.pid}),await new Promise((e=>setTimeout(e,500)))}catch(e){"ESRCH"!==e?.code&&this.logger.warn("Could not kill OpenCode",{error:(0,g.getErrorMessage)(e)})}const o=r.port||0,{resolveServeCommand:n}=await Promise.resolve().then(t.bind(t,9068)),i=n(),a=(0,w.spawn)(i.command,[...i.prependArgs,"--port",o+""],{stdio:["ignore","pipe","pipe"],cwd:this.options.projectPath,detached:!0,env:process.env}),l=new Promise((e=>{let t=""
214
- const s=setTimeout((()=>{this.logger.warn("Timeout waiting for OpenCode port, killing process")
215
- try{a.kill("SIGTERM")}catch{}e(null)}),1e4)
216
- a.stdout?.on("data",(r=>{t+=r.toString()
217
- const o=t.match(/listening on http:\/\/[^:]+:(\d+)/)
218
- o&&(clearTimeout(s),a.unref(),e({port:parseInt(o[1],10),pid:a.pid}))})),a.on("error",(()=>{clearTimeout(s)
219
- try{a.kill("SIGTERM")}catch{}e(null)}))})),u=await l
220
- u&&(this.trackChildPid(u.pid),c.default.writeFileSync(e,JSON.stringify({port:u.port,pid:u.pid,startedAt:(new Date).toISOString()},null,2)),this.logger.info("Restarted OpenCode",{port:u.port,pid:u.pid}),this.setOpenCodePort(u.port),d=!0)}}catch(e){this.logger.warn("Could not restart OpenCode",{error:(0,g.getErrorMessage)(e)})}s.json({success:!0,message:`Synced ${l} agent(s) to local files${d?" - OpenCode reloading":""}`,count:l,restarted:d})}catch(e){this.logger.error("Failed to sync agents",{error:(0,g.getErrorMessage)(e)}),s.status(500).json({success:!1,error:(0,g.getErrorMessage)(e)})}}async handleGenerateJournal(e,s){try{const{requestId:r}=e.body
196
+ const s=await this.configurer.fetchAgentsFromRemote(e.id)
197
+ if(!s||0===s.length)return void t.json({success:!0,message:"No agents to sync",count:0})
198
+ const r=await this.configurer.fetchProjectFromRemote(e.id)
199
+ this.logger.debug("Fetched project for global prompt",{projectId:e.id,hasProject:!!r,hasGlobalSystemPrompt:!!r?.metadata?.globalSystemPrompt})
200
+ const o=r?.metadata?.globalSystemPrompt
201
+ o?this.logger.info("Using global system prompt from project metadata",{projectId:e.id,promptLength:o.length}):this.logger.debug("No global system prompt found in project metadata")
202
+ const n=a.default.join(this.options.projectPath,".opencode","agent")
203
+ await c.default.promises.mkdir(n,{recursive:!0})
204
+ let i=0
205
+ for(const e of s){if(!e.enabled)continue
206
+ const t="alchemy",s=this.cachedDefaultModel||"anthropic/claude-opus-4-5",r=this.configurer.generateAgentMarkdown(e,t,s,o),l=a.default.join(n,e.name+".md")
207
+ await c.default.promises.writeFile(l,r,"utf8"),i++,this.logger.info("Synced agent file",{name:e.name,path:l,mode:e.mode})}try{const e=a.default.join(this.options.projectPath,"opencode.json")
208
+ if(c.default.existsSync(e)){const t=c.default.readFileSync(e,"utf-8"),o=JSON.parse(t),n=r?.metadata?.bashToolAgents||{}
209
+ if(o.agent){for(const e of s)e.enabled&&o.agent[e.name]&&e.name in n&&(o.agent[e.name].tools.bash=!!n[e.name])
210
+ c.default.writeFileSync(e,JSON.stringify(o,null,2),"utf-8"),this.logger.info("Updated opencode.json agent tools",{bashOverrides:Object.keys(n).length})}}}catch(e){this.logger.warn("Failed to update opencode.json agent tools",{error:(0,g.getErrorMessage)(e)})}let l=!1
211
+ try{const e=new v.SessionSpawnService({apiClient:this.apiClient,logger:this.logger,projectId:this.projectId,getDefaultModel:()=>this.cachedDefaultModel||void 0}).getOpenCodeServerUrl(this.options.projectPath)
212
+ e&&(await fetch(e+"/config/reload",{method:"POST",signal:AbortSignal.timeout(5e3)})).ok&&(this.logger.info("Triggered OpenCode config reload after agent sync"),l=!0)}catch(e){this.logger.warn("Could not reload OpenCode config",{error:(0,g.getErrorMessage)(e)})}t.json({success:!0,message:`Synced ${i} agent(s) to local files${l?" - config reloaded":""}`,count:i,reloaded:l})}catch(e){this.logger.error("Failed to sync agents",{error:(0,g.getErrorMessage)(e)}),t.status(500).json({success:!1,error:(0,g.getErrorMessage)(e)})}}async handleGenerateJournal(e,s){try{const{requestId:r}=e.body
221
213
  if(!r)return void s.status(400).json({success:!1,error:"requestId is required"})
222
214
  if(!/^req\d+$/.test(r))return void s.status(400).json({success:!1,error:"Invalid requestId format"})
223
215
  this.logger.info("Generating journal for request",{requestId:r})
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alchemylab",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "private": false,
5
5
  "description": "AlchemyLab - agentic coding IDEm",
6
6
  "author": "Testfire Software",
@@ -49,7 +49,7 @@
49
49
  "ws": "^8.14.2",
50
50
  "zod": "^3.22.4",
51
51
  "zod-to-json-schema": "^3.22.3",
52
- "alchemylab-opencode": "^1.0.12"
52
+ "alchemylab-opencode": "^1.0.13"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/chai": "^4.3.5",