@kelceyp/caw-server 1.0.45 → 1.0.48

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/main.js CHANGED
@@ -729,4 +729,4 @@ State: ${z.fields.state}
729
729
 
730
730
  To confirm, call delete_story with confirm=true`}]}}let J=await $.deleteStory(K,{id:q});return{content:[{type:"text",text:`Deleted story: ${J.id} (${J.descendantCount} descendants also deleted)`}]}}catch(J){return{content:[{type:"text",text:`Error: ${J.message}`}],isError:!0}}},O16={name:"delete_story",title:"Delete Story",description:"Soft delete a story (can be restored later). If confirm is false or omitted, returns impact preview.",schema:cL1,execute:QL1};j6();var lL1=A.object({id:A.string().describe('Story ID (e.g., "As1")')}),iL1=async({core:$,projectId:K},{id:q})=>{try{let Y=await $.incrementStoryJobCount(K,{id:q});if(!Y)return{content:[{type:"text",text:`Story ${q} not found`}],isError:!0};return{content:[{type:"text",text:`Incremented activeJobCount for story ${Y.id} to: ${Y.fields.activeJobCount}`}]}}catch(Y){return{content:[{type:"text",text:`Error: ${Y.message}`}],isError:!0}}},X16={name:"increment_story_job_count",title:"Increment Story Job Count",description:"Increment a story's activeJobCount field (for manual tracking of agent activity)",schema:lL1,execute:iL1};j6();var dL1=A.object({id:A.string().describe('Story ID (e.g., "As1")')}),nL1=async({core:$,projectId:K},{id:q})=>{try{let Y=await $.decrementStoryJobCount(K,{id:q});if(!Y)return{content:[{type:"text",text:`Story ${q} not found`}],isError:!0};return{content:[{type:"text",text:`Decremented activeJobCount for story ${Y.id} to: ${Y.fields.activeJobCount}`}]}}catch(Y){return{content:[{type:"text",text:`Error: ${Y.message}`}],isError:!0}}},P16={name:"decrement_story_job_count",title:"Decrement Story Job Count",description:"Decrement a story's activeJobCount field (for manual tracking of agent activity). Guards against going below zero.",schema:dL1,execute:nL1};var w16=[z16,W16,Z16,H16,O16,X16,P16];j6();var oL1=A.object({id:A.string().describe('Asset ID (e.g., "Aa1")')}),aL1=async({core:$,projectId:K},{id:q})=>{try{let{buffer:Y,mimeType:J,sizeBytes:z,hash:W,originalFilename:Z}=await $.readAssetBinary(K,{id:q});return{content:[{type:"image",data:Y.toString("base64"),mimeType:J},{type:"text",text:JSON.stringify({id:q,originalFilename:Z,sizeBytes:z,hash:W},null,2)}]}}catch(Y){return{content:[{type:"text",text:Y.code==="ASSET_NOT_FOUND"||Y.code==="BLOB_NOT_FOUND"?Y.message:`Error: ${Y.message}`}],isError:!0}}},T16={name:"read_asset",title:"Read Asset",description:"Read an asset image by ID. Returns the image as base64-encoded data that Claude can view. Supported formats: PNG, JPEG, GIF, WebP. Maximum size: 10MB.",schema:oL1,execute:aL1};var G16=[T16];j6();var rL1=A.object({store:A.string().optional().describe('Store code (default: "A")'),status:A.string().optional().describe("Filter by status (pending, running, completed, error)")}),sL1=async({core:$,projectId:K},{store:q,status:Y})=>{try{let J=await $.listJobs(K,{store:q||"A",status:Y});if(J.length===0)return{content:[{type:"text",text:"No jobs found"}]};return{content:[{type:"text",text:J.map((W)=>`${W.id}: ${W.name} [${W.fields.status}]`).join(`
731
731
  `)}]}}catch(J){return{content:[{type:"text",text:`Error: ${J.message}`}],isError:!0}}},j16={name:"list_jobs",title:"List Jobs",description:"List all jobs",schema:rL1,execute:sL1};j6();var tL1=A.object({id:A.string().describe('Job ID (e.g., "Aj1")')}),eL1=async({core:$,projectId:K},{id:q})=>{try{let Y=await $.getJob(K,{id:q}),J=Y.fields||{};return{content:[{type:"text",text:[`Job: ${Y.id}`,`Name: ${Y.name}`,`Status: ${J.status}`,`PID: ${J.pid||"N/A"}`,`Agent: ${J.agent}`,`Started: ${J.startedAt||"N/A"}`,`Completed: ${J.completedAt||"N/A"}`].join(`
732
- `)}]}}catch(Y){return{content:[{type:"text",text:`Error: ${Y.message}`}],isError:!0}}},v16={name:"read_job",title:"Read Job",description:"Get job details",schema:tL1,execute:eL1};var V16=[j16,v16];var $I1=({core:$,projectId:K})=>{let q=new ia({name:"caw-server",version:"0.0.1"},{capabilities:{tools:{}}}),Y=[...x66,...u66,...l66,...e66,...J16,...w16,...G16,...V16];for(let J of Y)q.registerTool(J.name,{title:J.title,description:J.description,inputSchema:J.schema},async(z,W)=>{try{let Z=W?.sessionId||W?.requestInfo?.headers?.["mcp-session-id"];return await J.execute({core:$,projectId:K,sessionId:Z},z)}catch(Z){return console.error(`Tool ${J.name} failed:`,Z),{content:[{type:"text",text:`Tool execution failed: ${Z.message}`}],isError:!0}}});return q},A16=Object.freeze({createMcpServer:$I1});var qI1=da.default("caw:mcp"),X5=da.default("caw:mcp:session"),YI1=({core:$})=>{let K=new Map;return Object.freeze({handleRequest:async(W,Z,{projectId:H})=>{let O=W.headers["mcp-session-id"];if(O){let G=K.get(O);if(!G)return X5("Session not found: %s",O),Z.status(404).json({jsonrpc:"2.0",error:{code:-32001,message:"Session not found. Server may have been restarted. If so, ask user to reconnect"},id:null});if(G.projectId!==H)return X5("Session %s belongs to project %s, not %s",O,G.projectId,H),Z.status(404).json({jsonrpc:"2.0",error:{code:-32001,message:"Session not found. Server may have been restarted. If so, ask user to reconnect"},id:null});X5("Routing request to existing session: %s",O),G.lastActivity=Date.now();try{return await G.transport.handleRequest(W,Z,W.body)}catch(j){console.error("MCP transport request failed:",j)}}X5("Creating new MCP session for project: %s",H);let X=null,P=new Lo({sessionIdGenerator:()=>{return X=KI1(),X5("Generated session ID: %s",X),X},onsessioninitialized:(G)=>{X5("Session initialized: %s",G),Z.setHeader("Mcp-Session-Id",G),T.sessionId=G,K.set(G,T),X5("Session stored: %s",G)}});X5("Creating new server for session");let w=A16.createMcpServer({core:$,projectId:H});try{await w.connect(P)}catch(G){return console.error("MCP server connect failed:",G),P.close?.(),w.close?.(),Z.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:"Internal server error"},id:null})}let T={sessionId:null,transport:P,server:w,projectId:H,createdAt:Date.now(),lastActivity:Date.now()};Z.on("finish",()=>{if(Z.statusCode!==200&&X&&K.has(X))X5("Request failed (status %d), cleaning up session: %s",Z.statusCode,X),K.delete(X),P.close?.(),w.close?.()});try{await P.handleRequest(W,Z,W.body)}catch(G){console.error("MCP transport request failed:",G)}},getSession:(W)=>{return K.get(W)},closeSession:(W)=>{let Z=K.get(W);if(!Z){X5("Cannot close session - not found: %s",W);return}X5("Closing session: %s",W),Z.transport.close?.(),Z.server.close?.(),K.delete(W)},cleanupIdle:(W)=>{let Z=Date.now(),H=0;for(let[O,X]of K.entries())if(Z-X.lastActivity>W)X5("Cleaning up idle session: %s (idle for %dms)",O,Z-X.lastActivity),X.transport.close?.(),X.server.close?.(),K.delete(O),H++;if(H>0)qI1("Cleaned up %d idle sessions",H)}})},M16=Object.freeze({create:YI1});var JI1=86400000,zI1=300000,WI1=({mcpSessionManager:$})=>{let{jobFns:K,controlFns:q}=xC.create({name:"cleanup-idle-mcp-sessions",interval:zI1,execute:async()=>{$.cleanupIdle(JI1)}});return{job:Object.freeze(K),control:q}},_16=Object.freeze({create:WI1});var WS=J46.default("caw:server"),cI1=async({port:$,databaseFilepath:K,assetsDir:q,lazilyCreateDb:Y,enableRest:J,enableSse:z,enableStatic:W,enableCrons:Z,enableMcp:H=!0,enableCli:O=!0,staticPath:X,kyselyFactory:P})=>{let w=await wi8.create({databaseFilepath:K,assetsDir:q,lazilyCreateDb:Y,kyselyFactory:P}),T=Hr.default();if(T.use(Hr.default.json()),T.get("/health",(f,k)=>{k.json({status:"ok"})}),T.get("/api/info",(f,k)=>{k.json({version:"1.0.45"})}),J)T.use("/api",Jo8),vi8.create(T,{core:w}),Mi8.create(T,{core:w}),_i8.create(T,{core:w}),fi8.create(T,{core:w}),Ri8.create(T,{core:w}),Di8.create(T,{core:w}),sn8.create(T,{core:w}),en8.create(T,{core:w}),Ko8.create(T,{core:w});if(z)Yo8.create(T,{core:w});if(W&&X)Gi8.create(T,{staticPath:X});if(H){WS("Initializing MCP subsystem...");let f=M16.create({core:w});w.registerCronJob(_16,{mcpSessionManager:f}),Wo8.create(T,{core:w,mcpSessionManager:f}),WS("MCP subsystem initialized")}if(O){WS("Initializing CLI Adapter subsystem...");let f=(await Promise.resolve().then(() => (l16(),Q16))).default,k=(await Promise.resolve().then(() => (o16(),n16))).default,R=(await Promise.resolve().then(() => ($46(),e16))).default,C=(await Promise.resolve().then(() => (Y46(),q46))).default,E=R.create({mcpClientFactory:f.create(),aliasGenerator:k.create(),core:w});await E.init(),C.create(T,{cliSessionManager:E}),WS("CLI Adapter subsystem initialized")}if(Z)w.startAllCrons();let G=null,j=new Set;return Object.freeze({app:T,core:w,start:async()=>{return new Promise((f)=>{G=T.listen($,()=>{let k=G.address().port;f(k)}),G.on("connection",(k)=>{j.add(k),k.on("close",()=>{j.delete(k)})})})},stop:async()=>{if(w.stopAllCrons(),G){for(let f of j)f.destroy();return j.clear(),new Promise((f)=>{G.close(()=>{f()})})}}})},z46=Object.freeze({create:cI1});var lI1=3131,iI1=ZS.join(ZS.dirname(QI1(import.meta.url)),"public_html"),dI1=!0,nI1=!0,oI1=!0,aI1=!0,rI1=!1,sI1=!0,tI1=!0,eI1=!0,b2=($,K)=>$!==void 0?$==="true":K,$x1=()=>{let $=process.env.CAW_ENV_DIR;if(!$)console.error("ERROR: CAW_ENV_DIR environment variable is required"),console.error("Set it to the path of your environment folder, e.g.:"),console.error(' export CAW_ENV_DIR="$HOME/.caw/dev"'),process.exit(1);return{databaseFilepath:ZS.join($,"caw.db"),assetsDir:ZS.join($,"assets")}},Kx1=async($)=>{let K=await z46.create($),q=await K.start();console.log(`Server listening on port ${q}`),process.on("SIGINT",()=>K.stop("SIGINT")),process.on("SIGTERM",()=>K.stop("SIGTERM"))},qx1=()=>{let{databaseFilepath:$,assetsDir:K}=$x1(),q=process.env.CAW_PORT?Number(process.env.CAW_PORT):lI1,Y=process.env.STATIC_PATH||iI1,J=b2(process.env.LAZY_CREATE_DB,dI1),z=b2(process.env.ENABLE_REST,nI1),W=b2(process.env.ENABLE_MCP,oI1),Z=b2(process.env.ENABLE_CLI,aI1),H=b2(process.env.ENABLE_WEBLLM_WSS,rI1),O=b2(process.env.ENABLE_SSE,sI1),X=b2(process.env.ENABLE_STATIC,tI1),P=b2(process.env.ENABLE_CRONS,eI1);return Object.freeze({port:q,staticPath:Y,databaseFilepath:$,assetsDir:K,lazilyCreateDb:J,enableRest:z,enableMcp:W,enableCli:Z,enableWebllmWss:H,enableSse:O,enableStatic:X,enableCrons:P})};await Kx1(qx1()).catch(($)=>{console.error("ERROR: Failed to start server:",$),process.exit(1)});
732
+ `)}]}}catch(Y){return{content:[{type:"text",text:`Error: ${Y.message}`}],isError:!0}}},v16={name:"read_job",title:"Read Job",description:"Get job details",schema:tL1,execute:eL1};var V16=[j16,v16];var $I1=({core:$,projectId:K})=>{let q=new ia({name:"caw-server",version:"0.0.1"},{capabilities:{tools:{}}}),Y=[...x66,...u66,...l66,...e66,...J16,...w16,...G16,...V16];for(let J of Y)q.registerTool(J.name,{title:J.title,description:J.description,inputSchema:J.schema},async(z,W)=>{try{let Z=W?.sessionId||W?.requestInfo?.headers?.["mcp-session-id"];return await J.execute({core:$,projectId:K,sessionId:Z},z)}catch(Z){return console.error(`Tool ${J.name} failed:`,Z),{content:[{type:"text",text:`Tool execution failed: ${Z.message}`}],isError:!0}}});return q},A16=Object.freeze({createMcpServer:$I1});var qI1=da.default("caw:mcp"),X5=da.default("caw:mcp:session"),YI1=({core:$})=>{let K=new Map;return Object.freeze({handleRequest:async(W,Z,{projectId:H})=>{let O=W.headers["mcp-session-id"];if(O){let G=K.get(O);if(!G)return X5("Session not found: %s",O),Z.status(404).json({jsonrpc:"2.0",error:{code:-32001,message:"Session not found. Server may have been restarted. If so, ask user to reconnect"},id:null});if(G.projectId!==H)return X5("Session %s belongs to project %s, not %s",O,G.projectId,H),Z.status(404).json({jsonrpc:"2.0",error:{code:-32001,message:"Session not found. Server may have been restarted. If so, ask user to reconnect"},id:null});X5("Routing request to existing session: %s",O),G.lastActivity=Date.now();try{return await G.transport.handleRequest(W,Z,W.body)}catch(j){console.error("MCP transport request failed:",j)}}X5("Creating new MCP session for project: %s",H);let X=null,P=new Lo({sessionIdGenerator:()=>{return X=KI1(),X5("Generated session ID: %s",X),X},onsessioninitialized:(G)=>{X5("Session initialized: %s",G),Z.setHeader("Mcp-Session-Id",G),T.sessionId=G,K.set(G,T),X5("Session stored: %s",G)}});X5("Creating new server for session");let w=A16.createMcpServer({core:$,projectId:H});try{await w.connect(P)}catch(G){return console.error("MCP server connect failed:",G),P.close?.(),w.close?.(),Z.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:"Internal server error"},id:null})}let T={sessionId:null,transport:P,server:w,projectId:H,createdAt:Date.now(),lastActivity:Date.now()};Z.on("finish",()=>{if(Z.statusCode!==200&&X&&K.has(X))X5("Request failed (status %d), cleaning up session: %s",Z.statusCode,X),K.delete(X),P.close?.(),w.close?.()});try{await P.handleRequest(W,Z,W.body)}catch(G){console.error("MCP transport request failed:",G)}},getSession:(W)=>{return K.get(W)},closeSession:(W)=>{let Z=K.get(W);if(!Z){X5("Cannot close session - not found: %s",W);return}X5("Closing session: %s",W),Z.transport.close?.(),Z.server.close?.(),K.delete(W)},cleanupIdle:(W)=>{let Z=Date.now(),H=0;for(let[O,X]of K.entries())if(Z-X.lastActivity>W)X5("Cleaning up idle session: %s (idle for %dms)",O,Z-X.lastActivity),X.transport.close?.(),X.server.close?.(),K.delete(O),H++;if(H>0)qI1("Cleaned up %d idle sessions",H)}})},M16=Object.freeze({create:YI1});var JI1=86400000,zI1=300000,WI1=({mcpSessionManager:$})=>{let{jobFns:K,controlFns:q}=xC.create({name:"cleanup-idle-mcp-sessions",interval:zI1,execute:async()=>{$.cleanupIdle(JI1)}});return{job:Object.freeze(K),control:q}},_16=Object.freeze({create:WI1});var WS=J46.default("caw:server"),cI1=async({port:$,databaseFilepath:K,assetsDir:q,lazilyCreateDb:Y,enableRest:J,enableSse:z,enableStatic:W,enableCrons:Z,enableMcp:H=!0,enableCli:O=!0,staticPath:X,kyselyFactory:P})=>{let w=await wi8.create({databaseFilepath:K,assetsDir:q,lazilyCreateDb:Y,kyselyFactory:P}),T=Hr.default();if(T.use(Hr.default.json()),T.get("/health",(f,k)=>{k.json({status:"ok"})}),T.get("/api/info",(f,k)=>{k.json({version:"1.0.47"})}),J)T.use("/api",Jo8),vi8.create(T,{core:w}),Mi8.create(T,{core:w}),_i8.create(T,{core:w}),fi8.create(T,{core:w}),Ri8.create(T,{core:w}),Di8.create(T,{core:w}),sn8.create(T,{core:w}),en8.create(T,{core:w}),Ko8.create(T,{core:w});if(z)Yo8.create(T,{core:w});if(W&&X)Gi8.create(T,{staticPath:X});if(H){WS("Initializing MCP subsystem...");let f=M16.create({core:w});w.registerCronJob(_16,{mcpSessionManager:f}),Wo8.create(T,{core:w,mcpSessionManager:f}),WS("MCP subsystem initialized")}if(O){WS("Initializing CLI Adapter subsystem...");let f=(await Promise.resolve().then(() => (l16(),Q16))).default,k=(await Promise.resolve().then(() => (o16(),n16))).default,R=(await Promise.resolve().then(() => ($46(),e16))).default,C=(await Promise.resolve().then(() => (Y46(),q46))).default,E=R.create({mcpClientFactory:f.create(),aliasGenerator:k.create(),core:w});await E.init(),C.create(T,{cliSessionManager:E}),WS("CLI Adapter subsystem initialized")}if(Z)w.startAllCrons();let G=null,j=new Set;return Object.freeze({app:T,core:w,start:async()=>{return new Promise((f)=>{G=T.listen($,()=>{let k=G.address().port;f(k)}),G.on("connection",(k)=>{j.add(k),k.on("close",()=>{j.delete(k)})})})},stop:async()=>{if(w.stopAllCrons(),G){for(let f of j)f.destroy();return j.clear(),new Promise((f)=>{G.close(()=>{f()})})}}})},z46=Object.freeze({create:cI1});var lI1=3131,iI1=ZS.join(ZS.dirname(QI1(import.meta.url)),"public_html"),dI1=!0,nI1=!0,oI1=!0,aI1=!0,rI1=!1,sI1=!0,tI1=!0,eI1=!0,b2=($,K)=>$!==void 0?$==="true":K,$x1=()=>{let $=process.env.CAW_ENV_DIR;if(!$)console.error("ERROR: CAW_ENV_DIR environment variable is required"),console.error("Set it to the path of your environment folder, e.g.:"),console.error(' export CAW_ENV_DIR="$HOME/.caw/dev"'),process.exit(1);return{databaseFilepath:ZS.join($,"caw.db"),assetsDir:ZS.join($,"assets")}},Kx1=async($)=>{let K=await z46.create($),q=await K.start();console.log(`Server listening on port ${q}`),process.on("SIGINT",()=>K.stop("SIGINT")),process.on("SIGTERM",()=>K.stop("SIGTERM"))},qx1=()=>{let{databaseFilepath:$,assetsDir:K}=$x1(),q=process.env.CAW_PORT?Number(process.env.CAW_PORT):lI1,Y=process.env.STATIC_PATH||iI1,J=b2(process.env.LAZY_CREATE_DB,dI1),z=b2(process.env.ENABLE_REST,nI1),W=b2(process.env.ENABLE_MCP,oI1),Z=b2(process.env.ENABLE_CLI,aI1),H=b2(process.env.ENABLE_WEBLLM_WSS,rI1),O=b2(process.env.ENABLE_SSE,sI1),X=b2(process.env.ENABLE_STATIC,tI1),P=b2(process.env.ENABLE_CRONS,eI1);return Object.freeze({port:q,staticPath:Y,databaseFilepath:$,assetsDir:K,lazilyCreateDb:J,enableRest:z,enableMcp:W,enableCli:Z,enableWebllmWss:H,enableSse:O,enableStatic:X,enableCrons:P})};await Kx1(qx1()).catch(($)=>{console.error("ERROR: Failed to start server:",$),process.exit(1)});