@whoz-oss/coday-server 0.55.0 → 0.55.2
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 +1 -1
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -1379,7 +1379,7 @@ ${d.output}`}else p=JSON.stringify(d,null,2);i.status(200).send(p)}catch(a){cons
|
|
|
1379
1379
|
in
|
|
1380
1380
|
project
|
|
1381
1381
|
:
|
|
1382
|
-
${a}`);let u=e.get(s);if(!u?.coday){i.status(404).json({error:`Thread '${s}' not found or not active`});return}if(u.username!==l){i.status(403).json({error:"Access denied: thread belongs to another user"});return}let f=u.coday.context?.aiThread;if(!f){i.status(500).json({error:"Thread not properly initialized"});return}f.truncateAtUserMessage(c)?(Se("MESSAGE",`Successfully truncated thread ${s} at message ${c}`),i.status(200).json({success:!0,message:"Message deleted successfully"})):i.status(400).json({error:"Failed to delete message. Message may not exist, may not be a user message, or may be the first message."})}catch(a){console.error("Error deleting message:",a);let s=a instanceof Error?a.message:"Unknown error";i.status(500).json({error:`Failed to delete message: ${s}`})}})}function S5e(r,e){r.get("/api/user/me",(t,n)=>{try{let i=e(t);if(!i){n.status(401).json({error:"Authentication required"});return}Se("USER",`GET current user: ${i}`),n.status(200).json({username:i})}catch(i){console.error("Error retrieving user info:",i);let a=i instanceof Error?i.message:"Unknown error";n.status(500).json({error:`Failed to retrieve user info: ${a}`})}})}function E5e(r,e,t,n,i,a,s,o){r.get("/api/projects/:projectName/agents",async(c,l)=>{try{let u=t(c),{projectName:f}=c.params;if(!f){l.status(400).json({error:"Project name is required"});return}Se("AGENT",`GET agents list: project="${f}", user="${u}"`);let d=e.getProject(f);if(!d){l.status(404).json({error:`Project '${f}' not found`});return}let p=new r2("agent-autocomplete"),m=new a2(n,u,p),h=new Q1(p,e,n),g=new eh(h,m),v=new th(m,h,p),b=new rh(h,m),x=new nh(m,h,p),E={user:m,project:h,integration:g,integrationConfig:v,memory:b,mcp:x,thread:s,logger:i,webhook:a};h.selectProject(f);let A=new Kd(p,m,h,i),C=new J1(p,A,E,d.config.path,o.agentFolders),I={...await Sy(d.config.path,p,{username:u,bio:m.config.bio}),root:d.config.path,name:f},w=new ap(I,u);w.oneshot=!0,Se("AGENT",`Initializing AgentService with projectPath: ${d.config.path}`),Se("AGENT",`Project config agents: ${d.config.agents?.length||0}`),Se("AGENT",`AgentFolders from options: ${JSON.stringify(o.agentFolders)}`),A.init(w),await C.initialize(w);let _=C.listAgentSummaries();Se("AGENT",`Total agents loaded: ${_.length}`),Se("AGENT",`Agent names: ${_.map(y=>y.name).join(", ")}`),await C.kill(),l.status(200).json(_)}catch(u){console.error("Error in agent autocomplete:",u);let f=u instanceof Error?u.message:"Unknown error";l.status(500).json({error:`Failed to get agent autocomplete: ${f}`})}})}import*as C5e from"crypto";import*as K$ from"path";var lh=class r{constructor(e,t,n){this.repository=e;this.defaultProject=t;this.isForcedMode=n}maskingService=new i2;listProjects(){let e=this.repository.listProjects();return this.isForcedMode&&this.defaultProject?e.filter(t=>t===this.defaultProject).map(t=>{let n=this.repository.getConfig(t);return{name:t,volatile:n?.volatile}}):e.map(t=>{let n=this.repository.getConfig(t);return{name:t,volatile:n?.volatile}})}getDefaultProject(){return this.defaultProject||null}getForcedMode(){return this.isForcedMode}getProject(e){this.checkAgainstForced(e);let t=this.repository.getConfig(e);if(t)return{name:e,config:t};if(!this.isForcedMode&&this.defaultProject){let n=process.cwd(),i=r.generateProjectId(n),a=K$.basename(n);if(e===a||e===i||e===this.defaultProject){let s=this.getOrCreateVolatileProject(n);if(t=this.repository.getConfig(s),t)return{name:s,config:t}}}return null}exists(e){return this.checkAgainstForced(e),this.repository.exists(e)}createProject(e,t){if(this.checkAgainstForced(e),!e||!t)throw new Error("Project name and path are required");if(!this.repository.createProject(e,t))throw new Error(`Project '${e}' already exists`)}updateProjectConfig(e,t){if(this.checkAgainstForced(e),!this.repository.exists(e))throw new Error(`Project '${e}' does not exist`);this.repository.saveConfig(e,t)}deleteProject(e){if(this.checkAgainstForced(e),!this.repository.deleteProject(e))throw new Error(`Project '${e}' does not exist`)}getProjectConfigForClient(e){this.checkAgainstForced(e);let t=this.repository.getConfig(e);return t?this.maskingService.maskConfig(t):null}updateProjectConfigFromClient(e,t){this.checkAgainstForced(e);let n=this.repository.getConfig(e);if(!n)throw new Error(`Project '${e}' does not exist`);let i=this.maskingService.unmaskConfig(t,n);this.repository.saveConfig(e,i)}checkAgainstForced(e){if(this.isForcedMode&&this.defaultProject&&this.defaultProject!==e)throw Error(`Project selection outside of ${this.defaultProject} not allowed`)}getOrCreateVolatileProject(e){let t=r.generateProjectId(e);if(this.repository.exists(t))return t;this.repository.createProject(t,e);let n=this.repository.getConfig(t);return n&&(n.volatile=!0,n.createdAt=Date.now(),this.repository.saveConfig(t,n)),t}static generateProjectId(e){let t=K$.basename(e),n=C5e.createHash("sha256").update(e).digest("hex").substring(0,8);return`${t}_${n}`}};var Z$=yr(uu(),1);import{promises as ll}from"fs";import j0 from"path";var Cpt={version:1,description:"Migrate AiThread MessageEvent.content from string to MessageContent",migrate:r=>{let e={...r};return!e.messages||!Array.isArray(e.messages)?(e.messages=[],e):(e.messages=e.messages.map(t=>{if(t.type!=="message")return t;let n=t.content;return t.content={...t,content:[{type:"text",content:n}]},t}),e)}},Apt={version:2,description:"Add starring field to threads for favorite functionality",migrate:r=>{let e={...r};return e.starring||(e.starring=[]),e}},J$=[Cpt,Apt];var A5e=async r=>{try{let e=await ll.readFile(r,"utf-8");return Z$.default.parse(e)}catch{return null}},kE=class{constructor(e){this.projectsDir=e}getThreadsDir(e){return j0.join(this.projectsDir,e,"threads")}async ensureThreadsDir(e){let t=this.getThreadsDir(e);try{await ll.mkdir(t,{recursive:!0})}catch(n){throw new Tc(`Failed to initialize threads directory for project ${e}`,n)}}getThreadFileName(e){return`${e.id}.yml`}async findThreadFile(e,t){try{let n=this.getThreadsDir(e),i=`${t}.yml`;try{return await ll.access(j0.join(n,i)),i}catch{}return(await ll.readdir(n)).find(o=>o.endsWith(`-${t}.yml`))||null}catch(n){throw new Tc(`Error finding thread ${t} in project ${e}`,n)}}async getById(e,t){try{let n=await this.findThreadFile(e,t);if(!n)return null;let i=this.getThreadsDir(e),a=j0.join(i,n),s=await A5e(a);if(!s)return null;let o=Z1(s,J$);return o.projectId||(o.projectId=e),o!==s&&Zn(a,o),new Ql(o)}catch(n){throw new Tc(`Failed to read thread ${t} from project ${e}`,n)}}async save(e,t){await this.ensureThreadsDir(e);try{if(t.id||(t.id=crypto.randomUUID()),t.projectId||(t.projectId=e),t.projectId!==e)throw new Error(`Thread projectId mismatch: expected ${e}, got ${t.projectId}`);let n=this.getThreadsDir(e),i=this.getThreadFileName(t),a=j0.join(n,i),s=await this.findThreadFile(e,t.id);if(s&&s!==i){let l=j0.join(n,s);try{await ll.unlink(l),console.log(`[THREAD-REPO] Migrated/renamed thread file: ${s} \u2192 ${i}`)}catch(u){console.warn(`[THREAD-REPO] Could not delete old thread file: ${s}`,u)}}let o={...t,version:J$.length+1},c=Z$.default.stringify(o);return await ll.writeFile(a,c,"utf-8"),t}catch(n){throw new Tc(`Failed to save thread ${t.id} to project ${e}`,n)}}async listByProject(e,t){try{let n=this.getThreadsDir(e);try{await ll.access(n)}catch{return[]}let i=await ll.readdir(n);return(await Promise.all(i.filter(s=>s.endsWith(".yml")).map(async s=>{let o=await A5e(j0.join(n,s));if(!o)return null;let c=o.projectId||e;return{id:o.id,username:o.username,projectId:c,name:o.name??"...",summary:o.summary??"",createdDate:o.createdDate??"",modifiedDate:o.modifiedDate??"",price:o.price??0,starring:o.starring??[]}}))).filter(s=>!!s).filter(s=>s.username===t).sort((s,o)=>s.modifiedDate>o.modifiedDate?-1:1)}catch(n){throw new Tc(`Failed to list threads for project ${e}`,n)}}async delete(e,t){try{let n=await this.findThreadFile(e,t);if(!n)return!1;let i=this.getThreadsDir(e);return await ll.unlink(j0.join(i,n)),!0}catch(n){throw new Tc(`Failed to delete thread ${t} from project ${e}`,n)}}};var TE=class{constructor(e,t,n){this.projectRepository=e;this.projectsDir=t;this.threadFileService=n}repositoryCache=new Map;getThreadRepository(e){let t=this.repositoryCache.get(e);if(t)return t;if(!this.projectRepository.getProjectInfo(e))throw new Error(`Project '${e}' not found`);let i=new kE(this.projectsDir);return this.repositoryCache.set(e,i),i}clearCache(e){e?this.repositoryCache.delete(e):this.repositoryCache.clear()}async listThreads(e,t){return await this.getThreadRepository(e).listByProject(e,t)}async getThread(e,t){return await this.getThreadRepository(e).getById(e,t)}async createThread(e,t,n){let i=this.getThreadRepository(e),a=new Ql({id:crypto.randomUUID(),username:t,projectId:e,name:n||"",price:0});return await i.save(e,a)}async updateThread(e,t,n){let i=this.getThreadRepository(e),a=await i.getById(e,t);if(!a)throw new Error(`Thread '${t}' not found in project '${e}'`);return n.name!==void 0&&(a.name=n.name),await i.save(e,a)}async starThread(e,t,n){let i=this.getThreadRepository(e),a=await i.getById(e,t);if(!a)throw new Error(`Thread '${t}' not found in project '${e}'`);return a.starring.includes(n)||a.starring.push(n),await i.save(e,a)}async unstarThread(e,t,n){let i=this.getThreadRepository(e),a=await i.getById(e,t);if(!a)throw new Error(`Thread '${t}' not found in project '${e}'`);return a.starring=a.starring.filter(s=>s!==n),await i.save(e,a)}async deleteThread(e,t){let i=await this.getThreadRepository(e).delete(e,t);return i&&await this.threadFileService.deleteThreadFiles(e,t),i}async exists(e,t){return await this.getThread(e,t)!==null}};import*as _i from"path";import*as M0 from"fs";import*as ea from"fs/promises";var DE=class{constructor(e){this.projectsDir=e}getThreadFilesDir(e,t){return _i.join(this.projectsDir,e,"threads",`${t}-files`)}async ensureThreadFilesDir(e,t){let n=this.getThreadFilesDir(e,t);M0.existsSync(n)||await ea.mkdir(n,{recursive:!0})}async listFiles(e,t){await this.ensureThreadFilesDir(e,t);let n=this.getThreadFilesDir(e,t),i=await ea.readdir(n);return await Promise.all(i.map(async s=>{let o=_i.join(n,s),c=await ea.stat(o);return{filename:s,size:c.size,lastModified:c.mtime.toISOString()}}))}async saveFile(e,t,n,i){let a=this.getThreadFilesDir(e,t);await ea.mkdir(a,{recursive:!0});let s=_i.join(a,n);await ea.writeFile(s,i)}async getFile(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=_i.join(i,n),s=_i.resolve(a),o=_i.resolve(i);if(!s.startsWith(o))throw new Error("Access denied: invalid file path");if(!M0.existsSync(a))throw new Error(`File '${n}' not found`);return await ea.readFile(a)}async getFilePath(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=_i.join(i,n),s=_i.resolve(a),o=_i.resolve(i);if(!s.startsWith(o))throw new Error("Access denied: invalid file path");if(!M0.existsSync(a))throw new Error(`File '${n}' not found`);return a}fileExists(e,t,n){let i=this.getThreadFilesDir(e,t),a=_i.join(i,n),s=_i.resolve(a),o=_i.resolve(i);return s.startsWith(o)?M0.existsSync(a):!1}async deleteFile(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=_i.join(i,n),s=_i.resolve(a),o=_i.resolve(i);if(!s.startsWith(o))throw new Error("Access denied: invalid file path");if(!M0.existsSync(a))throw new Error(`File '${n}' not found`);await ea.unlink(a)}async deleteThreadFiles(e,t){try{let n=this.getThreadFilesDir(e,t);M0.existsSync(n)&&(await ea.rm(n,{recursive:!0,force:!0}),console.log(`Deleted thread files directory: ${n}`))}catch(n){console.error(`Error deleting thread files for ${t}:`,n)}}};import*as uc from"node:path";import*as P5e from"node:os";import{existsSync as T5e,lstatSync as kpt,mkdirSync as D5e,readdirSync as Tpt}from"fs";var k5e=[QS];var PE=class r{projectsConfigPath;static PROJECT_FILENAME="project.yaml";constructor(e){let t=uc.join(P5e.userInfo().homedir,".coday");this.projectsConfigPath=uc.join(e??t,"projects"),D5e(this.projectsConfigPath,{recursive:!0})}listProjects(){return Tpt(this.projectsConfigPath).filter(t=>kpt(uc.join(this.projectsConfigPath,t)).isDirectory())}getProjectInfo(e){let t=uc.join(this.projectsConfigPath,e),n=uc.join(t,r.PROJECT_FILENAME);return T5e(n)?{name:e,configPath:t}:null}exists(e){return this.getProjectInfo(e)!==null}getConfig(e){let t=this.getProjectInfo(e);if(!t)return null;let n=uc.join(t.configPath,r.PROJECT_FILENAME),i=n2(n);if(!i)return null;let a=Z1(i,k5e);return a!==i&&Zn(n,a),a}saveConfig(e,t){let n=this.getProjectInfo(e);if(!n)throw new Error(`Project '${e}' does not exist`);let i=uc.join(n.configPath,r.PROJECT_FILENAME);Zn(i,t)}createProject(e,t){let n=uc.join(this.projectsConfigPath,e),i=uc.join(n,r.PROJECT_FILENAME);return T5e(i)?!1:(D5e(n,{recursive:!0}),Zn(i,{version:1,path:t,integration:{},storage:{type:"file"},agents:[]}),!0)}deleteProject(e){return this.getProjectInfo(e),!1}};var Ya=(0,aC.default)(),Tht=process.env.PORT?parseInt(process.env.PORT):process.env.BUILD_ENV==="development"?4100:3e3,Dht=p5e(Tht),Pht="x-forwarded-email",Xn=i5e();Se("INIT","Coday options:",Xn);var Z8e=!Xn.noLog,sC=new _E(Z8e,Xn.logFolder);Se("INIT",`Usage logging ${Z8e?"enabled":"disabled"} ${Xn.logFolder?`(custom folder: ${Xn.logFolder})`:""}`);var $L=new SE(Xn.configDir);Se("INIT","Webhook service initialized");Ya.use(aC.default.json({limit:"20mb"}));if(process.env.BUILD_ENV==="development"){let r="http://localhost:4200";Se("INIT",`Development mode: proxying to Angular dev server at ${r}`),Promise.resolve().then(()=>yr(K8e(),1)).then(({createProxyMiddleware:e})=>{let t=e({target:r,changeOrigin:!0,ws:!0});Ya.use("/",(n,i,a)=>{n.path.startsWith("/api")||n.path.startsWith("/events")?a():t(n,i,a)}),Se("INIT","Proxy middleware configured successfully")}).catch(e=>{console.error("Failed to load http-proxy-middleware:",e)})}else{let r=process.env.CODAY_CLIENT_PATH?dl.resolve(process.env.CODAY_CLIENT_PATH):dl.resolve(__dirname,"../coday-client/browser");if(Se("INIT",`Production mode: serving static files from ${r}`),process.env.CODAY_CLIENT_PATH&&Se("INIT","Using client path from CODAY_CLIENT_PATH environment variable"),!tC.existsSync(r))console.error(`ERROR: Client path does not exist: ${r}`),console.error("Please build the client first with: pnpm nx run client:build");else{let e=dl.join(r,"index.html");tC.existsSync(e)?Se("INIT",`Verified index.html exists at ${e}`):(console.error(`ERROR: index.html not found at: ${e}`),console.error("Client build may be incomplete. Try rebuilding with: pnpm nx run client:build"))}Ya.use(aC.default.static(r))}var rC=new PE(Xn.configDir),G6=Xn.project;if(G6&&!Xn.forcedProject){let r=process.cwd(),e=dl.basename(r);if(rC.exists(e)){let t=rC.getConfig(e);if(t&&t.path===r&&!t.volatile)Se("INIT",`Default mode: found existing non-volatile project '${e}' for current directory`),G6=e;else{let n=lh.generateProjectId(r);Se("INIT",`Default mode: existing project '${e}' doesn't match path, using volatile ID ${n}`),G6=n}}else{let t=lh.generateProjectId(r);Se("INIT",`Default mode: no existing project found, using volatile ID ${t}`),G6=t}}var LL=new lh(rC,G6,Xn.forcedProject),Y8e=dl.join(Xn.configDir,"projects"),X8e=new DE(Y8e),oC=new TE(rC,Y8e,X8e),cC=new rE(sC,$L,LL,oC),Oht=new r2("config-api"),Iht=new AE(Xn.configDir,Oht),Rht=["root","admin","administrator","system","daemon","nobody","node","app","service","docker","www-data","nginx","apache","ansible"];function mh(r){let e=Xn.auth?r.headers[Pht]:J8e.userInfo().username;if(Rht.includes(e.toLowerCase()))throw new Error(`Security error: Cannot run with username "${e}". This appears to be a system or service account. When running locally, ensure you are running as a regular user account. When running in production, ensure authentication is properly configured with --auth flag.`);return e}S5e(Ya,mh);d5e(Ya,Iht,mh);m5e(Ya,$L,mh,oC,cC,Xn,sC);g5e(Ya,LL);w5e(Ya,oC,X8e,cC,mh,Xn);_5e(Ya,cC,mh);E5e(Ya,LL,mh,Xn.configDir,sC,$L,oC,Xn);if(process.env.BUILD_ENV!=="development"){let r=process.env.CODAY_CLIENT_PATH?dl.resolve(process.env.CODAY_CLIENT_PATH):dl.resolve(__dirname,"../coday-client/browser"),e=dl.resolve(r,"index.html");Se("INIT",`Catch-all route will serve: ${e}`),Ya.use((t,n,i)=>{if(t.path.startsWith("/api")||t.path.startsWith("/events")){n.status(404).send("Not found");return}Se("ROUTER",`Serving index.html for client route: ${t.path}`),tC.readFile(e,"utf8",(a,s)=>{a?(Se("ERROR",`Failed to read index.html from ${e}:`,a),Se("ERROR",`File exists check: ${tC.existsSync(e)}`),i(a)):n.type("html").send(s)})})}var nC=null;Ya.use((r,e,t,n)=>{Se("ERROR",`Request error on ${e.method} ${e.path}:`,r.message),console.error(r.stack),process.env.BUILD_ENV==="development"?t.status(500).json({error:"Internal Server Error",message:r.message,stack:r.stack}):t.status(500).send("Something went wrong!")});Dht.then(async r=>{Ya.listen(r,()=>{console.log(`Server is running on http://localhost:${r}`)});try{Se("CLEANUP","Starting thread cleanup service...");let e=dl.join(Xn.configDir,"projects");nC=new CE(e,sC),await nC.start(),Se("CLEANUP","Thread cleanup service started successfully")}catch(e){console.error("Failed to start thread cleanup service:",e)}}).catch(r=>{console.error("Failed to start server:",r),process.exit(1)});var iC=!1;async function gh(r){iC&&(console.log(`Received ${r} during shutdown, forcing exit...`),process.exit(1)),iC=!0,console.log(`Received ${r}, shutting down gracefully...`);try{nC&&(console.log("Stopping thread cleanup service..."),await nC.stop()),console.log("Cleaning up thread Coday instances..."),await cC.shutdown(),console.log("Graceful shutdown completed"),process.exit(0)}catch(e){console.error("Error during graceful shutdown:",e),process.exit(1)}}process.on("SIGTERM",()=>gh("SIGTERM"));process.on("SIGINT",()=>gh("SIGINT"));process.on("SIGUSR2",()=>gh("SIGUSR2"));process.on("SIGHUP",()=>gh("SIGHUP"));process.on("uncaughtException",r=>{if(console.error("Uncaught exception:",r),r.message==="no elements in sequence"||r.constructor.name==="EmptyErrorImpl"){console.log("Detected RxJS EmptyError during system sleep - this is expected behavior"),console.log("Process will continue normally after system wake");return}iC||gh("uncaughtException")});process.on("unhandledRejection",(r,e)=>{if(console.error("Unhandled rejection at:",e,"reason:",r),r&&typeof r=="object"){let t=r;if(t.message==="no elements in sequence"||t.constructor?.name==="EmptyErrorImpl"){console.log("Detected RxJS EmptyError rejection during system sleep - this is expected behavior");return}if(t.name==="TimeoutError"||t.message?.includes("timeout")){console.log("Detected timeout error - handling gracefully without shutdown");return}if(t.name==="AbortError"||t.message?.includes("aborted")){console.log("Detected abort error - handling gracefully without shutdown");return}}console.error("Critical unhandled rejection detected"),iC||gh("unhandledRejection")});
|
|
1382
|
+
${a}`);let u=e.get(s);if(!u?.coday){i.status(404).json({error:`Thread '${s}' not found or not active`});return}if(u.username!==l){i.status(403).json({error:"Access denied: thread belongs to another user"});return}let f=u.coday.context?.aiThread;if(!f){i.status(500).json({error:"Thread not properly initialized"});return}f.truncateAtUserMessage(c)?(Se("MESSAGE",`Successfully truncated thread ${s} at message ${c}`),i.status(200).json({success:!0,message:"Message deleted successfully"})):i.status(400).json({error:"Failed to delete message. Message may not exist, may not be a user message, or may be the first message."})}catch(a){console.error("Error deleting message:",a);let s=a instanceof Error?a.message:"Unknown error";i.status(500).json({error:`Failed to delete message: ${s}`})}})}function S5e(r,e){r.get("/api/user/me",(t,n)=>{try{let i=e(t);if(!i){n.status(401).json({error:"Authentication required"});return}Se("USER",`GET current user: ${i}`),n.status(200).json({username:i})}catch(i){console.error("Error retrieving user info:",i);let a=i instanceof Error?i.message:"Unknown error";n.status(500).json({error:`Failed to retrieve user info: ${a}`})}})}function E5e(r,e,t,n,i,a,s,o){r.get("/api/projects/:projectName/agents",async(c,l)=>{try{let u=t(c),{projectName:f}=c.params;if(!f){l.status(400).json({error:"Project name is required"});return}Se("AGENT",`GET agents list: project="${f}", user="${u}"`);let d=e.getProject(f);if(!d){l.status(404).json({error:`Project '${f}' not found`});return}let p=new r2("agent-autocomplete"),m=new a2(n,u,p),h=new Q1(p,e,n),g=new eh(h,m),v=new th(m,h,p),b=new rh(h,m),x=new nh(m,h,p),E={user:m,project:h,integration:g,integrationConfig:v,memory:b,mcp:x,thread:s,logger:i,webhook:a};h.selectProject(f);let A=new Kd(p,m,h,i),C=new J1(p,A,E,d.config.path,o.agentFolders),I={...await Sy(d.config.path,p,{username:u,bio:m.config.bio}),root:d.config.path,name:f},w=new ap(I,u);w.oneshot=!0,Se("AGENT",`Initializing AgentService with projectPath: ${d.config.path}`),Se("AGENT",`Project config agents: ${d.config.agents?.length||0}`),Se("AGENT",`AgentFolders from options: ${JSON.stringify(o.agentFolders)}`),A.init(w),await C.initialize(w);let _=C.listAgentSummaries();Se("AGENT",`Total agents loaded: ${_.length}`),Se("AGENT",`Agent names: ${_.map(y=>y.name).join(", ")}`),await C.kill(),l.status(200).json(_)}catch(u){console.error("Error in agent autocomplete:",u);let f=u instanceof Error?u.message:"Unknown error";l.status(500).json({error:`Failed to get agent autocomplete: ${f}`})}})}import*as C5e from"crypto";import*as K$ from"path";var lh=class r{constructor(e,t,n){this.repository=e;this.defaultProject=t;this.isForcedMode=n}maskingService=new i2;listProjects(){let e=this.repository.listProjects();return this.isForcedMode&&this.defaultProject?e.filter(t=>t===this.defaultProject).map(t=>{let n=this.repository.getConfig(t);return{name:t,volatile:n?.volatile}}):e.map(t=>{let n=this.repository.getConfig(t);return{name:t,volatile:n?.volatile}})}getDefaultProject(){return this.defaultProject||null}getForcedMode(){return this.isForcedMode}getProject(e){this.checkAgainstForced(e);let t=this.repository.getConfig(e);if(t)return{name:e,config:t};if(!this.isForcedMode&&this.defaultProject){let n=process.cwd(),i=r.generateProjectId(n),a=K$.basename(n);if(e===a||e===i||e===this.defaultProject){let s=this.getOrCreateVolatileProject(n);if(t=this.repository.getConfig(s),t)return{name:s,config:t}}}return null}exists(e){return this.checkAgainstForced(e),this.repository.exists(e)}createProject(e,t){if(this.checkAgainstForced(e),!e||!t)throw new Error("Project name and path are required");if(!this.repository.createProject(e,t))throw new Error(`Project '${e}' already exists`)}updateProjectConfig(e,t){if(this.checkAgainstForced(e),!this.repository.exists(e))throw new Error(`Project '${e}' does not exist`);this.repository.saveConfig(e,t)}deleteProject(e){if(this.checkAgainstForced(e),!this.repository.deleteProject(e))throw new Error(`Project '${e}' does not exist`)}getProjectConfigForClient(e){this.checkAgainstForced(e);let t=this.repository.getConfig(e);return t?this.maskingService.maskConfig(t):null}updateProjectConfigFromClient(e,t){this.checkAgainstForced(e);let n=this.repository.getConfig(e);if(!n)throw new Error(`Project '${e}' does not exist`);let i=this.maskingService.unmaskConfig(t,n);this.repository.saveConfig(e,i)}checkAgainstForced(e){if(this.isForcedMode&&this.defaultProject&&this.defaultProject!==e)throw Error(`Project selection outside of ${this.defaultProject} not allowed`)}getOrCreateVolatileProject(e){let t=r.generateProjectId(e);if(this.repository.exists(t))return t;this.repository.createProject(t,e);let n=this.repository.getConfig(t);return n&&(n.volatile=!0,n.createdAt=Date.now(),this.repository.saveConfig(t,n)),t}static generateProjectId(e){let t=K$.basename(e),n=C5e.createHash("sha256").update(e).digest("hex").substring(0,8);return`${t}_${n}`}};var Z$=yr(uu(),1);import{promises as ll}from"fs";import j0 from"path";var Cpt={version:1,description:"Migrate AiThread MessageEvent.content from string to MessageContent",migrate:r=>{let e={...r};return!e.messages||!Array.isArray(e.messages)?(e.messages=[],e):(e.messages=e.messages.map(t=>{if(t.type!=="message")return t;let n=t.content;return t.content={...t,content:[{type:"text",content:n}]},t}),e)}},Apt={version:2,description:"Add starring field to threads for favorite functionality",migrate:r=>{let e={...r};return e.starring||(e.starring=[]),e}},J$=[Cpt,Apt];var A5e=async r=>{try{let e=await ll.readFile(r,"utf-8");return Z$.default.parse(e)}catch{return null}},kE=class{constructor(e){this.projectsDir=e}getThreadsDir(e){return j0.join(this.projectsDir,e,"threads")}async ensureThreadsDir(e){let t=this.getThreadsDir(e);try{await ll.mkdir(t,{recursive:!0})}catch(n){throw new Tc(`Failed to initialize threads directory for project ${e}`,n)}}getThreadFileName(e){return`${e.id}.yml`}async findThreadFile(e,t){try{let n=this.getThreadsDir(e),i=`${t}.yml`;try{return await ll.access(j0.join(n,i)),i}catch{}return(await ll.readdir(n)).find(o=>o.endsWith(`-${t}.yml`))||null}catch(n){throw new Tc(`Error finding thread ${t} in project ${e}`,n)}}async getById(e,t){try{let n=await this.findThreadFile(e,t);if(!n)return null;let i=this.getThreadsDir(e),a=j0.join(i,n),s=await A5e(a);if(!s)return null;let o=Z1(s,J$);return o.projectId||(o.projectId=e),o!==s&&Zn(a,o),new Ql(o)}catch(n){throw new Tc(`Failed to read thread ${t} from project ${e}`,n)}}async save(e,t){await this.ensureThreadsDir(e);try{if(t.id||(t.id=crypto.randomUUID()),t.projectId||(t.projectId=e),t.projectId!==e)throw new Error(`Thread projectId mismatch: expected ${e}, got ${t.projectId}`);let n=this.getThreadsDir(e),i=this.getThreadFileName(t),a=j0.join(n,i),s=await this.findThreadFile(e,t.id);if(s&&s!==i){let l=j0.join(n,s);try{await ll.unlink(l),console.log(`[THREAD-REPO] Migrated/renamed thread file: ${s} \u2192 ${i}`)}catch(u){console.warn(`[THREAD-REPO] Could not delete old thread file: ${s}`,u)}}let o={...t,version:J$.length+1},c=Z$.default.stringify(o);return await ll.writeFile(a,c,"utf-8"),t}catch(n){throw new Tc(`Failed to save thread ${t.id} to project ${e}`,n)}}async listByProject(e,t){try{let n=this.getThreadsDir(e);try{await ll.access(n)}catch{return[]}let i=await ll.readdir(n);return(await Promise.all(i.filter(s=>s.endsWith(".yml")).map(async s=>{let o=await A5e(j0.join(n,s));if(!o)return null;let c=o.projectId||e;return{id:o.id,username:o.username,projectId:c,name:o.name??"...",summary:o.summary??"",createdDate:o.createdDate??"",modifiedDate:o.modifiedDate??"",price:o.price??0,starring:o.starring??[]}}))).filter(s=>!!s).filter(s=>!t||s.username===t).sort((s,o)=>s.modifiedDate>o.modifiedDate?-1:1)}catch(n){throw new Tc(`Failed to list threads for project ${e}`,n)}}async delete(e,t){try{let n=await this.findThreadFile(e,t);if(!n)return!1;let i=this.getThreadsDir(e);return await ll.unlink(j0.join(i,n)),!0}catch(n){throw new Tc(`Failed to delete thread ${t} from project ${e}`,n)}}};var TE=class{constructor(e,t,n){this.projectRepository=e;this.projectsDir=t;this.threadFileService=n}repositoryCache=new Map;threadListCache=new Map;CACHE_TTL_MS=14400*1e3;loadingPromises=new Map;getThreadRepository(e){let t=this.repositoryCache.get(e);if(t)return t;if(!this.projectRepository.getProjectInfo(e))throw new Error(`Project '${e}' not found`);let i=new kE(this.projectsDir);return this.repositoryCache.set(e,i),i}clearCache(e){e?this.repositoryCache.delete(e):this.repositoryCache.clear()}async listThreads(e,t){let n=this.threadListCache.get(e);if(n&&Date.now()-n.timestamp<this.CACHE_TTL_MS)return n.data.filter(s=>s.username===t).sort((s,o)=>s.modifiedDate>o.modifiedDate?-1:1);let i=this.loadingPromises.get(e);if(i)return await i,this.listThreads(e,t);let a=this.loadThreadListFromDisk(e);this.loadingPromises.set(e,a);try{return(await a).filter(o=>o.username===t).sort((o,c)=>o.modifiedDate>c.modifiedDate?-1:1)}catch(s){throw this.threadListCache.delete(e),s}finally{this.loadingPromises.delete(e)}}async loadThreadListFromDisk(e){let n=await this.getThreadRepository(e).listByProject(e);return this.threadListCache.set(e,{data:n,timestamp:Date.now()}),n}updateThreadInCache(e,t){let n=this.threadListCache.get(e);if(!n)return;let i=n.data.findIndex(a=>a.id===t.id);i!==-1?n.data[i]=t:n.data.push(t)}removeThreadFromCache(e,t){let n=this.threadListCache.get(e);n&&(n.data=n.data.filter(i=>i.id!==t))}async getThread(e,t){return await this.getThreadRepository(e).getById(e,t)}async createThread(e,t,n){let i=this.getThreadRepository(e),a=new Ql({id:crypto.randomUUID(),username:t,projectId:e,name:n||"",price:0}),s=await i.save(e,a);return this.updateThreadInCache(e,{id:s.id,username:s.username,projectId:s.projectId,name:s.name,summary:s.summary,createdDate:s.createdDate,modifiedDate:s.modifiedDate,price:s.price,starring:s.starring}),s}async updateThread(e,t,n){let i=this.getThreadRepository(e),a=await i.getById(e,t);if(!a)throw new Error(`Thread '${t}' not found in project '${e}'`);n.name!==void 0&&(a.name=n.name);let s=await i.save(e,a);return this.updateThreadInCache(e,{id:s.id,username:s.username,projectId:s.projectId,name:s.name,summary:s.summary,createdDate:s.createdDate,modifiedDate:s.modifiedDate,price:s.price,starring:s.starring}),s}async starThread(e,t,n){let i=this.getThreadRepository(e),a=await i.getById(e,t);if(!a)throw new Error(`Thread '${t}' not found in project '${e}'`);a.starring.includes(n)||a.starring.push(n);let s=await i.save(e,a);return this.updateThreadInCache(e,{id:s.id,username:s.username,projectId:s.projectId,name:s.name,summary:s.summary,createdDate:s.createdDate,modifiedDate:s.modifiedDate,price:s.price,starring:s.starring}),s}async unstarThread(e,t,n){let i=this.getThreadRepository(e),a=await i.getById(e,t);if(!a)throw new Error(`Thread '${t}' not found in project '${e}'`);a.starring=a.starring.filter(o=>o!==n);let s=await i.save(e,a);return this.updateThreadInCache(e,{id:s.id,username:s.username,projectId:s.projectId,name:s.name,summary:s.summary,createdDate:s.createdDate,modifiedDate:s.modifiedDate,price:s.price,starring:s.starring}),s}async deleteThread(e,t){let i=await this.getThreadRepository(e).delete(e,t);return i&&(await this.threadFileService.deleteThreadFiles(e,t),this.removeThreadFromCache(e,t)),i}async exists(e,t){return await this.getThread(e,t)!==null}};import*as _i from"path";import*as M0 from"fs";import*as ea from"fs/promises";var DE=class{constructor(e){this.projectsDir=e}getThreadFilesDir(e,t){return _i.join(this.projectsDir,e,"threads",`${t}-files`)}async ensureThreadFilesDir(e,t){let n=this.getThreadFilesDir(e,t);M0.existsSync(n)||await ea.mkdir(n,{recursive:!0})}async listFiles(e,t){await this.ensureThreadFilesDir(e,t);let n=this.getThreadFilesDir(e,t),i=await ea.readdir(n);return await Promise.all(i.map(async s=>{let o=_i.join(n,s),c=await ea.stat(o);return{filename:s,size:c.size,lastModified:c.mtime.toISOString()}}))}async saveFile(e,t,n,i){let a=this.getThreadFilesDir(e,t);await ea.mkdir(a,{recursive:!0});let s=_i.join(a,n);await ea.writeFile(s,i)}async getFile(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=_i.join(i,n),s=_i.resolve(a),o=_i.resolve(i);if(!s.startsWith(o))throw new Error("Access denied: invalid file path");if(!M0.existsSync(a))throw new Error(`File '${n}' not found`);return await ea.readFile(a)}async getFilePath(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=_i.join(i,n),s=_i.resolve(a),o=_i.resolve(i);if(!s.startsWith(o))throw new Error("Access denied: invalid file path");if(!M0.existsSync(a))throw new Error(`File '${n}' not found`);return a}fileExists(e,t,n){let i=this.getThreadFilesDir(e,t),a=_i.join(i,n),s=_i.resolve(a),o=_i.resolve(i);return s.startsWith(o)?M0.existsSync(a):!1}async deleteFile(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=_i.join(i,n),s=_i.resolve(a),o=_i.resolve(i);if(!s.startsWith(o))throw new Error("Access denied: invalid file path");if(!M0.existsSync(a))throw new Error(`File '${n}' not found`);await ea.unlink(a)}async deleteThreadFiles(e,t){try{let n=this.getThreadFilesDir(e,t);M0.existsSync(n)&&(await ea.rm(n,{recursive:!0,force:!0}),console.log(`Deleted thread files directory: ${n}`))}catch(n){console.error(`Error deleting thread files for ${t}:`,n)}}};import*as uc from"node:path";import*as P5e from"node:os";import{existsSync as T5e,lstatSync as kpt,mkdirSync as D5e,readdirSync as Tpt}from"fs";var k5e=[QS];var PE=class r{projectsConfigPath;static PROJECT_FILENAME="project.yaml";constructor(e){let t=uc.join(P5e.userInfo().homedir,".coday");this.projectsConfigPath=uc.join(e??t,"projects"),D5e(this.projectsConfigPath,{recursive:!0})}listProjects(){return Tpt(this.projectsConfigPath).filter(t=>kpt(uc.join(this.projectsConfigPath,t)).isDirectory())}getProjectInfo(e){let t=uc.join(this.projectsConfigPath,e),n=uc.join(t,r.PROJECT_FILENAME);return T5e(n)?{name:e,configPath:t}:null}exists(e){return this.getProjectInfo(e)!==null}getConfig(e){let t=this.getProjectInfo(e);if(!t)return null;let n=uc.join(t.configPath,r.PROJECT_FILENAME),i=n2(n);if(!i)return null;let a=Z1(i,k5e);return a!==i&&Zn(n,a),a}saveConfig(e,t){let n=this.getProjectInfo(e);if(!n)throw new Error(`Project '${e}' does not exist`);let i=uc.join(n.configPath,r.PROJECT_FILENAME);Zn(i,t)}createProject(e,t){let n=uc.join(this.projectsConfigPath,e),i=uc.join(n,r.PROJECT_FILENAME);return T5e(i)?!1:(D5e(n,{recursive:!0}),Zn(i,{version:1,path:t,integration:{},storage:{type:"file"},agents:[]}),!0)}deleteProject(e){return this.getProjectInfo(e),!1}};var Ya=(0,aC.default)(),Tht=process.env.PORT?parseInt(process.env.PORT):process.env.BUILD_ENV==="development"?4100:3e3,Dht=p5e(Tht),Pht="x-forwarded-email",Xn=i5e();Se("INIT","Coday options:",Xn);var Z8e=!Xn.noLog,sC=new _E(Z8e,Xn.logFolder);Se("INIT",`Usage logging ${Z8e?"enabled":"disabled"} ${Xn.logFolder?`(custom folder: ${Xn.logFolder})`:""}`);var $L=new SE(Xn.configDir);Se("INIT","Webhook service initialized");Ya.use(aC.default.json({limit:"20mb"}));if(process.env.BUILD_ENV==="development"){let r="http://localhost:4200";Se("INIT",`Development mode: proxying to Angular dev server at ${r}`),Promise.resolve().then(()=>yr(K8e(),1)).then(({createProxyMiddleware:e})=>{let t=e({target:r,changeOrigin:!0,ws:!0});Ya.use("/",(n,i,a)=>{n.path.startsWith("/api")||n.path.startsWith("/events")?a():t(n,i,a)}),Se("INIT","Proxy middleware configured successfully")}).catch(e=>{console.error("Failed to load http-proxy-middleware:",e)})}else{let r=process.env.CODAY_CLIENT_PATH?dl.resolve(process.env.CODAY_CLIENT_PATH):dl.resolve(__dirname,"../coday-client/browser");if(Se("INIT",`Production mode: serving static files from ${r}`),process.env.CODAY_CLIENT_PATH&&Se("INIT","Using client path from CODAY_CLIENT_PATH environment variable"),!tC.existsSync(r))console.error(`ERROR: Client path does not exist: ${r}`),console.error("Please build the client first with: pnpm nx run client:build");else{let e=dl.join(r,"index.html");tC.existsSync(e)?Se("INIT",`Verified index.html exists at ${e}`):(console.error(`ERROR: index.html not found at: ${e}`),console.error("Client build may be incomplete. Try rebuilding with: pnpm nx run client:build"))}Ya.use(aC.default.static(r))}var rC=new PE(Xn.configDir),G6=Xn.project;if(G6&&!Xn.forcedProject){let r=process.cwd(),e=dl.basename(r);if(rC.exists(e)){let t=rC.getConfig(e);if(t&&t.path===r&&!t.volatile)Se("INIT",`Default mode: found existing non-volatile project '${e}' for current directory`),G6=e;else{let n=lh.generateProjectId(r);Se("INIT",`Default mode: existing project '${e}' doesn't match path, using volatile ID ${n}`),G6=n}}else{let t=lh.generateProjectId(r);Se("INIT",`Default mode: no existing project found, using volatile ID ${t}`),G6=t}}var LL=new lh(rC,G6,Xn.forcedProject),Y8e=dl.join(Xn.configDir,"projects"),X8e=new DE(Y8e),oC=new TE(rC,Y8e,X8e),cC=new rE(sC,$L,LL,oC),Oht=new r2("config-api"),Iht=new AE(Xn.configDir,Oht),Rht=["root","admin","administrator","system","daemon","nobody","node","app","service","docker","www-data","nginx","apache","ansible"];function mh(r){let e=Xn.auth?r.headers[Pht]:J8e.userInfo().username;if(Rht.includes(e.toLowerCase()))throw new Error(`Security error: Cannot run with username "${e}". This appears to be a system or service account. When running locally, ensure you are running as a regular user account. When running in production, ensure authentication is properly configured with --auth flag.`);return e}S5e(Ya,mh);d5e(Ya,Iht,mh);m5e(Ya,$L,mh,oC,cC,Xn,sC);g5e(Ya,LL);w5e(Ya,oC,X8e,cC,mh,Xn);_5e(Ya,cC,mh);E5e(Ya,LL,mh,Xn.configDir,sC,$L,oC,Xn);if(process.env.BUILD_ENV!=="development"){let r=process.env.CODAY_CLIENT_PATH?dl.resolve(process.env.CODAY_CLIENT_PATH):dl.resolve(__dirname,"../coday-client/browser"),e=dl.resolve(r,"index.html");Se("INIT",`Catch-all route will serve: ${e}`),Ya.use((t,n,i)=>{if(t.path.startsWith("/api")||t.path.startsWith("/events")){n.status(404).send("Not found");return}Se("ROUTER",`Serving index.html for client route: ${t.path}`),tC.readFile(e,"utf8",(a,s)=>{a?(Se("ERROR",`Failed to read index.html from ${e}:`,a),Se("ERROR",`File exists check: ${tC.existsSync(e)}`),i(a)):n.type("html").send(s)})})}var nC=null;Ya.use((r,e,t,n)=>{Se("ERROR",`Request error on ${e.method} ${e.path}:`,r.message),console.error(r.stack),process.env.BUILD_ENV==="development"?t.status(500).json({error:"Internal Server Error",message:r.message,stack:r.stack}):t.status(500).send("Something went wrong!")});Dht.then(async r=>{Ya.listen(r,()=>{console.log(`Server is running on http://localhost:${r}`)});try{Se("CLEANUP","Starting thread cleanup service...");let e=dl.join(Xn.configDir,"projects");nC=new CE(e,sC),await nC.start(),Se("CLEANUP","Thread cleanup service started successfully")}catch(e){console.error("Failed to start thread cleanup service:",e)}}).catch(r=>{console.error("Failed to start server:",r),process.exit(1)});var iC=!1;async function gh(r){iC&&(console.log(`Received ${r} during shutdown, forcing exit...`),process.exit(1)),iC=!0,console.log(`Received ${r}, shutting down gracefully...`);try{nC&&(console.log("Stopping thread cleanup service..."),await nC.stop()),console.log("Cleaning up thread Coday instances..."),await cC.shutdown(),console.log("Graceful shutdown completed"),process.exit(0)}catch(e){console.error("Error during graceful shutdown:",e),process.exit(1)}}process.on("SIGTERM",()=>gh("SIGTERM"));process.on("SIGINT",()=>gh("SIGINT"));process.on("SIGUSR2",()=>gh("SIGUSR2"));process.on("SIGHUP",()=>gh("SIGHUP"));process.on("uncaughtException",r=>{if(console.error("Uncaught exception:",r),r.message==="no elements in sequence"||r.constructor.name==="EmptyErrorImpl"){console.log("Detected RxJS EmptyError during system sleep - this is expected behavior"),console.log("Process will continue normally after system wake");return}iC||gh("uncaughtException")});process.on("unhandledRejection",(r,e)=>{if(console.error("Unhandled rejection at:",e,"reason:",r),r&&typeof r=="object"){let t=r;if(t.message==="no elements in sequence"||t.constructor?.name==="EmptyErrorImpl"){console.log("Detected RxJS EmptyError rejection during system sleep - this is expected behavior");return}if(t.name==="TimeoutError"||t.message?.includes("timeout")){console.log("Detected timeout error - handling gracefully without shutdown");return}if(t.name==="AbortError"||t.message?.includes("aborted")){console.log("Detected abort error - handling gracefully without shutdown");return}}console.error("Critical unhandled rejection detected"),iC||gh("unhandledRejection")});
|
|
1383
1383
|
/*! Bundled license information:
|
|
1384
1384
|
|
|
1385
1385
|
depd/index.js:
|