alchemylab 1.3.5 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,8 +48,8 @@ t.push(` ${s+1}. ${n}`)}))),t.push("Created: "+e.createdAt),t.push("Updated: "+
48
48
  t.push(` [${s}] ${e.id} ${e.title||"(untitled)"}`)}))),t.join("\n")}(i.data)):n(i.error||"Failed to get request")}case"wait-for-idle":{if(!e.sessionId)return n("sessionId is required for wait-for-idle")
49
49
  const i=e.timeoutSeconds||120,o=Date.now()+1e3*i,r=2e3
50
50
  let a=!1
51
- const d=Date.now()+1e4
52
- for(;Date.now()<d&&Date.now()<o;){const s=await t.sendCommand("get-session-status",{sessionId:e.sessionId})
51
+ const c=Date.now()+1e4
52
+ for(;Date.now()<c&&Date.now()<o;){const s=await t.sendCommand("get-session-status",{sessionId:e.sessionId})
53
53
  if(!s.success)return n(s.error||"Failed to check session status")
54
54
  if("busy"===s.data.status){a=!0
55
55
  break}await new Promise((e=>setTimeout(e,500)))}for(;Date.now()<o;){const i=await t.sendCommand("get-session-status",{sessionId:e.sessionId})
@@ -58,7 +58,7 @@ const o=i.data
58
58
  if(("idle"===o.status||"error"===o.status)&&a)return s(`Session ${o.id} is now ${o.status}. Title: ${o.title||"(none)"}`)
59
59
  "busy"===o.status&&(a=!0),await new Promise((e=>setTimeout(e,r)))}return n(`Session ${e.sessionId} did not become idle within ${i}s`)}default:return n("Unknown operation: "+i)}var r}
60
60
  const i=t(1569),o=t(8524)
61
- exports.CLIBridgeOperationsSchema=i.z.object({operation:i.z.enum(["list-sessions","get-messages","send-message","create-session","get-session-status","wait-for-idle","list-notifications","get-notification","respond-to-notification","list-requests","get-request"]).describe("The CLI operation to perform"),sessionId:i.z.string().optional().describe("OpenCode session ID"),message:i.z.string().optional().describe("Message text to send"),agent:i.z.string().optional().describe("Agent to use for the message"),variant:i.z.string().optional().describe('Thinking variant (e.g., "high", "max")'),system:i.z.string().optional().describe("System instructions for the message"),limit:i.z.number().optional().describe("Max number of messages to return"),directory:i.z.string().optional().describe("Directory for the new session"),title:i.z.string().optional().describe("Title for the new session"),parentId:i.z.string().optional().describe("Parent session ID for child sessions"),timeoutSeconds:i.z.number().optional().describe("Max seconds to wait (default: 120)"),includeArchived:i.z.boolean().optional().describe("Include archived sessions"),status:i.z.string().optional().describe('Filter sessions by status (e.g., "idle", "busy")'),agentType:i.z.string().optional().describe("Filter sessions by agent type"),search:i.z.string().optional().describe("Search sessions by title (case-insensitive substring match)"),requestId:i.z.string().optional().describe('Request ID (e.g., "req004643")'),type:i.z.string().optional().describe('Filter requests by type (e.g., "feature", "bugfix")'),offset:i.z.number().optional().describe("Offset for paginated results"),sortBy:i.z.string().optional().describe('Sort field (e.g., "created", "updated")'),sortDirection:i.z.string().optional().describe('Sort direction ("asc" or "desc")'),messageCode:i.z.string().optional().describe('Session message code (e.g., "Q-abc-001" or "R-abc-001")'),responseText:i.z.string().optional().describe("Text answer for free-form questions"),selectedOptions:i.z.array(i.z.string()).optional().describe("Selected option IDs for alternatives questions"),messageType:i.z.string().optional().describe('Filter by message type: "question" or "report"')})},5086(module){module.exports=require("ws")},5106(module){module.exports=require("zod-to-json-schema")},5802(module){module.exports=require("@modelcontextprotocol/sdk/server/stdio.js")},6865(module){module.exports=require("@modelcontextprotocol/sdk/server/index.js")},6982(module){module.exports=require("crypto")},8524(e,exports,t){var s=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
61
+ exports.CLIBridgeOperationsSchema=i.z.object({operation:i.z.enum(["list-sessions","get-messages","send-message","create-session","get-session-status","wait-for-idle","list-notifications","get-notification","respond-to-notification","list-requests","get-request"]).describe("The CLI operation to perform"),sessionId:i.z.string().optional().describe("OpenCode session ID"),message:i.z.string().optional().describe("Message text to send"),agent:i.z.string().optional().describe("Agent to use for the message"),variant:i.z.string().optional().describe('Thinking variant (e.g., "high", "max")'),system:i.z.string().optional().describe("System instructions for the message"),limit:i.z.number().optional().describe("Max number of messages to return"),directory:i.z.string().optional().describe("Directory for the new session"),title:i.z.string().optional().describe("Title for the new session"),parentId:i.z.string().optional().describe("Parent session ID for child sessions"),timeoutSeconds:i.z.number().optional().describe("Max seconds to wait (default: 120)"),includeArchived:i.z.boolean().optional().describe("Include archived sessions"),status:i.z.string().optional().describe('Filter sessions by status (e.g., "idle", "busy")'),agentType:i.z.string().optional().describe("Filter sessions by agent type"),search:i.z.string().optional().describe("Search sessions by title (case-insensitive substring match)"),requestId:i.z.string().optional().describe('Request ID (e.g., "req004643")'),type:i.z.string().optional().describe('Filter requests by type (e.g., "feature", "bugfix")'),offset:i.z.number().optional().describe("Offset for paginated results"),sortBy:i.z.string().optional().describe('Sort field (e.g., "created", "updated")'),sortDirection:i.z.string().optional().describe('Sort direction ("asc" or "desc")'),messageCode:i.z.string().optional().describe('Session message code (e.g., "Q-abc-001" or "R-abc-001")'),responseText:i.z.string().optional().describe("Text answer for free-form questions"),selectedOptions:i.z.array(i.z.string()).optional().describe("Selected option IDs for alternatives questions"),messageType:i.z.string().optional().describe('Filter by message type: "question" or "report"')})},5086(module){module.exports=require("ws")},5106(module){module.exports=require("zod-to-json-schema")},5802(module){module.exports=require("@modelcontextprotocol/sdk/server/stdio.js")},6865(module){module.exports=require("@modelcontextprotocol/sdk/server/index.js")},6928(module){module.exports=require("path")},6982(module){module.exports=require("crypto")},8524(e,exports,t){var s=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
62
62
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.CLIBridgeWebSocket=void 0,exports.setCLIBridge=function(e){o=e},exports.getCLIBridge=function(){return o}
63
63
  const n=t(5086),i=s(t(6982))
64
64
  exports.CLIBridgeWebSocket=class{constructor(e,t=3e4){this.wss=null,this.uiClient=null,this.pendingCommands=new Map,this.heartbeatInterval=null,this.logger=e,this.defaultTimeout=t}attach(e){this.wss=new n.WebSocketServer({server:e,path:"/ws/cli-bridge"}),this.wss.on("connection",(e=>{this.logger.info("[CLIBridge] UI client connected"),this.uiClient&&(this.logger.warn("[CLIBridge] Replacing existing UI client connection"),this.uiClient.close(1e3,"Replaced by new connection")),this.uiClient=e,this.startHeartbeat(),e.on("message",(e=>{try{const t=JSON.parse(e.toString())
@@ -71,18 +71,26 @@ try{this.uiClient.send(JSON.stringify(o))}catch(e){clearTimeout(r),this.pendingC
71
71
  t?(clearTimeout(t.timer),this.pendingCommands.delete(e.id),t.resolve(e)):this.logger.warn("[CLIBridge] Received response for unknown command",{id:e.id})}startHeartbeat(){this.stopHeartbeat(),this.heartbeatInterval=setInterval((()=>{this.uiClient&&this.uiClient.readyState===n.WebSocket.OPEN&&this.uiClient.ping()}),3e4)}stopHeartbeat(){this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null)}close(){this.stopHeartbeat()
72
72
  for(const[e,t]of this.pendingCommands)clearTimeout(t.timer),t.reject(Error("Bridge shutting down")),this.pendingCommands.delete(e)
73
73
  this.uiClient&&(this.uiClient.close(1e3,"Server shutting down"),this.uiClient=null),this.wss&&(this.wss.close(),this.wss=null)}}
74
- let o=null},9150(module){module.exports=require("@modelcontextprotocol/sdk/types.js")}},s={},n={};(()=>{Object.defineProperty(n,"__esModule",{value:!0})
75
- const t=e(6865),s=e(5802),i=e(9150),o=e(5106),r=e(2904),a=e(8524),d=process.argv.slice(2)
76
- let c=3456
77
- for(let e=0;e<d.length;e++)"--port"===d[e]&&d[e+1]&&(c=parseInt(d[e+1],10),e++)
78
- const u=(...e)=>process.stderr.write(`[cli-bridge] ${e.join(" ")}\n`),l=new class{isUIConnected(){return!0}async sendCommand(e,t={},s){return async function(e,t,s){const n=`http://127.0.0.1:${c}/api/cli-bridge/command`,i=new AbortController,o=s||3e4,r=setTimeout((()=>i.abort()),o+5e3)
74
+ let o=null},9150(module){module.exports=require("@modelcontextprotocol/sdk/types.js")},9414(e,exports,t){function s(e){const t=Date.now(),s=!e
75
+ if(s&&null!==c&&u>t-d)return c
76
+ const l=(0,i.join)(e||process.env.ALCHEMY_PROJECT_PATH||process.cwd(),r,a)
77
+ if((0,n.existsSync)(l))try{const e=(0,n.readFileSync)(l,"utf-8"),i=JSON.parse(e)
78
+ if("number"==typeof i.port&&i.port>0&&65536>i.port)return s&&(c=i.port,d=t),i.port}catch{}return s&&(c=o,d=t),o}Object.defineProperty(exports,"__esModule",{value:!0}),exports.getActionServerPort=s,exports.getActionServerBaseUrl=function(){return"http://localhost:"+s()}
79
+ const n=t(9896),i=t(6928),o=3456,r=".alchemy_lab",a="action-server.json"
80
+ let c=null,d=0
81
+ const u=5e3},9896(module){module.exports=require("fs")}},s={},n={};(()=>{Object.defineProperty(n,"__esModule",{value:!0})
82
+ const t=e(6865),s=e(5802),i=e(9150),o=e(5106),r=e(2904),a=e(8524),c=process.argv.slice(2)
83
+ let d=null
84
+ for(let e=0;e<c.length;e++)"--port"===c[e]&&c[e+1]&&(d=parseInt(c[e+1],10),e++)
85
+ if(null===d)try{const{getActionServerPort:t}=e(9414)
86
+ d=t()}catch{d=3456}const u=(...e)=>process.stderr.write(`[cli-bridge] ${e.join(" ")}\n`),l=new class{isUIConnected(){return!0}async sendCommand(e,t={},s){return async function(e,t,s){const n=`http://127.0.0.1:${d}/api/cli-bridge/command`,i=new AbortController,o=s||3e4,r=setTimeout((()=>i.abort()),o+5e3)
79
87
  try{const s=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:e,params:t,timeout:o}),signal:i.signal})
80
88
  if(!s.ok){const e=await s.text()
81
- return{success:!1,error:`Action server error (${s.status}): ${e}`}}return await s.json()}catch(e){return"AbortError"===e.name?{success:!1,error:`Command timed out after ${o/1e3}s`}:{success:!1,error:`Cannot reach action server at port ${c}: ${e.message}`}}finally{clearTimeout(r)}}(e,t,s)}};(0,a.setCLIBridge)(l)
89
+ return{success:!1,error:`Action server error (${s.status}): ${e}`}}return await s.json()}catch(e){return"AbortError"===e.name?{success:!1,error:`Command timed out after ${o/1e3}s`}:{success:!1,error:`Cannot reach action server at port ${d}: ${e.message}`}}finally{clearTimeout(r)}}(e,t,s)}};(0,a.setCLIBridge)(l)
82
90
  const p=new t.Server({name:"alchemy-cli-bridge",version:"1.0.0"},{capabilities:{tools:{}}})
83
91
  p.setRequestHandler(i.ListToolsRequestSchema,(async()=>({tools:[{name:"cli_operations",description:"Interact with OpenCode CLI sessions through alchemy-ui.\n\nOperations:\n list-sessions \u2014 List all active sessions with status and agent type\n Filters: status?, agentType?, search? (title), limit?, includeArchived?\n get-messages \u2014 Get messages from a session (params: sessionId, limit?)\n send-message \u2014 Send a message to a session (params: sessionId, message, agent?, variant?, system?)\n create-session \u2014 Create a new session (params: directory?, title?, parentId?)\n get-session-status \u2014 Check if a session is busy/idle (params: sessionId)\n wait-for-idle \u2014 Wait until a session finishes (params: sessionId, timeoutSeconds?)\n\nRequest operations (no UI connection needed):\n list-requests \u2014 List recent requests (params: status?, type?, limit?, offset?)\n get-request \u2014 Get a specific request with its tasks (params: requestId)\n\nNotification operations (no UI connection needed):\n list-notifications \u2014 List recent notifications (params: sessionId?, messageType?, status?, limit?)\n get-notification \u2014 Get a specific notification by code (params: messageCode)\n respond-to-notification \u2014 Answer a question or acknowledge a report (params: messageCode, responseText?, selectedOptions?)\n\nRequires: alchemy action server running (port 3456) and OpenCode running.",inputSchema:(0,o.zodToJsonSchema)(r.CLIBridgeOperationsSchema)}]}))),p.setRequestHandler(i.CallToolRequestSchema,(async e=>{const{name:t,arguments:s={}}=e.params
84
92
  if("cli_operations"!==t)return{content:[{type:"text",text:"Unknown tool: "+t}],isError:!0}
85
93
  try{const e=r.CLIBridgeOperationsSchema.parse(s)
86
- return await(0,r.handleCLIBridgeOperations)(e)}catch(e){return{content:[{type:"text",text:"Error: "+e.message}],isError:!0}}})),async function(){u("Starting CLI Bridge MCP server"),u("Action server port: "+c)
94
+ return await(0,r.handleCLIBridgeOperations)(e)}catch(e){return{content:[{type:"text",text:"Error: "+e.message}],isError:!0}}})),async function(){u("Starting CLI Bridge MCP server"),u("Action server port: "+d)
87
95
  const e=new s.StdioServerTransport
88
96
  await p.connect(e),u("CLI Bridge MCP server ready (stdio)")}().catch((e=>{u("Fatal error:",e),process.exit(1)})),process.on("SIGTERM",(()=>process.exit(0))),process.on("SIGINT",(()=>process.exit(0)))})(),module.exports=n})()