@whoz-oss/coday-server 0.105.1 → 0.105.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whoz-oss/coday-server",
3
- "version": "0.105.1",
3
+ "version": "0.105.2",
4
4
  "repository": "https://github.com/whoz-oss/coday",
5
5
  "type": "module",
6
6
  "main": "server/server.js",
package/server.js CHANGED
@@ -874,7 +874,7 @@ Are you sure you want to delete this MCP server configuration?
874
874
 
875
875
  Here are the information collected during previous chats:
876
876
  `),n.join(`
877
- `)):""}loadMemoriesFrom(e){this.memories=[],this.userMemoriesPath=this.readMemories(this.userMemoriesPath)?this.userMemoriesPath:void 0;let t=e?.configPath?tE.join(e.configPath,xM):void 0;this.projectMemoriesPath=this.readMemories(t)?t:void 0,e&&this.checkInit()}readMemories(e){if(!e)return!1;try{if(!Hit(e)){let n=kfe.stringify({memories:[]});Wit(e,n)}let t=ta(e);return t?(this.memories.push(...t.memories),!0):!1}catch{return!1}}checkInit(){if(!this.userMemoriesPath||!this.projectMemoriesPath)throw new Error("user or project path not set for memory service")}saveMemories(){this.checkInit();let e=this.memories.filter(n=>n.level==="USER"),t=this.memories.filter(n=>n.level==="PROJECT");Mn(this.userMemoriesPath,{memories:e}),Mn(this.projectMemoriesPath,{memories:t})}};import*as Cfe from"crypto";import*as Va from"node:fs/promises";import*as Fc from"path";var xm=class r{constructor(e,t,n){this.repository=e;this.defaultProject=t;this.isForcedMode=n}maskingService=new B2;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=Fc.basename(n);if(e===a||e===i||e===this.defaultProject){console.log(`[PROJECT_SERVICE] Creating volatile project for '${e}' at ${n}`);let o=this.getOrCreateVolatileProject(n);if(t=this.repository.getConfig(o),t)return{name:o,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}async registerWorktreeProject(e,t,n){let i=this.repository.getConfig(n),a=i?{...i,path:t,volatile:void 0,createdAt:void 0}:{version:1,path:t,integration:{},storage:{type:"file"},agents:[]};this.repository.createProject(e,t),this.repository.saveConfig(e,a);let o=this.repository.getProjectInfo(n);if(o){let s=this.repository.getProjectInfo(e);if(s)for(let c of["agents","prompts","schedulers","memories"]){let u=Fc.join(o.configPath,c),l=Fc.join(s.configPath,c);try{await Va.access(u),await Va.symlink(u,l)}catch{}}}}async unregisterWorktreeProject(e){let t=this.repository.getProjectInfo(e);if(!t)return;let n=e.lastIndexOf("__");if(n!==-1){let i=e.substring(0,n),a=this.repository.getProjectInfo(i);a&&await this.migrateThreadsToParent(t.configPath,a.configPath)}await Va.rm(t.configPath,{recursive:!0,force:!0})}async migrateThreadsToParent(e,t){let n=Fc.join(e,"threads"),i=Fc.join(t,"threads");try{await Va.access(n)}catch{return}await Va.mkdir(i,{recursive:!0});let a=await Va.readdir(n);for(let o of a){let s=Fc.join(n,o),c=Fc.join(i,o);try{await Va.access(c)}catch{await Va.rename(s,c)}}}static generateProjectId(e){let t=Fc.basename(e),n=Cfe.createHash("sha256").update(e).digest("hex").substring(0,8);return`${t}_${n}`}};var Dfe=ur(po(),1);import*as wm from"node:path";import*as Pfe from"node:os";import{mkdirSync as Vit}from"fs";var Git="projects",Tfe="project.yaml",_m=class{constructor(e,t,n){this.interactor=e;this.projectService=t;let i=wm.join(Pfe.userInfo().homedir,".coday");this.projectsConfigPath=wm.join(n??i,Git),Vit(this.projectsConfigPath,{recursive:!0}),this.projects=this.projectService.listProjects().map(a=>a.name)}projectsConfigPath;maskingService=new B2;projects;selectedProjectBehaviorSubject=new Dfe.BehaviorSubject(null);selectedProject$=this.selectedProjectBehaviorSubject.asObservable();selectProject(e){let t=wm.join(this.projectsConfigPath,e),n=wm.join(t,Tfe),i=this.projectService.getProject(e)?.config;if(!i?.path){console.log(`[PROJECT_STATE_SERVICE] ERROR: No project path in config for '${e}'`),this.interactor.error("Invalid selection, project path needed \u{1F622}.");return}let o={name:e,config:i,configPath:t};console.log(`[PROJECT_STATE_SERVICE] Selected '${e}' \u2192 ${i.path}`),this.updateSelectedProject(o),this.interactor.displayText(`Project local configuration used: ${n}`)}updateSelectedProject(e){this.selectedProjectBehaviorSubject.next(e)}get selectedProject(){return this.selectedProjectBehaviorSubject.value}save(e){let t=this.selectedProjectBehaviorSubject.value;if(!t){this.interactor.error("No current project selected, save not possible");return}let n={...t.config,...e};Mn(wm.join(t.configPath,Tfe),n),t.config=n,this.updateSelectedProject(t)}getConfigForClient(){let e=this.selectedProjectBehaviorSubject.value;return e?this.maskingService.maskConfig(e.config):null}updateConfigFromClient(e){let t=this.selectedProjectBehaviorSubject.value;if(!t){this.interactor.error("No current project selected, update not possible");return}let n=this.maskingService.unmaskConfig(e,t.config);this.save(n)}};import*as Gu from"node:path";import*as $fe from"node:os";import{randomUUID as Jit}from"node:crypto";import{existsSync as W2,mkdirSync as Kit,readdirSync as Ofe,unlinkSync as Yit}from"fs";import*as wM from"node:path";import*as Ife from"node:os";function Zit(r){return r.replace(/[^a-zA-Z0-9]/g,"_")}function Sm(r,e){try{let t=wM.join(Ife.userInfo().homedir,".coday"),n=Zit(r),i=wM.join(e??t,"users",n,"user.yaml"),a=ta(i);return a?a.groups?.includes("CODAY_ADMIN")??!1:!1}catch{return!1}}var rE=class{codayConfigDir;projectService;nativeHandlerStubs=[];constructor(e,t){let n=Gu.join($fe.userInfo().homedir,".coday");this.codayConfigDir=e??n,this.projectService=t}getProjectPath(e){if(this.projectService)return this.projectService.getProject(e)?.config.path}async getOrCreatePromptsDir(e,t){let n;if(t==="local")n=Gu.join(this.codayConfigDir,"projects",e,"prompts");else{let i=this.getProjectPath(e);if(!i)throw new Error("Project path not configured, cannot access project prompts");let a=await f2({text:"coday.yaml",root:i});if(a.length===0)throw new Error(`coday.yaml not found in project path: ${i}`);let o=Gu.dirname(a[0]);n=Gu.join(i,o,"prompts")}return W2(n)||(Kit(n,{recursive:!0}),console.log(`[PROMPT] Created prompts directory: ${n}`)),n}async getOrCreatePromptFilePath(e,t,n){let i=await this.getOrCreatePromptsDir(e,n);return Gu.join(i,`${t}.yml`)}async findPromptSource(e,t){let n=await this.getOrCreatePromptFilePath(e,t,"local");if(W2(n))return"local";if(this.projectService)try{let i=await this.getOrCreatePromptFilePath(e,t,"project");if(W2(i))return"project"}catch{}return null}async findProjectForPrompt(e){let t=Gu.join(this.codayConfigDir,"projects");if(!W2(t))return null;let n=Ofe(t,{withFileTypes:!0}).filter(i=>i.isDirectory()).map(i=>i.name);for(let i of n){let a=Gu.join(this.codayConfigDir,"projects",i,"prompts",`${e}.yml`);if(W2(a))return i;if(this.projectService)try{let o=await this.getOrCreatePromptFilePath(i,e,"project");if(W2(o))return i}catch{}}return null}validatePlaceholders(e){let t=/\{\{(\w+)\}\}/g,n=[],i=/^[A-Za-z][A-Za-z0-9-]*$/;if(e.forEach(a=>{let o;for(;(o=t.exec(a))!==null;){let s=o[1];s&&s!=="PARAMETERS"&&!i.test(s)&&n.push(s)}}),n.length>0)throw new Error(`Invalid parameter keys: ${n.join(", ")}. Keys must start with a letter and contain only letters, digits, and hyphens.`)}async create(e,t,n="local"){try{this.validatePlaceholders(t.commands);let i=Jit(),a={...t,id:i,source:n,createdAt:new Date().toISOString(),parameterFormat:this.getParameterFormat(t.commands)},o=await this.getOrCreatePromptFilePath(e,i,n);if(W2(o))throw new Error(`Prompt with ID ${i} already exists`);return Mn(o,a),console.log(`[PROMPT] Created prompt ${i} in ${n} for project ${e}`),a}catch(i){throw new Error(`Failed to create prompt: ${i instanceof Error?i.message:"Unknown error"}`)}}async get(e,t){try{let n=await this.findPromptSource(e,t);if(!n)return null;let i=await this.getOrCreatePromptFilePath(e,t,n),a=ta(i);return a?(a.source||(a.source=n),a):null}catch(n){return console.error(`Failed to get prompt ${t}:`,n),null}}async getById(e){try{let t=await this.findProjectForPrompt(e);if(!t)return null;let n=await this.get(t,e);return n?{prompt:n,projectName:t}:null}catch(t){return console.error(`Failed to get prompt ${e}:`,t),null}}async update(e,t,n,i){try{let a=await this.get(e,t);if(!a)return null;if(n.webhookEnabled!==void 0&&n.webhookEnabled!==a.webhookEnabled&&!Sm(i,this.codayConfigDir))throw new Error("Only CODAY_ADMIN can enable/disable webhook for prompts");let{id:o,createdAt:s,source:c,...u}=n;n.commands&&this.validatePlaceholders(n.commands);let l={...a,...u,updatedAt:new Date().toISOString()};n.commands&&(l.parameterFormat=this.getParameterFormat(n.commands));let f=await this.getOrCreatePromptFilePath(e,t,a.source);return Mn(f,l),console.log(`[PROMPT] Updated prompt ${t} (${a.source}) by user ${i}`),l}catch(a){throw console.error(`Failed to update prompt ${t}:`,a),a}}async delete(e,t){try{let n=await this.findPromptSource(e,t);if(!n)return!1;let i=await this.getOrCreatePromptFilePath(e,t,n);return Yit(i),console.log(`[PROMPT] Deleted prompt ${t} from ${n}`),!0}catch(n){return console.error(`Failed to delete prompt ${t}:`,n),!1}}getParameterFormat(e){if(e.some(a=>/\{\{PARAMETERS\}\}/.test(a)))return"";let n=/\{\{(\w+)\}\}/g,i=new Set;return e.forEach(a=>{let o;for(;(o=n.exec(a))!==null;){let s=o[1];s&&s!=="PARAMETERS"&&i.add(s)}}),i.size===0?"":Array.from(i).map(a=>`${a}=""`).join(" ")}registerNativeHandler(e){this.nativeHandlerStubs.find(t=>t.id===e.id)||this.nativeHandlerStubs.push(e)}async list(e,t=[]){try{let n=[],i=["local"];this.projectService&&i.push("project");for(let a of i)try{let o=await this.getOrCreatePromptsDir(e,a);if(!W2(o))continue;let c=Ofe(o).filter(u=>u.endsWith(".yml"));for(let u of c){let l=u.replace(".yml",""),f=await this.get(e,l);f&&n.push({id:f.id,name:f.name,description:f.description,webhookEnabled:f.webhookEnabled,createdBy:f.createdBy,createdAt:f.createdAt,updatedAt:f.updatedAt,source:f.source||a,parameterFormat:f.parameterFormat})}}catch(o){console.log(`[PROMPT] Could not access ${a} prompts for ${e}:`,o)}return n.push(...E0),n.push(...this.nativeHandlerStubs),n.push(...t),n.sort((a,o)=>new Date(o.createdAt).getTime()-new Date(a.createdAt).getTime())}catch(n){return console.error(`Failed to list prompts for project ${e}:`,n),[]}}async enableWebhook(e,t,n){return this.update(e,t,{webhookEnabled:!0},n)}async disableWebhook(e,t,n){return this.update(e,t,{webhookEnabled:!1},n)}};var jfe=ur(po(),1),nE=class{constructor(e){this.promptService=e}threadCodayManager;threadService;codayOptions;logger;initialize(e,t,n,i){this.threadCodayManager=e,this.threadService=t,this.codayOptions=n,this.logger=i}processCommands(e,t){let n;if(typeof t=="string"){let a=e.some(s=>/\{\{PARAMETERS\}\}/.test(s));if(e.some(s=>/\{\{(?!PARAMETERS\}\})\w+\}\}/.test(s)))throw new Error("Prompt contains structured placeholders ({{key}}). Use an object parameter instead of a string.");a?n=e.map(s=>s.replace(/\{\{PARAMETERS\}\}/g,t)):n=e.map((s,c)=>c===0?`${s} ${t}`.trim():s)}else typeof t=="object"&&t!==null?n=e.map(a=>{let o=a;return Object.entries(t).forEach(([s,c])=>{let u=`{{${s}}}`;o=o.replaceAll(u,String(c))}),o}):n=[...e];let i=new Set;if(n.forEach(a=>{let o=a.match(/\{\{(\w+)\}\}/g);o&&o.forEach(s=>i.add(s))}),i.size>0){let a=Array.from(i).map(o=>o.replace(/[{}]/g,"")).join(", ");throw new Error(`Missing required parameters: ${a}`)}return n}async executePrompt(e,t,n,i,a){if(!this.threadCodayManager||!this.threadService||!this.codayOptions||!this.logger)throw new Error("PromptExecutionService not initialized. Call initialize() first.");let{title:o,awaitFinalAnswer:s=!1,projectName:c}=a||{},u,l;if(c){if(l=c,u=await this.promptService.get(l,e),!u)throw new Error(`Prompt ${e} not found in project ${l}`)}else{let y=await this.promptService.getById(e);if(!y)throw new Error(`Prompt not found: ${e}`);u=y.prompt,l=y.projectName}if(i==="webhook"&&!u.webhookEnabled)throw new Error(`Prompt ${e} is not enabled for webhook execution`);if(!u.commands||u.commands.length===0)throw new Error("Prompt has no commands configured");let f=this.processCommands(u.commands,t);if(!n)throw new Error("Username is required");let d=(await this.threadService.createThread(l,n,o)).id;console.log(`[PROMPT_EXEC] Created new thread: ${d} for ${i} execution`);let m={...this.codayOptions,oneshot:!0,project:l,thread:d,prompts:f};console.log(`[PROMPT_EXEC] Creating instance for ${i} execution with ${f.length} prompts:`,f);let h=this.threadCodayManager.createWithoutConnection(d,l,n,m);h.prepareCoday();let g=h.coday.interactor,v={project:l,title:o??"Untitled",username:n,clientId:d,promptCount:f.length,awaitFinalAnswer:!!s,promptName:u.name,promptId:u.id,executionMode:i};if(i==="webhook"?this.logger.logWebhook(v):this.logger.logWebhook({...v,webhookName:u.name,webhookUuid:u.id}),s){let y=[],x=g.events.pipe((0,jfe.filter)(k=>(console.log(`[PROMPT_EXEC] Received event type: ${k.type}, role: ${k instanceof $t?k.role:"N/A"}`),k instanceof $t&&k.role==="assistant"&&!!k.name))).subscribe(k=>{y.push(k)});try{await h.coday.run(),x.unsubscribe();let k=y[y.length-1];return await this.threadCodayManager.cleanup(d),{threadId:d,lastEvent:k}}catch(k){x.unsubscribe();let S=k instanceof Error?k.message:"Unknown error";throw this.logger.logWebhookError({error:`Prompt execution failed: ${S}`,username:n,project:l,clientId:d}),console.error("[PROMPT_EXEC] Error waiting for prompt completion:",k),await this.threadCodayManager.cleanup(d),k}}else return h.coday.run().catch(y=>{console.error("[PROMPT_EXEC] Error during prompt Coday run:",y)}),setTimeout(()=>{this.threadCodayManager.cleanup(d).catch(y=>{console.error("[PROMPT_EXEC] Error cleaning up prompt thread after timeout:",y)})},300*1e3),{threadId:d}}};var X6=ur(Pc(),1);import*as ai from"fs";import*as Em from"path";import{randomUUID as Xit}from"node:crypto";var iE=class{constructor(e,t,n){this.logger=e;this.promptService=t;this.codayConfigDir=n}schedulers=new Map;checkInterval;CHECK_INTERVAL_MS=3e4;promptExecutionService;initializeExecution(e){this.promptExecutionService=e}async initialize(){console.log("[SCHEDULER] Initializing SchedulerService..."),await this.loadAllSchedulers(),this.startScheduler(),console.log(`[SCHEDULER] SchedulerService initialized with ${this.schedulers.size} schedulers`)}stop(){this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=void 0,console.log("[SCHEDULER] SchedulerService stopped"))}async loadAllSchedulers(){this.schedulers.clear();let e=Em.join(this.codayConfigDir,"projects");if(!ai.existsSync(e))return;let t=ai.readdirSync(e,{withFileTypes:!0}).filter(n=>n.isDirectory()).map(n=>n.name);for(let n of t)try{let i=await this.loadProjectSchedulers(n);for(let a of i)this.schedulers.set(a.id,a)}catch(i){console.error(`[SCHEDULER] Failed to load schedulers for project ${n}:`,i)}}async loadProjectSchedulers(e){let t=this.getSchedulersDir(e);if(!ai.existsSync(t))return[];let n=ai.readdirSync(t),i=[];for(let a of n)if(a.endsWith(".yml"))try{let o=Em.join(t,a),s=ai.readFileSync(o,"utf-8"),c=X6.parse(s),u=this.calculateNextRunSkippingMissed(c),l=u.occurrenceCount!==c.occurrenceCount;c.nextRun=u.nextRun,c.occurrenceCount=u.occurrenceCount,l&&await this.saveScheduler(c,e),i.push(c)}catch(o){console.error(`[SCHEDULER] Failed to load scheduler from ${a}:`,o)}return i}startScheduler(){this.checkInterval=setInterval(()=>{this.checkAndExecuteSchedulers()},this.CHECK_INTERVAL_MS),this.checkAndExecuteSchedulers()}async checkAndExecuteSchedulers(){for(let e of this.schedulers.values())e.enabled&&yce(e.schedule,e.nextRun??null,e.occurrenceCount??0)&&this.executeScheduler(e).catch(t=>{console.error(`[SCHEDULER] Failed to execute scheduler ${e.id}:`,t)})}async executeSchedulerInternal(e,t,n){if(!this.promptExecutionService)throw new Error("PromptExecutionService not initialized");console.log(`[SCHEDULER] Executing scheduler "${e.name}" (${e.id}) [${n}]`);let i=e.parameters;e.parameters&&typeof e.parameters=="object"&&Object.keys(e.parameters).length===1&&"PARAMETERS"in e.parameters&&(i=String(e.parameters.PARAMETERS));let a=await this.promptExecutionService.executePrompt(e.promptId,i,e.createdBy,"scheduled",{title:n==="scheduled"?`Scheduled: ${e.name}`:`Manual: ${e.name}`,awaitFinalAnswer:!1,projectName:t});return console.log(`[SCHEDULER] Scheduler "${e.name}" executed successfully. Thread: ${a.threadId}`),a.threadId}async executeScheduler(e){let t=new Date().toISOString();console.log(`[SCHEDULER] Executing scheduler "${e.name}" (${e.id})`);let n=this.findProjectForScheduler(e.id);if(!n){console.error(`[SCHEDULER] Cannot find project for scheduler ${e.id}, skipping execution`);return}let i,a,o;e.lastRun=t,e.occurrenceCount=(e.occurrenceCount??0)+1,e.nextRun=lh(e.schedule,new Date,e.occurrenceCount);try{await this.saveScheduler(e,n),console.log(`[SCHEDULER] Next execution for "${e.name}": ${e.nextRun}`),this.schedulers.set(e.id,e),a=await this.executeSchedulerInternal(e,n,"scheduled"),i=!0}catch(s){i=!1,o=s instanceof Error?s.message:String(s),console.error(`[SCHEDULER] Scheduler "${e.name}" failed:`,s)}this.logger.logTriggerExecution({triggerId:e.id,triggerName:e.name,webhookUuid:e.promptId,projectName:n,success:i,threadId:a,error:o})}validateSchedule(e){return vce(e)}calculateNextRunSkippingMissed(e){let t=new Date,n=e.occurrenceCount??0,i=e.nextRun;if(!i)return{nextRun:lh(e.schedule,t,n),occurrenceCount:n};if(new Date(i)>=t)return{nextRun:i,occurrenceCount:n};let a=1e3,o=0,s=0;for(;o<a;){if(n++,s++,i=lh(e.schedule,t,n),!i)return s>0&&console.log(`[SCHEDULER] Scheduler "${e.name}" (${e.id}) expired after skipping ${s} missed occurrence(s)`),{nextRun:null,occurrenceCount:n};if(new Date(i)>=t)return s>0&&console.log(`[SCHEDULER] Scheduler "${e.name}" (${e.id}) skipped ${s} missed occurrence(s), next run: ${i}`),{nextRun:i,occurrenceCount:n};o++}return console.warn(`[SCHEDULER] Could not find future nextRun for scheduler ${e.id} after ${a} iterations`),{nextRun:null,occurrenceCount:n}}getSchedulersDir(e){return Em.join(this.codayConfigDir,"projects",e,"schedulers")}getSchedulerFilePath(e,t){return Em.join(this.getSchedulersDir(e),`${t}.yml`)}findProjectForScheduler(e){let t=Em.join(this.codayConfigDir,"projects");if(!ai.existsSync(t))return null;let n=ai.readdirSync(t,{withFileTypes:!0}).filter(i=>i.isDirectory()).map(i=>i.name);for(let i of n){let a=this.getSchedulerFilePath(i,e);if(ai.existsSync(a))return i}return null}canAccessScheduler(e,t){return e.createdBy===t?!0:Sm(t,this.codayConfigDir)}async listSchedulers(e,t){return(await this.loadProjectSchedulers(e)).filter(i=>this.canAccessScheduler(i,t)).map(i=>({id:i.id,name:i.name,enabled:i.enabled,promptId:i.promptId,schedule:i.schedule,parameters:i.parameters,lastRun:i.lastRun,nextRun:i.nextRun,createdBy:i.createdBy}))}async getScheduler(e,t,n){let i=this.getSchedulerFilePath(e,t);if(!ai.existsSync(i))return null;try{let a=ai.readFileSync(i,"utf-8"),o=X6.parse(a),s=this.calculateNextRunSkippingMissed(o);return o.nextRun=s.nextRun,o.occurrenceCount=s.occurrenceCount,n&&!this.canAccessScheduler(o,n)?(console.log(`[SCHEDULER] Access denied for user ${n} to scheduler ${t}`),null):o}catch(a){return console.error(`[SCHEDULER] Failed to load scheduler ${t}:`,a),null}}async createScheduler(e,t,n){let i=this.validateSchedule(t.schedule);if(!i.valid)throw new Error(`Invalid schedule: ${i.error}`);if(!await this.promptService.getById(t.promptId))throw new Error(`Prompt not found: ${t.promptId}`);let o={id:Xit(),name:t.name,enabled:t.enabled??!0,promptId:t.promptId,schedule:t.schedule,parameters:t.parameters,createdBy:n,createdAt:new Date().toISOString(),nextRun:lh(t.schedule,new Date,0),occurrenceCount:0};return await this.saveScheduler(o,e),this.schedulers.set(o.id,o),console.log(`[SCHEDULER] Created scheduler "${o.name}" (${o.id}) for project ${e}`),o}async updateScheduler(e,t,n,i){let a=await this.getScheduler(e,t,i);if(!a)throw new Error(`Scheduler not found or access denied: ${t}`);if(console.log(`[SCHEDULER] Updating scheduler ${t} by user ${i}`),n.name!==void 0&&(a.name=n.name),n.enabled!==void 0&&(a.enabled=n.enabled),n.parameters!==void 0&&(a.parameters=n.parameters),n.promptId!==void 0){if(!await this.promptService.getById(n.promptId))throw new Error(`Prompt not found: ${n.promptId}`);a.promptId=n.promptId}if(n.schedule!==void 0){let o=this.validateSchedule(n.schedule);if(!o.valid)throw new Error(`Invalid schedule: ${o.error}`);a.schedule=n.schedule,a.occurrenceCount=0,a.nextRun=lh(n.schedule,new Date,0)}return await this.saveScheduler(a,e),this.schedulers.set(a.id,a),console.log(`[SCHEDULER] Updated scheduler "${a.name}" (${a.id})`),a}async deleteScheduler(e,t,n){if(!await this.getScheduler(e,t,n))return!1;let a=this.getSchedulerFilePath(e,t);return ai.unlinkSync(a),this.schedulers.delete(t),console.log(`[SCHEDULER] Deleted scheduler ${t} by user ${n}`),!0}async enableScheduler(e,t,n){return this.updateScheduler(e,t,{enabled:!0},n)}async disableScheduler(e,t,n){return this.updateScheduler(e,t,{enabled:!1},n)}async runSchedulerNow(e,t,n){let i=await this.getScheduler(e,t,n);if(!i)throw new Error(`Scheduler not found or access denied: ${t}`);let a=await this.executeSchedulerInternal(i,e,"manual");return i.lastRun=new Date().toISOString(),await this.saveScheduler(i,e),this.schedulers.set(i.id,i),this.logger.logTriggerExecution({triggerId:i.id,triggerName:i.name,webhookUuid:i.promptId,projectName:e,success:!0,threadId:a}),a}async saveScheduler(e,t){if(!t&&(t=this.findProjectForScheduler(e.id),!t))throw new Error(`Cannot find project for scheduler ${e.id}`);let n=this.getSchedulersDir(t);ai.mkdirSync(n,{recursive:!0});let i=this.getSchedulerFilePath(t,e.id),a=X6.stringify(e);ai.writeFileSync(i,a,"utf-8")}};import*as Mc from"node:path";import*as Ffe from"node:os";import{existsSync as Rfe,lstatSync as Qit,mkdirSync as Nfe,readdirSync as eat}from"fs";var aE=class r{projectsConfigPath;static PROJECT_FILENAME="project.yaml";constructor(e){let t=Mc.join(Ffe.userInfo().homedir,".coday");this.projectsConfigPath=Mc.join(e??t,"projects"),Nfe(this.projectsConfigPath,{recursive:!0})}listProjects(){return eat(this.projectsConfigPath).filter(t=>Qit(Mc.join(this.projectsConfigPath,t)).isDirectory())}getProjectInfo(e){let t=Mc.join(this.projectsConfigPath,e),n=Mc.join(t,r.PROJECT_FILENAME);return Rfe(n)?{name:e,configPath:t}:null}exists(e){return this.getProjectInfo(e)!==null}getConfig(e){let t=this.getProjectInfo(e);if(!t)return console.log(`[PROJECT_REPO] No project info found for: '${e}'`),null;let n=Mc.join(t.configPath,r.PROJECT_FILENAME),i=ta(n);if(!i)return console.log(`[PROJECT_REPO] Failed to load config for '${e}' from ${n}`),null;let a=uh(i,bce);return a!==i&&(console.log(`[PROJECT_REPO] Config migrated for '${e}', saving...`),Mn(n,a)),a}saveConfig(e,t){let n=this.getProjectInfo(e);if(!n)throw new Error(`Project '${e}' does not exist`);let i=Mc.join(n.configPath,r.PROJECT_FILENAME);Mn(i,t)}createProject(e,t){let n=Mc.join(this.projectsConfigPath,e),i=Mc.join(n,r.PROJECT_FILENAME);return Rfe(i)?!1:(console.log(`[PROJECT_REPO] Creating project '${e}' with path: ${t}`),Nfe(n,{recursive:!0}),Mn(i,{version:1,path:t,integration:{},storage:{type:"file"},agents:[]}),console.log(`[PROJECT_REPO] Project '${e}' created successfully`),!0)}deleteProject(e){return this.getProjectInfo(e),!1}};var _M=ur(Pc(),1);import{promises as Zu}from"fs";import Jp from"path";var Mfe=async r=>{try{let e=await Zu.readFile(r,"utf-8");return _M.default.parse(e)}catch{return null}},oE=class{constructor(e){this.projectsDir=e}getThreadsDir(e){return Jp.join(this.projectsDir,e,"threads")}async ensureThreadsDir(e){let t=this.getThreadsDir(e);try{await Zu.mkdir(t,{recursive:!0})}catch(n){throw new Eu(`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 Zu.access(Jp.join(n,i)),i}catch{}return(await Zu.readdir(n)).find(s=>s.endsWith(`-${t}.yml`))||null}catch(n){throw new Eu(`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=Jp.join(i,n),o=await Mfe(a);if(!o)return null;let s=uh(o,YR);return s.projectId||(s.projectId=e),s!==o&&Mn(a,s),new ku(s)}catch(n){throw new Eu(`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=Jp.join(n,i),o=await this.findThreadFile(e,t.id);if(o&&o!==i){let u=Jp.join(n,o);try{await Zu.unlink(u),console.log(`[THREAD-REPO] Migrated/renamed thread file: ${o} \u2192 ${i}`)}catch(l){console.warn(`[THREAD-REPO] Could not delete old thread file: ${o}`,l)}}let s={...t.serialize(),version:YR.length+1},c=_M.default.stringify(s);return await Zu.writeFile(a,c,"utf-8"),t}catch(n){throw new Eu(`Failed to save thread ${t.id} to project ${e}`,n)}}async listByProject(e){try{let t=this.getThreadsDir(e);try{await Zu.access(t)}catch{return[]}let n=await Zu.readdir(t);return(await Promise.all(n.filter(a=>a.endsWith(".yml")).map(async a=>{let o=await Mfe(Jp.join(t,a));if(!o)return null;let s=o.projectId||e;return{id:o.id,username:o.username,projectId:s,name:o.name??"...",summary:o.summary??"",createdDate:o.createdDate??"",modifiedDate:o.modifiedDate??"",price:o.price??0,starring:o.starring??[],users:Array.isArray(o.users)?o.users.map(c=>typeof c=="string"?{userId:c}:c):o.username?[{userId:o.username}]:[],parentThreadId:o.parentThreadId,parentEventId:o.parentEventId,delegatedAgentName:o.delegatedAgentName,delegatedTask:o.delegatedTask}}))).filter(a=>!!a).sort((a,o)=>a.modifiedDate>o.modifiedDate?-1:1)}catch(t){throw new Eu(`Failed to list threads for project ${e}`,t)}}async delete(e,t){try{let n=await this.findThreadFile(e,t);if(!n)return!1;let i=this.getThreadsDir(e);return await Zu.unlink(Jp.join(i,n)),!0}catch(n){throw new Eu(`Failed to delete thread ${t} from project ${e}`,n)}}};var sE=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 oE(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(o=>rn(o,t)).sort((o,s)=>o.modifiedDate>s.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(s=>rn(s,t)).sort((s,c)=>s.modifiedDate>c.modifiedDate?-1:1)}catch(o){throw this.threadListCache.delete(e),o}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}toThreadSummary(e){return{id:e.id,username:e.username,projectId:e.projectId,name:e.name,summary:e.summary,createdDate:e.createdDate,modifiedDate:e.modifiedDate,price:e.price,starring:e.starring,users:e.users,parentThreadId:e.parentThreadId,parentEventId:e.parentEventId,delegatedAgentName:e.delegatedAgentName,delegatedTask:e.delegatedTask}}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 ku({id:crypto.randomUUID(),username:t,projectId:e,name:n||"",price:0}),o=await i.save(e,a);return this.updateThreadInCache(e,this.toThreadSummary(o)),o}async updateThread(e,t,n){let i=this.getThreadRepository(e),a=await i.getById(e,t);if(!a){let c=this.threadListCache.get(e)?.data.find(u=>u.id===t);if(c)a=new ku({id:c.id,username:c.username,projectId:c.projectId,name:c.name,price:c.price});else throw new Error(`Thread '${t}' not found in project '${e}'`)}n.name!==void 0&&(a.name=n.name),n.summary!==void 0&&(a.summary=n.summary),n.users!==void 0&&(a.users=n.users);let o=await i.save(e,a);return this.updateThreadInCache(e,this.toThreadSummary(o)),o}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 o=await i.save(e,a);return this.updateThreadInCache(e,this.toThreadSummary(o)),o}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(s=>s!==n);let o=await i.save(e,a);return this.updateThreadInCache(e,this.toThreadSummary(o)),o}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 saveThread(e,t){let i=await this.getThreadRepository(e).save(e,t);return this.updateThreadInCache(e,this.toThreadSummary(i)),i}async listAllThreads(e){let t=this.threadListCache.get(e);if(t&&Date.now()-t.timestamp<this.CACHE_TTL_MS)return t.data.sort((a,o)=>a.modifiedDate>o.modifiedDate?-1:1);let n=this.loadingPromises.get(e);if(n)return await n,this.listAllThreads(e);let i=this.loadThreadListFromDisk(e);this.loadingPromises.set(e,i);try{return(await i).sort((o,s)=>o.modifiedDate>s.modifiedDate?-1:1)}catch(a){throw this.threadListCache.delete(e),a}finally{this.loadingPromises.delete(e)}}async exists(e,t){return await this.getThread(e,t)!==null}};var Bfe=ur(Pc(),1);import*as ba from"fs/promises";import*as Q6 from"path";var Lfe=5,qfe=24,Ufe=100,zfe={SHORT_THREADS:7,LONG_THREADS:30},cE=class{constructor(e,t){this.projectsConfigPath=e;this.logger=t}cleanupTimer=null;initialTimer=null;isRunning=!1;async start(){if(this.isRunning){this.log("Thread cleanup service already running");return}this.isRunning=!0,this.log("Starting thread cleanup service with user message-based retention"),this.initialTimer=setTimeout(async()=>{await this.performCleanup(),this.cleanupTimer=setInterval(async()=>{await this.performCleanup()},qfe*60*60*1e3),this.log(`Thread cleanup scheduled every ${qfe} hours`)},Lfe*60*1e3),this.log(`Initial cleanup scheduled in ${Lfe} minutes`)}async stop(){this.initialTimer&&(clearTimeout(this.initialTimer),this.initialTimer=null),this.cleanupTimer&&(clearInterval(this.cleanupTimer),this.cleanupTimer=null),this.isRunning=!1,this.log("Thread cleanup service stopped (all timers cleared)")}async performCleanup(){let e=Date.now(),t=0,n=0,i=0;try{this.log("Starting thread cleanup...");let a=await ba.readdir(this.projectsConfigPath);this.log(`Found ${a.length} projects to scan`);for(let s of a)try{let c=Q6.join(this.projectsConfigPath,s);if(!(await ba.lstat(c)).isDirectory())continue;let l=Q6.join(c,"threads");try{await ba.access(l)}catch{continue}let{scanned:f,deleted:p,errors:d}=await this.cleanupProjectThreads(s,l);t+=f,n+=p,i+=d}catch(c){this.logError(`Error processing project ${s}: ${c}`),i++}let o=Date.now()-e;this.log(`Cleanup completed: ${n}/${t} threads deleted across all projects in ${o}ms (${i} errors)`)}catch(a){let o=Date.now()-e;this.logError(`Cleanup failed after ${o}ms: ${a}`)}}async cleanupProjectThreads(e,t){let n=0,i=0,a=0;try{let s=(await ba.readdir(t)).filter(c=>c.endsWith(".yml"));if(n=s.length,s.length===0)return{scanned:n,deleted:i,errors:a};this.log(`Scanning ${s.length} threads in project ${e}`);for(let c=0;c<s.length;c+=Ufe){let u=s.slice(c,c+Ufe),l=await this.processBatch(u,t,e);i+=l.deleted,a+=l.errors}i>0&&this.log(`Project ${e}: deleted ${i}/${n} expired threads`)}catch(o){this.logError(`Error scanning project ${e}: ${o}`),a++}return{scanned:n,deleted:i,errors:a}}async processBatch(e,t,n){let i=0,a=0;return await Promise.all(e.map(async o=>{let s=Q6.join(t,o),c;try{let u=await ba.readFile(s,"utf-8");c=Bfe.parse(u)}catch(u){await ba.unlink(s),this.logError(`Error processing file ${o} in project ${n}: ${u}`)}if(!(!c||!c.modifiedDate)&&!(c.starring&&Array.isArray(c.starring)&&c.starring.length>0)&&this.shouldDeleteThread(c)){let u=this.countUserMessages(c.messages||[]),l=this.getDaysSinceModified(c.modifiedDate),f=c.id||o.replace(".yml","");await ba.unlink(s),await this.deleteThreadFiles(t,f),i++,this.logger.logThreadCleanup(n,o),console.log(`ThreadCleanup: Deleted thread ${f} and its files directory (${u} user messages, ${l} days old)`)}})),{deleted:i,errors:a}}shouldDeleteThread(e){if(!e||!e.modifiedDate)return!1;let n=this.countUserMessages(e.messages||[])<=3?zfe.SHORT_THREADS:zfe.LONG_THREADS;return this.getDaysSinceModified(e.modifiedDate)>n}countUserMessages(e){return e.filter(t=>t&&t.type==="message"&&t.role==="user").length}getDaysSinceModified(e){let t=new Date(e),i=new Date().getTime()-t.getTime();return Math.floor(i/(1e3*60*60*24))}async deleteThreadFiles(e,t){try{let n=Q6.join(e,`${t}-files`);try{await ba.access(n),await ba.rm(n,{recursive:!0,force:!0}),console.log(`ThreadCleanup: Deleted files directory ${n}`)}catch(i){if(i.code!=="ENOENT")throw i}}catch(n){console.error(`ThreadCleanup: Error deleting files for ${t}:`,n)}}log(e){let t=new Date().toISOString();console.log(`[${t}] ThreadCleanup: ${e}`)}logError(e){let t=new Date().toISOString();console.error(`[${t}] ThreadCleanup ERROR: ${e}`)}async forceCleanup(){this.log("Manual cleanup triggered"),await this.performCleanup()}};import*as qi from"path";import*as Kp from"fs";import*as xa from"fs/promises";var uE=class{constructor(e){this.projectsDir=e}getThreadFilesDir(e,t){return qi.join(this.projectsDir,e,"threads",`${t}-files`)}async ensureThreadFilesDir(e,t){let n=this.getThreadFilesDir(e,t);Kp.existsSync(n)||await xa.mkdir(n,{recursive:!0})}async listFiles(e,t){await this.ensureThreadFilesDir(e,t);let n=this.getThreadFilesDir(e,t),i=await xa.readdir(n);return await Promise.all(i.map(async o=>{let s=qi.join(n,o),c=await xa.stat(s);return{filename:o,size:c.size,lastModified:c.mtime.toISOString()}}))}async saveFile(e,t,n,i){let a=this.getThreadFilesDir(e,t);await xa.mkdir(a,{recursive:!0});let o=qi.join(a,n);await xa.writeFile(o,i)}async getFile(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=qi.join(i,n),o=qi.resolve(a),s=qi.resolve(i);if(!o.startsWith(s))throw new Error("Access denied: invalid file path");if(!Kp.existsSync(a))throw new Error(`File '${n}' not found`);return await xa.readFile(a)}async getFilePath(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=qi.join(i,n),o=qi.resolve(a),s=qi.resolve(i);if(!o.startsWith(s))throw new Error("Access denied: invalid file path");if(!Kp.existsSync(a))throw new Error(`File '${n}' not found`);return a}fileExists(e,t,n){let i=this.getThreadFilesDir(e,t),a=qi.join(i,n),o=qi.resolve(a),s=qi.resolve(i);return o.startsWith(s)?Kp.existsSync(a):!1}async deleteFile(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=qi.join(i,n),o=qi.resolve(a),s=qi.resolve(i);if(!o.startsWith(s))throw new Error("Access denied: invalid file path");if(!Kp.existsSync(a))throw new Error(`File '${n}' not found`);await xa.unlink(a)}async deleteThreadFiles(e,t){try{let n=this.getThreadFilesDir(e,t);Kp.existsSync(n)&&(await xa.rm(n,{recursive:!0,force:!0}),console.log(`Deleted thread files directory: ${n}`))}catch(n){console.error(`Error deleting thread files for ${t}:`,n)}}};var Hfe=ur(po(),1);var lE=class{constructor(e,t,n,i){this.threadRepository=t;this.projectId=n;this.interactor=i;this.username=e.username}activeThread$=new Hfe.BehaviorSubject(null);isKilled=!1;activeThread=this.activeThread$.asObservable();username;async kill(){this.isKilled=!0,this.activeThread$.complete()}async create(e){let t=new ku({id:"",username:this.username,name:e??"",price:0});return this.activeThread$.next(t),t}async select(e){let t=await this.threadRepository.getById(this.projectId,e);if(!t)throw new Error(`Thread ${e} not found`);return this.activeThread$.next(t),t}async save(e){let t=this.activeThread$.value;if(!t){console.error(`No thread existing when save attempt with name '${e}'`);return}e&&(t.name=e);let n=await this.threadRepository.save(this.projectId,t);this.activeThread$.next(n)}async autoSave(e){if(this.isKilled){console.log("Autosave skipped: service has been killed");return}let t=this.activeThread$.value;if(!t||t.messagesLength==0){console.log(`Autosave of an empty or falsy thread aborted, threadId: ${t?.id}, user: ${this.username}`);return}try{e&&(t.name=e),await this.threadRepository.save(this.projectId,t),this.interactor&&this.interactor.sendEvent(new gc({threadId:t.id,name:t.name||void 0}))}catch(n){console.log("Autosave failed (service may have been killed):",n instanceof Error?n.message:n)}}async truncateAtUserMessage(e){let t=this.activeThread$.value;if(!t)return console.error("No active thread available for truncation"),!1;let n=t.truncateAtUserMessage(e);return n||this.interactor?.warn("Failed to truncate thread."),n}getCurrentThread(){return this.activeThread$.value}};async function Wfe(r,e){let t=e.project.selectedProject,n=e.user.getUserData(t.name),i=await eE(t.config.path,r,n),a=new A0({...i,root:t.config.path,name:t.name},e.user.username);return console.log(`[BUILD_CONTEXT] Context for '${a.project.name}' \u2192 root: ${a.project.root}, desc: ${a.project.description?.length||0} chars`),a}var fE=class extends Re{constructor(t,n){super({commandWord:"select-project",description:"Select an existing project"});this.interactor=t;this.services=n}async handle(t,n){try{let i=this.getSubCommand(t);return await this.selectProject(i)??n}catch(i){return this.interactor.error(`Invalid project selection because: ${i.toString()}`),n}}async selectProject(t){return this.services.project.selectProject(t),this.services.project.selectedProject?Wfe(this.interactor,this.services):null}};var pE=class extends Re{constructor(t,n,i){super({commandWord:"add",description:"Add a new integration configuration. User level is default, use --project/-p for project level."});this.interactor=t;this.service=n;this.editHandler=i}async handle(t,n){let a=!!Tt(this.getSubCommand(t),[{key:"project",alias:"p"}]).project,o=a?"project":"user",s=this.service.getMergedIntegrations(),c=Object.keys(s),u=Qf.filter(h=>!c.includes(h));if(u.length===0)return this.interactor.displayText(`All available integrations (${Qf.join(", ")}) are already configured.`),n;let l=await this.interactor.chooseOption(u.sort(),"Select integration to add:",`Available integrations to configure:
877
+ `)):""}loadMemoriesFrom(e){this.memories=[],this.userMemoriesPath=this.readMemories(this.userMemoriesPath)?this.userMemoriesPath:void 0;let t=e?.configPath?tE.join(e.configPath,xM):void 0;this.projectMemoriesPath=this.readMemories(t)?t:void 0,e&&this.checkInit()}readMemories(e){if(!e)return!1;try{if(!Hit(e)){let n=kfe.stringify({memories:[]});Wit(e,n)}let t=ta(e);return t?(this.memories.push(...t.memories),!0):!1}catch{return!1}}checkInit(){if(!this.userMemoriesPath||!this.projectMemoriesPath)throw new Error("user or project path not set for memory service")}saveMemories(){this.checkInit();let e=this.memories.filter(n=>n.level==="USER"),t=this.memories.filter(n=>n.level==="PROJECT");Mn(this.userMemoriesPath,{memories:e}),Mn(this.projectMemoriesPath,{memories:t})}};import*as Cfe from"crypto";import*as Va from"node:fs/promises";import*as Fc from"path";var xm=class r{constructor(e,t,n){this.repository=e;this.defaultProject=t;this.isForcedMode=n}maskingService=new B2;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=Fc.basename(n);if(e===a||e===i||e===this.defaultProject){console.log(`[PROJECT_SERVICE] Creating volatile project for '${e}' at ${n}`);let o=this.getOrCreateVolatileProject(n);if(t=this.repository.getConfig(o),t)return{name:o,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}async registerWorktreeProject(e,t,n){let i=this.repository.getConfig(n),a=i?{...i,path:t,volatile:void 0,createdAt:void 0}:{version:1,path:t,integration:{},storage:{type:"file"},agents:[]};this.repository.createProject(e,t),this.repository.saveConfig(e,a);let o=this.repository.getProjectInfo(n);if(o){let s=this.repository.getProjectInfo(e);if(s)for(let c of["agents","prompts","schedulers","memories"]){let u=Fc.join(o.configPath,c),l=Fc.join(s.configPath,c);try{await Va.access(u),await Va.symlink(u,l)}catch{}}}}async unregisterWorktreeProject(e){let t=this.repository.getProjectInfo(e);if(!t)return;let n=e.lastIndexOf("__");if(n!==-1){let i=e.substring(0,n),a=this.repository.getProjectInfo(i);a&&await this.migrateThreadsToParent(t.configPath,a.configPath)}await Va.rm(t.configPath,{recursive:!0,force:!0})}async migrateThreadsToParent(e,t){let n=Fc.join(e,"threads"),i=Fc.join(t,"threads");try{await Va.access(n)}catch{return}await Va.mkdir(i,{recursive:!0});let a=await Va.readdir(n);for(let o of a){let s=Fc.join(n,o),c=Fc.join(i,o);try{await Va.access(c)}catch{await Va.rename(s,c)}}}static generateProjectId(e){let t=Fc.basename(e),n=Cfe.createHash("sha256").update(e).digest("hex").substring(0,8);return`${t}_${n}`}};var Dfe=ur(po(),1);import*as wm from"node:path";import*as Pfe from"node:os";import{mkdirSync as Vit}from"fs";var Git="projects",Tfe="project.yaml",_m=class{constructor(e,t,n){this.interactor=e;this.projectService=t;let i=wm.join(Pfe.userInfo().homedir,".coday");this.projectsConfigPath=wm.join(n??i,Git),Vit(this.projectsConfigPath,{recursive:!0}),this.projects=this.projectService.listProjects().map(a=>a.name)}projectsConfigPath;maskingService=new B2;projects;selectedProjectBehaviorSubject=new Dfe.BehaviorSubject(null);selectedProject$=this.selectedProjectBehaviorSubject.asObservable();selectProject(e){let t=wm.join(this.projectsConfigPath,e),n=wm.join(t,Tfe),i=this.projectService.getProject(e)?.config;if(!i?.path){console.log(`[PROJECT_STATE_SERVICE] ERROR: No project path in config for '${e}'`),this.interactor.error("Invalid selection, project path needed \u{1F622}.");return}let o={name:e,config:i,configPath:t};console.log(`[PROJECT_STATE_SERVICE] Selected '${e}' \u2192 ${i.path}`),this.updateSelectedProject(o),this.interactor.displayText(`Project local configuration used: ${n}`)}updateSelectedProject(e){this.selectedProjectBehaviorSubject.next(e)}get selectedProject(){return this.selectedProjectBehaviorSubject.value}save(e){let t=this.selectedProjectBehaviorSubject.value;if(!t){this.interactor.error("No current project selected, save not possible");return}let n={...t.config,...e};Mn(wm.join(t.configPath,Tfe),n),t.config=n,this.updateSelectedProject(t)}getConfigForClient(){let e=this.selectedProjectBehaviorSubject.value;return e?this.maskingService.maskConfig(e.config):null}updateConfigFromClient(e){let t=this.selectedProjectBehaviorSubject.value;if(!t){this.interactor.error("No current project selected, update not possible");return}let n=this.maskingService.unmaskConfig(e,t.config);this.save(n)}};import*as Gu from"node:path";import*as $fe from"node:os";import{randomUUID as Jit}from"node:crypto";import{existsSync as W2,mkdirSync as Kit,readdirSync as Ofe,unlinkSync as Yit}from"fs";import*as wM from"node:path";import*as Ife from"node:os";function Zit(r){return r.replace(/[^a-zA-Z0-9]/g,"_")}function Sm(r,e){try{let t=wM.join(Ife.userInfo().homedir,".coday"),n=Zit(r),i=wM.join(e??t,"users",n,"user.yaml"),a=ta(i);return a?a.groups?.includes("CODAY_ADMIN")??!1:!1}catch{return!1}}var rE=class{codayConfigDir;projectService;nativeHandlerStubs=[];constructor(e,t){let n=Gu.join($fe.userInfo().homedir,".coday");this.codayConfigDir=e??n,this.projectService=t}getProjectPath(e){if(this.projectService)return this.projectService.getProject(e)?.config.path}async getOrCreatePromptsDir(e,t){let n;if(t==="local")n=Gu.join(this.codayConfigDir,"projects",e,"prompts");else{let i=this.getProjectPath(e);if(!i)throw new Error("Project path not configured, cannot access project prompts");let a=await f2({text:"coday.yaml",root:i});if(a.length===0)throw new Error(`coday.yaml not found in project path: ${i}`);let o=Gu.dirname(a[0]);n=Gu.join(i,o,"prompts")}return W2(n)||(Kit(n,{recursive:!0}),console.log(`[PROMPT] Created prompts directory: ${n}`)),n}async getOrCreatePromptFilePath(e,t,n){let i=await this.getOrCreatePromptsDir(e,n);return Gu.join(i,`${t}.yml`)}async findPromptSource(e,t){let n=await this.getOrCreatePromptFilePath(e,t,"local");if(W2(n))return"local";if(this.projectService)try{let i=await this.getOrCreatePromptFilePath(e,t,"project");if(W2(i))return"project"}catch{}return null}async findProjectForPrompt(e){let t=Gu.join(this.codayConfigDir,"projects");if(!W2(t))return null;let n=Ofe(t,{withFileTypes:!0}).filter(i=>i.isDirectory()).map(i=>i.name);for(let i of n){let a=Gu.join(this.codayConfigDir,"projects",i,"prompts",`${e}.yml`);if(W2(a))return i;if(this.projectService)try{let o=await this.getOrCreatePromptFilePath(i,e,"project");if(W2(o))return i}catch{}}return null}validatePlaceholders(e){let t=/\{\{(\w+)\}\}/g,n=[],i=/^[A-Za-z][A-Za-z0-9-]*$/;if(e.forEach(a=>{let o;for(;(o=t.exec(a))!==null;){let s=o[1];s&&s!=="PARAMETERS"&&!i.test(s)&&n.push(s)}}),n.length>0)throw new Error(`Invalid parameter keys: ${n.join(", ")}. Keys must start with a letter and contain only letters, digits, and hyphens.`)}async create(e,t,n="local"){try{this.validatePlaceholders(t.commands);let i=Jit(),a={...t,id:i,source:n,createdAt:new Date().toISOString(),parameterFormat:this.getParameterFormat(t.commands)},o=await this.getOrCreatePromptFilePath(e,i,n);if(W2(o))throw new Error(`Prompt with ID ${i} already exists`);return Mn(o,a),console.log(`[PROMPT] Created prompt ${i} in ${n} for project ${e}`),a}catch(i){throw new Error(`Failed to create prompt: ${i instanceof Error?i.message:"Unknown error"}`)}}async get(e,t){try{let n=await this.findPromptSource(e,t);if(!n)return null;let i=await this.getOrCreatePromptFilePath(e,t,n),a=ta(i);return a?(a.source||(a.source=n),a):null}catch(n){return console.error(`Failed to get prompt ${t}:`,n),null}}async getById(e){try{let t=await this.findProjectForPrompt(e);if(!t)return null;let n=await this.get(t,e);return n?{prompt:n,projectName:t}:null}catch(t){return console.error(`Failed to get prompt ${e}:`,t),null}}async update(e,t,n,i){try{let a=await this.get(e,t);if(!a)return null;if(n.webhookEnabled!==void 0&&n.webhookEnabled!==a.webhookEnabled&&!Sm(i,this.codayConfigDir))throw new Error("Only CODAY_ADMIN can enable/disable webhook for prompts");let{id:o,createdAt:s,source:c,...u}=n;n.commands&&this.validatePlaceholders(n.commands);let l={...a,...u,updatedAt:new Date().toISOString()};n.commands&&(l.parameterFormat=this.getParameterFormat(n.commands));let f=await this.getOrCreatePromptFilePath(e,t,a.source);return Mn(f,l),console.log(`[PROMPT] Updated prompt ${t} (${a.source}) by user ${i}`),l}catch(a){throw console.error(`Failed to update prompt ${t}:`,a),a}}async delete(e,t){try{let n=await this.findPromptSource(e,t);if(!n)return!1;let i=await this.getOrCreatePromptFilePath(e,t,n);return Yit(i),console.log(`[PROMPT] Deleted prompt ${t} from ${n}`),!0}catch(n){return console.error(`Failed to delete prompt ${t}:`,n),!1}}getParameterFormat(e){if(e.some(a=>/\{\{PARAMETERS\}\}/.test(a)))return"";let n=/\{\{(\w+)\}\}/g,i=new Set;return e.forEach(a=>{let o;for(;(o=n.exec(a))!==null;){let s=o[1];s&&s!=="PARAMETERS"&&i.add(s)}}),i.size===0?"":Array.from(i).map(a=>`${a}=""`).join(" ")}registerNativeHandler(e){this.nativeHandlerStubs.find(t=>t.id===e.id)||this.nativeHandlerStubs.push(e)}async list(e,t=[]){try{let n=[],i=["local"];this.projectService&&i.push("project");for(let a of i)try{let o=await this.getOrCreatePromptsDir(e,a);if(!W2(o))continue;let c=Ofe(o).filter(u=>u.endsWith(".yml"));for(let u of c){let l=u.replace(".yml",""),f=await this.get(e,l);f&&n.push({id:f.id,name:f.name,description:f.description,webhookEnabled:f.webhookEnabled,createdBy:f.createdBy,createdAt:f.createdAt,updatedAt:f.updatedAt,source:f.source||a,parameterFormat:f.parameterFormat})}}catch(o){console.log(`[PROMPT] Could not access ${a} prompts for ${e}:`,o)}return n.push(...E0),n.push(...this.nativeHandlerStubs),n.push(...t),n.sort((a,o)=>new Date(o.createdAt).getTime()-new Date(a.createdAt).getTime())}catch(n){return console.error(`Failed to list prompts for project ${e}:`,n),[]}}async enableWebhook(e,t,n){return this.update(e,t,{webhookEnabled:!0},n)}async disableWebhook(e,t,n){return this.update(e,t,{webhookEnabled:!1},n)}};var jfe=ur(po(),1),nE=class{constructor(e){this.promptService=e}threadCodayManager;threadService;codayOptions;logger;initialize(e,t,n,i){this.threadCodayManager=e,this.threadService=t,this.codayOptions=n,this.logger=i}processCommands(e,t){let n;if(typeof t=="string"){let a=e.some(s=>/\{\{PARAMETERS\}\}/.test(s));if(e.some(s=>/\{\{(?!PARAMETERS\}\})\w+\}\}/.test(s)))throw new Error("Prompt contains structured placeholders ({{key}}). Use an object parameter instead of a string.");a?n=e.map(s=>s.replace(/\{\{PARAMETERS\}\}/g,t)):n=e.map((s,c)=>c===0?`${s} ${t}`.trim():s)}else typeof t=="object"&&t!==null?n=e.map(a=>{let o=a;return Object.entries(t).forEach(([s,c])=>{let u=`{{${s}}}`;o=o.replaceAll(u,String(c))}),o}):n=[...e];let i=new Set;if(n.forEach(a=>{let o=a.match(/\{\{(\w+)\}\}/g);o&&o.forEach(s=>i.add(s))}),i.size>0){let a=Array.from(i).map(o=>o.replace(/[{}]/g,"")).join(", ");throw new Error(`Missing required parameters: ${a}`)}return n}async executePrompt(e,t,n,i,a){if(!this.threadCodayManager||!this.threadService||!this.codayOptions||!this.logger)throw new Error("PromptExecutionService not initialized. Call initialize() first.");let{title:o,awaitFinalAnswer:s=!1,projectName:c}=a||{},u,l;if(c){if(l=c,u=await this.promptService.get(l,e),!u)throw new Error(`Prompt ${e} not found in project ${l}`)}else{let y=await this.promptService.getById(e);if(!y)throw new Error(`Prompt not found: ${e}`);u=y.prompt,l=y.projectName}if(i==="webhook"&&!u.webhookEnabled)throw new Error(`Prompt ${e} is not enabled for webhook execution`);if(!u.commands||u.commands.length===0)throw new Error("Prompt has no commands configured");let f=this.processCommands(u.commands,t);if(!n)throw new Error("Username is required");let d=(await this.threadService.createThread(l,n,o)).id;console.log(`[PROMPT_EXEC] Created new thread: ${d} for ${i} execution`);let m={...this.codayOptions,oneshot:!0,project:l,thread:d,prompts:f};console.log(`[PROMPT_EXEC] Creating instance for ${i} execution with ${f.length} prompts:`,f);let h=this.threadCodayManager.createWithoutConnection(d,l,n,m);h.prepareCoday();let g=h.coday.interactor,v={project:l,title:o??"Untitled",username:n,clientId:d,promptCount:f.length,awaitFinalAnswer:!!s,promptName:u.name,promptId:u.id,executionMode:i};if(i==="webhook"?this.logger.logWebhook(v):this.logger.logWebhook({...v,webhookName:u.name,webhookUuid:u.id}),s){let y=[],x=g.events.pipe((0,jfe.filter)(k=>(console.log(`[PROMPT_EXEC] Received event type: ${k.type}, role: ${k instanceof $t?k.role:"N/A"}`),k instanceof $t&&k.role==="assistant"&&!!k.name))).subscribe(k=>{y.push(k)});try{await h.coday.run(),x.unsubscribe();let k=y[y.length-1];return await this.threadCodayManager.cleanup(d),{threadId:d,lastEvent:k}}catch(k){x.unsubscribe();let S=k instanceof Error?k.message:"Unknown error";throw this.logger.logWebhookError({error:`Prompt execution failed: ${S}`,username:n,project:l,clientId:d}),console.error("[PROMPT_EXEC] Error waiting for prompt completion:",k),await this.threadCodayManager.cleanup(d),k}}else return h.coday.run().catch(y=>{console.error("[PROMPT_EXEC] Error during prompt Coday run:",y)}),setTimeout(()=>{this.threadCodayManager.cleanup(d).catch(y=>{console.error("[PROMPT_EXEC] Error cleaning up prompt thread after timeout:",y)})},300*1e3),{threadId:d}}};var X6=ur(Pc(),1);import*as ai from"fs";import*as Em from"path";import{randomUUID as Xit}from"node:crypto";var iE=class{constructor(e,t,n){this.logger=e;this.promptService=t;this.codayConfigDir=n}schedulers=new Map;checkInterval;CHECK_INTERVAL_MS=3e4;promptExecutionService;initializeExecution(e){this.promptExecutionService=e}async initialize(){console.log("[SCHEDULER] Initializing SchedulerService..."),await this.loadAllSchedulers(),this.startScheduler(),console.log(`[SCHEDULER] SchedulerService initialized with ${this.schedulers.size} schedulers`)}stop(){this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=void 0,console.log("[SCHEDULER] SchedulerService stopped"))}async loadAllSchedulers(){this.schedulers.clear();let e=Em.join(this.codayConfigDir,"projects");if(!ai.existsSync(e))return;let t=ai.readdirSync(e,{withFileTypes:!0}).filter(n=>n.isDirectory()).map(n=>n.name);for(let n of t)try{let i=await this.loadProjectSchedulers(n);for(let a of i)this.schedulers.set(a.id,a)}catch(i){console.error(`[SCHEDULER] Failed to load schedulers for project ${n}:`,i)}}async loadProjectSchedulers(e){let t=this.getSchedulersDir(e);if(!ai.existsSync(t))return[];let n=ai.readdirSync(t),i=[];for(let a of n)if(a.endsWith(".yml"))try{let o=Em.join(t,a),s=ai.readFileSync(o,"utf-8"),c=X6.parse(s),u=this.calculateNextRunSkippingMissed(c),l=u.occurrenceCount!==c.occurrenceCount;c.nextRun=u.nextRun,c.occurrenceCount=u.occurrenceCount,l&&await this.saveScheduler(c,e),i.push(c)}catch(o){console.error(`[SCHEDULER] Failed to load scheduler from ${a}:`,o)}return i}startScheduler(){this.checkInterval=setInterval(()=>{this.checkAndExecuteSchedulers()},this.CHECK_INTERVAL_MS),this.checkAndExecuteSchedulers()}async checkAndExecuteSchedulers(){for(let e of this.schedulers.values())e.enabled&&yce(e.schedule,e.nextRun??null,e.occurrenceCount??0)&&this.executeScheduler(e).catch(t=>{console.error(`[SCHEDULER] Failed to execute scheduler ${e.id}:`,t)})}async executeSchedulerInternal(e,t,n){if(!this.promptExecutionService)throw new Error("PromptExecutionService not initialized");console.log(`[SCHEDULER] Executing scheduler "${e.name}" (${e.id}) [${n}]`);let i=e.parameters;e.parameters&&typeof e.parameters=="object"&&Object.keys(e.parameters).length===1&&"PARAMETERS"in e.parameters&&(i=String(e.parameters.PARAMETERS));let a=await this.promptExecutionService.executePrompt(e.promptId,i,e.createdBy,"scheduled",{title:n==="scheduled"?`Scheduled: ${e.name}`:`Manual: ${e.name}`,awaitFinalAnswer:!1,projectName:t});return console.log(`[SCHEDULER] Scheduler "${e.name}" executed successfully. Thread: ${a.threadId}`),a.threadId}async executeScheduler(e){let t=new Date().toISOString();console.log(`[SCHEDULER] Executing scheduler "${e.name}" (${e.id})`);let n=this.findProjectForScheduler(e.id);if(!n){console.error(`[SCHEDULER] Cannot find project for scheduler ${e.id}, skipping execution`);return}let i,a,o;e.lastRun=t,e.occurrenceCount=(e.occurrenceCount??0)+1,e.nextRun=lh(e.schedule,new Date,e.occurrenceCount);try{await this.saveScheduler(e,n),console.log(`[SCHEDULER] Next execution for "${e.name}": ${e.nextRun}`),this.schedulers.set(e.id,e),a=await this.executeSchedulerInternal(e,n,"scheduled"),i=!0}catch(s){i=!1,o=s instanceof Error?s.message:String(s),console.error(`[SCHEDULER] Scheduler "${e.name}" failed:`,s)}this.logger.logTriggerExecution({triggerId:e.id,triggerName:e.name,webhookUuid:e.promptId,projectName:n,success:i,threadId:a,error:o})}validateSchedule(e){return vce(e)}calculateNextRunSkippingMissed(e){let t=new Date,n=e.occurrenceCount??0,i=e.nextRun;if(!i)return{nextRun:lh(e.schedule,t,n),occurrenceCount:n};if(new Date(i)>=t)return{nextRun:i,occurrenceCount:n};let a=1e3,o=0,s=0;for(;o<a;){if(n++,s++,i=lh(e.schedule,t,n),!i)return s>0&&console.log(`[SCHEDULER] Scheduler "${e.name}" (${e.id}) expired after skipping ${s} missed occurrence(s)`),{nextRun:null,occurrenceCount:n};if(new Date(i)>=t)return s>0&&console.log(`[SCHEDULER] Scheduler "${e.name}" (${e.id}) skipped ${s} missed occurrence(s), next run: ${i}`),{nextRun:i,occurrenceCount:n};o++}return console.warn(`[SCHEDULER] Could not find future nextRun for scheduler ${e.id} after ${a} iterations`),{nextRun:null,occurrenceCount:n}}getSchedulersDir(e){return Em.join(this.codayConfigDir,"projects",e,"schedulers")}getSchedulerFilePath(e,t){return Em.join(this.getSchedulersDir(e),`${t}.yml`)}findProjectForScheduler(e){let t=Em.join(this.codayConfigDir,"projects");if(!ai.existsSync(t))return null;let n=ai.readdirSync(t,{withFileTypes:!0}).filter(i=>i.isDirectory()).map(i=>i.name);for(let i of n){let a=this.getSchedulerFilePath(i,e);if(ai.existsSync(a))return i}return null}canAccessScheduler(e,t){return e.createdBy===t?!0:Sm(t,this.codayConfigDir)}async listSchedulers(e,t){return(await this.loadProjectSchedulers(e)).filter(i=>this.canAccessScheduler(i,t)).map(i=>({id:i.id,name:i.name,enabled:i.enabled,promptId:i.promptId,schedule:i.schedule,parameters:i.parameters,lastRun:i.lastRun,nextRun:i.nextRun,createdBy:i.createdBy}))}async getScheduler(e,t,n){let i=this.getSchedulerFilePath(e,t);if(!ai.existsSync(i))return null;try{let a=ai.readFileSync(i,"utf-8"),o=X6.parse(a),s=this.calculateNextRunSkippingMissed(o);return o.nextRun=s.nextRun,o.occurrenceCount=s.occurrenceCount,n&&!this.canAccessScheduler(o,n)?(console.log(`[SCHEDULER] Access denied for user ${n} to scheduler ${t}`),null):o}catch(a){return console.error(`[SCHEDULER] Failed to load scheduler ${t}:`,a),null}}async createScheduler(e,t,n){let i=this.validateSchedule(t.schedule);if(!i.valid)throw new Error(`Invalid schedule: ${i.error}`);if(!await this.promptService.getById(t.promptId))throw new Error(`Prompt not found: ${t.promptId}`);let o={id:Xit(),name:t.name,enabled:t.enabled??!0,promptId:t.promptId,schedule:t.schedule,parameters:t.parameters,createdBy:n,createdAt:new Date().toISOString(),nextRun:lh(t.schedule,new Date,0),occurrenceCount:0};return await this.saveScheduler(o,e),this.schedulers.set(o.id,o),console.log(`[SCHEDULER] Created scheduler "${o.name}" (${o.id}) for project ${e}`),o}async updateScheduler(e,t,n,i){let a=await this.getScheduler(e,t,i);if(!a)throw new Error(`Scheduler not found or access denied: ${t}`);if(console.log(`[SCHEDULER] Updating scheduler ${t} by user ${i}`),n.name!==void 0&&(a.name=n.name),n.enabled!==void 0&&(a.enabled=n.enabled),n.parameters!==void 0&&(a.parameters=n.parameters),n.promptId!==void 0){if(!await this.promptService.getById(n.promptId))throw new Error(`Prompt not found: ${n.promptId}`);a.promptId=n.promptId}if(n.schedule!==void 0){let o=this.validateSchedule(n.schedule);if(!o.valid)throw new Error(`Invalid schedule: ${o.error}`);a.schedule=n.schedule,a.occurrenceCount=0,a.nextRun=lh(n.schedule,new Date,0)}return await this.saveScheduler(a,e),this.schedulers.set(a.id,a),console.log(`[SCHEDULER] Updated scheduler "${a.name}" (${a.id})`),a}async deleteScheduler(e,t,n){if(!await this.getScheduler(e,t,n))return!1;let a=this.getSchedulerFilePath(e,t);return ai.unlinkSync(a),this.schedulers.delete(t),console.log(`[SCHEDULER] Deleted scheduler ${t} by user ${n}`),!0}async enableScheduler(e,t,n){return this.updateScheduler(e,t,{enabled:!0},n)}async disableScheduler(e,t,n){return this.updateScheduler(e,t,{enabled:!1},n)}async runSchedulerNow(e,t,n){let i=await this.getScheduler(e,t,n);if(!i)throw new Error(`Scheduler not found or access denied: ${t}`);let a=await this.executeSchedulerInternal(i,e,"manual");return i.lastRun=new Date().toISOString(),await this.saveScheduler(i,e),this.schedulers.set(i.id,i),this.logger.logTriggerExecution({triggerId:i.id,triggerName:i.name,webhookUuid:i.promptId,projectName:e,success:!0,threadId:a}),a}async saveScheduler(e,t){if(!t&&(t=this.findProjectForScheduler(e.id),!t))throw new Error(`Cannot find project for scheduler ${e.id}`);let n=this.getSchedulersDir(t);ai.mkdirSync(n,{recursive:!0});let i=this.getSchedulerFilePath(t,e.id),a=X6.stringify(e);ai.writeFileSync(i,a,"utf-8")}};import*as Mc from"node:path";import*as Ffe from"node:os";import{existsSync as Rfe,lstatSync as Qit,mkdirSync as Nfe,readdirSync as eat}from"fs";var aE=class r{projectsConfigPath;static PROJECT_FILENAME="project.yaml";constructor(e){let t=Mc.join(Ffe.userInfo().homedir,".coday");this.projectsConfigPath=Mc.join(e??t,"projects"),Nfe(this.projectsConfigPath,{recursive:!0})}listProjects(){return eat(this.projectsConfigPath).filter(t=>Qit(Mc.join(this.projectsConfigPath,t)).isDirectory())}getProjectInfo(e){let t=Mc.join(this.projectsConfigPath,e),n=Mc.join(t,r.PROJECT_FILENAME);return Rfe(n)?{name:e,configPath:t}:null}exists(e){return this.getProjectInfo(e)!==null}getConfig(e){let t=this.getProjectInfo(e);if(!t)return console.log(`[PROJECT_REPO] No project info found for: '${e}'`),null;let n=Mc.join(t.configPath,r.PROJECT_FILENAME),i=ta(n);if(!i)return console.log(`[PROJECT_REPO] Failed to load config for '${e}' from ${n}`),null;let a=uh(i,bce);return a!==i&&(console.log(`[PROJECT_REPO] Config migrated for '${e}', saving...`),Mn(n,a)),a}saveConfig(e,t){let n=this.getProjectInfo(e);if(!n)throw new Error(`Project '${e}' does not exist`);let i=Mc.join(n.configPath,r.PROJECT_FILENAME);Mn(i,t)}createProject(e,t){let n=Mc.join(this.projectsConfigPath,e),i=Mc.join(n,r.PROJECT_FILENAME);return Rfe(i)?!1:(console.log(`[PROJECT_REPO] Creating project '${e}' with path: ${t}`),Nfe(n,{recursive:!0}),Mn(i,{version:1,path:t,integration:{},storage:{type:"file"},agents:[]}),console.log(`[PROJECT_REPO] Project '${e}' created successfully`),!0)}deleteProject(e){return this.getProjectInfo(e),!1}};var _M=ur(Pc(),1);import{promises as Zu}from"fs";import Jp from"path";var Mfe=async r=>{try{let e=await Zu.readFile(r,"utf-8");return _M.default.parse(e)}catch{return null}},oE=class{constructor(e){this.projectsDir=e}getThreadsDir(e){return Jp.join(this.projectsDir,e,"threads")}async ensureThreadsDir(e){let t=this.getThreadsDir(e);try{await Zu.mkdir(t,{recursive:!0})}catch(n){throw new Eu(`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 Zu.access(Jp.join(n,i)),i}catch{}return(await Zu.readdir(n)).find(s=>s.endsWith(`-${t}.yml`))||null}catch(n){throw new Eu(`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=Jp.join(i,n),o=await Mfe(a);if(!o)return null;let s=uh(o,YR);return s.projectId||(s.projectId=e),s!==o&&Mn(a,s),new ku(s)}catch(n){throw new Eu(`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=Jp.join(n,i),o=await this.findThreadFile(e,t.id);if(o&&o!==i){let u=Jp.join(n,o);try{await Zu.unlink(u),console.log(`[THREAD-REPO] Migrated/renamed thread file: ${o} \u2192 ${i}`)}catch(l){console.warn(`[THREAD-REPO] Could not delete old thread file: ${o}`,l)}}let s={...t.serialize(),version:YR.length+1},c=_M.default.stringify(s);return await Zu.writeFile(a,c,"utf-8"),t}catch(n){throw new Eu(`Failed to save thread ${t.id} to project ${e}`,n)}}async listByProject(e){try{let t=this.getThreadsDir(e);try{await Zu.access(t)}catch{return[]}let n=await Zu.readdir(t);return(await Promise.all(n.filter(a=>a.endsWith(".yml")).map(async a=>{let o=await Mfe(Jp.join(t,a));if(!o)return null;let s=o.projectId||e;return{id:o.id,username:o.username,projectId:s,name:o.name??"...",summary:o.summary??"",createdDate:o.createdDate??"",modifiedDate:o.modifiedDate??"",price:o.price??0,starring:o.starring??[],users:Array.isArray(o.users)?o.users.map(c=>typeof c=="string"?{userId:c}:c):o.username?[{userId:o.username}]:[],parentThreadId:o.parentThreadId,parentEventId:o.parentEventId,delegatedAgentName:o.delegatedAgentName,delegatedTask:o.delegatedTask}}))).filter(a=>!!a).sort((a,o)=>a.modifiedDate>o.modifiedDate?-1:1)}catch(t){throw new Eu(`Failed to list threads for project ${e}`,t)}}async delete(e,t){try{let n=await this.findThreadFile(e,t);if(!n)return!1;let i=this.getThreadsDir(e);return await Zu.unlink(Jp.join(i,n)),!0}catch(n){throw new Eu(`Failed to delete thread ${t} from project ${e}`,n)}}};var sE=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 oE(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(o=>rn(o,t)).sort((o,s)=>o.modifiedDate>s.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(s=>rn(s,t)).sort((s,c)=>s.modifiedDate>c.modifiedDate?-1:1)}catch(o){throw this.threadListCache.delete(e),o}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}toThreadSummary(e){return{id:e.id,username:e.username,projectId:e.projectId,name:e.name,summary:e.summary,createdDate:e.createdDate,modifiedDate:e.modifiedDate,price:e.price,starring:e.starring,users:e.users,parentThreadId:e.parentThreadId,parentEventId:e.parentEventId,delegatedAgentName:e.delegatedAgentName,delegatedTask:e.delegatedTask}}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 ku({id:crypto.randomUUID(),username:t,projectId:e,name:n||"",price:0}),o=await i.save(e,a);return this.updateThreadInCache(e,this.toThreadSummary(o)),o}async updateThread(e,t,n){let i=this.getThreadRepository(e),a=await i.getById(e,t);if(!a){let c=this.threadListCache.get(e)?.data.find(u=>u.id===t);if(c)a=new ku({id:c.id,username:c.username,projectId:c.projectId,name:c.name,summary:c.summary,price:c.price,starring:c.starring,users:c.users,parentThreadId:c.parentThreadId,parentEventId:c.parentEventId,delegatedAgentName:c.delegatedAgentName,delegatedTask:c.delegatedTask});else throw new Error(`Thread '${t}' not found in project '${e}'`)}n.name!==void 0&&(a.name=n.name),n.summary!==void 0&&(a.summary=n.summary),n.users!==void 0&&(a.users=n.users);let o=await i.save(e,a);return this.updateThreadInCache(e,this.toThreadSummary(o)),o}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 o=await i.save(e,a);return this.updateThreadInCache(e,this.toThreadSummary(o)),o}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(s=>s!==n);let o=await i.save(e,a);return this.updateThreadInCache(e,this.toThreadSummary(o)),o}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 saveThread(e,t){let i=await this.getThreadRepository(e).save(e,t);return this.updateThreadInCache(e,this.toThreadSummary(i)),i}async listAllThreads(e){let t=this.threadListCache.get(e);if(t&&Date.now()-t.timestamp<this.CACHE_TTL_MS)return t.data.sort((a,o)=>a.modifiedDate>o.modifiedDate?-1:1);let n=this.loadingPromises.get(e);if(n)return await n,this.listAllThreads(e);let i=this.loadThreadListFromDisk(e);this.loadingPromises.set(e,i);try{return(await i).sort((o,s)=>o.modifiedDate>s.modifiedDate?-1:1)}catch(a){throw this.threadListCache.delete(e),a}finally{this.loadingPromises.delete(e)}}async exists(e,t){return await this.getThread(e,t)!==null}};var Bfe=ur(Pc(),1);import*as ba from"fs/promises";import*as Q6 from"path";var Lfe=5,qfe=24,Ufe=100,zfe={SHORT_THREADS:7,LONG_THREADS:30},cE=class{constructor(e,t){this.projectsConfigPath=e;this.logger=t}cleanupTimer=null;initialTimer=null;isRunning=!1;async start(){if(this.isRunning){this.log("Thread cleanup service already running");return}this.isRunning=!0,this.log("Starting thread cleanup service with user message-based retention"),this.initialTimer=setTimeout(async()=>{await this.performCleanup(),this.cleanupTimer=setInterval(async()=>{await this.performCleanup()},qfe*60*60*1e3),this.log(`Thread cleanup scheduled every ${qfe} hours`)},Lfe*60*1e3),this.log(`Initial cleanup scheduled in ${Lfe} minutes`)}async stop(){this.initialTimer&&(clearTimeout(this.initialTimer),this.initialTimer=null),this.cleanupTimer&&(clearInterval(this.cleanupTimer),this.cleanupTimer=null),this.isRunning=!1,this.log("Thread cleanup service stopped (all timers cleared)")}async performCleanup(){let e=Date.now(),t=0,n=0,i=0;try{this.log("Starting thread cleanup...");let a=await ba.readdir(this.projectsConfigPath);this.log(`Found ${a.length} projects to scan`);for(let s of a)try{let c=Q6.join(this.projectsConfigPath,s);if(!(await ba.lstat(c)).isDirectory())continue;let l=Q6.join(c,"threads");try{await ba.access(l)}catch{continue}let{scanned:f,deleted:p,errors:d}=await this.cleanupProjectThreads(s,l);t+=f,n+=p,i+=d}catch(c){this.logError(`Error processing project ${s}: ${c}`),i++}let o=Date.now()-e;this.log(`Cleanup completed: ${n}/${t} threads deleted across all projects in ${o}ms (${i} errors)`)}catch(a){let o=Date.now()-e;this.logError(`Cleanup failed after ${o}ms: ${a}`)}}async cleanupProjectThreads(e,t){let n=0,i=0,a=0;try{let s=(await ba.readdir(t)).filter(c=>c.endsWith(".yml"));if(n=s.length,s.length===0)return{scanned:n,deleted:i,errors:a};this.log(`Scanning ${s.length} threads in project ${e}`);for(let c=0;c<s.length;c+=Ufe){let u=s.slice(c,c+Ufe),l=await this.processBatch(u,t,e);i+=l.deleted,a+=l.errors}i>0&&this.log(`Project ${e}: deleted ${i}/${n} expired threads`)}catch(o){this.logError(`Error scanning project ${e}: ${o}`),a++}return{scanned:n,deleted:i,errors:a}}async processBatch(e,t,n){let i=0,a=0;return await Promise.all(e.map(async o=>{let s=Q6.join(t,o),c;try{let u=await ba.readFile(s,"utf-8");c=Bfe.parse(u)}catch(u){await ba.unlink(s),this.logError(`Error processing file ${o} in project ${n}: ${u}`)}if(!(!c||!c.modifiedDate)&&!(c.starring&&Array.isArray(c.starring)&&c.starring.length>0)&&this.shouldDeleteThread(c)){let u=this.countUserMessages(c.messages||[]),l=this.getDaysSinceModified(c.modifiedDate),f=c.id||o.replace(".yml","");await ba.unlink(s),await this.deleteThreadFiles(t,f),i++,this.logger.logThreadCleanup(n,o),console.log(`ThreadCleanup: Deleted thread ${f} and its files directory (${u} user messages, ${l} days old)`)}})),{deleted:i,errors:a}}shouldDeleteThread(e){if(!e||!e.modifiedDate)return!1;let n=this.countUserMessages(e.messages||[])<=3?zfe.SHORT_THREADS:zfe.LONG_THREADS;return this.getDaysSinceModified(e.modifiedDate)>n}countUserMessages(e){return e.filter(t=>t&&t.type==="message"&&t.role==="user").length}getDaysSinceModified(e){let t=new Date(e),i=new Date().getTime()-t.getTime();return Math.floor(i/(1e3*60*60*24))}async deleteThreadFiles(e,t){try{let n=Q6.join(e,`${t}-files`);try{await ba.access(n),await ba.rm(n,{recursive:!0,force:!0}),console.log(`ThreadCleanup: Deleted files directory ${n}`)}catch(i){if(i.code!=="ENOENT")throw i}}catch(n){console.error(`ThreadCleanup: Error deleting files for ${t}:`,n)}}log(e){let t=new Date().toISOString();console.log(`[${t}] ThreadCleanup: ${e}`)}logError(e){let t=new Date().toISOString();console.error(`[${t}] ThreadCleanup ERROR: ${e}`)}async forceCleanup(){this.log("Manual cleanup triggered"),await this.performCleanup()}};import*as qi from"path";import*as Kp from"fs";import*as xa from"fs/promises";var uE=class{constructor(e){this.projectsDir=e}getThreadFilesDir(e,t){return qi.join(this.projectsDir,e,"threads",`${t}-files`)}async ensureThreadFilesDir(e,t){let n=this.getThreadFilesDir(e,t);Kp.existsSync(n)||await xa.mkdir(n,{recursive:!0})}async listFiles(e,t){await this.ensureThreadFilesDir(e,t);let n=this.getThreadFilesDir(e,t),i=await xa.readdir(n);return await Promise.all(i.map(async o=>{let s=qi.join(n,o),c=await xa.stat(s);return{filename:o,size:c.size,lastModified:c.mtime.toISOString()}}))}async saveFile(e,t,n,i){let a=this.getThreadFilesDir(e,t);await xa.mkdir(a,{recursive:!0});let o=qi.join(a,n);await xa.writeFile(o,i)}async getFile(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=qi.join(i,n),o=qi.resolve(a),s=qi.resolve(i);if(!o.startsWith(s))throw new Error("Access denied: invalid file path");if(!Kp.existsSync(a))throw new Error(`File '${n}' not found`);return await xa.readFile(a)}async getFilePath(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=qi.join(i,n),o=qi.resolve(a),s=qi.resolve(i);if(!o.startsWith(s))throw new Error("Access denied: invalid file path");if(!Kp.existsSync(a))throw new Error(`File '${n}' not found`);return a}fileExists(e,t,n){let i=this.getThreadFilesDir(e,t),a=qi.join(i,n),o=qi.resolve(a),s=qi.resolve(i);return o.startsWith(s)?Kp.existsSync(a):!1}async deleteFile(e,t,n){await this.ensureThreadFilesDir(e,t);let i=this.getThreadFilesDir(e,t),a=qi.join(i,n),o=qi.resolve(a),s=qi.resolve(i);if(!o.startsWith(s))throw new Error("Access denied: invalid file path");if(!Kp.existsSync(a))throw new Error(`File '${n}' not found`);await xa.unlink(a)}async deleteThreadFiles(e,t){try{let n=this.getThreadFilesDir(e,t);Kp.existsSync(n)&&(await xa.rm(n,{recursive:!0,force:!0}),console.log(`Deleted thread files directory: ${n}`))}catch(n){console.error(`Error deleting thread files for ${t}:`,n)}}};var Hfe=ur(po(),1);var lE=class{constructor(e,t,n,i){this.threadRepository=t;this.projectId=n;this.interactor=i;this.username=e.username}activeThread$=new Hfe.BehaviorSubject(null);isKilled=!1;activeThread=this.activeThread$.asObservable();username;async kill(){this.isKilled=!0,this.activeThread$.complete()}async create(e){let t=new ku({id:"",username:this.username,name:e??"",price:0});return this.activeThread$.next(t),t}async select(e){let t=await this.threadRepository.getById(this.projectId,e);if(!t)throw new Error(`Thread ${e} not found`);return this.activeThread$.next(t),t}async save(e){let t=this.activeThread$.value;if(!t){console.error(`No thread existing when save attempt with name '${e}'`);return}e&&(t.name=e);let n=await this.threadRepository.save(this.projectId,t);this.activeThread$.next(n)}async autoSave(e){if(this.isKilled){console.log("Autosave skipped: service has been killed");return}let t=this.activeThread$.value;if(!t||t.messagesLength==0){console.log(`Autosave of an empty or falsy thread aborted, threadId: ${t?.id}, user: ${this.username}`);return}try{e&&(t.name=e),await this.threadRepository.save(this.projectId,t),this.interactor&&this.interactor.sendEvent(new gc({threadId:t.id,name:t.name||void 0}))}catch(n){console.log("Autosave failed (service may have been killed):",n instanceof Error?n.message:n)}}async truncateAtUserMessage(e){let t=this.activeThread$.value;if(!t)return console.error("No active thread available for truncation"),!1;let n=t.truncateAtUserMessage(e);return n||this.interactor?.warn("Failed to truncate thread."),n}getCurrentThread(){return this.activeThread$.value}};async function Wfe(r,e){let t=e.project.selectedProject,n=e.user.getUserData(t.name),i=await eE(t.config.path,r,n),a=new A0({...i,root:t.config.path,name:t.name},e.user.username);return console.log(`[BUILD_CONTEXT] Context for '${a.project.name}' \u2192 root: ${a.project.root}, desc: ${a.project.description?.length||0} chars`),a}var fE=class extends Re{constructor(t,n){super({commandWord:"select-project",description:"Select an existing project"});this.interactor=t;this.services=n}async handle(t,n){try{let i=this.getSubCommand(t);return await this.selectProject(i)??n}catch(i){return this.interactor.error(`Invalid project selection because: ${i.toString()}`),n}}async selectProject(t){return this.services.project.selectProject(t),this.services.project.selectedProject?Wfe(this.interactor,this.services):null}};var pE=class extends Re{constructor(t,n,i){super({commandWord:"add",description:"Add a new integration configuration. User level is default, use --project/-p for project level."});this.interactor=t;this.service=n;this.editHandler=i}async handle(t,n){let a=!!Tt(this.getSubCommand(t),[{key:"project",alias:"p"}]).project,o=a?"project":"user",s=this.service.getMergedIntegrations(),c=Object.keys(s),u=Qf.filter(h=>!c.includes(h));if(u.length===0)return this.interactor.displayText(`All available integrations (${Qf.join(", ")}) are already configured.`),n;let l=await this.interactor.chooseOption(u.sort(),"Select integration to add:",`Available integrations to configure:
878
878
 
879
879
  ${u.map(h=>`- **${h}**`).join(`
880
880
  `)}
@@ -1154,7 +1154,7 @@ Maximum wait time is 300 seconds (5 minutes).`,parameters:{type:"object",propert
1154
1154
  `):"No threads found."}catch(l){let f=`Failed to list threads: ${l instanceof Error?l.message:"Unknown error"}`;return this.interactor.error(f),f}}}};i.push(s);let c={type:"function",function:{name:`${this.name}__get_thread_content`,description:"Get the message content (user and assistant messages only, no tool calls) of a specific thread by its id. Useful to query or summarize another thread without switching to it.",parameters:{type:"object",properties:{threadId:{type:"string",description:"The id of the thread to read."},lastN:{type:"number",description:"Optional: only return the last N text messages. If omitted, returns all messages."}}},parse:JSON.parse,function:async({threadId:l,lastN:f})=>{try{let p=await this.threadService.getThread(a,l);if(!p)return`Thread '${l}' not found.`;if(!rn(p,o))return`Access denied: thread '${l}' belongs to another user.`;let{messages:d}=await p.getMessages(void 0,void 0),m=d.filter(h=>h instanceof $t).map(h=>{let g=h.role==="user"?`[${h.name||o}]`:`[${h.name||"assistant"}]`,v=h.content.filter(y=>y.type==="text").map(y=>y.content).join(`
1155
1155
  `);return`${g} ${v}`});return f&&f>0&&(m=m.slice(-f)),m.length?m.join(`
1156
1156
 
1157
- `):"Thread has no text messages."}catch(p){let d=`Failed to get thread content: ${p instanceof Error?p.message:"Unknown error"}`;return this.interactor.error(d),d}}}};i.push(c);let u={type:"function",function:{name:`${this.name}__update_thread`,description:"Update the name and/or summary of a thread. Defaults to the current thread if no threadId is provided. Use this to rename or summarize a thread after a conversation.",parameters:{type:"object",properties:{name:{type:"string",description:"New name for the thread. Short, descriptive title of the conversation."},summary:{type:"string",description:"Summary of the thread content. 2-4 sentences capturing the main topics and outcomes."},threadId:{type:"string",description:"Id of the thread to update. Defaults to the current thread if omitted."}}},parse:JSON.parse,function:async({name:l,summary:f,threadId:p})=>{try{let d=p??t.aiThread?.id;if(!d)return"No thread id provided and no current thread available.";if(!l&&!f)return"At least one of name or summary must be provided.";let m=await this.threadService.getThread(a,d);if(!m)return`Thread '${d}' not found.`;if(!rn(m,o))return`Access denied: thread '${d}' belongs to another user.`;l!==void 0&&(m.name=l),f!==void 0&&(m.summary=f),await this.threadService.getThreadRepository(a).save(a,m),this.threadService.clearCache(a),this.interactor.sendEvent(new gc({threadId:d,name:l,summary:f}));let g=[];return l!==void 0&&g.push(`name: "${l}"`),f!==void 0&&g.push("summary updated"),`Thread '${d}' updated: ${g.join(", ")}.`}catch(d){let m=`Failed to update thread: ${d instanceof Error?d.message:"Unknown error"}`;return this.interactor.error(m),m}}}};return i.push(u),i}};var j8=class extends Vt{constructor(t,n,i,a){super(t,i,a);this.memoryService=n}static TYPE="MEMORY";async buildTools(t,n){let i=[],a=async({title:d})=>{try{if(d){let m=this.memoryService.listMemories("PROJECT",n),h=this.memoryService.listMemories("USER",n),v=[...m,...h].find(y=>y.title===d);return v?`# ${v.title}
1157
+ `):"Thread has no text messages."}catch(p){let d=`Failed to get thread content: ${p instanceof Error?p.message:"Unknown error"}`;return this.interactor.error(d),d}}}};i.push(c);let u={type:"function",function:{name:`${this.name}__update_thread`,description:"Update the name and/or summary of a thread. Defaults to the current thread if no threadId is provided. Use this to rename or summarize a thread after a conversation.",parameters:{type:"object",properties:{name:{type:"string",description:"New name for the thread. Short, descriptive title of the conversation."},summary:{type:"string",description:"Summary of the thread content. 2-4 sentences capturing the main topics and outcomes."},threadId:{type:"string",description:"Id of the thread to update. Defaults to the current thread if omitted."}}},parse:JSON.parse,function:async({name:l,summary:f,threadId:p})=>{try{let d=p??t.aiThread?.id;if(!d)return"No thread id provided and no current thread available.";if(!l&&!f)return"At least one of name or summary must be provided.";let m=await this.threadService.getThread(a,d);if(!m)return`Thread '${d}' not found.`;if(!rn(m,o))return`Access denied: thread '${d}' belongs to another user.`;await this.threadService.updateThread(a,d,{name:l,summary:f}),this.interactor.sendEvent(new gc({threadId:d,name:l,summary:f}));let h=[];return l!==void 0&&h.push(`name: "${l}"`),f!==void 0&&h.push("summary updated"),`Thread '${d}' updated: ${h.join(", ")}.`}catch(d){let m=`Failed to update thread: ${d instanceof Error?d.message:"Unknown error"}`;return this.interactor.error(m),m}}}};return i.push(u),i}};var j8=class extends Vt{constructor(t,n,i,a){super(t,i,a);this.memoryService=n}static TYPE="MEMORY";async buildTools(t,n){let i=[],a=async({title:d})=>{try{if(d){let m=this.memoryService.listMemories("PROJECT",n),h=this.memoryService.listMemories("USER",n),v=[...m,...h].find(y=>y.title===d);return v?`# ${v.title}
1158
1158
 
1159
1159
  **Level:** ${v.level}
1160
1160