@whoz-oss/coday-server 3.9.0 → 3.10.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.
- package/package.json +1 -1
- package/server.js +3 -3
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -1721,16 +1721,16 @@ Transcript:
|
|
|
1721
1721
|
${s.join(`
|
|
1722
1722
|
`)}
|
|
1723
1723
|
|
|
1724
|
-
JSON:`,c,u;try{let p=(await this.aiClient.complete(o,{maxTokens:300})).replace(/^```(?:json)?\s*/i,"").replace(/\s*```$/,"").trim(),h=JSON.parse(p);c=typeof h.name=="string"?h.name.trim().slice(0,60):void 0,u=typeof h.summary=="string"?h.summary.trim():void 0}catch(d){ie("POST_PROCESSOR",`Failed to parse AI response for thread ${e.id}:`,d);return}if(!c&&!u){ie("POST_PROCESSOR",`Nothing to update for thread ${e.id}`);return}let f={};u&&(f.summary=u),c&&!e.name&&(f.name=c);try{await this.threadService.updateThread(r,e.id,f),ie("POST_PROCESSOR",`Thread ${e.id} updated \u2014 name: ${f.name??"(kept)"}, summary: ${!!f.summary}`)}catch(d){ie("POST_PROCESSOR",`Failed to persist updates for thread ${e.id}:`,d)}}};var aV=class t{constructor(e,r,n,i,s,a,o,c,u,f,d,p
|
|
1724
|
+
JSON:`,c,u;try{let p=(await this.aiClient.complete(o,{maxTokens:300})).replace(/^```(?:json)?\s*/i,"").replace(/\s*```$/,"").trim(),h=JSON.parse(p);c=typeof h.name=="string"?h.name.trim().slice(0,60):void 0,u=typeof h.summary=="string"?h.summary.trim():void 0}catch(d){ie("POST_PROCESSOR",`Failed to parse AI response for thread ${e.id}:`,d);return}if(!c&&!u){ie("POST_PROCESSOR",`Nothing to update for thread ${e.id}`);return}let f={};u&&(f.summary=u),c&&!e.name&&(f.name=c);try{await this.threadService.updateThread(r,e.id,f),ie("POST_PROCESSOR",`Thread ${e.id} updated \u2014 name: ${f.name??"(kept)"}, summary: ${!!f.summary}`)}catch(d){ie("POST_PROCESSOR",`Failed to persist updates for thread ${e.id}:`,d)}}};var aV=class t{constructor(e,r,n,i,s,a,o,c,u,f,d,p){this.threadId=e;this.projectName=r;this.username=n;this.options=i;this.logger=s;this.projectService=a;this.threadService=o;this.promptService=c;this.mcpPool=u;this.onTimeout=f;this.projectEventManager=d;this.setPendingInviteCb=p;this.resetInactivityTimeout()}connections=new Set;lastActivity=Date.now();inactivityTimeout;isOneshot=!1;isReplaying=!1;isCleaningUp=!1;coday;static INTERACTIVE_TIMEOUT=480*60*1e3;static ONESHOT_TIMEOUT=1800*1e3;addConnection(e){this.connections.has(e)||(this.connections.add(e),this.updateActivity(),this.isOneshot=!1,ie("THREAD_CODAY",`Added SSE connection to thread ${this.threadId} (total: ${this.connections.size})`),ie("THREAD_CODAY",`Replaying thread history for new connection to ${this.threadId}`),this.replayThreadHistory(e))}async replayThreadHistory(e){try{let r;if(this.coday?.context?.aiThread)r=(await this.coday.context.aiThread.getMessages(void 0,void 0)).messages;else{let n=await this.threadService.getThread(this.projectName,this.threadId);if(!n){ie("THREAD_CODAY",`No thread found on disk for replay in ${this.threadId}`);return}r=n.getAllMessages()}ie("THREAD_CODAY",`Replaying ${r.length} messages for thread ${this.threadId}`);for(let n of r){if(n.type==="invite"||n.type==="choice")continue;let i=`data: ${JSON.stringify(n)}
|
|
1725
1725
|
|
|
1726
|
-
`;e.writableEnded||e.write(
|
|
1726
|
+
`;e.writableEnded||e.write(i)}this.isReplaying=!0;try{this.coday?.interactor.replayLastQuestion()}finally{this.isReplaying=!1}}catch(r){ie("THREAD_CODAY","Error replaying thread history:",r)}}removeConnection(e){this.connections.delete(e),ie("THREAD_CODAY",`Removed SSE connection from thread ${this.threadId} (remaining: ${this.connections.size})`)}get connectionCount(){return this.connections.size}updateActivity(){this.lastActivity=Date.now(),this.resetInactivityTimeout()}resetInactivityTimeout(){this.inactivityTimeout&&clearTimeout(this.inactivityTimeout);let e=this.isOneshot?t.ONESHOT_TIMEOUT:t.INTERACTIVE_TIMEOUT;this.inactivityTimeout=setTimeout(()=>{let r=Date.now()-this.lastActivity;ie("THREAD_CODAY",`Inactivity timeout reached for thread ${this.threadId} after ${Math.round(r/1e3)}s`),this.onTimeout(this.threadId)},e)}markAsOneshot(){this.isOneshot=!0,this.resetInactivityTimeout()}getInactiveTime(){return Date.now()-this.lastActivity}prepareCoday(){if(this.updateActivity(),this.coday)return ie("THREAD_CODAY",`Coday already running for thread ${this.threadId}`),!1;ie("THREAD_CODAY",`Creating Coday instance for thread ${this.threadId}`),console.log(`[THREAD_CODAY] Preparing instance for thread '${this.threadId}' (project: ${this.projectName}, user: ${this.username})`);let e=new Xf(this.threadId),r=new C0(this.options.configDir,this.username,e),n=new py(e,this.projectService,this.options.configDir),i=new ay(n,r),s=new sy(r,n,e),a=new uy(n,r),o=new cy(r,n,e);return e.events.subscribe(c=>{this.broadcastEvent(c)}),this.coday=new nV(e,this.options,{user:r,project:n,projectService:this.projectService,integration:i,integrationConfig:s,memory:a,mcp:o,mcpPool:this.mcpPool,thread:this.threadService,prompt:this.promptService,logger:this.logger,options:this.options}),console.log(`[THREAD_CODAY] Instance created for thread '${this.threadId}'`),!0}async runOneshot(e){if(this.prepareCoday(),!this.coday)throw new Error(`prepareCoday() failed for thread ${this.threadId} \u2014 coday instance is undefined`);if(this.projectEventManager?.broadcast(this.projectName,new Ts({threadId:this.threadId})),e?.awaitFinalAnswer){let r=[],n=this.coday.interactor.events.pipe((0,tmt.filter)(i=>i instanceof fr&&i.role==="assistant"&&!!i.name)).subscribe(i=>r.push(i));try{return await this.coday.run(),n.unsubscribe(),r[r.length-1]}catch(i){throw n.unsubscribe(),i}}else{this.coday.run().catch(r=>{ie("THREAD_CODAY",`Error during oneshot run for thread ${this.threadId}:`,r),console.error(`Oneshot run failed for thread ${this.threadId}:`,r)});return}}startCoday(){this.updateActivity();let e=this.prepareCoday();return this.coday?e?(this.coday.run().catch(r=>{ie("THREAD_CODAY",`Error during Coday run for thread ${this.threadId}:`,r),console.error(`Coday run failed for thread ${this.threadId}:`,r)}).finally(()=>{ie("THREAD_CODAY",`Coday run finished for thread ${this.threadId}`)}),e):(ie("THREAD_CODAY",`Instance already running for thread ${this.threadId}, skipping run()`),!1):!1}sendHeartbeat(){if(this.connections.size!==0)try{let e=new Im({});this.broadcastEvent(e)}catch(e){ie("THREAD_CODAY",`Error sending heartbeat for thread ${this.threadId}:`,e)}}broadcastEvent(e){if(!this.isReplaying&&(e instanceof ps&&e.invite!==o8||e instanceof hs)&&(this.setPendingInviteCb(this.threadId),this.projectEventManager?.broadcast(this.projectName,new Ts({threadId:this.threadId}))),!this.isReplaying&&e instanceof fr&&e.role==="assistant"){let n=e.getTextContent().trim();if(n){let i=n.split(`
|
|
1727
1727
|
`).map(a=>a.trim()).filter(Boolean);(i[i.length-1]??"").includes("?")&&(this.setPendingInviteCb(this.threadId),this.projectEventManager?.broadcast(this.projectName,new Ts({threadId:this.threadId})))}}if(e instanceof Ts&&(e.name||e.summary)&&!this.isCleaningUp&&(ie("THREAD_CODAY",`Updating thread cache for ${this.threadId} name/summary`),(async()=>{try{let n=await this.threadService.getThread(this.projectName,this.threadId);if(!n)return;e.name&&(n.name=e.name),e.summary&&(n.summary=e.summary),n.messagesLength>0&&await this.threadService.updateThread(this.projectName,this.threadId,{name:e.name,summary:e.summary})}catch(n){ie("THREAD_CODAY","Error updating thread cache:",n)}})(),this.projectEventManager?.broadcast(this.projectName,e)),e instanceof ps&&e.invite!==o8||e instanceof hs){let n={...e,threadId:this.threadId};this.projectEventManager?.broadcast(this.projectName,n)}let r=`data: ${JSON.stringify(e)}
|
|
1728
1728
|
|
|
1729
1729
|
`;for(let n of this.connections)try{n.writableEnded?this.connections.delete(n):n.write(r)}catch(i){ie("THREAD_CODAY","Error broadcasting to connection:",i),this.connections.delete(n)}}stop(){this.coday?.stop()}async handleOAuthCallback(e){if(!this.coday){ie("THREAD_CODAY",`Cannot handle OAuth callback: Coday not initialized for thread ${this.threadId}`);return}if(!this.coday.services.agent){ie("THREAD_CODAY","Cannot handle OAuth callback: Agent service not initialized");return}let n=this.coday.services.agent?.toolbox;if(!n){ie("THREAD_CODAY","Cannot handle OAuth callback: Toolbox not initialized");return}ie("THREAD_CODAY",`Routing OAuth callback for ${e.integrationName}`),await n.handleOAuthCallback(e)}async cleanup(){this.isCleaningUp=!0,ie("THREAD_CODAY",`Cleaning up thread ${this.threadId}`),this.inactivityTimeout&&(clearTimeout(this.inactivityTimeout),this.inactivityTimeout=void 0);for(let n of this.connections)try{n.end()}catch(i){ie("THREAD_CODAY","Error closing connection:",i)}this.connections.clear();let e,r;if(this.coday){let n=this.coday.aiThreadService;e=this.coday.context?.aiThread??n?.getCurrentThread();let i=this.coday.aiClientProvider;r=i?.getClient(void 0,"SMALL")??i?.getClient(void 0),ie("THREAD_CODAY",`Pre-kill snapshot for ${this.threadId}: thread=${!!e} (${e?.messagesLength??0} msgs), aiClient=${!!r}`)}if(this.coday){try{await this.coday.kill()}catch(n){ie("THREAD_CODAY","Error during Coday kill:",n)}this.coday=void 0}if(e&&r){let n=new sV(r,this.threadService);try{let i=Date.now();await Promise.race([n.process(e,this.projectName).then(()=>"completed"),new Promise(a=>setTimeout(()=>a("timeout"),1e4))])==="timeout"?ie("THREAD_CODAY",`Post-processing TIMED OUT for thread ${this.threadId} after 10s (thread data is safe, only name/summary may be missing)`):ie("THREAD_CODAY",`Post-processing completed for thread ${this.threadId} in ${Date.now()-i}ms`)}catch(i){ie("THREAD_CODAY",`Post-processing error for thread ${this.threadId}:`,i)}}else ie("THREAD_CODAY",`Skipping post-processing for thread ${this.threadId}: no thread or AI client`)}},oV=class t{constructor(e,r,n,i,s){this.logger=e;this.projectService=r;this.threadService=n;this.promptService=i;this.mcpPool=s;this.heartbeatInterval=setInterval(()=>this.sendHeartbeats(),t.HEARTBEAT_INTERVAL),ie("THREAD_CODAY_MANAGER","Heartbeat mechanism started"),this.projectEventManager.onNewConnection=(a,o)=>{this.replayActiveStatusForProject(a,o)},this.projectEventManager.onNewGlobalConnection=a=>{for(let o of this.instances.values()){if(!this.pendingInvites.has(o.threadId))continue;let c=o.coday?.interactor?.getLastQuestionEvent();if(c){let u={...c,threadId:o.threadId,projectName:o.projectName},f=`data: ${JSON.stringify(u)}
|
|
1730
1730
|
|
|
1731
1731
|
`;try{a.writableEnded||a.write(f)}catch{}}}}}instances=new Map;heartbeatInterval;projectEventManager=new iV;pendingInvites=new Set;static HEARTBEAT_INTERVAL=3e4;setPendingInvite(e){this.pendingInvites.add(e)}clearPendingInvite(e){this.pendingInvites.delete(e)}hasPendingInvite(e){return this.pendingInvites.has(e)}replayActiveStatusForProject(e,r){for(let n of this.instances.values()){if(n.projectName!==e||!this.pendingInvites.has(n.threadId))continue;let i=n.coday?.interactor?.getLastQuestionEvent();if(i){let s={...i,threadId:n.threadId},a=`data: ${JSON.stringify(s)}
|
|
1732
1732
|
|
|
1733
|
-
`;try{r.writableEnded||r.write(a)}catch{}}}}sendHeartbeats(){for(let e of this.instances.values())e.connectionCount>0&&e.sendHeartbeat();this.projectEventManager.sendGlobalHeartbeat(new Im({}))}handleInstanceTimeout=async e=>{ie("THREAD_CODAY_MANAGER",`Handling timeout for thread ${e}`),await this.cleanup(e)};getOrCreate(e,r,n,i,s){let a=this.instances.get(e);return a?ie("THREAD_CODAY",`Reusing existing instance for thread ${e}`):(ie("THREAD_CODAY",`Creating new instance for thread ${e}`),a=new aV(e,r,n,i,this.logger,this.projectService,this.threadService,this.promptService,this.mcpPool,this.handleInstanceTimeout,this.projectEventManager,o=>this.setPendingInvite(o)
|
|
1733
|
+
`;try{r.writableEnded||r.write(a)}catch{}}}}sendHeartbeats(){for(let e of this.instances.values())e.connectionCount>0&&e.sendHeartbeat();this.projectEventManager.sendGlobalHeartbeat(new Im({}))}handleInstanceTimeout=async e=>{ie("THREAD_CODAY_MANAGER",`Handling timeout for thread ${e}`),await this.cleanup(e)};getOrCreate(e,r,n,i,s){let a=this.instances.get(e);return a?ie("THREAD_CODAY",`Reusing existing instance for thread ${e}`):(ie("THREAD_CODAY",`Creating new instance for thread ${e}`),a=new aV(e,r,n,i,this.logger,this.projectService,this.threadService,this.promptService,this.mcpPool,this.handleInstanceTimeout,this.projectEventManager,o=>this.setPendingInvite(o)),this.instances.set(e,a)),a.addConnection(s),a}createWithoutConnection(e,r,n,i){let s=this.instances.get(e);return s?ie("THREAD_CODAY",`Reusing existing instance for thread ${e}`):(ie("THREAD_CODAY",`Creating new instance for thread ${e} (no SSE connection)`),s=new aV(e,r,n,i,this.logger,this.projectService,this.threadService,this.promptService,this.mcpPool,this.handleInstanceTimeout,this.projectEventManager,a=>this.setPendingInvite(a)),s.markAsOneshot(),this.instances.set(e,s)),s}get(e){return this.instances.get(e)}removeConnection(e,r){let n=this.instances.get(e);n&&(n.removeConnection(r),n.connectionCount===0&&ie("THREAD_CODAY",`Thread ${e} has no active connections but instance kept alive`))}stop(e){let r=this.instances.get(e);r&&r.stop()}async cleanup(e){let r=this.instances.get(e);r&&(await r.cleanup(),await this.mcpPool.releaseThread(e),this.pendingInvites.delete(e),this.instances.delete(e),ie("THREAD_CODAY",`Removed instance for thread ${e}`))}getStats(){let e=0,r=0;for(let n of this.instances.values())n.connectionCount>0&&e++,n.isOneshot&&r++;return{total:this.instances.size,withConnections:e,oneshot:r}}async shutdown(){ie("THREAD_CODAY_MANAGER",`Shutting down ${this.instances.size} thread instances`),this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),ie("THREAD_CODAY_MANAGER","Heartbeat mechanism stopped"));let e=[];for(let[r,n]of this.instances.entries())ie("THREAD_CODAY_MANAGER",`Cleaning up thread ${r}`),e.push(n.cleanup().then(()=>this.mcpPool.releaseThread(r)).catch(i=>{ie("THREAD_CODAY_MANAGER",`Error cleaning up thread ${r}:`,i)}));await Promise.all(e),this.instances.clear(),this.pendingInvites.clear(),await this.mcpPool.shutdown(),this.projectEventManager.shutdown(),ie("THREAD_CODAY_MANAGER","All thread instances cleaned up")}};async function DT(t,e=100,r=!1){let n=await import("node:net");return new Promise((i,s)=>{function a(o,c){let u=n.createServer();u.listen(o,()=>{u.close(()=>{ie("PORT",`Port ${o} is available`),i(o)})}),u.on("error",f=>{f.code==="EADDRINUSE"?r?s(new Error(`Port ${o} is already in use. Please free the port and restart CodayTwin.`)):c>0?(ie("PORT",`Port ${o} is in use, trying next`),a(o+1,c-1)):s(new Error(`Could not find an available port starting from ${t}`)):s(f)})}a(t,e)})}function rmt(t,e,r){t.get("/api/config/user",(n,i)=>{try{let s=r(n);if(!s){i.status(401).json({error:"Username not found in request headers"});return}ie("CONFIG",`GET user config for: ${s}`);let c={...e.getUserService(s).getConfigForClient(),username:s};i.status(200).json(c)}catch(s){console.error("Error retrieving user config:",s),i.status(500).json({error:"Failed to retrieve user configuration"})}}),t.put("/api/config/user",(n,i)=>{try{let s=r(n);if(!s){i.status(401).json({error:"Username not found in request headers"});return}let a=n.body;if(!a||typeof a!="object"){i.status(422).json({error:"Invalid configuration format"});return}if(typeof a.version!="number"){i.status(422).json({error:"Configuration must have a version number"});return}ie("CONFIG",`PUT user config for: ${s}`),e.getUserService(s).updateConfigFromClient(a),i.status(200).json({success:!0,message:"User configuration updated successfully"})}catch(s){console.error("Error updating user config:",s);let a=s instanceof Error?s.message:"Unknown error";i.status(500).json({error:`Failed to update user configuration: ${a}`})}})}import{execFile as vx}from"child_process";import*as nmt from"path";function rt(t){return Array.isArray(t)?t[0]||"":t||""}function imt(t,e,r,n,i,s,a){t.get("/api/projects",(o,c)=>{try{ie("PROJECT","GET all projects");let u=e.listProjects(),f=e.getDefaultProject(),d=e.getForcedMode();c.status(200).json({projects:u,defaultProject:f,forcedProject:d?f:null})}catch(u){console.error("Error listing projects:",u),c.status(500).json({error:"Failed to list projects"})}}),t.get("/api/projects/:name",(o,c)=>{try{let u=rt(o.params.name);if(!u){c.status(400).json({error:"Project name is required"});return}ie("PROJECT",`GET project: ${u}`);let f=e.getProject(u);if(!f){c.status(404).json({error:`Project '${u}' not found`});return}c.status(200).json(f)}catch(u){console.error("Error retrieving project:",u),c.status(500).json({error:"Failed to retrieve project"})}}),t.post("/api/projects",(o,c)=>{try{let{name:u,path:f}=o.body;if(!u||!f){c.status(400).json({error:"Project name and path are required"});return}ie("PROJECT",`POST create project: ${u} at ${f}`),e.createProject(u,f),c.status(201).json({success:!0,message:`Project '${u}' created successfully`})}catch(u){console.error("Error creating project:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to create project: ${f}`})}}),t.get("/api/projects/:name/config",(o,c)=>{try{let u=rt(o.params.name);if(!u){c.status(400).json({error:"Project name is required"});return}ie("PROJECT",`GET project config: ${u}`);let f=e.getProjectConfigForClient(u);if(!f){c.status(404).json({error:`Project '${u}' not found`});return}c.status(200).json(f)}catch(u){console.error("Error retrieving project config:",u),c.status(500).json({error:"Failed to retrieve project configuration"})}}),t.put("/api/projects/:name/config",(o,c)=>{try{let u=rt(o.params.name);if(!u){c.status(400).json({error:"Project name is required"});return}let f=o.body;if(!f||typeof f!="object"){c.status(422).json({error:"Invalid configuration format"});return}if(typeof f.version!="number"){c.status(422).json({error:"Configuration must have a version number"});return}if(!f.path||typeof f.path!="string"){c.status(422).json({error:"Configuration must have a valid path"});return}ie("PROJECT",`PUT project config: ${u}`),e.updateProjectConfigFromClient(u,f),c.status(200).json({success:!0,message:"Project configuration updated successfully"})}catch(u){console.error("Error updating project config:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to update project configuration: ${f}`})}}),t.get("/api/threads",async(o,c)=>{if(!n||!i){c.status(503).json({error:"Global thread listing not available"});return}try{let u=i(o);if(!u){c.status(401).json({error:"Authentication required"});return}let f=e.listProjects(),p=(await Promise.all(f.map(async h=>{try{return(await n.listThreads(h.name,u)).map(g=>({...g,projectId:h.name,pendingInvite:s?.hasPendingInvite(g.id)||void 0}))}catch{return[]}}))).flat();c.status(200).json(p)}catch(u){console.error("Error listing all threads:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to list threads: ${f}`})}}),t.get("/api/projects/:name/git/branches",async(o,c)=>{let u=rt(o.params.name);if(!u){c.status(400).json({error:"Project name is required"});return}let f=e.getProject(u);if(!f){c.status(404).json({error:`Project '${u}' not found`});return}let d=f.config.path;if(!d){c.status(422).json({error:`Project '${u}' has no configured path`});return}try{let p=await new Promise((h,m)=>{vx("git",["branch","-a","--format=%(refname:short)"],{cwd:d},(g,v)=>{if(g){m(g);return}let y=v.split(`
|
|
1734
1734
|
`).map(b=>b.trim()).filter(b=>b&&!b.includes("HEAD")).map(b=>b.replace(/^origin\//,""));h([...new Set(y)].sort())})});c.status(200).json({branches:p})}catch(p){let h=p instanceof Error?p.message:"Unknown error";c.status(500).json({error:`Failed to list branches: ${h}`})}}),t.post("/api/projects/:name/missions",async(o,c)=>{if(!n||!i||!s||!a){c.status(503).json({error:"Mission creation not available"});return}let u=rt(o.params.name);if(!u){c.status(400).json({error:"Project name is required"});return}let{agentName:f,task:d,mode:p,branch:h,issueNumber:m,branchType:g}=o.body;if(!f||!d||!p){c.status(400).json({error:"agentName, task and mode are required"});return}if(p==="worktree"&&!h){c.status(400).json({error:"branch is required for worktree mode"});return}let v=i(o);if(!v){c.status(401).json({error:"Authentication required"});return}try{let y=u,b;if(p==="worktree"&&h){let F=m??d.match(/([A-Z]+-\d+)/)?.[1]??Date.now().toString(),P=`${g??"feature"}/${v}/${F}`;b=`coday__${P.replace(/[^a-zA-Z0-9]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}`;let k=e.getProject(u);if(!k?.config?.path){c.status(422).json({error:`Project '${u}' has no configured path`});return}let D=k.config.path,O=nmt.resolve(D,"..",b);await new Promise((N,R)=>{vx("git",["worktree","add","-b",P,O,h],{cwd:D},j=>{j?R(new Error(`git worktree add failed: ${j.message}`)):N()})}),await e.registerWorktreeProject(b,O,u),y=b}let x=`@${f} ${d}`,C=(await n.createThread(y,v)).id;if(b){let F=await n.getThread(y,C);F&&(F.worktreeProject=b,await n.saveThread(y,F))}let T={...a,oneshot:!1,project:y,thread:C,prompts:[x]};s.createWithoutConnection(C,y,v,T).startCoday(),c.status(201).json({threadId:C,projectId:y})}catch(y){console.error("Error creating mission:",y);let b=y instanceof Error?y.message:"Unknown error";c.status(500).json({error:`Failed to create mission: ${b}`})}}),t.delete("/api/projects/:name/missions/:threadId",async(o,c)=>{if(!n||!i){c.status(503).json({error:"Mission management not available"});return}let u=rt(o.params.name),f=rt(o.params.threadId);if(!u||!f){c.status(400).json({error:"Project name and thread ID are required"});return}try{let d=await n.getThread(u,f);if(!d){c.status(404).json({error:`Thread '${f}' not found`});return}let p=d.worktreeProject;if(s?.stop(f),await n.deleteThread(u,f),p){let m=e.getProject(p)?.config?.path;if(m){let v=e.getProject(u)?.config?.path;if(v){let y=await new Promise(b=>{vx("git",["rev-parse","--abbrev-ref","HEAD"],{cwd:m},(x,S)=>b(x?null:S.trim()))});await new Promise(b=>{vx("git",["worktree","remove","--force",m],{cwd:v},()=>b())}),await new Promise(b=>{vx("git",["worktree","prune"],{cwd:v},()=>b())}),y&&y!=="HEAD"&&await new Promise(b=>{vx("git",["branch","-D",y],{cwd:v},()=>b())})}}await e.unregisterWorktreeProject(p)}c.status(200).json({success:!0})}catch(d){console.error("Error closing mission:",d);let p=d instanceof Error?d.message:"Unknown error";c.status(500).json({error:`Failed to close mission: ${p}`})}}),t.get("/api/event-stream",(o,c)=>{if(!r){c.status(503).send("Event stream not available");return}ie("GLOBAL_SSE","New global SSE connection"),c.setHeader("Content-Type","text/event-stream"),c.setHeader("Cache-Control","no-cache"),c.setHeader("Connection","keep-alive"),r.addGlobalConnection(c),o.on("close",()=>{ie("GLOBAL_SSE","Global SSE client disconnected"),r.removeGlobalConnection(c)})}),t.get("/api/projects/:name/event-stream",(o,c)=>{let u=rt(o.params.name);if(!u){c.status(400).send("Project name is required");return}if(!r){c.status(503).send("Project event stream not available");return}ie("PROJECT_SSE",`New SSE connection for project ${u}`),c.setHeader("Content-Type","text/event-stream"),c.setHeader("Cache-Control","no-cache"),c.setHeader("Connection","keep-alive"),r.addConnection(u,c),o.on("close",()=>{ie("PROJECT_SSE",`Client disconnected from project ${u}`),r.removeConnection(u,c)})}),t.delete("/api/projects/:name",async(o,c)=>{try{let u=rt(o.params.name);if(!u){c.status(400).json({error:"Project name is required"});return}let f=o.query.removeGitWorktree==="true";ie("PROJECT",`DELETE project: ${u}${f?" (with git worktree removal)":""}`),await e.deleteProject(u,{removeGitWorktree:f}),c.status(200).json({success:!0,message:`Project '${u}' deleted successfully`})}catch(u){console.error("Error deleting project:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to delete project: ${f}`})}})}import{existsSync as ILr,readFileSync as DLr}from"fs";async function cV(t,e,r,n,i){let o=(n.getUserService(r).config.ai||[]).find(v=>v.name.toLowerCase()==="openai"),c=process.env.OPENAI_API_KEY||o?.apiKey,u=o?.url;if(!c)throw new Error("OpenAI provider not configured. Whisper transcription requires an OpenAI API key.");let f=(await Promise.resolve().then(()=>(L$(),zse))).default,d=new f({apiKey:c,...u?{baseURL:u}:{}}),{toFile:p}=await Promise.resolve().then(()=>(L$(),zse)),h=e.split("/")[1]?.replace("x-","")||"webm",m=await p(t,`recording.${h}`,{type:e});return(await d.audio.transcriptions.create({model:"whisper-1",file:m,...i?{language:i}:{}})).text}function smt(t,e,r,n,i,s,a){t.get("/api/projects/:projectName/threads",async(o,c)=>{try{let u=rt(o.params.projectName);if(!u){c.status(400).json({error:"Project name is required"});return}let f=i(o);if(!f){c.status(401).json({error:"Authentication required"});return}ie("THREAD",`GET threads for project: ${u}, user: ${f}`);let p=(await e.listThreads(u,f)).map(h=>({...h,pendingInvite:n.hasPendingInvite(h.id)||void 0}));c.status(200).json(p)}catch(u){console.error("Error listing threads:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to list threads: ${f}`})}}),t.post("/api/projects/:projectName/threads",async(o,c)=>{try{let u=rt(o.params.projectName);if(!u){c.status(400).json({error:"Project name is required"});return}let f=i(o);if(!f){c.status(401).json({error:"Authentication required"});return}let{name:d}=o.body;ie("THREAD",`POST create thread in project: ${u}, user: ${f}, name: ${d||"untitled"}`);let p=await e.createThread(u,f,d);c.status(201).json({success:!0,thread:{id:p.id,name:p.name,projectId:p.projectId,username:p.username,createdDate:p.createdDate,modifiedDate:p.modifiedDate}})}catch(u){console.error("Error creating thread:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to create thread: ${f}`})}}),t.get("/api/projects/:projectName/threads/:threadId",async(o,c)=>{try{let u=rt(o.params.projectName),f=rt(o.params.threadId);if(!u||!f){c.status(400).json({error:"Project name and thread ID are required"});return}let d=i(o);if(!d){c.status(401).json({error:"Authentication required"});return}ie("THREAD",`GET thread: ${f} from project: ${u}`);let p=await e.getThread(u,f);if(!p){c.status(404).json({error:`Thread '${f}' not found in project '${u}'`});return}if(!An(p,d)){c.status(403).json({error:"Access denied: thread belongs to another user"});return}c.status(200).json({id:p.id,name:p.name,projectId:p.projectId,username:p.username,summary:p.summary,createdDate:p.createdDate,modifiedDate:p.modifiedDate,price:p.price,messageCount:p.messagesLength,users:p.users})}catch(u){console.error("Error retrieving thread:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to retrieve thread: ${f}`})}}),t.put("/api/projects/:projectName/threads/:threadId",async(o,c)=>{try{let u=rt(o.params.projectName),f=rt(o.params.threadId);if(!u||!f){c.status(400).json({error:"Project name and thread ID are required"});return}let d=i(o);if(!d){c.status(401).json({error:"Authentication required"});return}let{name:p,users:h}=o.body,m=await e.getThread(u,f);if(!m){c.status(404).json({error:`Thread '${f}' not found in project '${u}'`});return}if(!An(m,d)){c.status(403).json({error:"Access denied: thread belongs to another user"});return}let g;if(h!==void 0){if(!An(m,d)){c.status(403).json({error:"Access denied: only thread participants can modify the users list"});return}if(!Array.isArray(h)){c.status(400).json({error:"Invalid users format: must be an array"});return}for(let y of h)if(!y||typeof y.userId!="string"||y.userId.trim()===""){c.status(400).json({error:"Invalid users format: each user must have a non-empty userId string"});return}g=h}ie("THREAD",`PUT update thread: ${f} in project: ${u}`);let v=await e.updateThread(u,f,{name:p,users:g});if(g!==void 0){let b=n.get(f)?.coday?.context?.aiThread;b&&(b.users=g,ie("THREAD",`Synced users to live AiThread for thread ${f}`))}c.status(200).json({success:!0,thread:{id:v.id,name:v.name,projectId:v.projectId,modifiedDate:v.modifiedDate}})}catch(u){console.error("Error updating thread:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to update thread: ${f}`})}}),t.get("/api/projects/:projectName/threads/:threadId/messages",async(o,c)=>{try{let u=rt(o.params.projectName),f=rt(o.params.threadId);if(!u||!f){c.status(400).json({error:"Project name and thread ID are required"});return}let d=i(o);if(!d){c.status(401).json({error:"Authentication required"});return}ie("THREAD",`GET messages for thread: ${f} in project: ${u}`);let p=await e.getThread(u,f);if(!p){c.status(404).json({error:`Thread '${f}' not found in project '${u}'`});return}if(!An(p,d)){c.status(403).json({error:"Access denied: thread belongs to another user"});return}let{messages:h}=await p.getMessages(void 0,void 0);c.status(200).json({messages:h})}catch(u){console.error("Error retrieving thread messages:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to retrieve thread messages: ${f}`})}}),t.post("/api/projects/:projectName/threads/:threadId/star",async(o,c)=>{try{let u=rt(o.params.projectName),f=rt(o.params.threadId);if(!u||!f){c.status(400).json({error:"Project name and thread ID are required"});return}let d=i(o);if(!d){c.status(401).json({error:"Authentication required"});return}if(!await e.getThread(u,f)){c.status(404).json({error:`Thread '${f}' not found in project '${u}'`});return}ie("THREAD",`POST star thread: ${f} in project: ${u} by user: ${d}`);let h=await e.starThread(u,f,d);c.status(200).json({success:!0,thread:{id:h.id,starring:h.starring,modifiedDate:h.modifiedDate}})}catch(u){console.error("Error starring thread:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to star thread: ${f}`})}}),t.delete("/api/projects/:projectName/threads/:threadId/star",async(o,c)=>{try{let u=rt(o.params.projectName),f=rt(o.params.threadId);if(!u||!f){c.status(400).json({error:"Project name and thread ID are required"});return}let d=i(o);if(!d){c.status(401).json({error:"Authentication required"});return}if(!await e.getThread(u,f)){c.status(404).json({error:`Thread '${f}' not found in project '${u}'`});return}ie("THREAD",`DELETE unstar thread: ${f} in project: ${u} by user: ${d}`);let h=await e.unstarThread(u,f,d);c.status(200).json({success:!0,thread:{id:h.id,starring:h.starring,modifiedDate:h.modifiedDate}})}catch(u){console.error("Error unstarring thread:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to unstar thread: ${f}`})}}),t.post("/api/projects/:projectName/threads/batch-done",async(o,c)=>{try{let u=rt(o.params.projectName);if(!u){c.status(400).json({error:"Project name is required"});return}let f=i(o);if(!f){c.status(401).json({error:"Authentication required"});return}let{threadIds:d}=o.body;if(!Array.isArray(d)||d.length===0){c.status(400).json({error:"threadIds must be a non-empty array"});return}ie("THREAD",`POST batch-done: ${d.length} thread(s) in project: ${u} by user: ${f}`);let p=0;for(let h of d)try{let m=await e.getThread(u,h);if(!m||!An(m,f)){ie("THREAD",`batch-done: skipping thread ${h} (not found or no access)`);continue}await e.updateThread(u,h,{closedByUser:!0}),p++}catch(m){console.error(`batch-done: error closing thread ${h}:`,m)}p>0&&n.projectEventManager.broadcast(u,new Ts({threadId:""})),c.status(200).json({success:!0,count:p})}catch(u){console.error("Error in batch-done:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to batch-close threads: ${f}`})}}),t.post("/api/projects/:projectName/threads/:threadId/done",async(o,c)=>{try{let u=rt(o.params.projectName),f=rt(o.params.threadId);if(!u||!f){c.status(400).json({error:"Project name and thread ID are required"});return}let d=i(o);if(!d){c.status(401).json({error:"Authentication required"});return}let p=await e.getThread(u,f);if(!p){c.status(404).json({error:`Thread '${f}' not found in project '${u}'`});return}if(!An(p,d)){c.status(403).json({error:"Access denied: thread belongs to another user"});return}ie("THREAD",`POST mark as done: ${f} in project: ${u} by user: ${d}`);let h=await e.updateThread(u,f,{closedByUser:!0});n.projectEventManager.broadcast(u,new Ts({threadId:h.id})),c.status(200).json({success:!0,thread:{id:h.id,closedByUser:h.closedByUser,modifiedDate:h.modifiedDate}})}catch(u){console.error("Error marking thread as done:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to mark thread as done: ${f}`})}}),t.delete("/api/projects/:projectName/threads/:threadId/done",async(o,c)=>{try{let u=rt(o.params.projectName),f=rt(o.params.threadId);if(!u||!f){c.status(400).json({error:"Project name and thread ID are required"});return}let d=i(o);if(!d){c.status(401).json({error:"Authentication required"});return}let p=await e.getThread(u,f);if(!p){c.status(404).json({error:`Thread '${f}' not found in project '${u}'`});return}if(!An(p,d)){c.status(403).json({error:"Access denied: thread belongs to another user"});return}ie("THREAD",`DELETE mark as active: ${f} in project: ${u} by user: ${d}`);let h=await e.updateThread(u,f,{closedByUser:!1});n.projectEventManager.broadcast(u,new Ts({threadId:h.id})),c.status(200).json({success:!0,thread:{id:h.id,closedByUser:h.closedByUser,modifiedDate:h.modifiedDate}})}catch(u){console.error("Error unmarking thread as done:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to unmark thread as done: ${f}`})}}),t.post("/api/projects/:projectName/threads/:threadId/stop",async(o,c)=>{try{let u=rt(o.params.projectName),f=rt(o.params.threadId);if(!u||!f){c.status(400).json({error:"Project name and thread ID are required"});return}let d=i(o);if(!d){c.status(401).json({error:"Authentication required"});return}let p=await e.getThread(u,f);if(!p){c.status(404).json({error:`Thread '${f}' not found in project '${u}'`});return}if(!An(p,d)){c.status(403).json({error:"Access denied: thread belongs to another user"});return}ie("THREAD",`POST stop thread: ${f} in project: ${u}`),n.stop(f),c.status(200).json({success:!0,message:"Stop signal sent successfully"})}catch(u){console.error("Error stopping thread:",u);let f=u instanceof Error?u.message:"Unknown error";c.status(500).json({error:`Failed to stop thread: ${f}`})}}),t.delete("/api/projects/:projectName/threads/:threadId",async(o,c)=>{try{let u=rt(o.params.projectName),f=rt(o.params.threadId);if(!u||!f){c.status(400).json({error:"Project name and thread ID are required"});return}let d=i(o);if(!d){c.status(401).json({error:"Authentication required"});return}let p=await e.getThread(u,f);if(!p){c.status(404).json({error:`Thread '${f}' not found in project '${u}'`});return}if(!An(p,d)){c.status(403).json({error:"Access denied: thread belongs to another user"});return}ie("THREAD",`DELETE
|
|
1735
1735
|
thread:
|
|
1736
1736
|
${f}
|