diff --git a/dist/worker-service.cjs b/dist/worker-service.cjs index 3a72d634..20078f9f 100755 --- a/dist/worker-service.cjs +++ b/dist/worker-service.cjs @@ -60,7 +60,7 @@ Please see the 3.x to 4.x migration guide for details on how to update your app. `))}if(Xa(`[Query.streamInput] Finished processing ${r} messages from input stream`),Xa(`[Query.streamInput] About to check MCP servers. this.sdkMcpTransports.size = ${this.sdkMcpTransports.size}`),this.sdkMcpTransports.size>0&&this.firstResultReceivedPromise){Xa("[Query.streamInput] Entering Promise.race to wait for result");let a=1e4,i;await Promise.race([this.firstResultReceivedPromise.then(()=>{Xa("[Query.streamInput] Received first result, closing input stream"),i&&clearTimeout(i)}),new Promise(s=>{i=setTimeout(()=>{Xa("[Query.streamInput] Timed out waiting for first result, closing input stream"),s()},a)})]),i&&clearTimeout(i)}Xa("[Query] Calling transport.endInput() to close stdin to CLI process"),this.transport.endInput()}catch(r){if(!(r instanceof jt))throw r}}handleHookCallbacks(e,r,a,i){let s=this.hookCallbacks.get(e);if(!s)throw new Error(`No hook callback found for ID: ${e}`);return s(r,a,{signal:i})}sendMcpServerMessageToCli(e,r){if("id"in r&&r.id!==null&&r.id!==void 0){let a=`${e}:${r.id}`,i=this.pendingMcpResponses.get(a);if(i){i.resolve(r),this.pendingMcpResponses.delete(a);return}}throw new Error("No pending request found")}handleMcpControlRequest(e,r,a){let i="id"in r.message?r.message.id:null,s=`${e}:${i}`;return new Promise((n,o)=>{let l=null,c=()=>{l&&clearTimeout(l),this.pendingMcpResponses.delete(s)},p=d=>{c(),n(d)},u=d=>{c(),o(d)};if(this.pendingMcpResponses.set(s,{resolve:p,reject:u}),a.onmessage)a.onmessage(r.message);else{c(),o(new Error("No message handler registered"));return}l=setTimeout(()=>{this.pendingMcpResponses.has(s)&&(c(),o(new Error("Request timeout")))},3e4)})}};function DP({prompt:t,options:{abortController:e=Rv(),additionalDirectories:r=[],agents:a,allowedTools:i=[],appendSystemPrompt:s,canUseTool:n,continue:o,customSystemPrompt:l,cwd:c,disallowedTools:p=[],env:u,executable:d=Iv()?"bun":"node",executableArgs:h=[],extraArgs:v={},fallbackModel:f,forkSession:g,hooks:b,includePartialMessages:y,maxThinkingTokens:w,maxTurns:O,mcpServers:A,model:E,pathToClaudeCodeExecutable:P,permissionMode:j="default",permissionPromptToolName:q,resume:F,resumeSessionAt:T,settingSources:k,stderr:R,strictMcpConfig:$}={}}){if(u||(u={...process.env}),u.CLAUDE_CODE_ENTRYPOINT||(u.CLAUDE_CODE_ENTRYPOINT="sdk-ts"),!P)throw new Error("pathToClaudeCodeExecutable is required");let L={},B=new Map;if(A)for(let[Y,ee]of Object.entries(A))ee.type==="sdk"&&"instance"in ee?(B.set(Y,ee.instance),L[Y]={type:"sdk",name:Y}):L[Y]=ee;let Z=typeof t=="string",J=new bc({abortController:e,additionalDirectories:r,agents:a,cwd:c,executable:d,executableArgs:h,extraArgs:v,pathToClaudeCodeExecutable:P,env:u,forkSession:g,stderr:R,customSystemPrompt:l,appendSystemPrompt:s,maxThinkingTokens:w,maxTurns:O,model:E,fallbackModel:f,permissionMode:j,permissionPromptToolName:q,continueConversation:o,resume:F,resumeSessionAt:T,settingSources:k,allowedTools:i,disallowedTools:p,mcpServers:L,strictMcpConfig:$,canUseTool:!!n,hooks:!!b,includePartialMessages:y}),Q=new Sc(J,Z,n,b,e,B);return typeof t=="string"?J.write(JSON.stringify({type:"user",session_id:"",message:{role:"user",content:[{type:"text",text:t}]},parent_tool_use_id:null})+` `):Q.streamInput(t),Q}var m={};X4(m,{void:()=>x2,util:()=>ve,unknown:()=>v2,union:()=>_2,undefined:()=>f2,tuple:()=>k2,transformer:()=>bv,symbol:()=>d2,string:()=>Gv,strictObject:()=>w2,setErrorMap:()=>$P,set:()=>R2,record:()=>P2,quotelessJson:()=>qP,promise:()=>D2,preprocess:()=>$2,pipeline:()=>F2,ostring:()=>L2,optional:()=>q2,onumber:()=>M2,oboolean:()=>z2,objectUtil:()=>kc,object:()=>b2,number:()=>Wv,nullable:()=>N2,null:()=>m2,never:()=>g2,nativeEnum:()=>j2,nan:()=>l2,map:()=>T2,makeIssue:()=>Yi,literal:()=>O2,lazy:()=>A2,late:()=>o2,isValid:()=>qt,isDirty:()=>Tc,isAsync:()=>jn,isAborted:()=>Pc,intersection:()=>S2,instanceof:()=>c2,getParsedType:()=>Ya,getErrorMap:()=>Ji,function:()=>C2,enum:()=>I2,effect:()=>bv,discriminatedUnion:()=>E2,defaultErrorMap:()=>jr,datetimeRegex:()=>Hv,date:()=>u2,custom:()=>Vv,coerce:()=>U2,boolean:()=>Kv,bigint:()=>p2,array:()=>y2,any:()=>h2,addIssueToContext:()=>V,ZodVoid:()=>qr,ZodUnknown:()=>at,ZodUnion:()=>Ut,ZodUndefined:()=>Mt,ZodType:()=>ce,ZodTuple:()=>Ua,ZodTransformer:()=>ha,ZodSymbol:()=>Dr,ZodString:()=>ut,ZodSet:()=>$r,ZodSchema:()=>ce,ZodRecord:()=>as,ZodReadonly:()=>Qt,ZodPromise:()=>ft,ZodPipeline:()=>qn,ZodParsedType:()=>W,ZodOptional:()=>Ea,ZodObject:()=>oa,ZodNumber:()=>Nt,ZodNullable:()=>Ba,ZodNull:()=>zt,ZodNever:()=>Oa,ZodNativeEnum:()=>Gt,ZodNaN:()=>Fr,ZodMap:()=>Nr,ZodLiteral:()=>Zt,ZodLazy:()=>Ht,ZodIssueCode:()=>U,ZodIntersection:()=>Bt,ZodFunction:()=>ts,ZodFirstPartyTypeKind:()=>te,ZodError:()=>ma,ZodEnum:()=>Vt,ZodEffects:()=>ha,ZodDiscriminatedUnion:()=>es,ZodDefault:()=>Wt,ZodDate:()=>Lt,ZodCatch:()=>Kt,ZodBranded:()=>Dn,ZodBoolean:()=>Ft,ZodBigInt:()=>$t,ZodArray:()=>tt,ZodAny:()=>dt,Schema:()=>ce,ParseStatus:()=>Je,OK:()=>ta,NEVER:()=>B2,INVALID:()=>ae,EMPTY_PATH:()=>FP,DIRTY:()=>Ir,BRAND:()=>s2});var ve;(function(t){t.assertEqual=i=>{};function e(i){}t.assertIs=e;function r(i){throw new Error}t.assertNever=r,t.arrayToEnum=i=>{let s={};for(let n of i)s[n]=n;return s},t.getValidEnumValues=i=>{let s=t.objectKeys(i).filter(o=>typeof i[i[o]]!="number"),n={};for(let o of s)n[o]=i[o];return t.objectValues(n)},t.objectValues=i=>t.objectKeys(i).map(function(s){return i[s]}),t.objectKeys=typeof Object.keys=="function"?i=>Object.keys(i):i=>{let s=[];for(let n in i)Object.prototype.hasOwnProperty.call(i,n)&&s.push(n);return s},t.find=(i,s)=>{for(let n of i)if(s(n))return n},t.isInteger=typeof Number.isInteger=="function"?i=>Number.isInteger(i):i=>typeof i=="number"&&Number.isFinite(i)&&Math.floor(i)===i;function a(i,s=" | "){return i.map(n=>typeof n=="string"?`'${n}'`:n).join(s)}t.joinValues=a,t.jsonStringifyReplacer=(i,s)=>typeof s=="bigint"?s.toString():s})(ve||(ve={}));var kc;(function(t){t.mergeShapes=(e,r)=>({...e,...r})})(kc||(kc={}));var W=ve.arrayToEnum(["string","nan","number","integer","float","boolean","date","bigint","symbol","function","undefined","null","array","object","unknown","promise","void","never","map","set"]),Ya=t=>{switch(typeof t){case"undefined":return W.undefined;case"string":return W.string;case"number":return Number.isNaN(t)?W.nan:W.number;case"boolean":return W.boolean;case"function":return W.function;case"bigint":return W.bigint;case"symbol":return W.symbol;case"object":return Array.isArray(t)?W.array:t===null?W.null:t.then&&typeof t.then=="function"&&t.catch&&typeof t.catch=="function"?W.promise:typeof Map<"u"&&t instanceof Map?W.map:typeof Set<"u"&&t instanceof Set?W.set:typeof Date<"u"&&t instanceof Date?W.date:W.object;default:return W.unknown}},U=ve.arrayToEnum(["invalid_type","invalid_literal","custom","invalid_union","invalid_union_discriminator","invalid_enum_value","unrecognized_keys","invalid_arguments","invalid_return_type","invalid_date","invalid_string","too_small","too_big","invalid_intersection_types","not_multiple_of","not_finite"]),qP=t=>JSON.stringify(t,null,2).replace(/"([^"]+)":/g,"$1:"),ma=class t extends Error{get errors(){return this.issues}constructor(e){super(),this.issues=[],this.addIssue=a=>{this.issues=[...this.issues,a]},this.addIssues=(a=[])=>{this.issues=[...this.issues,...a]};let r=new.target.prototype;Object.setPrototypeOf?Object.setPrototypeOf(this,r):this.__proto__=r,this.name="ZodError",this.issues=e}format(e){let r=e||function(s){return s.message},a={_errors:[]},i=s=>{for(let n of s.issues)if(n.code==="invalid_union")n.unionErrors.map(i);else if(n.code==="invalid_return_type")i(n.returnTypeError);else if(n.code==="invalid_arguments")i(n.argumentsError);else if(n.path.length===0)a._errors.push(r(n));else{let o=a,l=0;for(;lr.message){let r={},a=[];for(let i of this.issues)if(i.path.length>0){let s=i.path[0];r[s]=r[s]||[],r[s].push(e(i))}else a.push(e(i));return{formErrors:a,fieldErrors:r}}get formErrors(){return this.flatten()}};ma.create=t=>new ma(t);var NP=(t,e)=>{let r;switch(t.code){case U.invalid_type:t.received===W.undefined?r="Required":r=`Expected ${t.expected}, received ${t.received}`;break;case U.invalid_literal:r=`Invalid literal value, expected ${JSON.stringify(t.expected,ve.jsonStringifyReplacer)}`;break;case U.unrecognized_keys:r=`Unrecognized key(s) in object: ${ve.joinValues(t.keys,", ")}`;break;case U.invalid_union:r="Invalid input";break;case U.invalid_union_discriminator:r=`Invalid discriminator value. Expected ${ve.joinValues(t.options)}`;break;case U.invalid_enum_value:r=`Invalid enum value. Expected ${ve.joinValues(t.options)}, received '${t.received}'`;break;case U.invalid_arguments:r="Invalid function arguments";break;case U.invalid_return_type:r="Invalid function return type";break;case U.invalid_date:r="Invalid date";break;case U.invalid_string:typeof t.validation=="object"?"includes"in t.validation?(r=`Invalid input: must include "${t.validation.includes}"`,typeof t.validation.position=="number"&&(r=`${r} at one or more positions greater than or equal to ${t.validation.position}`)):"startsWith"in t.validation?r=`Invalid input: must start with "${t.validation.startsWith}"`:"endsWith"in t.validation?r=`Invalid input: must end with "${t.validation.endsWith}"`:ve.assertNever(t.validation):t.validation!=="regex"?r=`Invalid ${t.validation}`:r="Invalid";break;case U.too_small:t.type==="array"?r=`Array must contain ${t.exact?"exactly":t.inclusive?"at least":"more than"} ${t.minimum} element(s)`:t.type==="string"?r=`String must contain ${t.exact?"exactly":t.inclusive?"at least":"over"} ${t.minimum} character(s)`:t.type==="number"?r=`Number must be ${t.exact?"exactly equal to ":t.inclusive?"greater than or equal to ":"greater than "}${t.minimum}`:t.type==="bigint"?r=`Number must be ${t.exact?"exactly equal to ":t.inclusive?"greater than or equal to ":"greater than "}${t.minimum}`:t.type==="date"?r=`Date must be ${t.exact?"exactly equal to ":t.inclusive?"greater than or equal to ":"greater than "}${new Date(Number(t.minimum))}`:r="Invalid input";break;case U.too_big:t.type==="array"?r=`Array must contain ${t.exact?"exactly":t.inclusive?"at most":"less than"} ${t.maximum} element(s)`:t.type==="string"?r=`String must contain ${t.exact?"exactly":t.inclusive?"at most":"under"} ${t.maximum} character(s)`:t.type==="number"?r=`Number must be ${t.exact?"exactly":t.inclusive?"less than or equal to":"less than"} ${t.maximum}`:t.type==="bigint"?r=`BigInt must be ${t.exact?"exactly":t.inclusive?"less than or equal to":"less than"} ${t.maximum}`:t.type==="date"?r=`Date must be ${t.exact?"exactly":t.inclusive?"smaller than or equal to":"smaller than"} ${new Date(Number(t.maximum))}`:r="Invalid input";break;case U.custom:r="Invalid input";break;case U.invalid_intersection_types:r="Intersection results could not be merged";break;case U.not_multiple_of:r=`Number must be a multiple of ${t.multipleOf}`;break;case U.not_finite:r="Number must be finite";break;default:r=e.defaultError,ve.assertNever(t)}return{message:r}},jr=NP,zv=jr;function $P(t){zv=t}function Ji(){return zv}var Yi=t=>{let{data:e,path:r,errorMaps:a,issueData:i}=t,s=[...r,...i.path||[]],n={...i,path:s};if(i.message!==void 0)return{...i,path:s,message:i.message};let o="",l=a.filter(c=>!!c).slice().reverse();for(let c of l)o=c(n,{data:e,defaultError:o}).message;return{...i,path:s,message:o}},FP=[];function V(t,e){let r=Ji(),a=Yi({issueData:e,data:t.data,path:t.path,errorMaps:[t.common.contextualErrorMap,t.schemaErrorMap,r,r===jr?void 0:jr].filter(i=>!!i)});t.common.issues.push(a)}var Je=class t{constructor(){this.value="valid"}dirty(){this.value==="valid"&&(this.value="dirty")}abort(){this.value!=="aborted"&&(this.value="aborted")}static mergeArray(e,r){let a=[];for(let i of r){if(i.status==="aborted")return ae;i.status==="dirty"&&e.dirty(),a.push(i.value)}return{status:e.value,value:a}}static async mergeObjectAsync(e,r){let a=[];for(let i of r){let s=await i.key,n=await i.value;a.push({key:s,value:n})}return t.mergeObjectSync(e,a)}static mergeObjectSync(e,r){let a={};for(let i of r){let{key:s,value:n}=i;if(s.status==="aborted"||n.status==="aborted")return ae;s.status==="dirty"&&e.dirty(),n.status==="dirty"&&e.dirty(),s.value!=="__proto__"&&(typeof n.value<"u"||i.alwaysSet)&&(a[s.value]=n.value)}return{status:e.value,value:a}}},ae=Object.freeze({status:"aborted"}),Ir=t=>({status:"dirty",value:t}),ta=t=>({status:"valid",value:t}),Pc=t=>t.status==="aborted",Tc=t=>t.status==="dirty",qt=t=>t.status==="valid",jn=t=>typeof Promise<"u"&&t instanceof Promise,X;(function(t){t.errToObj=e=>typeof e=="string"?{message:e}:e||{},t.toString=e=>typeof e=="string"?e:e?.message})(X||(X={}));var Sa=class{constructor(e,r,a,i){this._cachedPath=[],this.parent=e,this.data=r,this._path=a,this._key=i}get path(){return this._cachedPath.length||(Array.isArray(this._key)?this._cachedPath.push(...this._path,...this._key):this._cachedPath.push(...this._path,this._key)),this._cachedPath}},xv=(t,e)=>{if(qt(e))return{success:!0,data:e.value};if(!t.common.issues.length)throw new Error("Validation failed but no issues detected.");return{success:!1,get error(){if(this._error)return this._error;let r=new ma(t.common.issues);return this._error=r,this._error}}};function le(t){if(!t)return{};let{errorMap:e,invalid_type_error:r,required_error:a,description:i}=t;if(e&&(r||a))throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`);return e?{errorMap:e,description:i}:{errorMap:(n,o)=>{let{message:l}=t;return n.code==="invalid_enum_value"?{message:l??o.defaultError}:typeof o.data>"u"?{message:l??a??o.defaultError}:n.code!=="invalid_type"?{message:o.defaultError}:{message:l??r??o.defaultError}},description:i}}var ce=class{get description(){return this._def.description}_getType(e){return Ya(e.data)}_getOrReturnCtx(e,r){return r||{common:e.parent.common,data:e.data,parsedType:Ya(e.data),schemaErrorMap:this._def.errorMap,path:e.path,parent:e.parent}}_processInputParams(e){return{status:new Je,ctx:{common:e.parent.common,data:e.data,parsedType:Ya(e.data),schemaErrorMap:this._def.errorMap,path:e.path,parent:e.parent}}}_parseSync(e){let r=this._parse(e);if(jn(r))throw new Error("Synchronous parse encountered promise.");return r}_parseAsync(e){let r=this._parse(e);return Promise.resolve(r)}parse(e,r){let a=this.safeParse(e,r);if(a.success)return a.data;throw a.error}safeParse(e,r){let a={common:{issues:[],async:r?.async??!1,contextualErrorMap:r?.errorMap},path:r?.path||[],schemaErrorMap:this._def.errorMap,parent:null,data:e,parsedType:Ya(e)},i=this._parseSync({data:e,path:a.path,parent:a});return xv(a,i)}"~validate"(e){let r={common:{issues:[],async:!!this["~standard"].async},path:[],schemaErrorMap:this._def.errorMap,parent:null,data:e,parsedType:Ya(e)};if(!this["~standard"].async)try{let a=this._parseSync({data:e,path:[],parent:r});return qt(a)?{value:a.value}:{issues:r.common.issues}}catch(a){a?.message?.toLowerCase()?.includes("encountered")&&(this["~standard"].async=!0),r.common={issues:[],async:!0}}return this._parseAsync({data:e,path:[],parent:r}).then(a=>qt(a)?{value:a.value}:{issues:r.common.issues})}async parseAsync(e,r){let a=await this.safeParseAsync(e,r);if(a.success)return a.data;throw a.error}async safeParseAsync(e,r){let a={common:{issues:[],contextualErrorMap:r?.errorMap,async:!0},path:r?.path||[],schemaErrorMap:this._def.errorMap,parent:null,data:e,parsedType:Ya(e)},i=this._parse({data:e,path:a.path,parent:a}),s=await(jn(i)?i:Promise.resolve(i));return xv(a,s)}refine(e,r){let a=i=>typeof r=="string"||typeof r>"u"?{message:r}:typeof r=="function"?r(i):r;return this._refinement((i,s)=>{let n=e(i),o=()=>s.addIssue({code:U.custom,...a(i)});return typeof Promise<"u"&&n instanceof Promise?n.then(l=>l?!0:(o(),!1)):n?!0:(o(),!1)})}refinement(e,r){return this._refinement((a,i)=>e(a)?!0:(i.addIssue(typeof r=="function"?r(a,i):r),!1))}_refinement(e){return new ha({schema:this,typeName:te.ZodEffects,effect:{type:"refinement",refinement:e}})}superRefine(e){return this._refinement(e)}constructor(e){this.spa=this.safeParseAsync,this._def=e,this.parse=this.parse.bind(this),this.safeParse=this.safeParse.bind(this),this.parseAsync=this.parseAsync.bind(this),this.safeParseAsync=this.safeParseAsync.bind(this),this.spa=this.spa.bind(this),this.refine=this.refine.bind(this),this.refinement=this.refinement.bind(this),this.superRefine=this.superRefine.bind(this),this.optional=this.optional.bind(this),this.nullable=this.nullable.bind(this),this.nullish=this.nullish.bind(this),this.array=this.array.bind(this),this.promise=this.promise.bind(this),this.or=this.or.bind(this),this.and=this.and.bind(this),this.transform=this.transform.bind(this),this.brand=this.brand.bind(this),this.default=this.default.bind(this),this.catch=this.catch.bind(this),this.describe=this.describe.bind(this),this.pipe=this.pipe.bind(this),this.readonly=this.readonly.bind(this),this.isNullable=this.isNullable.bind(this),this.isOptional=this.isOptional.bind(this),this["~standard"]={version:1,vendor:"zod",validate:r=>this["~validate"](r)}}optional(){return Ea.create(this,this._def)}nullable(){return Ba.create(this,this._def)}nullish(){return this.nullable().optional()}array(){return tt.create(this)}promise(){return ft.create(this,this._def)}or(e){return Ut.create([this,e],this._def)}and(e){return Bt.create(this,e,this._def)}transform(e){return new ha({...le(this._def),schema:this,typeName:te.ZodEffects,effect:{type:"transform",transform:e}})}default(e){let r=typeof e=="function"?e:()=>e;return new Wt({...le(this._def),innerType:this,defaultValue:r,typeName:te.ZodDefault})}brand(){return new Dn({typeName:te.ZodBranded,type:this,...le(this._def)})}catch(e){let r=typeof e=="function"?e:()=>e;return new Kt({...le(this._def),innerType:this,catchValue:r,typeName:te.ZodCatch})}describe(e){let r=this.constructor;return new r({...this._def,description:e})}pipe(e){return qn.create(this,e)}readonly(){return Qt.create(this)}isOptional(){return this.safeParse(void 0).success}isNullable(){return this.safeParse(null).success}},LP=/^c[^\s-]{8,}$/i,MP=/^[0-9a-z]+$/,zP=/^[0-9A-HJKMNP-TV-Z]{26}$/i,UP=/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i,BP=/^[a-z0-9_-]{21}$/i,HP=/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,ZP=/^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/,VP=/^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i,GP="^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$",gc,WP=/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,KP=/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/,QP=/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/,XP=/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,JP=/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,YP=/^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/,Uv="((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))",e2=new RegExp(`^${Uv}$`);function Bv(t){let e="[0-5]\\d";t.precision?e=`${e}\\.\\d{${t.precision}}`:t.precision==null&&(e=`${e}(\\.\\d+)?`);let r=t.precision?"+":"?";return`([01]\\d|2[0-3]):[0-5]\\d(:${e})${r}`}function a2(t){return new RegExp(`^${Bv(t)}$`)}function Hv(t){let e=`${Uv}T${Bv(t)}`,r=[];return r.push(t.local?"Z?":"Z"),t.offset&&r.push("([+-]\\d{2}:?\\d{2})"),e=`${e}(${r.join("|")})`,new RegExp(`^${e}$`)}function t2(t,e){return!!((e==="v4"||!e)&&WP.test(t)||(e==="v6"||!e)&&QP.test(t))}function r2(t,e){if(!HP.test(t))return!1;try{let[r]=t.split(".");if(!r)return!1;let a=r.replace(/-/g,"+").replace(/_/g,"/").padEnd(r.length+(4-r.length%4)%4,"="),i=JSON.parse(atob(a));return!(typeof i!="object"||i===null||"typ"in i&&i?.typ!=="JWT"||!i.alg||e&&i.alg!==e)}catch{return!1}}function n2(t,e){return!!((e==="v4"||!e)&&KP.test(t)||(e==="v6"||!e)&&XP.test(t))}var ut=class t extends ce{_parse(e){if(this._def.coerce&&(e.data=String(e.data)),this._getType(e)!==W.string){let s=this._getOrReturnCtx(e);return V(s,{code:U.invalid_type,expected:W.string,received:s.parsedType}),ae}let a=new Je,i;for(let s of this._def.checks)if(s.kind==="min")e.data.lengths.value&&(i=this._getOrReturnCtx(e,i),V(i,{code:U.too_big,maximum:s.value,type:"string",inclusive:!0,exact:!1,message:s.message}),a.dirty());else if(s.kind==="length"){let n=e.data.length>s.value,o=e.data.lengthe.test(i),{validation:r,code:U.invalid_string,...X.errToObj(a)})}_addCheck(e){return new t({...this._def,checks:[...this._def.checks,e]})}email(e){return this._addCheck({kind:"email",...X.errToObj(e)})}url(e){return this._addCheck({kind:"url",...X.errToObj(e)})}emoji(e){return this._addCheck({kind:"emoji",...X.errToObj(e)})}uuid(e){return this._addCheck({kind:"uuid",...X.errToObj(e)})}nanoid(e){return this._addCheck({kind:"nanoid",...X.errToObj(e)})}cuid(e){return this._addCheck({kind:"cuid",...X.errToObj(e)})}cuid2(e){return this._addCheck({kind:"cuid2",...X.errToObj(e)})}ulid(e){return this._addCheck({kind:"ulid",...X.errToObj(e)})}base64(e){return this._addCheck({kind:"base64",...X.errToObj(e)})}base64url(e){return this._addCheck({kind:"base64url",...X.errToObj(e)})}jwt(e){return this._addCheck({kind:"jwt",...X.errToObj(e)})}ip(e){return this._addCheck({kind:"ip",...X.errToObj(e)})}cidr(e){return this._addCheck({kind:"cidr",...X.errToObj(e)})}datetime(e){return typeof e=="string"?this._addCheck({kind:"datetime",precision:null,offset:!1,local:!1,message:e}):this._addCheck({kind:"datetime",precision:typeof e?.precision>"u"?null:e?.precision,offset:e?.offset??!1,local:e?.local??!1,...X.errToObj(e?.message)})}date(e){return this._addCheck({kind:"date",message:e})}time(e){return typeof e=="string"?this._addCheck({kind:"time",precision:null,message:e}):this._addCheck({kind:"time",precision:typeof e?.precision>"u"?null:e?.precision,...X.errToObj(e?.message)})}duration(e){return this._addCheck({kind:"duration",...X.errToObj(e)})}regex(e,r){return this._addCheck({kind:"regex",regex:e,...X.errToObj(r)})}includes(e,r){return this._addCheck({kind:"includes",value:e,position:r?.position,...X.errToObj(r?.message)})}startsWith(e,r){return this._addCheck({kind:"startsWith",value:e,...X.errToObj(r)})}endsWith(e,r){return this._addCheck({kind:"endsWith",value:e,...X.errToObj(r)})}min(e,r){return this._addCheck({kind:"min",value:e,...X.errToObj(r)})}max(e,r){return this._addCheck({kind:"max",value:e,...X.errToObj(r)})}length(e,r){return this._addCheck({kind:"length",value:e,...X.errToObj(r)})}nonempty(e){return this.min(1,X.errToObj(e))}trim(){return new t({...this._def,checks:[...this._def.checks,{kind:"trim"}]})}toLowerCase(){return new t({...this._def,checks:[...this._def.checks,{kind:"toLowerCase"}]})}toUpperCase(){return new t({...this._def,checks:[...this._def.checks,{kind:"toUpperCase"}]})}get isDatetime(){return!!this._def.checks.find(e=>e.kind==="datetime")}get isDate(){return!!this._def.checks.find(e=>e.kind==="date")}get isTime(){return!!this._def.checks.find(e=>e.kind==="time")}get isDuration(){return!!this._def.checks.find(e=>e.kind==="duration")}get isEmail(){return!!this._def.checks.find(e=>e.kind==="email")}get isURL(){return!!this._def.checks.find(e=>e.kind==="url")}get isEmoji(){return!!this._def.checks.find(e=>e.kind==="emoji")}get isUUID(){return!!this._def.checks.find(e=>e.kind==="uuid")}get isNANOID(){return!!this._def.checks.find(e=>e.kind==="nanoid")}get isCUID(){return!!this._def.checks.find(e=>e.kind==="cuid")}get isCUID2(){return!!this._def.checks.find(e=>e.kind==="cuid2")}get isULID(){return!!this._def.checks.find(e=>e.kind==="ulid")}get isIP(){return!!this._def.checks.find(e=>e.kind==="ip")}get isCIDR(){return!!this._def.checks.find(e=>e.kind==="cidr")}get isBase64(){return!!this._def.checks.find(e=>e.kind==="base64")}get isBase64url(){return!!this._def.checks.find(e=>e.kind==="base64url")}get minLength(){let e=null;for(let r of this._def.checks)r.kind==="min"&&(e===null||r.value>e)&&(e=r.value);return e}get maxLength(){let e=null;for(let r of this._def.checks)r.kind==="max"&&(e===null||r.valuenew ut({checks:[],typeName:te.ZodString,coerce:t?.coerce??!1,...le(t)});function i2(t,e){let r=(t.toString().split(".")[1]||"").length,a=(e.toString().split(".")[1]||"").length,i=r>a?r:a,s=Number.parseInt(t.toFixed(i).replace(".","")),n=Number.parseInt(e.toFixed(i).replace(".",""));return s%n/10**i}var Nt=class t extends ce{constructor(){super(...arguments),this.min=this.gte,this.max=this.lte,this.step=this.multipleOf}_parse(e){if(this._def.coerce&&(e.data=Number(e.data)),this._getType(e)!==W.number){let s=this._getOrReturnCtx(e);return V(s,{code:U.invalid_type,expected:W.number,received:s.parsedType}),ae}let a,i=new Je;for(let s of this._def.checks)s.kind==="int"?ve.isInteger(e.data)||(a=this._getOrReturnCtx(e,a),V(a,{code:U.invalid_type,expected:"integer",received:"float",message:s.message}),i.dirty()):s.kind==="min"?(s.inclusive?e.datas.value:e.data>=s.value)&&(a=this._getOrReturnCtx(e,a),V(a,{code:U.too_big,maximum:s.value,type:"number",inclusive:s.inclusive,exact:!1,message:s.message}),i.dirty()):s.kind==="multipleOf"?i2(e.data,s.value)!==0&&(a=this._getOrReturnCtx(e,a),V(a,{code:U.not_multiple_of,multipleOf:s.value,message:s.message}),i.dirty()):s.kind==="finite"?Number.isFinite(e.data)||(a=this._getOrReturnCtx(e,a),V(a,{code:U.not_finite,message:s.message}),i.dirty()):ve.assertNever(s);return{status:i.value,value:e.data}}gte(e,r){return this.setLimit("min",e,!0,X.toString(r))}gt(e,r){return this.setLimit("min",e,!1,X.toString(r))}lte(e,r){return this.setLimit("max",e,!0,X.toString(r))}lt(e,r){return this.setLimit("max",e,!1,X.toString(r))}setLimit(e,r,a,i){return new t({...this._def,checks:[...this._def.checks,{kind:e,value:r,inclusive:a,message:X.toString(i)}]})}_addCheck(e){return new t({...this._def,checks:[...this._def.checks,e]})}int(e){return this._addCheck({kind:"int",message:X.toString(e)})}positive(e){return this._addCheck({kind:"min",value:0,inclusive:!1,message:X.toString(e)})}negative(e){return this._addCheck({kind:"max",value:0,inclusive:!1,message:X.toString(e)})}nonpositive(e){return this._addCheck({kind:"max",value:0,inclusive:!0,message:X.toString(e)})}nonnegative(e){return this._addCheck({kind:"min",value:0,inclusive:!0,message:X.toString(e)})}multipleOf(e,r){return this._addCheck({kind:"multipleOf",value:e,message:X.toString(r)})}finite(e){return this._addCheck({kind:"finite",message:X.toString(e)})}safe(e){return this._addCheck({kind:"min",inclusive:!0,value:Number.MIN_SAFE_INTEGER,message:X.toString(e)})._addCheck({kind:"max",inclusive:!0,value:Number.MAX_SAFE_INTEGER,message:X.toString(e)})}get minValue(){let e=null;for(let r of this._def.checks)r.kind==="min"&&(e===null||r.value>e)&&(e=r.value);return e}get maxValue(){let e=null;for(let r of this._def.checks)r.kind==="max"&&(e===null||r.valuee.kind==="int"||e.kind==="multipleOf"&&ve.isInteger(e.value))}get isFinite(){let e=null,r=null;for(let a of this._def.checks){if(a.kind==="finite"||a.kind==="int"||a.kind==="multipleOf")return!0;a.kind==="min"?(r===null||a.value>r)&&(r=a.value):a.kind==="max"&&(e===null||a.valuenew Nt({checks:[],typeName:te.ZodNumber,coerce:t?.coerce||!1,...le(t)});var $t=class t extends ce{constructor(){super(...arguments),this.min=this.gte,this.max=this.lte}_parse(e){if(this._def.coerce)try{e.data=BigInt(e.data)}catch{return this._getInvalidInput(e)}if(this._getType(e)!==W.bigint)return this._getInvalidInput(e);let a,i=new Je;for(let s of this._def.checks)s.kind==="min"?(s.inclusive?e.datas.value:e.data>=s.value)&&(a=this._getOrReturnCtx(e,a),V(a,{code:U.too_big,type:"bigint",maximum:s.value,inclusive:s.inclusive,message:s.message}),i.dirty()):s.kind==="multipleOf"?e.data%s.value!==BigInt(0)&&(a=this._getOrReturnCtx(e,a),V(a,{code:U.not_multiple_of,multipleOf:s.value,message:s.message}),i.dirty()):ve.assertNever(s);return{status:i.value,value:e.data}}_getInvalidInput(e){let r=this._getOrReturnCtx(e);return V(r,{code:U.invalid_type,expected:W.bigint,received:r.parsedType}),ae}gte(e,r){return this.setLimit("min",e,!0,X.toString(r))}gt(e,r){return this.setLimit("min",e,!1,X.toString(r))}lte(e,r){return this.setLimit("max",e,!0,X.toString(r))}lt(e,r){return this.setLimit("max",e,!1,X.toString(r))}setLimit(e,r,a,i){return new t({...this._def,checks:[...this._def.checks,{kind:e,value:r,inclusive:a,message:X.toString(i)}]})}_addCheck(e){return new t({...this._def,checks:[...this._def.checks,e]})}positive(e){return this._addCheck({kind:"min",value:BigInt(0),inclusive:!1,message:X.toString(e)})}negative(e){return this._addCheck({kind:"max",value:BigInt(0),inclusive:!1,message:X.toString(e)})}nonpositive(e){return this._addCheck({kind:"max",value:BigInt(0),inclusive:!0,message:X.toString(e)})}nonnegative(e){return this._addCheck({kind:"min",value:BigInt(0),inclusive:!0,message:X.toString(e)})}multipleOf(e,r){return this._addCheck({kind:"multipleOf",value:e,message:X.toString(r)})}get minValue(){let e=null;for(let r of this._def.checks)r.kind==="min"&&(e===null||r.value>e)&&(e=r.value);return e}get maxValue(){let e=null;for(let r of this._def.checks)r.kind==="max"&&(e===null||r.valuenew $t({checks:[],typeName:te.ZodBigInt,coerce:t?.coerce??!1,...le(t)});var Ft=class extends ce{_parse(e){if(this._def.coerce&&(e.data=!!e.data),this._getType(e)!==W.boolean){let a=this._getOrReturnCtx(e);return V(a,{code:U.invalid_type,expected:W.boolean,received:a.parsedType}),ae}return ta(e.data)}};Ft.create=t=>new Ft({typeName:te.ZodBoolean,coerce:t?.coerce||!1,...le(t)});var Lt=class t extends ce{_parse(e){if(this._def.coerce&&(e.data=new Date(e.data)),this._getType(e)!==W.date){let s=this._getOrReturnCtx(e);return V(s,{code:U.invalid_type,expected:W.date,received:s.parsedType}),ae}if(Number.isNaN(e.data.getTime())){let s=this._getOrReturnCtx(e);return V(s,{code:U.invalid_date}),ae}let a=new Je,i;for(let s of this._def.checks)s.kind==="min"?e.data.getTime()s.value&&(i=this._getOrReturnCtx(e,i),V(i,{code:U.too_big,message:s.message,inclusive:!0,exact:!1,maximum:s.value,type:"date"}),a.dirty()):ve.assertNever(s);return{status:a.value,value:new Date(e.data.getTime())}}_addCheck(e){return new t({...this._def,checks:[...this._def.checks,e]})}min(e,r){return this._addCheck({kind:"min",value:e.getTime(),message:X.toString(r)})}max(e,r){return this._addCheck({kind:"max",value:e.getTime(),message:X.toString(r)})}get minDate(){let e=null;for(let r of this._def.checks)r.kind==="min"&&(e===null||r.value>e)&&(e=r.value);return e!=null?new Date(e):null}get maxDate(){let e=null;for(let r of this._def.checks)r.kind==="max"&&(e===null||r.valuenew Lt({checks:[],coerce:t?.coerce||!1,typeName:te.ZodDate,...le(t)});var Dr=class extends ce{_parse(e){if(this._getType(e)!==W.symbol){let a=this._getOrReturnCtx(e);return V(a,{code:U.invalid_type,expected:W.symbol,received:a.parsedType}),ae}return ta(e.data)}};Dr.create=t=>new Dr({typeName:te.ZodSymbol,...le(t)});var Mt=class extends ce{_parse(e){if(this._getType(e)!==W.undefined){let a=this._getOrReturnCtx(e);return V(a,{code:U.invalid_type,expected:W.undefined,received:a.parsedType}),ae}return ta(e.data)}};Mt.create=t=>new Mt({typeName:te.ZodUndefined,...le(t)});var zt=class extends ce{_parse(e){if(this._getType(e)!==W.null){let a=this._getOrReturnCtx(e);return V(a,{code:U.invalid_type,expected:W.null,received:a.parsedType}),ae}return ta(e.data)}};zt.create=t=>new zt({typeName:te.ZodNull,...le(t)});var dt=class extends ce{constructor(){super(...arguments),this._any=!0}_parse(e){return ta(e.data)}};dt.create=t=>new dt({typeName:te.ZodAny,...le(t)});var at=class extends ce{constructor(){super(...arguments),this._unknown=!0}_parse(e){return ta(e.data)}};at.create=t=>new at({typeName:te.ZodUnknown,...le(t)});var Oa=class extends ce{_parse(e){let r=this._getOrReturnCtx(e);return V(r,{code:U.invalid_type,expected:W.never,received:r.parsedType}),ae}};Oa.create=t=>new Oa({typeName:te.ZodNever,...le(t)});var qr=class extends ce{_parse(e){if(this._getType(e)!==W.undefined){let a=this._getOrReturnCtx(e);return V(a,{code:U.invalid_type,expected:W.void,received:a.parsedType}),ae}return ta(e.data)}};qr.create=t=>new qr({typeName:te.ZodVoid,...le(t)});var tt=class t extends ce{_parse(e){let{ctx:r,status:a}=this._processInputParams(e),i=this._def;if(r.parsedType!==W.array)return V(r,{code:U.invalid_type,expected:W.array,received:r.parsedType}),ae;if(i.exactLength!==null){let n=r.data.length>i.exactLength.value,o=r.data.lengthi.maxLength.value&&(V(r,{code:U.too_big,maximum:i.maxLength.value,type:"array",inclusive:!0,exact:!1,message:i.maxLength.message}),a.dirty()),r.common.async)return Promise.all([...r.data].map((n,o)=>i.type._parseAsync(new Sa(r,n,r.path,o)))).then(n=>Je.mergeArray(a,n));let s=[...r.data].map((n,o)=>i.type._parseSync(new Sa(r,n,r.path,o)));return Je.mergeArray(a,s)}get element(){return this._def.type}min(e,r){return new t({...this._def,minLength:{value:e,message:X.toString(r)}})}max(e,r){return new t({...this._def,maxLength:{value:e,message:X.toString(r)}})}length(e,r){return new t({...this._def,exactLength:{value:e,message:X.toString(r)}})}nonempty(e){return this.min(1,e)}};tt.create=(t,e)=>new tt({type:t,minLength:null,maxLength:null,exactLength:null,typeName:te.ZodArray,...le(e)});function Or(t){if(t instanceof oa){let e={};for(let r in t.shape){let a=t.shape[r];e[r]=Ea.create(Or(a))}return new oa({...t._def,shape:()=>e})}else return t instanceof tt?new tt({...t._def,type:Or(t.element)}):t instanceof Ea?Ea.create(Or(t.unwrap())):t instanceof Ba?Ba.create(Or(t.unwrap())):t instanceof Ua?Ua.create(t.items.map(e=>Or(e))):t}var oa=class t extends ce{constructor(){super(...arguments),this._cached=null,this.nonstrict=this.passthrough,this.augment=this.extend}_getCached(){if(this._cached!==null)return this._cached;let e=this._def.shape(),r=ve.objectKeys(e);return this._cached={shape:e,keys:r},this._cached}_parse(e){if(this._getType(e)!==W.object){let c=this._getOrReturnCtx(e);return V(c,{code:U.invalid_type,expected:W.object,received:c.parsedType}),ae}let{status:a,ctx:i}=this._processInputParams(e),{shape:s,keys:n}=this._getCached(),o=[];if(!(this._def.catchall instanceof Oa&&this._def.unknownKeys==="strip"))for(let c in i.data)n.includes(c)||o.push(c);let l=[];for(let c of n){let p=s[c],u=i.data[c];l.push({key:{status:"valid",value:c},value:p._parse(new Sa(i,u,i.path,c)),alwaysSet:c in i.data})}if(this._def.catchall instanceof Oa){let c=this._def.unknownKeys;if(c==="passthrough")for(let p of o)l.push({key:{status:"valid",value:p},value:{status:"valid",value:i.data[p]}});else if(c==="strict")o.length>0&&(V(i,{code:U.unrecognized_keys,keys:o}),a.dirty());else if(c!=="strip")throw new Error("Internal ZodObject error: invalid unknownKeys value.")}else{let c=this._def.catchall;for(let p of o){let u=i.data[p];l.push({key:{status:"valid",value:p},value:c._parse(new Sa(i,u,i.path,p)),alwaysSet:p in i.data})}}return i.common.async?Promise.resolve().then(async()=>{let c=[];for(let p of l){let u=await p.key,d=await p.value;c.push({key:u,value:d,alwaysSet:p.alwaysSet})}return c}).then(c=>Je.mergeObjectSync(a,c)):Je.mergeObjectSync(a,l)}get shape(){return this._def.shape()}strict(e){return X.errToObj,new t({...this._def,unknownKeys:"strict",...e!==void 0?{errorMap:(r,a)=>{let i=this._def.errorMap?.(r,a).message??a.defaultError;return r.code==="unrecognized_keys"?{message:X.errToObj(e).message??i}:{message:i}}}:{}})}strip(){return new t({...this._def,unknownKeys:"strip"})}passthrough(){return new t({...this._def,unknownKeys:"passthrough"})}extend(e){return new t({...this._def,shape:()=>({...this._def.shape(),...e})})}merge(e){return new t({unknownKeys:e._def.unknownKeys,catchall:e._def.catchall,shape:()=>({...this._def.shape(),...e._def.shape()}),typeName:te.ZodObject})}setKey(e,r){return this.augment({[e]:r})}catchall(e){return new t({...this._def,catchall:e})}pick(e){let r={};for(let a of ve.objectKeys(e))e[a]&&this.shape[a]&&(r[a]=this.shape[a]);return new t({...this._def,shape:()=>r})}omit(e){let r={};for(let a of ve.objectKeys(this.shape))e[a]||(r[a]=this.shape[a]);return new t({...this._def,shape:()=>r})}deepPartial(){return Or(this)}partial(e){let r={};for(let a of ve.objectKeys(this.shape)){let i=this.shape[a];e&&!e[a]?r[a]=i:r[a]=i.optional()}return new t({...this._def,shape:()=>r})}required(e){let r={};for(let a of ve.objectKeys(this.shape))if(e&&!e[a])r[a]=this.shape[a];else{let s=this.shape[a];for(;s instanceof Ea;)s=s._def.innerType;r[a]=s}return new t({...this._def,shape:()=>r})}keyof(){return Zv(ve.objectKeys(this.shape))}};oa.create=(t,e)=>new oa({shape:()=>t,unknownKeys:"strip",catchall:Oa.create(),typeName:te.ZodObject,...le(e)});oa.strictCreate=(t,e)=>new oa({shape:()=>t,unknownKeys:"strict",catchall:Oa.create(),typeName:te.ZodObject,...le(e)});oa.lazycreate=(t,e)=>new oa({shape:t,unknownKeys:"strip",catchall:Oa.create(),typeName:te.ZodObject,...le(e)});var Ut=class extends ce{_parse(e){let{ctx:r}=this._processInputParams(e),a=this._def.options;function i(s){for(let o of s)if(o.result.status==="valid")return o.result;for(let o of s)if(o.result.status==="dirty")return r.common.issues.push(...o.ctx.common.issues),o.result;let n=s.map(o=>new ma(o.ctx.common.issues));return V(r,{code:U.invalid_union,unionErrors:n}),ae}if(r.common.async)return Promise.all(a.map(async s=>{let n={...r,common:{...r.common,issues:[]},parent:null};return{result:await s._parseAsync({data:r.data,path:r.path,parent:n}),ctx:n}})).then(i);{let s,n=[];for(let l of a){let c={...r,common:{...r.common,issues:[]},parent:null},p=l._parseSync({data:r.data,path:r.path,parent:c});if(p.status==="valid")return p;p.status==="dirty"&&!s&&(s={result:p,ctx:c}),c.common.issues.length&&n.push(c.common.issues)}if(s)return r.common.issues.push(...s.ctx.common.issues),s.result;let o=n.map(l=>new ma(l));return V(r,{code:U.invalid_union,unionErrors:o}),ae}}get options(){return this._def.options}};Ut.create=(t,e)=>new Ut({options:t,typeName:te.ZodUnion,...le(e)});var Ja=t=>t instanceof Ht?Ja(t.schema):t instanceof ha?Ja(t.innerType()):t instanceof Zt?[t.value]:t instanceof Vt?t.options:t instanceof Gt?ve.objectValues(t.enum):t instanceof Wt?Ja(t._def.innerType):t instanceof Mt?[void 0]:t instanceof zt?[null]:t instanceof Ea?[void 0,...Ja(t.unwrap())]:t instanceof Ba?[null,...Ja(t.unwrap())]:t instanceof Dn||t instanceof Qt?Ja(t.unwrap()):t instanceof Kt?Ja(t._def.innerType):[],es=class t extends ce{_parse(e){let{ctx:r}=this._processInputParams(e);if(r.parsedType!==W.object)return V(r,{code:U.invalid_type,expected:W.object,received:r.parsedType}),ae;let a=this.discriminator,i=r.data[a],s=this.optionsMap.get(i);return s?r.common.async?s._parseAsync({data:r.data,path:r.path,parent:r}):s._parseSync({data:r.data,path:r.path,parent:r}):(V(r,{code:U.invalid_union_discriminator,options:Array.from(this.optionsMap.keys()),path:[a]}),ae)}get discriminator(){return this._def.discriminator}get options(){return this._def.options}get optionsMap(){return this._def.optionsMap}static create(e,r,a){let i=new Map;for(let s of r){let n=Ja(s.shape[e]);if(!n.length)throw new Error(`A discriminator value for key \`${e}\` could not be extracted from all schema options`);for(let o of n){if(i.has(o))throw new Error(`Discriminator property ${String(e)} has duplicate value ${String(o)}`);i.set(o,s)}}return new t({typeName:te.ZodDiscriminatedUnion,discriminator:e,options:r,optionsMap:i,...le(a)})}};function Rc(t,e){let r=Ya(t),a=Ya(e);if(t===e)return{valid:!0,data:t};if(r===W.object&&a===W.object){let i=ve.objectKeys(e),s=ve.objectKeys(t).filter(o=>i.indexOf(o)!==-1),n={...t,...e};for(let o of s){let l=Rc(t[o],e[o]);if(!l.valid)return{valid:!1};n[o]=l.data}return{valid:!0,data:n}}else if(r===W.array&&a===W.array){if(t.length!==e.length)return{valid:!1};let i=[];for(let s=0;s{if(Pc(s)||Pc(n))return ae;let o=Rc(s.value,n.value);return o.valid?((Tc(s)||Tc(n))&&r.dirty(),{status:r.value,value:o.data}):(V(a,{code:U.invalid_intersection_types}),ae)};return a.common.async?Promise.all([this._def.left._parseAsync({data:a.data,path:a.path,parent:a}),this._def.right._parseAsync({data:a.data,path:a.path,parent:a})]).then(([s,n])=>i(s,n)):i(this._def.left._parseSync({data:a.data,path:a.path,parent:a}),this._def.right._parseSync({data:a.data,path:a.path,parent:a}))}};Bt.create=(t,e,r)=>new Bt({left:t,right:e,typeName:te.ZodIntersection,...le(r)});var Ua=class t extends ce{_parse(e){let{status:r,ctx:a}=this._processInputParams(e);if(a.parsedType!==W.array)return V(a,{code:U.invalid_type,expected:W.array,received:a.parsedType}),ae;if(a.data.lengththis._def.items.length&&(V(a,{code:U.too_big,maximum:this._def.items.length,inclusive:!0,exact:!1,type:"array"}),r.dirty());let s=[...a.data].map((n,o)=>{let l=this._def.items[o]||this._def.rest;return l?l._parse(new Sa(a,n,a.path,o)):null}).filter(n=>!!n);return a.common.async?Promise.all(s).then(n=>Je.mergeArray(r,n)):Je.mergeArray(r,s)}get items(){return this._def.items}rest(e){return new t({...this._def,rest:e})}};Ua.create=(t,e)=>{if(!Array.isArray(t))throw new Error("You must pass an array of schemas to z.tuple([ ... ])");return new Ua({items:t,typeName:te.ZodTuple,rest:null,...le(e)})};var as=class t extends ce{get keySchema(){return this._def.keyType}get valueSchema(){return this._def.valueType}_parse(e){let{status:r,ctx:a}=this._processInputParams(e);if(a.parsedType!==W.object)return V(a,{code:U.invalid_type,expected:W.object,received:a.parsedType}),ae;let i=[],s=this._def.keyType,n=this._def.valueType;for(let o in a.data)i.push({key:s._parse(new Sa(a,o,a.path,o)),value:n._parse(new Sa(a,a.data[o],a.path,o)),alwaysSet:o in a.data});return a.common.async?Je.mergeObjectAsync(r,i):Je.mergeObjectSync(r,i)}get element(){return this._def.valueType}static create(e,r,a){return r instanceof ce?new t({keyType:e,valueType:r,typeName:te.ZodRecord,...le(a)}):new t({keyType:ut.create(),valueType:e,typeName:te.ZodRecord,...le(r)})}},Nr=class extends ce{get keySchema(){return this._def.keyType}get valueSchema(){return this._def.valueType}_parse(e){let{status:r,ctx:a}=this._processInputParams(e);if(a.parsedType!==W.map)return V(a,{code:U.invalid_type,expected:W.map,received:a.parsedType}),ae;let i=this._def.keyType,s=this._def.valueType,n=[...a.data.entries()].map(([o,l],c)=>({key:i._parse(new Sa(a,o,a.path,[c,"key"])),value:s._parse(new Sa(a,l,a.path,[c,"value"]))}));if(a.common.async){let o=new Map;return Promise.resolve().then(async()=>{for(let l of n){let c=await l.key,p=await l.value;if(c.status==="aborted"||p.status==="aborted")return ae;(c.status==="dirty"||p.status==="dirty")&&r.dirty(),o.set(c.value,p.value)}return{status:r.value,value:o}})}else{let o=new Map;for(let l of n){let c=l.key,p=l.value;if(c.status==="aborted"||p.status==="aborted")return ae;(c.status==="dirty"||p.status==="dirty")&&r.dirty(),o.set(c.value,p.value)}return{status:r.value,value:o}}}};Nr.create=(t,e,r)=>new Nr({valueType:e,keyType:t,typeName:te.ZodMap,...le(r)});var $r=class t extends ce{_parse(e){let{status:r,ctx:a}=this._processInputParams(e);if(a.parsedType!==W.set)return V(a,{code:U.invalid_type,expected:W.set,received:a.parsedType}),ae;let i=this._def;i.minSize!==null&&a.data.sizei.maxSize.value&&(V(a,{code:U.too_big,maximum:i.maxSize.value,type:"set",inclusive:!0,exact:!1,message:i.maxSize.message}),r.dirty());let s=this._def.valueType;function n(l){let c=new Set;for(let p of l){if(p.status==="aborted")return ae;p.status==="dirty"&&r.dirty(),c.add(p.value)}return{status:r.value,value:c}}let o=[...a.data.values()].map((l,c)=>s._parse(new Sa(a,l,a.path,c)));return a.common.async?Promise.all(o).then(l=>n(l)):n(o)}min(e,r){return new t({...this._def,minSize:{value:e,message:X.toString(r)}})}max(e,r){return new t({...this._def,maxSize:{value:e,message:X.toString(r)}})}size(e,r){return this.min(e,r).max(e,r)}nonempty(e){return this.min(1,e)}};$r.create=(t,e)=>new $r({valueType:t,minSize:null,maxSize:null,typeName:te.ZodSet,...le(e)});var ts=class t extends ce{constructor(){super(...arguments),this.validate=this.implement}_parse(e){let{ctx:r}=this._processInputParams(e);if(r.parsedType!==W.function)return V(r,{code:U.invalid_type,expected:W.function,received:r.parsedType}),ae;function a(o,l){return Yi({data:o,path:r.path,errorMaps:[r.common.contextualErrorMap,r.schemaErrorMap,Ji(),jr].filter(c=>!!c),issueData:{code:U.invalid_arguments,argumentsError:l}})}function i(o,l){return Yi({data:o,path:r.path,errorMaps:[r.common.contextualErrorMap,r.schemaErrorMap,Ji(),jr].filter(c=>!!c),issueData:{code:U.invalid_return_type,returnTypeError:l}})}let s={errorMap:r.common.contextualErrorMap},n=r.data;if(this._def.returns instanceof ft){let o=this;return ta(async function(...l){let c=new ma([]),p=await o._def.args.parseAsync(l,s).catch(h=>{throw c.addIssue(a(l,h)),c}),u=await Reflect.apply(n,this,p);return await o._def.returns._def.type.parseAsync(u,s).catch(h=>{throw c.addIssue(i(u,h)),c})})}else{let o=this;return ta(function(...l){let c=o._def.args.safeParse(l,s);if(!c.success)throw new ma([a(l,c.error)]);let p=Reflect.apply(n,this,c.data),u=o._def.returns.safeParse(p,s);if(!u.success)throw new ma([i(p,u.error)]);return u.data})}}parameters(){return this._def.args}returnType(){return this._def.returns}args(...e){return new t({...this._def,args:Ua.create(e).rest(at.create())})}returns(e){return new t({...this._def,returns:e})}implement(e){return this.parse(e)}strictImplement(e){return this.parse(e)}static create(e,r,a){return new t({args:e||Ua.create([]).rest(at.create()),returns:r||at.create(),typeName:te.ZodFunction,...le(a)})}},Ht=class extends ce{get schema(){return this._def.getter()}_parse(e){let{ctx:r}=this._processInputParams(e);return this._def.getter()._parse({data:r.data,path:r.path,parent:r})}};Ht.create=(t,e)=>new Ht({getter:t,typeName:te.ZodLazy,...le(e)});var Zt=class extends ce{_parse(e){if(e.data!==this._def.value){let r=this._getOrReturnCtx(e);return V(r,{received:r.data,code:U.invalid_literal,expected:this._def.value}),ae}return{status:"valid",value:e.data}}get value(){return this._def.value}};Zt.create=(t,e)=>new Zt({value:t,typeName:te.ZodLiteral,...le(e)});function Zv(t,e){return new Vt({values:t,typeName:te.ZodEnum,...le(e)})}var Vt=class t extends ce{_parse(e){if(typeof e.data!="string"){let r=this._getOrReturnCtx(e),a=this._def.values;return V(r,{expected:ve.joinValues(a),received:r.parsedType,code:U.invalid_type}),ae}if(this._cache||(this._cache=new Set(this._def.values)),!this._cache.has(e.data)){let r=this._getOrReturnCtx(e),a=this._def.values;return V(r,{received:r.data,code:U.invalid_enum_value,options:a}),ae}return ta(e.data)}get options(){return this._def.values}get enum(){let e={};for(let r of this._def.values)e[r]=r;return e}get Values(){let e={};for(let r of this._def.values)e[r]=r;return e}get Enum(){let e={};for(let r of this._def.values)e[r]=r;return e}extract(e,r=this._def){return t.create(e,{...this._def,...r})}exclude(e,r=this._def){return t.create(this.options.filter(a=>!e.includes(a)),{...this._def,...r})}};Vt.create=Zv;var Gt=class extends ce{_parse(e){let r=ve.getValidEnumValues(this._def.values),a=this._getOrReturnCtx(e);if(a.parsedType!==W.string&&a.parsedType!==W.number){let i=ve.objectValues(r);return V(a,{expected:ve.joinValues(i),received:a.parsedType,code:U.invalid_type}),ae}if(this._cache||(this._cache=new Set(ve.getValidEnumValues(this._def.values))),!this._cache.has(e.data)){let i=ve.objectValues(r);return V(a,{received:a.data,code:U.invalid_enum_value,options:i}),ae}return ta(e.data)}get enum(){return this._def.values}};Gt.create=(t,e)=>new Gt({values:t,typeName:te.ZodNativeEnum,...le(e)});var ft=class extends ce{unwrap(){return this._def.type}_parse(e){let{ctx:r}=this._processInputParams(e);if(r.parsedType!==W.promise&&r.common.async===!1)return V(r,{code:U.invalid_type,expected:W.promise,received:r.parsedType}),ae;let a=r.parsedType===W.promise?r.data:Promise.resolve(r.data);return ta(a.then(i=>this._def.type.parseAsync(i,{path:r.path,errorMap:r.common.contextualErrorMap})))}};ft.create=(t,e)=>new ft({type:t,typeName:te.ZodPromise,...le(e)});var ha=class extends ce{innerType(){return this._def.schema}sourceType(){return this._def.schema._def.typeName===te.ZodEffects?this._def.schema.sourceType():this._def.schema}_parse(e){let{status:r,ctx:a}=this._processInputParams(e),i=this._def.effect||null,s={addIssue:n=>{V(a,n),n.fatal?r.abort():r.dirty()},get path(){return a.path}};if(s.addIssue=s.addIssue.bind(s),i.type==="preprocess"){let n=i.transform(a.data,s);if(a.common.async)return Promise.resolve(n).then(async o=>{if(r.value==="aborted")return ae;let l=await this._def.schema._parseAsync({data:o,path:a.path,parent:a});return l.status==="aborted"?ae:l.status==="dirty"||r.value==="dirty"?Ir(l.value):l});{if(r.value==="aborted")return ae;let o=this._def.schema._parseSync({data:n,path:a.path,parent:a});return o.status==="aborted"?ae:o.status==="dirty"||r.value==="dirty"?Ir(o.value):o}}if(i.type==="refinement"){let n=o=>{let l=i.refinement(o,s);if(a.common.async)return Promise.resolve(l);if(l instanceof Promise)throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead.");return o};if(a.common.async===!1){let o=this._def.schema._parseSync({data:a.data,path:a.path,parent:a});return o.status==="aborted"?ae:(o.status==="dirty"&&r.dirty(),n(o.value),{status:r.value,value:o.value})}else return this._def.schema._parseAsync({data:a.data,path:a.path,parent:a}).then(o=>o.status==="aborted"?ae:(o.status==="dirty"&&r.dirty(),n(o.value).then(()=>({status:r.value,value:o.value}))))}if(i.type==="transform")if(a.common.async===!1){let n=this._def.schema._parseSync({data:a.data,path:a.path,parent:a});if(!qt(n))return ae;let o=i.transform(n.value,s);if(o instanceof Promise)throw new Error("Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.");return{status:r.value,value:o}}else return this._def.schema._parseAsync({data:a.data,path:a.path,parent:a}).then(n=>qt(n)?Promise.resolve(i.transform(n.value,s)).then(o=>({status:r.value,value:o})):ae);ve.assertNever(i)}};ha.create=(t,e,r)=>new ha({schema:t,typeName:te.ZodEffects,effect:e,...le(r)});ha.createWithPreprocess=(t,e,r)=>new ha({schema:e,effect:{type:"preprocess",transform:t},typeName:te.ZodEffects,...le(r)});var Ea=class extends ce{_parse(e){return this._getType(e)===W.undefined?ta(void 0):this._def.innerType._parse(e)}unwrap(){return this._def.innerType}};Ea.create=(t,e)=>new Ea({innerType:t,typeName:te.ZodOptional,...le(e)});var Ba=class extends ce{_parse(e){return this._getType(e)===W.null?ta(null):this._def.innerType._parse(e)}unwrap(){return this._def.innerType}};Ba.create=(t,e)=>new Ba({innerType:t,typeName:te.ZodNullable,...le(e)});var Wt=class extends ce{_parse(e){let{ctx:r}=this._processInputParams(e),a=r.data;return r.parsedType===W.undefined&&(a=this._def.defaultValue()),this._def.innerType._parse({data:a,path:r.path,parent:r})}removeDefault(){return this._def.innerType}};Wt.create=(t,e)=>new Wt({innerType:t,typeName:te.ZodDefault,defaultValue:typeof e.default=="function"?e.default:()=>e.default,...le(e)});var Kt=class extends ce{_parse(e){let{ctx:r}=this._processInputParams(e),a={...r,common:{...r.common,issues:[]}},i=this._def.innerType._parse({data:a.data,path:a.path,parent:{...a}});return jn(i)?i.then(s=>({status:"valid",value:s.status==="valid"?s.value:this._def.catchValue({get error(){return new ma(a.common.issues)},input:a.data})})):{status:"valid",value:i.status==="valid"?i.value:this._def.catchValue({get error(){return new ma(a.common.issues)},input:a.data})}}removeCatch(){return this._def.innerType}};Kt.create=(t,e)=>new Kt({innerType:t,typeName:te.ZodCatch,catchValue:typeof e.catch=="function"?e.catch:()=>e.catch,...le(e)});var Fr=class extends ce{_parse(e){if(this._getType(e)!==W.nan){let a=this._getOrReturnCtx(e);return V(a,{code:U.invalid_type,expected:W.nan,received:a.parsedType}),ae}return{status:"valid",value:e.data}}};Fr.create=t=>new Fr({typeName:te.ZodNaN,...le(t)});var s2=Symbol("zod_brand"),Dn=class extends ce{_parse(e){let{ctx:r}=this._processInputParams(e),a=r.data;return this._def.type._parse({data:a,path:r.path,parent:r})}unwrap(){return this._def.type}},qn=class t extends ce{_parse(e){let{status:r,ctx:a}=this._processInputParams(e);if(a.common.async)return(async()=>{let s=await this._def.in._parseAsync({data:a.data,path:a.path,parent:a});return s.status==="aborted"?ae:s.status==="dirty"?(r.dirty(),Ir(s.value)):this._def.out._parseAsync({data:s.value,path:a.path,parent:a})})();{let i=this._def.in._parseSync({data:a.data,path:a.path,parent:a});return i.status==="aborted"?ae:i.status==="dirty"?(r.dirty(),{status:"dirty",value:i.value}):this._def.out._parseSync({data:i.value,path:a.path,parent:a})}}static create(e,r){return new t({in:e,out:r,typeName:te.ZodPipeline})}},Qt=class extends ce{_parse(e){let r=this._def.innerType._parse(e),a=i=>(qt(i)&&(i.value=Object.freeze(i.value)),i);return jn(r)?r.then(i=>a(i)):a(r)}unwrap(){return this._def.innerType}};Qt.create=(t,e)=>new Qt({innerType:t,typeName:te.ZodReadonly,...le(e)});function yv(t,e){let r=typeof t=="function"?t(e):typeof t=="string"?{message:t}:t;return typeof r=="string"?{message:r}:r}function Vv(t,e={},r){return t?dt.create().superRefine((a,i)=>{let s=t(a);if(s instanceof Promise)return s.then(n=>{if(!n){let o=yv(e,a),l=o.fatal??r??!0;i.addIssue({code:"custom",...o,fatal:l})}});if(!s){let n=yv(e,a),o=n.fatal??r??!0;i.addIssue({code:"custom",...n,fatal:o})}}):dt.create()}var o2={object:oa.lazycreate},te;(function(t){t.ZodString="ZodString",t.ZodNumber="ZodNumber",t.ZodNaN="ZodNaN",t.ZodBigInt="ZodBigInt",t.ZodBoolean="ZodBoolean",t.ZodDate="ZodDate",t.ZodSymbol="ZodSymbol",t.ZodUndefined="ZodUndefined",t.ZodNull="ZodNull",t.ZodAny="ZodAny",t.ZodUnknown="ZodUnknown",t.ZodNever="ZodNever",t.ZodVoid="ZodVoid",t.ZodArray="ZodArray",t.ZodObject="ZodObject",t.ZodUnion="ZodUnion",t.ZodDiscriminatedUnion="ZodDiscriminatedUnion",t.ZodIntersection="ZodIntersection",t.ZodTuple="ZodTuple",t.ZodRecord="ZodRecord",t.ZodMap="ZodMap",t.ZodSet="ZodSet",t.ZodFunction="ZodFunction",t.ZodLazy="ZodLazy",t.ZodLiteral="ZodLiteral",t.ZodEnum="ZodEnum",t.ZodEffects="ZodEffects",t.ZodNativeEnum="ZodNativeEnum",t.ZodOptional="ZodOptional",t.ZodNullable="ZodNullable",t.ZodDefault="ZodDefault",t.ZodCatch="ZodCatch",t.ZodPromise="ZodPromise",t.ZodBranded="ZodBranded",t.ZodPipeline="ZodPipeline",t.ZodReadonly="ZodReadonly"})(te||(te={}));var c2=(t,e={message:`Input not instance of ${t.name}`})=>Vv(r=>r instanceof t,e),Gv=ut.create,Wv=Nt.create,l2=Fr.create,p2=$t.create,Kv=Ft.create,u2=Lt.create,d2=Dr.create,f2=Mt.create,m2=zt.create,h2=dt.create,v2=at.create,g2=Oa.create,x2=qr.create,y2=tt.create,b2=oa.create,w2=oa.strictCreate,_2=Ut.create,E2=es.create,S2=Bt.create,k2=Ua.create,P2=as.create,T2=Nr.create,R2=$r.create,C2=ts.create,A2=Ht.create,O2=Zt.create,I2=Vt.create,j2=Gt.create,D2=ft.create,bv=ha.create,q2=Ea.create,N2=Ba.create,$2=ha.createWithPreprocess,F2=qn.create,L2=()=>Gv().optional(),M2=()=>Wv().optional(),z2=()=>Kv().optional(),U2={string:t=>ut.create({...t,coerce:!0}),number:t=>Nt.create({...t,coerce:!0}),boolean:t=>Ft.create({...t,coerce:!0}),bigint:t=>$t.create({...t,coerce:!0}),date:t=>Lt.create({...t,coerce:!0})},B2=ae;var ss="2.0",Qv=m.union([m.string(),m.number().int()]),Xv=m.string(),H2=m.object({progressToken:m.optional(Qv)}).passthrough(),ka=m.object({_meta:m.optional(H2)}).passthrough(),ca=m.object({method:m.string(),params:m.optional(ka)}),$n=m.object({_meta:m.optional(m.object({}).passthrough())}).passthrough(),Ha=m.object({method:m.string(),params:m.optional($n)}),Pa=m.object({_meta:m.optional(m.object({}).passthrough())}).passthrough(),os=m.union([m.string(),m.number().int()]),Z2=m.object({jsonrpc:m.literal(ss),id:os}).merge(ca).strict();var V2=m.object({jsonrpc:m.literal(ss)}).merge(Ha).strict();var G2=m.object({jsonrpc:m.literal(ss),id:os,result:Pa}).strict();var wv;(function(t){t[t.ConnectionClosed=-32e3]="ConnectionClosed",t[t.RequestTimeout=-32001]="RequestTimeout",t[t.ParseError=-32700]="ParseError",t[t.InvalidRequest=-32600]="InvalidRequest",t[t.MethodNotFound=-32601]="MethodNotFound",t[t.InvalidParams=-32602]="InvalidParams",t[t.InternalError=-32603]="InternalError"})(wv||(wv={}));var W2=m.object({jsonrpc:m.literal(ss),id:os,error:m.object({code:m.number().int(),message:m.string(),data:m.optional(m.unknown())})}).strict();var LR=m.union([Z2,V2,G2,W2]),Jv=Pa.strict(),Yv=Ha.extend({method:m.literal("notifications/cancelled"),params:$n.extend({requestId:os,reason:m.string().optional()})}),Fn=m.object({name:m.string(),title:m.optional(m.string())}).passthrough(),eg=Fn.extend({version:m.string()}),K2=m.object({experimental:m.optional(m.object({}).passthrough()),sampling:m.optional(m.object({}).passthrough()),elicitation:m.optional(m.object({}).passthrough()),roots:m.optional(m.object({listChanged:m.optional(m.boolean())}).passthrough())}).passthrough(),Q2=ca.extend({method:m.literal("initialize"),params:ka.extend({protocolVersion:m.string(),capabilities:K2,clientInfo:eg})}),X2=m.object({experimental:m.optional(m.object({}).passthrough()),logging:m.optional(m.object({}).passthrough()),completions:m.optional(m.object({}).passthrough()),prompts:m.optional(m.object({listChanged:m.optional(m.boolean())}).passthrough()),resources:m.optional(m.object({subscribe:m.optional(m.boolean()),listChanged:m.optional(m.boolean())}).passthrough()),tools:m.optional(m.object({listChanged:m.optional(m.boolean())}).passthrough())}).passthrough(),J2=Pa.extend({protocolVersion:m.string(),capabilities:X2,serverInfo:eg,instructions:m.optional(m.string())}),Y2=Ha.extend({method:m.literal("notifications/initialized")}),ag=ca.extend({method:m.literal("ping")}),e9=m.object({progress:m.number(),total:m.optional(m.number()),message:m.optional(m.string())}).passthrough(),tg=Ha.extend({method:m.literal("notifications/progress"),params:$n.merge(e9).extend({progressToken:Qv})}),cs=ca.extend({params:ka.extend({cursor:m.optional(Xv)}).optional()}),ls=Pa.extend({nextCursor:m.optional(Xv)}),rg=m.object({uri:m.string(),mimeType:m.optional(m.string()),_meta:m.optional(m.object({}).passthrough())}).passthrough(),ng=rg.extend({text:m.string()}),qc=m.string().refine(t=>{try{return atob(t),!0}catch{return!1}},{message:"Invalid Base64 string"}),ig=rg.extend({blob:qc}),sg=Fn.extend({uri:m.string(),description:m.optional(m.string()),mimeType:m.optional(m.string()),_meta:m.optional(m.object({}).passthrough())}),a9=Fn.extend({uriTemplate:m.string(),description:m.optional(m.string()),mimeType:m.optional(m.string()),_meta:m.optional(m.object({}).passthrough())}),t9=cs.extend({method:m.literal("resources/list")}),r9=ls.extend({resources:m.array(sg)}),n9=cs.extend({method:m.literal("resources/templates/list")}),i9=ls.extend({resourceTemplates:m.array(a9)}),s9=ca.extend({method:m.literal("resources/read"),params:ka.extend({uri:m.string()})}),o9=Pa.extend({contents:m.array(m.union([ng,ig]))}),c9=Ha.extend({method:m.literal("notifications/resources/list_changed")}),l9=ca.extend({method:m.literal("resources/subscribe"),params:ka.extend({uri:m.string()})}),p9=ca.extend({method:m.literal("resources/unsubscribe"),params:ka.extend({uri:m.string()})}),u9=Ha.extend({method:m.literal("notifications/resources/updated"),params:$n.extend({uri:m.string()})}),d9=m.object({name:m.string(),description:m.optional(m.string()),required:m.optional(m.boolean())}).passthrough(),f9=Fn.extend({description:m.optional(m.string()),arguments:m.optional(m.array(d9)),_meta:m.optional(m.object({}).passthrough())}),m9=cs.extend({method:m.literal("prompts/list")}),h9=ls.extend({prompts:m.array(f9)}),v9=ca.extend({method:m.literal("prompts/get"),params:ka.extend({name:m.string(),arguments:m.optional(m.record(m.string()))})}),Nc=m.object({type:m.literal("text"),text:m.string(),_meta:m.optional(m.object({}).passthrough())}).passthrough(),$c=m.object({type:m.literal("image"),data:qc,mimeType:m.string(),_meta:m.optional(m.object({}).passthrough())}).passthrough(),Fc=m.object({type:m.literal("audio"),data:qc,mimeType:m.string(),_meta:m.optional(m.object({}).passthrough())}).passthrough(),g9=m.object({type:m.literal("resource"),resource:m.union([ng,ig]),_meta:m.optional(m.object({}).passthrough())}).passthrough(),x9=sg.extend({type:m.literal("resource_link")}),og=m.union([Nc,$c,Fc,x9,g9]),y9=m.object({role:m.enum(["user","assistant"]),content:og}).passthrough(),b9=Pa.extend({description:m.optional(m.string()),messages:m.array(y9)}),w9=Ha.extend({method:m.literal("notifications/prompts/list_changed")}),_9=m.object({title:m.optional(m.string()),readOnlyHint:m.optional(m.boolean()),destructiveHint:m.optional(m.boolean()),idempotentHint:m.optional(m.boolean()),openWorldHint:m.optional(m.boolean())}).passthrough(),E9=Fn.extend({description:m.optional(m.string()),inputSchema:m.object({type:m.literal("object"),properties:m.optional(m.object({}).passthrough()),required:m.optional(m.array(m.string()))}).passthrough(),outputSchema:m.optional(m.object({type:m.literal("object"),properties:m.optional(m.object({}).passthrough()),required:m.optional(m.array(m.string()))}).passthrough()),annotations:m.optional(_9),_meta:m.optional(m.object({}).passthrough())}),S9=cs.extend({method:m.literal("tools/list")}),k9=ls.extend({tools:m.array(E9)}),cg=Pa.extend({content:m.array(og).default([]),structuredContent:m.object({}).passthrough().optional(),isError:m.optional(m.boolean())}),MR=cg.or(Pa.extend({toolResult:m.unknown()})),P9=ca.extend({method:m.literal("tools/call"),params:ka.extend({name:m.string(),arguments:m.optional(m.record(m.unknown()))})}),T9=Ha.extend({method:m.literal("notifications/tools/list_changed")}),lg=m.enum(["debug","info","notice","warning","error","critical","alert","emergency"]),R9=ca.extend({method:m.literal("logging/setLevel"),params:ka.extend({level:lg})}),C9=Ha.extend({method:m.literal("notifications/message"),params:$n.extend({level:lg,logger:m.optional(m.string()),data:m.unknown()})}),A9=m.object({name:m.string().optional()}).passthrough(),O9=m.object({hints:m.optional(m.array(A9)),costPriority:m.optional(m.number().min(0).max(1)),speedPriority:m.optional(m.number().min(0).max(1)),intelligencePriority:m.optional(m.number().min(0).max(1))}).passthrough(),I9=m.object({role:m.enum(["user","assistant"]),content:m.union([Nc,$c,Fc])}).passthrough(),j9=ca.extend({method:m.literal("sampling/createMessage"),params:ka.extend({messages:m.array(I9),systemPrompt:m.optional(m.string()),includeContext:m.optional(m.enum(["none","thisServer","allServers"])),temperature:m.optional(m.number()),maxTokens:m.number().int(),stopSequences:m.optional(m.array(m.string())),metadata:m.optional(m.object({}).passthrough()),modelPreferences:m.optional(O9)})}),D9=Pa.extend({model:m.string(),stopReason:m.optional(m.enum(["endTurn","stopSequence","maxTokens"]).or(m.string())),role:m.enum(["user","assistant"]),content:m.discriminatedUnion("type",[Nc,$c,Fc])}),q9=m.object({type:m.literal("boolean"),title:m.optional(m.string()),description:m.optional(m.string()),default:m.optional(m.boolean())}).passthrough(),N9=m.object({type:m.literal("string"),title:m.optional(m.string()),description:m.optional(m.string()),minLength:m.optional(m.number()),maxLength:m.optional(m.number()),format:m.optional(m.enum(["email","uri","date","date-time"]))}).passthrough(),$9=m.object({type:m.enum(["number","integer"]),title:m.optional(m.string()),description:m.optional(m.string()),minimum:m.optional(m.number()),maximum:m.optional(m.number())}).passthrough(),F9=m.object({type:m.literal("string"),title:m.optional(m.string()),description:m.optional(m.string()),enum:m.array(m.string()),enumNames:m.optional(m.array(m.string()))}).passthrough(),L9=m.union([q9,N9,$9,F9]),M9=ca.extend({method:m.literal("elicitation/create"),params:ka.extend({message:m.string(),requestedSchema:m.object({type:m.literal("object"),properties:m.record(m.string(),L9),required:m.optional(m.array(m.string()))}).passthrough()})}),z9=Pa.extend({action:m.enum(["accept","decline","cancel"]),content:m.optional(m.record(m.string(),m.unknown()))}),U9=m.object({type:m.literal("ref/resource"),uri:m.string()}).passthrough(),B9=m.object({type:m.literal("ref/prompt"),name:m.string()}).passthrough(),H9=ca.extend({method:m.literal("completion/complete"),params:ka.extend({ref:m.union([B9,U9]),argument:m.object({name:m.string(),value:m.string()}).passthrough(),context:m.optional(m.object({arguments:m.optional(m.record(m.string(),m.string()))}))})}),Z9=Pa.extend({completion:m.object({values:m.array(m.string()).max(100),total:m.optional(m.number().int()),hasMore:m.optional(m.boolean())}).passthrough()}),V9=m.object({uri:m.string().startsWith("file://"),name:m.optional(m.string()),_meta:m.optional(m.object({}).passthrough())}).passthrough(),G9=ca.extend({method:m.literal("roots/list")}),W9=Pa.extend({roots:m.array(V9)}),K9=Ha.extend({method:m.literal("notifications/roots/list_changed")}),zR=m.union([ag,Q2,H9,R9,v9,m9,t9,n9,s9,l9,p9,P9,S9]),UR=m.union([Yv,tg,Y2,K9]),BR=m.union([Jv,D9,z9,W9]),HR=m.union([ag,j9,M9,G9]),ZR=m.union([Yv,tg,C9,u9,c9,T9,w9]),VR=m.union([Jv,J2,Z9,b9,h9,r9,i9,o9,cg,k9]);var GR=Q4(O8(),1);var WR=Symbol("Let zodToJsonSchema decide on which parser to use");var KR=new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");var Cc;(function(t){t.Completable="McpCompletable"})(Cc||(Cc={}));var rs=class extends ce{_parse(e){let{ctx:r}=this._processInputParams(e),a=r.data;return this._def.type._parse({data:a,path:r.path,parent:r})}unwrap(){return this._def.type}};rs.create=(t,e)=>new rs({type:t,typeName:Cc.Completable,complete:e.complete,...Q9(e)});function Q9(t){if(!t)return{};let{errorMap:e,invalid_type_error:r,required_error:a,description:i}=t;if(e&&(r||a))throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`);return e?{errorMap:e,description:i}:{errorMap:(n,o)=>{var l,c;let{message:p}=t;return n.code==="invalid_enum_value"?{message:p??o.defaultError}:typeof o.data>"u"?{message:(l=p??a)!==null&&l!==void 0?l:o.defaultError}:n.code!=="invalid_type"?{message:o.defaultError}:{message:(c=p??r)!==null&&c!==void 0?c:o.defaultError}},description:i}}function pg({prompt:t,options:e}){let{systemPrompt:r,settingSources:a,...i}=e??{},s,n;r===void 0?s="":typeof r=="string"?s=r:r.type==="preset"&&(n=r.append);let o=i.pathToClaudeCodeExecutable;if(!o){let l=(0,Pv.fileURLToPath)(X9.url),c=(0,yc.join)(l,"..");o=(0,yc.join)(c,"cli.js")}return process.env.CLAUDE_AGENT_SDK_VERSION="0.1.15",DP({prompt:t,options:{...i,pathToClaudeCodeExecutable:o,customSystemPrompt:s,appendSystemPrompt:n,settingSources:a??[]}})}var fg=Hn(require("better-sqlite3"),1);var la=require("path"),Lc=require("os"),Mc=require("fs");var mt=process.env.CLAUDE_MEM_DATA_DIR||(0,la.join)((0,Lc.homedir)(),".claude-mem"),zc=process.env.CLAUDE_CONFIG_DIR||(0,la.join)((0,Lc.homedir)(),".claude"),JR=(0,la.join)(mt,"archives"),YR=(0,la.join)(mt,"logs"),e5=(0,la.join)(mt,"trash"),a5=(0,la.join)(mt,"backups"),t5=(0,la.join)(mt,"settings.json"),ug=(0,la.join)(mt,"claude-mem.db"),r5=(0,la.join)(zc,"settings.json"),n5=(0,la.join)(zc,"commands"),i5=(0,la.join)(zc,"CLAUDE.md");function dg(t){(0,Mc.mkdirSync)(t,{recursive:!0})}var Uc=(s=>(s[s.DEBUG=0]="DEBUG",s[s.INFO=1]="INFO",s[s.WARN=2]="WARN",s[s.ERROR=3]="ERROR",s[s.SILENT=4]="SILENT",s))(Uc||{}),Bc=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=Uc[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,r){return`obs-${e}-${r}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let r=Object.keys(e);return r.length===0?"{}":r.length<=3?JSON.stringify(e):`{${r.length} keys: ${r.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,r){if(!r)return e;try{let a=typeof r=="string"?JSON.parse(r):r;if(e==="Bash"&&a.command){let i=a.command.length>50?a.command.substring(0,50)+"...":a.command;return`${e}(${i})`}if(e==="Read"&&a.file_path){let i=a.file_path.split("/").pop()||a.file_path;return`${e}(${i})`}if(e==="Edit"&&a.file_path){let i=a.file_path.split("/").pop()||a.file_path;return`${e}(${i})`}if(e==="Write"&&a.file_path){let i=a.file_path.split("/").pop()||a.file_path;return`${e}(${i})`}return e}catch{return e}}log(e,r,a,i,s){if(e0&&(u=` {${Object.entries(g).map(([y,w])=>`${y}=${w}`).join(", ")}}`)}let d=`[${n}] [${o}] [${l}] ${c}${a}${u}${p}`;e===3?console.error(d):console.log(d)}debug(e,r,a,i){this.log(0,e,r,a,i)}info(e,r,a,i){this.log(1,e,r,a,i)}warn(e,r,a,i){this.log(2,e,r,a,i)}error(e,r,a,i){this.log(3,e,r,a,i)}dataIn(e,r,a,i){this.info(e,`\u2192 ${r}`,a,i)}dataOut(e,r,a,i){this.info(e,`\u2190 ${r}`,a,i)}success(e,r,a,i){this.info(e,`\u2713 ${r}`,a,i)}failure(e,r,a,i){this.error(e,`\u2717 ${r}`,a,i)}timing(e,r,a,i){this.info(e,`\u23F1 ${r}`,i,{duration:`${a}ms`})}},pe=new Bc;var Ia=class{db;constructor(){dg(mt),this.db=new fg.default(ug),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(a=>a.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[HooksDatabase] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[HooksDatabase] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(c=>c.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[HooksDatabase] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to session_summaries table"));let l=this.db.pragma("index_list(session_summaries)").some(c=>c.unique===1)}catch(e){console.error("[HooksDatabase] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(a=>a.unique===1))return;console.error("[HooksDatabase] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` +`+JSON.stringify(s,null,2):p=" "+this.formatData(s));let u="";if(i){let{sessionId:h,sdkSessionId:v,correlationId:f,...g}=i;Object.keys(g).length>0&&(u=` {${Object.entries(g).map(([y,w])=>`${y}=${w}`).join(", ")}}`)}let d=`[${n}] [${o}] [${l}] ${c}${a}${u}${p}`;e===3?console.error(d):console.log(d)}debug(e,r,a,i){this.log(0,e,r,a,i)}info(e,r,a,i){this.log(1,e,r,a,i)}warn(e,r,a,i){this.log(2,e,r,a,i)}error(e,r,a,i){this.log(3,e,r,a,i)}dataIn(e,r,a,i){this.info(e,`\u2192 ${r}`,a,i)}dataOut(e,r,a,i){this.info(e,`\u2190 ${r}`,a,i)}success(e,r,a,i){this.info(e,`\u2713 ${r}`,a,i)}failure(e,r,a,i){this.error(e,`\u2717 ${r}`,a,i)}timing(e,r,a,i){this.info(e,`\u23F1 ${r}`,i,{duration:`${a}ms`})}},pe=new Bc;var Ia=class{db;constructor(){dg(mt),this.db=new fg.default(ug),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(a=>a.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[SessionStore] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[SessionStore] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(c=>c.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[SessionStore] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to session_summaries table"));let l=this.db.pragma("index_list(session_summaries)").some(c=>c.unique===1)}catch(e){console.error("[SessionStore] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(a=>a.unique===1))return;console.error("[SessionStore] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE session_summaries_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -88,7 +88,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let r=Obje CREATE INDEX idx_session_summaries_sdk_session ON session_summaries(sdk_session_id); CREATE INDEX idx_session_summaries_project ON session_summaries(project); CREATE INDEX idx_session_summaries_created ON session_summaries(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(a){throw this.db.exec("ROLLBACK"),a}}catch(e){console.error("[HooksDatabase] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(a=>a.name==="title"))return;console.error("[HooksDatabase] Adding hierarchical fields to observations table..."),this.db.exec(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(a){throw this.db.exec("ROLLBACK"),a}}catch(e){console.error("[SessionStore] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(a=>a.name==="title"))return;console.error("[SessionStore] Adding hierarchical fields to observations table..."),this.db.exec(` ALTER TABLE observations ADD COLUMN title TEXT; ALTER TABLE observations ADD COLUMN subtitle TEXT; ALTER TABLE observations ADD COLUMN facts TEXT; @@ -96,7 +96,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let r=Obje ALTER TABLE observations ADD COLUMN concepts TEXT; ALTER TABLE observations ADD COLUMN files_read TEXT; ALTER TABLE observations ADD COLUMN files_modified TEXT; - `),console.error("[HooksDatabase] Successfully added hierarchical fields to observations table")}catch(e){console.error("[HooksDatabase] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let r=this.db.pragma("table_info(observations)").find(a=>a.name==="text");if(!r||r.notnull===0)return;console.error("[HooksDatabase] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` + `),console.error("[SessionStore] Successfully added hierarchical fields to observations table")}catch(e){console.error("[SessionStore] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let r=this.db.pragma("table_info(observations)").find(a=>a.name==="text");if(!r||r.notnull===0)return;console.error("[SessionStore] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE observations_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -126,7 +126,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let r=Obje CREATE INDEX idx_observations_project ON observations(project); CREATE INDEX idx_observations_type ON observations(type); CREATE INDEX idx_observations_created ON observations(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully made observations.text nullable")}catch(a){throw this.db.exec("ROLLBACK"),a}}catch(e){console.error("[HooksDatabase] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,r=10){return this.db.prepare(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully made observations.text nullable")}catch(a){throw this.db.exec("ROLLBACK"),a}}catch(e){console.error("[SessionStore] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,r=10){return this.db.prepare(` SELECT request, investigated, learned, completed, next_steps, files_read, files_edited, notes, prompt_number, created_at diff --git a/plugin/scripts/cleanup-hook.js b/plugin/scripts/cleanup-hook.js index 4659fda3..3a57f7e7 100755 --- a/plugin/scripts/cleanup-hook.js +++ b/plugin/scripts/cleanup-hook.js @@ -1,7 +1,7 @@ #!/usr/bin/env node -import N from"better-sqlite3";import{join as a,dirname as P,basename as B}from"path";import{homedir as k}from"os";import{existsSync as j,mkdirSync as I}from"fs";var c=process.env.CLAUDE_MEM_DATA_DIR||a(k(),".claude-mem"),u=process.env.CLAUDE_CONFIG_DIR||a(k(),".claude"),W=a(c,"archives"),G=a(c,"logs"),q=a(c,"trash"),K=a(c,"backups"),Y=a(c,"settings.json"),S=a(c,"claude-mem.db"),J=a(u,"settings.json"),V=a(u,"commands"),Q=a(u,"CLAUDE.md");function R(o){I(o,{recursive:!0})}var _=(n=>(n[n.DEBUG=0]="DEBUG",n[n.INFO=1]="INFO",n[n.WARN=2]="WARN",n[n.ERROR=3]="ERROR",n[n.SILENT=4]="SILENT",n))(_||{}),E=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=_[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,t){return`obs-${e}-${t}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} -${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Object.keys(e);return t.length===0?"{}":t.length<=3?JSON.stringify(e):`{${t.length} keys: ${t.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,t){if(!t)return e;try{let s=typeof t=="string"?JSON.parse(t):t;if(e==="Bash"&&s.command){let r=s.command.length>50?s.command.substring(0,50)+"...":s.command;return`${e}(${r})`}if(e==="Read"&&s.file_path){let r=s.file_path.split("/").pop()||s.file_path;return`${e}(${r})`}if(e==="Edit"&&s.file_path){let r=s.file_path.split("/").pop()||s.file_path;return`${e}(${r})`}if(e==="Write"&&s.file_path){let r=s.file_path.split("/").pop()||s.file_path;return`${e}(${r})`}return e}catch{return e}}log(e,t,s,r,n){if(e0&&(T=` {${Object.entries(h).map(([O,v])=>`${O}=${v}`).join(", ")}}`)}let f=`[${d}] [${l}] [${b}] ${i}${s}${T}${p}`;e===3?console.error(f):console.log(f)}debug(e,t,s,r){this.log(0,e,t,s,r)}info(e,t,s,r){this.log(1,e,t,s,r)}warn(e,t,s,r){this.log(2,e,t,s,r)}error(e,t,s,r){this.log(3,e,t,s,r)}dataIn(e,t,s,r){this.info(e,`\u2192 ${t}`,s,r)}dataOut(e,t,s,r){this.info(e,`\u2190 ${t}`,s,r)}success(e,t,s,r){this.info(e,`\u2713 ${t}`,s,r)}failure(e,t,s,r){this.error(e,`\u2717 ${t}`,s,r)}timing(e,t,s,r){this.info(e,`\u23F1 ${t}`,r,{duration:`${s}ms`})}},D=new E;var m=class{db;constructor(){R(c),this.db=new N(S),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(s=>s.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[HooksDatabase] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[HooksDatabase] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(i=>i.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[HooksDatabase] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(i=>i.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(i=>i.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to session_summaries table"));let b=this.db.pragma("index_list(session_summaries)").some(i=>i.unique===1)}catch(e){console.error("[HooksDatabase] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(s=>s.unique===1))return;console.error("[HooksDatabase] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` +import N from"better-sqlite3";import{join as a,dirname as B,basename as H}from"path";import{homedir as S}from"os";import{existsSync as j,mkdirSync as I}from"fs";var c=process.env.CLAUDE_MEM_DATA_DIR||a(S(),".claude-mem"),u=process.env.CLAUDE_CONFIG_DIR||a(S(),".claude"),W=a(c,"archives"),G=a(c,"logs"),q=a(c,"trash"),K=a(c,"backups"),Y=a(c,"settings.json"),R=a(c,"claude-mem.db"),J=a(u,"settings.json"),V=a(u,"commands"),Q=a(u,"CLAUDE.md");function L(o){I(o,{recursive:!0})}var _=(n=>(n[n.DEBUG=0]="DEBUG",n[n.INFO=1]="INFO",n[n.WARN=2]="WARN",n[n.ERROR=3]="ERROR",n[n.SILENT=4]="SILENT",n))(_||{}),E=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=_[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,t){return`obs-${e}-${t}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} +${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Object.keys(e);return t.length===0?"{}":t.length<=3?JSON.stringify(e):`{${t.length} keys: ${t.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,t){if(!t)return e;try{let s=typeof t=="string"?JSON.parse(t):t;if(e==="Bash"&&s.command){let r=s.command.length>50?s.command.substring(0,50)+"...":s.command;return`${e}(${r})`}if(e==="Read"&&s.file_path){let r=s.file_path.split("/").pop()||s.file_path;return`${e}(${r})`}if(e==="Edit"&&s.file_path){let r=s.file_path.split("/").pop()||s.file_path;return`${e}(${r})`}if(e==="Write"&&s.file_path){let r=s.file_path.split("/").pop()||s.file_path;return`${e}(${r})`}return e}catch{return e}}log(e,t,s,r,n){if(e0&&(b=` {${Object.entries(h).map(([O,v])=>`${O}=${v}`).join(", ")}}`)}let f=`[${d}] [${l}] [${T}] ${i}${s}${b}${p}`;e===3?console.error(f):console.log(f)}debug(e,t,s,r){this.log(0,e,t,s,r)}info(e,t,s,r){this.log(1,e,t,s,r)}warn(e,t,s,r){this.log(2,e,t,s,r)}error(e,t,s,r){this.log(3,e,t,s,r)}dataIn(e,t,s,r){this.info(e,`\u2192 ${t}`,s,r)}dataOut(e,t,s,r){this.info(e,`\u2190 ${t}`,s,r)}success(e,t,s,r){this.info(e,`\u2713 ${t}`,s,r)}failure(e,t,s,r){this.error(e,`\u2717 ${t}`,s,r)}timing(e,t,s,r){this.info(e,`\u23F1 ${t}`,r,{duration:`${s}ms`})}},k=new E;var m=class{db;constructor(){L(c),this.db=new N(R),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(s=>s.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[SessionStore] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[SessionStore] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(i=>i.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[SessionStore] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(i=>i.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(i=>i.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to session_summaries table"));let T=this.db.pragma("index_list(session_summaries)").some(i=>i.unique===1)}catch(e){console.error("[SessionStore] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(s=>s.unique===1))return;console.error("[SessionStore] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE session_summaries_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -29,7 +29,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje CREATE INDEX idx_session_summaries_sdk_session ON session_summaries(sdk_session_id); CREATE INDEX idx_session_summaries_project ON session_summaries(project); CREATE INDEX idx_session_summaries_created ON session_summaries(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[HooksDatabase] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(s=>s.name==="title"))return;console.error("[HooksDatabase] Adding hierarchical fields to observations table..."),this.db.exec(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[SessionStore] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(s=>s.name==="title"))return;console.error("[SessionStore] Adding hierarchical fields to observations table..."),this.db.exec(` ALTER TABLE observations ADD COLUMN title TEXT; ALTER TABLE observations ADD COLUMN subtitle TEXT; ALTER TABLE observations ADD COLUMN facts TEXT; @@ -37,7 +37,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje ALTER TABLE observations ADD COLUMN concepts TEXT; ALTER TABLE observations ADD COLUMN files_read TEXT; ALTER TABLE observations ADD COLUMN files_modified TEXT; - `),console.error("[HooksDatabase] Successfully added hierarchical fields to observations table")}catch(e){console.error("[HooksDatabase] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let t=this.db.pragma("table_info(observations)").find(s=>s.name==="text");if(!t||t.notnull===0)return;console.error("[HooksDatabase] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` + `),console.error("[SessionStore] Successfully added hierarchical fields to observations table")}catch(e){console.error("[SessionStore] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let t=this.db.pragma("table_info(observations)").find(s=>s.name==="text");if(!t||t.notnull===0)return;console.error("[SessionStore] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE observations_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -67,7 +67,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje CREATE INDEX idx_observations_project ON observations(project); CREATE INDEX idx_observations_type ON observations(type); CREATE INDEX idx_observations_created ON observations(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully made observations.text nullable")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[HooksDatabase] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,t=10){return this.db.prepare(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully made observations.text nullable")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[SessionStore] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,t=10){return this.db.prepare(` SELECT request, investigated, learned, completed, next_steps, files_read, files_edited, notes, prompt_number, created_at @@ -146,7 +146,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje UPDATE sdk_sessions SET sdk_session_id = ? WHERE id = ? AND sdk_session_id IS NULL - `).run(t,e).changes===0?(D.debug("DB","sdk_session_id already set, skipping update",{sessionId:e,sdkSessionId:t}),!1):!0}setWorkerPort(e,t){this.db.prepare(` + `).run(t,e).changes===0?(k.debug("DB","sdk_session_id already set, skipping update",{sessionId:e,sdkSessionId:t}),!1):!0}setWorkerPort(e,t){this.db.prepare(` UPDATE sdk_sessions SET worker_port = ? WHERE id = ? @@ -177,5 +177,5 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje UPDATE sdk_sessions SET status = 'failed', completed_at = ?, completed_at_epoch = ? WHERE status = 'active' - `).run(e.toISOString(),t).changes}close(){this.db.close()}};async function L(o){try{console.error("[claude-mem cleanup] Hook fired",{input:o?{session_id:o.session_id,cwd:o.cwd,reason:o.reason}:null}),o||(console.log("No input provided - this script is designed to run as a Claude Code SessionEnd hook"),console.log(` -Expected input format:`),console.log(JSON.stringify({session_id:"string",cwd:"string",transcript_path:"string",hook_event_name:"SessionEnd",reason:"exit"},null,2)),process.exit(0));let{session_id:e,reason:t}=o;console.error("[claude-mem cleanup] Searching for active SDK session",{session_id:e,reason:t});let s=new m,r=s.findActiveSDKSession(e);if(r||(console.error("[claude-mem cleanup] No active SDK session found",{session_id:e}),s.close(),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)),console.error("[claude-mem cleanup] Active SDK session found",{session_id:r.id,sdk_session_id:r.sdk_session_id,project:r.project,worker_port:r.worker_port}),r.worker_port)try{let n=await fetch(`http://127.0.0.1:${r.worker_port}/sessions/${r.id}`,{method:"DELETE",signal:AbortSignal.timeout(5e3)});n.ok?console.error("[claude-mem cleanup] Session deleted successfully via HTTP"):console.error("[claude-mem cleanup] Failed to delete session:",await n.text())}catch(n){console.error("[claude-mem cleanup] HTTP DELETE error:",n.message)}else console.error("[claude-mem cleanup] No worker port, cannot send DELETE request");try{s.markSessionFailed(r.id),console.error("[claude-mem cleanup] Session marked as failed in database")}catch(n){console.error("[claude-mem cleanup] Failed to mark session as failed:",n)}s.close(),console.error("[claude-mem cleanup] Cleanup completed successfully"),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}catch(e){console.error("[claude-mem cleanup] Unexpected error in hook",{error:e.message,stack:e.stack,name:e.name}),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}}import{stdin as A}from"process";var g="";A.on("data",o=>g+=o);A.on("end",async()=>{try{let o=g.trim()?JSON.parse(g):void 0;await L(o)}catch(o){console.error(`[claude-mem cleanup-hook error: ${o.message}]`),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}}); + `).run(e.toISOString(),t).changes}close(){this.db.close()}};async function A(o){try{console.error("[claude-mem cleanup] Hook fired",{input:o?{session_id:o.session_id,cwd:o.cwd,reason:o.reason}:null}),o||(console.log("No input provided - this script is designed to run as a Claude Code SessionEnd hook"),console.log(` +Expected input format:`),console.log(JSON.stringify({session_id:"string",cwd:"string",transcript_path:"string",hook_event_name:"SessionEnd",reason:"exit"},null,2)),process.exit(0));let{session_id:e,reason:t}=o;console.error("[claude-mem cleanup] Searching for active SDK session",{session_id:e,reason:t});let s=new m,r=s.findActiveSDKSession(e);if(r||(console.error("[claude-mem cleanup] No active SDK session found",{session_id:e}),s.close(),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)),console.error("[claude-mem cleanup] Active SDK session found",{session_id:r.id,sdk_session_id:r.sdk_session_id,project:r.project,worker_port:r.worker_port}),r.worker_port)try{let n=await fetch(`http://127.0.0.1:${r.worker_port}/sessions/${r.id}`,{method:"DELETE",signal:AbortSignal.timeout(5e3)});n.ok?console.error("[claude-mem cleanup] Session deleted successfully via HTTP"):console.error("[claude-mem cleanup] Failed to delete session:",await n.text())}catch(n){console.error("[claude-mem cleanup] HTTP DELETE error:",n.message)}else console.error("[claude-mem cleanup] No worker port, cannot send DELETE request");try{s.markSessionFailed(r.id),console.error("[claude-mem cleanup] Session marked as failed in database")}catch(n){console.error("[claude-mem cleanup] Failed to mark session as failed:",n)}s.close(),console.error("[claude-mem cleanup] Cleanup completed successfully"),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}catch(e){console.error("[claude-mem cleanup] Unexpected error in hook",{error:e.message,stack:e.stack,name:e.name}),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}}import{stdin as D}from"process";var g="";D.on("data",o=>g+=o);D.on("end",async()=>{try{let o=g.trim()?JSON.parse(g):void 0;await A(o)}catch(o){console.error(`[claude-mem cleanup-hook error: ${o.message}]`),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}}); diff --git a/plugin/scripts/context-hook.js b/plugin/scripts/context-hook.js index f38bb37b..71bbe80f 100755 --- a/plugin/scripts/context-hook.js +++ b/plugin/scripts/context-hook.js @@ -1,7 +1,7 @@ #!/usr/bin/env node -import N from"path";import I from"better-sqlite3";import{join as p,dirname as H,basename as P}from"path";import{homedir as S}from"os";import{existsSync as X,mkdirSync as y}from"fs";var d=process.env.CLAUDE_MEM_DATA_DIR||p(S(),".claude-mem"),_=process.env.CLAUDE_CONFIG_DIR||p(S(),".claude"),W=p(d,"archives"),G=p(d,"logs"),q=p(d,"trash"),Y=p(d,"backups"),J=p(d,"settings.json"),D=p(d,"claude-mem.db"),K=p(_,"settings.json"),V=p(_,"commands"),Q=p(_,"CLAUDE.md");function k(c){y(c,{recursive:!0})}var E=(r=>(r[r.DEBUG=0]="DEBUG",r[r.INFO=1]="INFO",r[r.WARN=2]="WARN",r[r.ERROR=3]="ERROR",r[r.SILENT=4]="SILENT",r))(E||{}),g=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=E[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,t){return`obs-${e}-${t}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} +import C from"path";import O from"better-sqlite3";import{join as p,dirname as P,basename as B}from"path";import{homedir as R}from"os";import{existsSync as X,mkdirSync as N}from"fs";var d=process.env.CLAUDE_MEM_DATA_DIR||p(R(),".claude-mem"),_=process.env.CLAUDE_CONFIG_DIR||p(R(),".claude"),W=p(d,"archives"),G=p(d,"logs"),q=p(d,"trash"),Y=p(d,"backups"),J=p(d,"settings.json"),A=p(d,"claude-mem.db"),K=p(_,"settings.json"),V=p(_,"commands"),Q=p(_,"CLAUDE.md");function L(c){N(c,{recursive:!0})}var E=(r=>(r[r.DEBUG=0]="DEBUG",r[r.INFO=1]="INFO",r[r.WARN=2]="WARN",r[r.ERROR=3]="ERROR",r[r.SILENT=4]="SILENT",r))(E||{}),g=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=E[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,t){return`obs-${e}-${t}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Object.keys(e);return t.length===0?"{}":t.length<=3?JSON.stringify(e):`{${t.length} keys: ${t.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,t){if(!t)return e;try{let s=typeof t=="string"?JSON.parse(t):t;if(e==="Bash"&&s.command){let n=s.command.length>50?s.command.substring(0,50)+"...":s.command;return`${e}(${n})`}if(e==="Read"&&s.file_path){let n=s.file_path.split("/").pop()||s.file_path;return`${e}(${n})`}if(e==="Edit"&&s.file_path){let n=s.file_path.split("/").pop()||s.file_path;return`${e}(${n})`}if(e==="Write"&&s.file_path){let n=s.file_path.split("/").pop()||s.file_path;return`${e}(${n})`}return e}catch{return e}}log(e,t,s,n,r){if(e0&&(h=` {${Object.entries(R).map(([L,v])=>`${L}=${v}`).join(", ")}}`)}let f=`[${i}] [${o}] [${u}] ${a}${s}${h}${l}`;e===3?console.error(f):console.log(f)}debug(e,t,s,n){this.log(0,e,t,s,n)}info(e,t,s,n){this.log(1,e,t,s,n)}warn(e,t,s,n){this.log(2,e,t,s,n)}error(e,t,s,n){this.log(3,e,t,s,n)}dataIn(e,t,s,n){this.info(e,`\u2192 ${t}`,s,n)}dataOut(e,t,s,n){this.info(e,`\u2190 ${t}`,s,n)}success(e,t,s,n){this.info(e,`\u2713 ${t}`,s,n)}failure(e,t,s,n){this.error(e,`\u2717 ${t}`,s,n)}timing(e,t,s,n){this.info(e,`\u23F1 ${t}`,n,{duration:`${s}ms`})}},A=new g;var m=class{db;constructor(){k(d),this.db=new I(D),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(s=>s.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[HooksDatabase] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[HooksDatabase] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(a=>a.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[HooksDatabase] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(a=>a.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(a=>a.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to session_summaries table"));let u=this.db.pragma("index_list(session_summaries)").some(a=>a.unique===1)}catch(e){console.error("[HooksDatabase] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(s=>s.unique===1))return;console.error("[HooksDatabase] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` +`+JSON.stringify(r,null,2):l=" "+this.formatData(r));let h="";if(n){let{sessionId:D,sdkSessionId:k,correlationId:x,...S}=n;Object.keys(S).length>0&&(h=` {${Object.entries(S).map(([y,I])=>`${y}=${I}`).join(", ")}}`)}let f=`[${i}] [${o}] [${u}] ${a}${s}${h}${l}`;e===3?console.error(f):console.log(f)}debug(e,t,s,n){this.log(0,e,t,s,n)}info(e,t,s,n){this.log(1,e,t,s,n)}warn(e,t,s,n){this.log(2,e,t,s,n)}error(e,t,s,n){this.log(3,e,t,s,n)}dataIn(e,t,s,n){this.info(e,`\u2192 ${t}`,s,n)}dataOut(e,t,s,n){this.info(e,`\u2190 ${t}`,s,n)}success(e,t,s,n){this.info(e,`\u2713 ${t}`,s,n)}failure(e,t,s,n){this.error(e,`\u2717 ${t}`,s,n)}timing(e,t,s,n){this.info(e,`\u23F1 ${t}`,n,{duration:`${s}ms`})}},v=new g;var m=class{db;constructor(){L(d),this.db=new O(A),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(s=>s.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[SessionStore] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[SessionStore] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(a=>a.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[SessionStore] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(a=>a.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(a=>a.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to session_summaries table"));let u=this.db.pragma("index_list(session_summaries)").some(a=>a.unique===1)}catch(e){console.error("[SessionStore] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(s=>s.unique===1))return;console.error("[SessionStore] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE session_summaries_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -29,7 +29,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje CREATE INDEX idx_session_summaries_sdk_session ON session_summaries(sdk_session_id); CREATE INDEX idx_session_summaries_project ON session_summaries(project); CREATE INDEX idx_session_summaries_created ON session_summaries(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[HooksDatabase] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(s=>s.name==="title"))return;console.error("[HooksDatabase] Adding hierarchical fields to observations table..."),this.db.exec(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[SessionStore] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(s=>s.name==="title"))return;console.error("[SessionStore] Adding hierarchical fields to observations table..."),this.db.exec(` ALTER TABLE observations ADD COLUMN title TEXT; ALTER TABLE observations ADD COLUMN subtitle TEXT; ALTER TABLE observations ADD COLUMN facts TEXT; @@ -37,7 +37,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje ALTER TABLE observations ADD COLUMN concepts TEXT; ALTER TABLE observations ADD COLUMN files_read TEXT; ALTER TABLE observations ADD COLUMN files_modified TEXT; - `),console.error("[HooksDatabase] Successfully added hierarchical fields to observations table")}catch(e){console.error("[HooksDatabase] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let t=this.db.pragma("table_info(observations)").find(s=>s.name==="text");if(!t||t.notnull===0)return;console.error("[HooksDatabase] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` + `),console.error("[SessionStore] Successfully added hierarchical fields to observations table")}catch(e){console.error("[SessionStore] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let t=this.db.pragma("table_info(observations)").find(s=>s.name==="text");if(!t||t.notnull===0)return;console.error("[SessionStore] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE observations_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -67,7 +67,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje CREATE INDEX idx_observations_project ON observations(project); CREATE INDEX idx_observations_type ON observations(type); CREATE INDEX idx_observations_created ON observations(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully made observations.text nullable")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[HooksDatabase] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,t=10){return this.db.prepare(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully made observations.text nullable")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[SessionStore] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,t=10){return this.db.prepare(` SELECT request, investigated, learned, completed, next_steps, files_read, files_edited, notes, prompt_number, created_at @@ -146,7 +146,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje UPDATE sdk_sessions SET sdk_session_id = ? WHERE id = ? AND sdk_session_id IS NULL - `).run(t,e).changes===0?(A.debug("DB","sdk_session_id already set, skipping update",{sessionId:e,sdkSessionId:t}),!1):!0}setWorkerPort(e,t){this.db.prepare(` + `).run(t,e).changes===0?(v.debug("DB","sdk_session_id already set, skipping update",{sessionId:e,sdkSessionId:t}),!1):!0}setWorkerPort(e,t){this.db.prepare(` UPDATE sdk_sessions SET worker_port = ? WHERE id = ? @@ -177,7 +177,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje UPDATE sdk_sessions SET status = 'failed', completed_at = ?, completed_at_epoch = ? WHERE status = 'active' - `).run(e.toISOString(),t).changes}close(){this.db.close()}};function b(c){let e=c?.cwd??process.cwd(),t=e?N.basename(e):"unknown-project",s=new m;try{let n=s.getRecentSessionsWithStatus(t,3);if(n.length===0){console.log(`# Recent Session Context + `).run(e.toISOString(),t).changes}close(){this.db.close()}};function T(c){let e=c?.cwd??process.cwd(),t=e?C.basename(e):"unknown-project",s=new m;try{let n=s.getRecentSessionsWithStatus(t,3);if(n.length===0){console.log(`# Recent Session Context No previous sessions found for this project yet.`);return}let r=[];r.push("# Recent Session Context"),r.push(""),r.push(`Showing last ${n.length} session(s) for **${t}**:`),r.push("");for(let i of n)if(i.sdk_session_id){if(r.push("---"),r.push(""),i.has_summary){let o=s.getSummaryForSession(i.sdk_session_id);if(o){let u=o.prompt_number?` (Prompt #${o.prompt_number})`:"";if(r.push(`**Summary${u}**`),r.push(""),o.request&&r.push(`**Request:** ${o.request}`),o.completed&&r.push(`**Completed:** ${o.completed}`),o.learned&&r.push(`**Learned:** ${o.learned}`),o.next_steps&&r.push(`**Next Steps:** ${o.next_steps}`),o.files_read)try{let a=JSON.parse(o.files_read);Array.isArray(a)&&a.length>0&&r.push(`**Files Read:** ${a.join(", ")}`)}catch{o.files_read.trim()&&r.push(`**Files Read:** ${o.files_read}`)}if(o.files_edited)try{let a=JSON.parse(o.files_edited);Array.isArray(a)&&a.length>0&&r.push(`**Files Edited:** ${a.join(", ")}`)}catch{o.files_edited.trim()&&r.push(`**Files Edited:** ${o.files_edited}`)}r.push(`**Date:** ${o.created_at.split("T")[0]}`)}}else if(i.status==="active"){r.push("**In Progress**"),r.push(""),i.user_prompt&&r.push(`**Request:** ${i.user_prompt}`);let o=s.getObservationsForSession(i.sdk_session_id);if(o.length>0){r.push(""),r.push(`**Observations (${o.length}):**`);for(let u of o)r.push(`- ${u.title}`)}else r.push(""),r.push("*No observations yet*");r.push(""),r.push("**Status:** Active - summary pending"),r.push(`**Date:** ${i.started_at.split("T")[0]}`)}else r.push(`**${i.status.charAt(0).toUpperCase()+i.status.slice(1)}**`),r.push(""),i.user_prompt&&r.push(`**Request:** ${i.user_prompt}`),r.push(""),r.push(`**Status:** ${i.status} - no summary available`),r.push(`**Date:** ${i.started_at.split("T")[0]}`);r.push("")}console.log(r.join(` -`))}finally{s.close()}}import{stdin as T}from"process";try{if(T.isTTY)b();else{let c="";T.on("data",e=>c+=e),T.on("end",()=>{let e=c.trim()?JSON.parse(c):void 0;b(e),process.exit(0)})}}catch(c){console.error(`[claude-mem context-hook error: ${c.message}]`),process.exit(0)} +`))}finally{s.close()}}import{stdin as b}from"process";try{if(b.isTTY)T();else{let c="";b.on("data",e=>c+=e),b.on("end",()=>{let e=c.trim()?JSON.parse(c):void 0;T(e),process.exit(0)})}}catch(c){console.error(`[claude-mem context-hook error: ${c.message}]`),process.exit(0)} diff --git a/plugin/scripts/new-hook.js b/plugin/scripts/new-hook.js index da47009b..44391173 100755 --- a/plugin/scripts/new-hook.js +++ b/plugin/scripts/new-hook.js @@ -1,7 +1,7 @@ #!/usr/bin/env node -import x from"path";import I from"better-sqlite3";import{join as u,dirname as j,basename as X}from"path";import{homedir as k}from"os";import{existsSync as K,mkdirSync as y}from"fs";var m=process.env.CLAUDE_MEM_DATA_DIR||u(k(),".claude-mem"),g=process.env.CLAUDE_CONFIG_DIR||u(k(),".claude"),J=u(m,"archives"),Y=u(m,"logs"),V=u(m,"trash"),Q=u(m,"backups"),z=u(m,"settings.json"),R=u(m,"claude-mem.db"),Z=u(g,"settings.json"),ee=u(g,"commands"),se=u(g,"CLAUDE.md");function O(o){y(o,{recursive:!0})}var b=(n=>(n[n.DEBUG=0]="DEBUG",n[n.INFO=1]="INFO",n[n.WARN=2]="WARN",n[n.ERROR=3]="ERROR",n[n.SILENT=4]="SILENT",n))(b||{}),T=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=b[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,s){return`obs-${e}-${s}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} +import x from"path";import v from"better-sqlite3";import{join as u,dirname as j,basename as X}from"path";import{homedir as R}from"os";import{existsSync as K,mkdirSync as I}from"fs";var m=process.env.CLAUDE_MEM_DATA_DIR||u(R(),".claude-mem"),g=process.env.CLAUDE_CONFIG_DIR||u(R(),".claude"),J=u(m,"archives"),Y=u(m,"logs"),V=u(m,"trash"),Q=u(m,"backups"),z=u(m,"settings.json"),k=u(m,"claude-mem.db"),Z=u(g,"settings.json"),ee=u(g,"commands"),se=u(g,"CLAUDE.md");function O(o){I(o,{recursive:!0})}var b=(n=>(n[n.DEBUG=0]="DEBUG",n[n.INFO=1]="INFO",n[n.WARN=2]="WARN",n[n.ERROR=3]="ERROR",n[n.SILENT=4]="SILENT",n))(b||{}),T=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=b[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,s){return`obs-${e}-${s}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Object.keys(e);return s.length===0?"{}":s.length<=3?JSON.stringify(e):`{${s.length} keys: ${s.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,s){if(!s)return e;try{let t=typeof s=="string"?JSON.parse(s):s;if(e==="Bash"&&t.command){let r=t.command.length>50?t.command.substring(0,50)+"...":t.command;return`${e}(${r})`}if(e==="Read"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}if(e==="Edit"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}if(e==="Write"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}return e}catch{return e}}log(e,s,t,r,n){if(e0&&(l=` {${Object.entries(S).map(([C,N])=>`${C}=${N}`).join(", ")}}`)}let h=`[${a}] [${i}] [${d}] ${c}${t}${l}${p}`;e===3?console.error(h):console.log(h)}debug(e,s,t,r){this.log(0,e,s,t,r)}info(e,s,t,r){this.log(1,e,s,t,r)}warn(e,s,t,r){this.log(2,e,s,t,r)}error(e,s,t,r){this.log(3,e,s,t,r)}dataIn(e,s,t,r){this.info(e,`\u2192 ${s}`,t,r)}dataOut(e,s,t,r){this.info(e,`\u2190 ${s}`,t,r)}success(e,s,t,r){this.info(e,`\u2713 ${s}`,t,r)}failure(e,s,t,r){this.error(e,`\u2717 ${s}`,t,r)}timing(e,s,t,r){this.info(e,`\u23F1 ${s}`,r,{duration:`${t}ms`})}},D=new T;var _=class{db;constructor(){O(m),this.db=new I(R),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(t=>t.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[HooksDatabase] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[HooksDatabase] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(c=>c.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[HooksDatabase] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to session_summaries table"));let d=this.db.pragma("index_list(session_summaries)").some(c=>c.unique===1)}catch(e){console.error("[HooksDatabase] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(t=>t.unique===1))return;console.error("[HooksDatabase] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` +`+JSON.stringify(n,null,2):p=" "+this.formatData(n));let l="";if(r){let{sessionId:U,sdkSessionId:P,correlationId:M,...h}=r;Object.keys(h).length>0&&(l=` {${Object.entries(h).map(([N,y])=>`${N}=${y}`).join(", ")}}`)}let S=`[${a}] [${i}] [${d}] ${c}${t}${l}${p}`;e===3?console.error(S):console.log(S)}debug(e,s,t,r){this.log(0,e,s,t,r)}info(e,s,t,r){this.log(1,e,s,t,r)}warn(e,s,t,r){this.log(2,e,s,t,r)}error(e,s,t,r){this.log(3,e,s,t,r)}dataIn(e,s,t,r){this.info(e,`\u2192 ${s}`,t,r)}dataOut(e,s,t,r){this.info(e,`\u2190 ${s}`,t,r)}success(e,s,t,r){this.info(e,`\u2713 ${s}`,t,r)}failure(e,s,t,r){this.error(e,`\u2717 ${s}`,t,r)}timing(e,s,t,r){this.info(e,`\u23F1 ${s}`,r,{duration:`${t}ms`})}},A=new T;var _=class{db;constructor(){O(m),this.db=new v(k),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(t=>t.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[SessionStore] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[SessionStore] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(c=>c.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[SessionStore] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(c=>c.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to session_summaries table"));let d=this.db.pragma("index_list(session_summaries)").some(c=>c.unique===1)}catch(e){console.error("[SessionStore] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(t=>t.unique===1))return;console.error("[SessionStore] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE session_summaries_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -29,7 +29,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje CREATE INDEX idx_session_summaries_sdk_session ON session_summaries(sdk_session_id); CREATE INDEX idx_session_summaries_project ON session_summaries(project); CREATE INDEX idx_session_summaries_created ON session_summaries(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(t){throw this.db.exec("ROLLBACK"),t}}catch(e){console.error("[HooksDatabase] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(t=>t.name==="title"))return;console.error("[HooksDatabase] Adding hierarchical fields to observations table..."),this.db.exec(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(t){throw this.db.exec("ROLLBACK"),t}}catch(e){console.error("[SessionStore] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(t=>t.name==="title"))return;console.error("[SessionStore] Adding hierarchical fields to observations table..."),this.db.exec(` ALTER TABLE observations ADD COLUMN title TEXT; ALTER TABLE observations ADD COLUMN subtitle TEXT; ALTER TABLE observations ADD COLUMN facts TEXT; @@ -37,7 +37,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje ALTER TABLE observations ADD COLUMN concepts TEXT; ALTER TABLE observations ADD COLUMN files_read TEXT; ALTER TABLE observations ADD COLUMN files_modified TEXT; - `),console.error("[HooksDatabase] Successfully added hierarchical fields to observations table")}catch(e){console.error("[HooksDatabase] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let s=this.db.pragma("table_info(observations)").find(t=>t.name==="text");if(!s||s.notnull===0)return;console.error("[HooksDatabase] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` + `),console.error("[SessionStore] Successfully added hierarchical fields to observations table")}catch(e){console.error("[SessionStore] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let s=this.db.pragma("table_info(observations)").find(t=>t.name==="text");if(!s||s.notnull===0)return;console.error("[SessionStore] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE observations_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -67,7 +67,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje CREATE INDEX idx_observations_project ON observations(project); CREATE INDEX idx_observations_type ON observations(type); CREATE INDEX idx_observations_created ON observations(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully made observations.text nullable")}catch(t){throw this.db.exec("ROLLBACK"),t}}catch(e){console.error("[HooksDatabase] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,s=10){return this.db.prepare(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully made observations.text nullable")}catch(t){throw this.db.exec("ROLLBACK"),t}}catch(e){console.error("[SessionStore] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,s=10){return this.db.prepare(` SELECT request, investigated, learned, completed, next_steps, files_read, files_edited, notes, prompt_number, created_at @@ -146,7 +146,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje UPDATE sdk_sessions SET sdk_session_id = ? WHERE id = ? AND sdk_session_id IS NULL - `).run(s,e).changes===0?(D.debug("DB","sdk_session_id already set, skipping update",{sessionId:e,sdkSessionId:s}),!1):!0}setWorkerPort(e,s){this.db.prepare(` + `).run(s,e).changes===0?(A.debug("DB","sdk_session_id already set, skipping update",{sessionId:e,sdkSessionId:s}),!1):!0}setWorkerPort(e,s){this.db.prepare(` UPDATE sdk_sessions SET worker_port = ? WHERE id = ? @@ -177,4 +177,4 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje UPDATE sdk_sessions SET status = 'failed', completed_at = ?, completed_at_epoch = ? WHERE status = 'active' - `).run(e.toISOString(),s).changes}close(){this.db.close()}};function v(o,e,s){return o==="PreCompact"?e?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:s.reason||"Pre-compact operation failed",suppressOutput:!0}:o==="SessionStart"?e&&s.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s.context}}:{continue:!0,suppressOutput:!0}:o==="UserPromptSubmit"||o==="PostToolUse"?{continue:!0,suppressOutput:!0}:o==="Stop"?{continue:!0,suppressOutput:!0}:{continue:e,suppressOutput:!0,...s.reason&&!e?{stopReason:s.reason}:{}}}function E(o,e,s={}){let t=v(o,e,s);return JSON.stringify(t)}async function w(){let{readFileSync:o,existsSync:e}=await import("fs"),{join:s}=await import("path"),{homedir:t}=await import("os"),r=s(t(),".claude-mem","worker.port");if(!e(r))return null;try{let n=o(r,"utf8").trim();return parseInt(n,10)}catch{return null}}async function A(o){if(!o)throw new Error("newHook requires input");let{session_id:e,cwd:s,prompt:t}=o,r=x.basename(s),n=new _;try{let a=n.findActiveSDKSession(e),i,d=!1;if(a){i=a.id;let p=n.incrementPromptCounter(i);console.error(`[new-hook] Continuing session ${i}, prompt #${p}`)}else{let p=n.findAnySDKSession(e);if(p){i=p.id,n.reactivateSession(i,t);let l=n.incrementPromptCounter(i);d=!0,console.error(`[new-hook] Reactivated session ${i}, prompt #${l}`)}else{i=n.createSDKSession(e,r,t);let l=n.incrementPromptCounter(i);d=!0,console.error(`[new-hook] Created new session ${i}, prompt #${l}`)}}let c=await w();if(!c){console.error("[new-hook] Worker service not running. Start with: npm run worker:start"),console.log(E("UserPromptSubmit",!0));return}if(d){let p=await fetch(`http://127.0.0.1:${c}/sessions/${i}/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({project:r,userPrompt:t}),signal:AbortSignal.timeout(5e3)});p.ok||console.error("[new-hook] Failed to init session:",await p.text())}console.log(E("UserPromptSubmit",!0))}catch(a){console.error("[new-hook] FATAL ERROR:",a.message),console.error("[new-hook] Stack:",a.stack),console.error("[new-hook] Full error:",JSON.stringify(a,Object.getOwnPropertyNames(a))),console.log(E("UserPromptSubmit",!0))}finally{n.close()}}import{stdin as L}from"process";var f="";L.on("data",o=>f+=o);L.on("end",async()=>{try{let o=f.trim()?JSON.parse(f):void 0;await A(o),process.exit(0)}catch(o){console.error(`[claude-mem new-hook error: ${o.message}]`),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}}); + `).run(e.toISOString(),s).changes}close(){this.db.close()}};function D(o,e,s){return o==="PreCompact"?e?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:s.reason||"Pre-compact operation failed",suppressOutput:!0}:o==="SessionStart"?e&&s.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s.context}}:{continue:!0,suppressOutput:!0}:o==="UserPromptSubmit"||o==="PostToolUse"?{continue:!0,suppressOutput:!0}:o==="Stop"?{continue:!0,suppressOutput:!0}:{continue:e,suppressOutput:!0,...s.reason&&!e?{stopReason:s.reason}:{}}}function E(o,e,s={}){let t=D(o,e,s);return JSON.stringify(t)}async function w(){let{readFileSync:o,existsSync:e}=await import("fs"),{join:s}=await import("path"),{homedir:t}=await import("os"),r=s(t(),".claude-mem","worker.port");if(!e(r))return null;try{let n=o(r,"utf8").trim();return parseInt(n,10)}catch{return null}}async function L(o){if(!o)throw new Error("newHook requires input");let{session_id:e,cwd:s,prompt:t}=o,r=x.basename(s),n=new _;try{let a=n.findActiveSDKSession(e),i,d=!1;if(a){i=a.id;let p=n.incrementPromptCounter(i);console.error(`[new-hook] Continuing session ${i}, prompt #${p}`)}else{let p=n.findAnySDKSession(e);if(p){i=p.id,n.reactivateSession(i,t);let l=n.incrementPromptCounter(i);d=!0,console.error(`[new-hook] Reactivated session ${i}, prompt #${l}`)}else{i=n.createSDKSession(e,r,t);let l=n.incrementPromptCounter(i);d=!0,console.error(`[new-hook] Created new session ${i}, prompt #${l}`)}}let c=await w();if(!c){console.error("[new-hook] Worker service not running. Start with: npm run worker:start"),console.log(E("UserPromptSubmit",!0));return}if(d){let p=await fetch(`http://127.0.0.1:${c}/sessions/${i}/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({project:r,userPrompt:t}),signal:AbortSignal.timeout(5e3)});p.ok||console.error("[new-hook] Failed to init session:",await p.text())}console.log(E("UserPromptSubmit",!0))}catch(a){console.error("[new-hook] FATAL ERROR:",a.message),console.error("[new-hook] Stack:",a.stack),console.error("[new-hook] Full error:",JSON.stringify(a,Object.getOwnPropertyNames(a))),console.log(E("UserPromptSubmit",!0))}finally{n.close()}}import{stdin as C}from"process";var f="";C.on("data",o=>f+=o);C.on("end",async()=>{try{let o=f.trim()?JSON.parse(f):void 0;await L(o),process.exit(0)}catch(o){console.error(`[claude-mem new-hook error: ${o.message}]`),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}}); diff --git a/plugin/scripts/save-hook.js b/plugin/scripts/save-hook.js index 9ad258e9..d637da86 100755 --- a/plugin/scripts/save-hook.js +++ b/plugin/scripts/save-hook.js @@ -1,7 +1,7 @@ #!/usr/bin/env node -import C from"better-sqlite3";import{join as c,dirname as X,basename as j}from"path";import{homedir as O}from"os";import{existsSync as K,mkdirSync as v}from"fs";var p=process.env.CLAUDE_MEM_DATA_DIR||c(O(),".claude-mem"),g=process.env.CLAUDE_CONFIG_DIR||c(O(),".claude"),q=c(p,"archives"),J=c(p,"logs"),Y=c(p,"trash"),V=c(p,"backups"),Q=c(p,"settings.json"),k=c(p,"claude-mem.db"),z=c(g,"settings.json"),Z=c(g,"commands"),ee=c(g,"CLAUDE.md");function L(n){v(n,{recursive:!0})}var b=(o=>(o[o.DEBUG=0]="DEBUG",o[o.INFO=1]="INFO",o[o.WARN=2]="WARN",o[o.ERROR=3]="ERROR",o[o.SILENT=4]="SILENT",o))(b||{}),T=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=b[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,s){return`obs-${e}-${s}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} -${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Object.keys(e);return s.length===0?"{}":s.length<=3?JSON.stringify(e):`{${s.length} keys: ${s.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,s){if(!s)return e;try{let t=typeof s=="string"?JSON.parse(s):s;if(e==="Bash"&&t.command){let r=t.command.length>50?t.command.substring(0,50)+"...":t.command;return`${e}(${r})`}if(e==="Read"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}if(e==="Edit"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}if(e==="Write"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}return e}catch{return e}}log(e,s,t,r,o){if(e0&&(h=` {${Object.entries(R).map(([I,N])=>`${I}=${N}`).join(", ")}}`)}let S=`[${i}] [${d}] [${_}] ${a}${t}${h}${m}`;e===3?console.error(S):console.log(S)}debug(e,s,t,r){this.log(0,e,s,t,r)}info(e,s,t,r){this.log(1,e,s,t,r)}warn(e,s,t,r){this.log(2,e,s,t,r)}error(e,s,t,r){this.log(3,e,s,t,r)}dataIn(e,s,t,r){this.info(e,`\u2192 ${s}`,t,r)}dataOut(e,s,t,r){this.info(e,`\u2190 ${s}`,t,r)}success(e,s,t,r){this.info(e,`\u2713 ${s}`,t,r)}failure(e,s,t,r){this.error(e,`\u2717 ${s}`,t,r)}timing(e,s,t,r){this.info(e,`\u23F1 ${s}`,r,{duration:`${t}ms`})}},u=new T;var E=class{db;constructor(){L(p),this.db=new C(k),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(t=>t.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[HooksDatabase] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[HooksDatabase] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(a=>a.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[HooksDatabase] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(a=>a.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(a=>a.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to session_summaries table"));let _=this.db.pragma("index_list(session_summaries)").some(a=>a.unique===1)}catch(e){console.error("[HooksDatabase] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(t=>t.unique===1))return;console.error("[HooksDatabase] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` +import y from"better-sqlite3";import{join as c,dirname as X,basename as j}from"path";import{homedir as O}from"os";import{existsSync as K,mkdirSync as C}from"fs";var p=process.env.CLAUDE_MEM_DATA_DIR||c(O(),".claude-mem"),g=process.env.CLAUDE_CONFIG_DIR||c(O(),".claude"),q=c(p,"archives"),J=c(p,"logs"),Y=c(p,"trash"),V=c(p,"backups"),Q=c(p,"settings.json"),L=c(p,"claude-mem.db"),z=c(g,"settings.json"),Z=c(g,"commands"),ee=c(g,"CLAUDE.md");function k(n){C(n,{recursive:!0})}var T=(o=>(o[o.DEBUG=0]="DEBUG",o[o.INFO=1]="INFO",o[o.WARN=2]="WARN",o[o.ERROR=3]="ERROR",o[o.SILENT=4]="SILENT",o))(T||{}),b=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=T[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,s){return`obs-${e}-${s}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} +${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Object.keys(e);return s.length===0?"{}":s.length<=3?JSON.stringify(e):`{${s.length} keys: ${s.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,s){if(!s)return e;try{let t=typeof s=="string"?JSON.parse(s):s;if(e==="Bash"&&t.command){let r=t.command.length>50?t.command.substring(0,50)+"...":t.command;return`${e}(${r})`}if(e==="Read"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}if(e==="Edit"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}if(e==="Write"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}return e}catch{return e}}log(e,s,t,r,o){if(e0&&(S=` {${Object.entries(R).map(([N,v])=>`${N}=${v}`).join(", ")}}`)}let h=`[${i}] [${d}] [${_}] ${a}${t}${S}${m}`;e===3?console.error(h):console.log(h)}debug(e,s,t,r){this.log(0,e,s,t,r)}info(e,s,t,r){this.log(1,e,s,t,r)}warn(e,s,t,r){this.log(2,e,s,t,r)}error(e,s,t,r){this.log(3,e,s,t,r)}dataIn(e,s,t,r){this.info(e,`\u2192 ${s}`,t,r)}dataOut(e,s,t,r){this.info(e,`\u2190 ${s}`,t,r)}success(e,s,t,r){this.info(e,`\u2713 ${s}`,t,r)}failure(e,s,t,r){this.error(e,`\u2717 ${s}`,t,r)}timing(e,s,t,r){this.info(e,`\u23F1 ${s}`,r,{duration:`${t}ms`})}},u=new b;var E=class{db;constructor(){k(p),this.db=new y(L),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(t=>t.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[SessionStore] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[SessionStore] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(a=>a.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[SessionStore] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(a=>a.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(a=>a.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to session_summaries table"));let _=this.db.pragma("index_list(session_summaries)").some(a=>a.unique===1)}catch(e){console.error("[SessionStore] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(t=>t.unique===1))return;console.error("[SessionStore] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE session_summaries_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -29,7 +29,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje CREATE INDEX idx_session_summaries_sdk_session ON session_summaries(sdk_session_id); CREATE INDEX idx_session_summaries_project ON session_summaries(project); CREATE INDEX idx_session_summaries_created ON session_summaries(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(t){throw this.db.exec("ROLLBACK"),t}}catch(e){console.error("[HooksDatabase] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(t=>t.name==="title"))return;console.error("[HooksDatabase] Adding hierarchical fields to observations table..."),this.db.exec(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(t){throw this.db.exec("ROLLBACK"),t}}catch(e){console.error("[SessionStore] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(t=>t.name==="title"))return;console.error("[SessionStore] Adding hierarchical fields to observations table..."),this.db.exec(` ALTER TABLE observations ADD COLUMN title TEXT; ALTER TABLE observations ADD COLUMN subtitle TEXT; ALTER TABLE observations ADD COLUMN facts TEXT; @@ -37,7 +37,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje ALTER TABLE observations ADD COLUMN concepts TEXT; ALTER TABLE observations ADD COLUMN files_read TEXT; ALTER TABLE observations ADD COLUMN files_modified TEXT; - `),console.error("[HooksDatabase] Successfully added hierarchical fields to observations table")}catch(e){console.error("[HooksDatabase] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let s=this.db.pragma("table_info(observations)").find(t=>t.name==="text");if(!s||s.notnull===0)return;console.error("[HooksDatabase] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` + `),console.error("[SessionStore] Successfully added hierarchical fields to observations table")}catch(e){console.error("[SessionStore] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let s=this.db.pragma("table_info(observations)").find(t=>t.name==="text");if(!s||s.notnull===0)return;console.error("[SessionStore] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE observations_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -67,7 +67,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje CREATE INDEX idx_observations_project ON observations(project); CREATE INDEX idx_observations_type ON observations(type); CREATE INDEX idx_observations_created ON observations(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully made observations.text nullable")}catch(t){throw this.db.exec("ROLLBACK"),t}}catch(e){console.error("[HooksDatabase] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,s=10){return this.db.prepare(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully made observations.text nullable")}catch(t){throw this.db.exec("ROLLBACK"),t}}catch(e){console.error("[SessionStore] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,s=10){return this.db.prepare(` SELECT request, investigated, learned, completed, next_steps, files_read, files_edited, notes, prompt_number, created_at @@ -177,4 +177,4 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje UPDATE sdk_sessions SET status = 'failed', completed_at = ?, completed_at_epoch = ? WHERE status = 'active' - `).run(e.toISOString(),s).changes}close(){this.db.close()}};function y(n,e,s){return n==="PreCompact"?e?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:s.reason||"Pre-compact operation failed",suppressOutput:!0}:n==="SessionStart"?e&&s.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s.context}}:{continue:!0,suppressOutput:!0}:n==="UserPromptSubmit"||n==="PostToolUse"?{continue:!0,suppressOutput:!0}:n==="Stop"?{continue:!0,suppressOutput:!0}:{continue:e,suppressOutput:!0,...s.reason&&!e?{stopReason:s.reason}:{}}}function l(n,e,s={}){let t=y(n,e,s);return JSON.stringify(t)}var x=new Set(["ListMcpResourcesTool"]);async function D(n){if(!n)throw new Error("saveHook requires input");let{session_id:e,tool_name:s,tool_input:t,tool_output:r}=n;if(x.has(s)){console.log(l("PostToolUse",!0));return}let o=new E,i=o.findActiveSDKSession(e);if(!i){o.close(),console.log(l("PostToolUse",!0));return}if(!i.worker_port){o.close(),u.error("HOOK","No worker port for session",{sessionId:i.id}),console.log(l("PostToolUse",!0));return}let d=o.getPromptCounter(i.id);o.close();let _=u.formatTool(s,t);try{u.dataIn("HOOK",`PostToolUse: ${_}`,{sessionId:i.id,workerPort:i.worker_port});let a=await fetch(`http://127.0.0.1:${i.worker_port}/sessions/${i.id}/observations`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tool_name:s,tool_input:t!==void 0?JSON.stringify(t):"{}",tool_output:r!==void 0?JSON.stringify(r):"{}",prompt_number:d}),signal:AbortSignal.timeout(2e3)});if(a.ok)u.debug("HOOK","Observation sent successfully",{sessionId:i.id,toolName:s});else{let m=await a.text();u.failure("HOOK","Failed to send observation",{sessionId:i.id,status:a.status},m)}}catch(a){u.failure("HOOK","Error sending observation",{sessionId:i.id},a)}finally{console.log(l("PostToolUse",!0))}}import{stdin as A}from"process";var f="";A.on("data",n=>f+=n);A.on("end",async()=>{try{let n=f.trim()?JSON.parse(f):void 0;await D(n),process.exit(0)}catch(n){console.error(`[claude-mem save-hook error: ${n.message}]`),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}}); + `).run(e.toISOString(),s).changes}close(){this.db.close()}};function D(n,e,s){return n==="PreCompact"?e?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:s.reason||"Pre-compact operation failed",suppressOutput:!0}:n==="SessionStart"?e&&s.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s.context}}:{continue:!0,suppressOutput:!0}:n==="UserPromptSubmit"||n==="PostToolUse"?{continue:!0,suppressOutput:!0}:n==="Stop"?{continue:!0,suppressOutput:!0}:{continue:e,suppressOutput:!0,...s.reason&&!e?{stopReason:s.reason}:{}}}function l(n,e,s={}){let t=D(n,e,s);return JSON.stringify(t)}var x=new Set(["ListMcpResourcesTool"]);async function A(n){if(!n)throw new Error("saveHook requires input");let{session_id:e,tool_name:s,tool_input:t,tool_output:r}=n;if(x.has(s)){console.log(l("PostToolUse",!0));return}let o=new E,i=o.findActiveSDKSession(e);if(!i){o.close(),console.log(l("PostToolUse",!0));return}if(!i.worker_port){o.close(),u.error("HOOK","No worker port for session",{sessionId:i.id}),console.log(l("PostToolUse",!0));return}let d=o.getPromptCounter(i.id);o.close();let _=u.formatTool(s,t);try{u.dataIn("HOOK",`PostToolUse: ${_}`,{sessionId:i.id,workerPort:i.worker_port});let a=await fetch(`http://127.0.0.1:${i.worker_port}/sessions/${i.id}/observations`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tool_name:s,tool_input:t!==void 0?JSON.stringify(t):"{}",tool_output:r!==void 0?JSON.stringify(r):"{}",prompt_number:d}),signal:AbortSignal.timeout(2e3)});if(a.ok)u.debug("HOOK","Observation sent successfully",{sessionId:i.id,toolName:s});else{let m=await a.text();u.failure("HOOK","Failed to send observation",{sessionId:i.id,status:a.status},m)}}catch(a){u.failure("HOOK","Error sending observation",{sessionId:i.id},a)}finally{console.log(l("PostToolUse",!0))}}import{stdin as I}from"process";var f="";I.on("data",n=>f+=n);I.on("end",async()=>{try{let n=f.trim()?JSON.parse(f):void 0;await A(n),process.exit(0)}catch(n){console.error(`[claude-mem save-hook error: ${n.message}]`),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}}); diff --git a/plugin/scripts/summary-hook.js b/plugin/scripts/summary-hook.js index 48ea825d..8f2c117d 100755 --- a/plugin/scripts/summary-hook.js +++ b/plugin/scripts/summary-hook.js @@ -1,7 +1,7 @@ #!/usr/bin/env node -import N from"better-sqlite3";import{join as a,dirname as $,basename as X}from"path";import{homedir as k}from"os";import{existsSync as G,mkdirSync as C}from"fs";var c=process.env.CLAUDE_MEM_DATA_DIR||a(k(),".claude-mem"),E=process.env.CLAUDE_CONFIG_DIR||a(k(),".claude"),q=a(c,"archives"),K=a(c,"logs"),J=a(c,"trash"),Y=a(c,"backups"),V=a(c,"settings.json"),O=a(c,"claude-mem.db"),Q=a(E,"settings.json"),z=a(E,"commands"),Z=a(E,"CLAUDE.md");function D(o){C(o,{recursive:!0})}var g=(n=>(n[n.DEBUG=0]="DEBUG",n[n.INFO=1]="INFO",n[n.WARN=2]="WARN",n[n.ERROR=3]="ERROR",n[n.SILENT=4]="SILENT",n))(g||{}),b=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=g[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,t){return`obs-${e}-${t}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} +import v from"better-sqlite3";import{join as a,dirname as $,basename as X}from"path";import{homedir as O}from"os";import{existsSync as G,mkdirSync as N}from"fs";var c=process.env.CLAUDE_MEM_DATA_DIR||a(O(),".claude-mem"),E=process.env.CLAUDE_CONFIG_DIR||a(O(),".claude"),q=a(c,"archives"),K=a(c,"logs"),J=a(c,"trash"),Y=a(c,"backups"),V=a(c,"settings.json"),k=a(c,"claude-mem.db"),Q=a(E,"settings.json"),z=a(E,"commands"),Z=a(E,"CLAUDE.md");function L(o){N(o,{recursive:!0})}var g=(n=>(n[n.DEBUG=0]="DEBUG",n[n.INFO=1]="INFO",n[n.WARN=2]="WARN",n[n.ERROR=3]="ERROR",n[n.SILENT=4]="SILENT",n))(g||{}),b=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=g[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,t){return`obs-${e}-${t}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Object.keys(e);return t.length===0?"{}":t.length<=3?JSON.stringify(e):`{${t.length} keys: ${t.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,t){if(!t)return e;try{let s=typeof t=="string"?JSON.parse(t):t;if(e==="Bash"&&s.command){let r=s.command.length>50?s.command.substring(0,50)+"...":s.command;return`${e}(${r})`}if(e==="Read"&&s.file_path){let r=s.file_path.split("/").pop()||s.file_path;return`${e}(${r})`}if(e==="Edit"&&s.file_path){let r=s.file_path.split("/").pop()||s.file_path;return`${e}(${r})`}if(e==="Write"&&s.file_path){let r=s.file_path.split("/").pop()||s.file_path;return`${e}(${r})`}return e}catch{return e}}log(e,t,s,r,n){if(e0&&(h=` {${Object.entries(R).map(([I,y])=>`${I}=${y}`).join(", ")}}`)}let S=`[${u}] [${d}] [${f}] ${i}${s}${h}${_}`;e===3?console.error(S):console.log(S)}debug(e,t,s,r){this.log(0,e,t,s,r)}info(e,t,s,r){this.log(1,e,t,s,r)}warn(e,t,s,r){this.log(2,e,t,s,r)}error(e,t,s,r){this.log(3,e,t,s,r)}dataIn(e,t,s,r){this.info(e,`\u2192 ${t}`,s,r)}dataOut(e,t,s,r){this.info(e,`\u2190 ${t}`,s,r)}success(e,t,s,r){this.info(e,`\u2713 ${t}`,s,r)}failure(e,t,s,r){this.error(e,`\u2717 ${t}`,s,r)}timing(e,t,s,r){this.info(e,`\u23F1 ${t}`,r,{duration:`${s}ms`})}},p=new b;var m=class{db;constructor(){D(c),this.db=new N(O),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(s=>s.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[HooksDatabase] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[HooksDatabase] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(i=>i.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[HooksDatabase] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(i=>i.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(i=>i.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[HooksDatabase] Added prompt_number column to session_summaries table"));let f=this.db.pragma("index_list(session_summaries)").some(i=>i.unique===1)}catch(e){console.error("[HooksDatabase] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(s=>s.unique===1))return;console.error("[HooksDatabase] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` +`+JSON.stringify(n,null,2):_=" "+this.formatData(n));let S="";if(r){let{sessionId:x,sdkSessionId:U,correlationId:w,...R}=r;Object.keys(R).length>0&&(S=` {${Object.entries(R).map(([y,C])=>`${y}=${C}`).join(", ")}}`)}let h=`[${u}] [${d}] [${f}] ${i}${s}${S}${_}`;e===3?console.error(h):console.log(h)}debug(e,t,s,r){this.log(0,e,t,s,r)}info(e,t,s,r){this.log(1,e,t,s,r)}warn(e,t,s,r){this.log(2,e,t,s,r)}error(e,t,s,r){this.log(3,e,t,s,r)}dataIn(e,t,s,r){this.info(e,`\u2192 ${t}`,s,r)}dataOut(e,t,s,r){this.info(e,`\u2190 ${t}`,s,r)}success(e,t,s,r){this.info(e,`\u2713 ${t}`,s,r)}failure(e,t,s,r){this.error(e,`\u2717 ${t}`,s,r)}timing(e,t,s,r){this.info(e,`\u23F1 ${t}`,r,{duration:`${s}ms`})}},p=new b;var m=class{db;constructor(){L(c),this.db=new v(k),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable()}ensureWorkerPortColumn(){try{this.db.pragma("table_info(sdk_sessions)").some(s=>s.name==="worker_port")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),console.error("[SessionStore] Added worker_port column to sdk_sessions table"))}catch(e){console.error("[SessionStore] Migration error:",e.message)}}ensurePromptTrackingColumns(){try{this.db.pragma("table_info(sdk_sessions)").some(i=>i.name==="prompt_counter")||(this.db.exec("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),console.error("[SessionStore] Added prompt_counter column to sdk_sessions table")),this.db.pragma("table_info(observations)").some(i=>i.name==="prompt_number")||(this.db.exec("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to observations table")),this.db.pragma("table_info(session_summaries)").some(i=>i.name==="prompt_number")||(this.db.exec("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),console.error("[SessionStore] Added prompt_number column to session_summaries table"));let f=this.db.pragma("index_list(session_summaries)").some(i=>i.unique===1)}catch(e){console.error("[SessionStore] Prompt tracking migration error:",e.message)}}removeSessionSummariesUniqueConstraint(){try{if(!this.db.pragma("index_list(session_summaries)").some(s=>s.unique===1))return;console.error("[SessionStore] Removing UNIQUE constraint from session_summaries.sdk_session_id..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE session_summaries_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -29,7 +29,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje CREATE INDEX idx_session_summaries_sdk_session ON session_summaries(sdk_session_id); CREATE INDEX idx_session_summaries_project ON session_summaries(project); CREATE INDEX idx_session_summaries_created ON session_summaries(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[HooksDatabase] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(s=>s.name==="title"))return;console.error("[HooksDatabase] Adding hierarchical fields to observations table..."),this.db.exec(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[SessionStore] Migration error (remove UNIQUE constraint):",e.message)}}addObservationHierarchicalFields(){try{if(this.db.pragma("table_info(observations)").some(s=>s.name==="title"))return;console.error("[SessionStore] Adding hierarchical fields to observations table..."),this.db.exec(` ALTER TABLE observations ADD COLUMN title TEXT; ALTER TABLE observations ADD COLUMN subtitle TEXT; ALTER TABLE observations ADD COLUMN facts TEXT; @@ -37,7 +37,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje ALTER TABLE observations ADD COLUMN concepts TEXT; ALTER TABLE observations ADD COLUMN files_read TEXT; ALTER TABLE observations ADD COLUMN files_modified TEXT; - `),console.error("[HooksDatabase] Successfully added hierarchical fields to observations table")}catch(e){console.error("[HooksDatabase] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let t=this.db.pragma("table_info(observations)").find(s=>s.name==="text");if(!t||t.notnull===0)return;console.error("[HooksDatabase] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` + `),console.error("[SessionStore] Successfully added hierarchical fields to observations table")}catch(e){console.error("[SessionStore] Migration error (add hierarchical fields):",e.message)}}makeObservationsTextNullable(){try{let t=this.db.pragma("table_info(observations)").find(s=>s.name==="text");if(!t||t.notnull===0)return;console.error("[SessionStore] Making observations.text nullable..."),this.db.exec("BEGIN TRANSACTION");try{this.db.exec(` CREATE TABLE observations_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, sdk_session_id TEXT NOT NULL, @@ -67,7 +67,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje CREATE INDEX idx_observations_project ON observations(project); CREATE INDEX idx_observations_type ON observations(type); CREATE INDEX idx_observations_created ON observations(created_at_epoch DESC); - `),this.db.exec("COMMIT"),console.error("[HooksDatabase] Successfully made observations.text nullable")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[HooksDatabase] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,t=10){return this.db.prepare(` + `),this.db.exec("COMMIT"),console.error("[SessionStore] Successfully made observations.text nullable")}catch(s){throw this.db.exec("ROLLBACK"),s}}catch(e){console.error("[SessionStore] Migration error (make text nullable):",e.message)}}getRecentSummaries(e,t=10){return this.db.prepare(` SELECT request, investigated, learned, completed, next_steps, files_read, files_edited, notes, prompt_number, created_at @@ -177,4 +177,4 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Obje UPDATE sdk_sessions SET status = 'failed', completed_at = ?, completed_at_epoch = ? WHERE status = 'active' - `).run(e.toISOString(),t).changes}close(){this.db.close()}};function v(o,e,t){return o==="PreCompact"?e?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:t.reason||"Pre-compact operation failed",suppressOutput:!0}:o==="SessionStart"?e&&t.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:t.context}}:{continue:!0,suppressOutput:!0}:o==="UserPromptSubmit"||o==="PostToolUse"?{continue:!0,suppressOutput:!0}:o==="Stop"?{continue:!0,suppressOutput:!0}:{continue:e,suppressOutput:!0,...t.reason&&!e?{stopReason:t.reason}:{}}}function l(o,e,t={}){let s=v(o,e,t);return JSON.stringify(s)}async function L(o){if(!o)throw new Error("summaryHook requires input");let{session_id:e}=o,t=new m,s=t.findActiveSDKSession(e);if(!s){t.close(),console.log(l("Stop",!0));return}if(!s.worker_port){t.close(),p.error("HOOK","No worker port for session",{sessionId:s.id}),console.log(l("Stop",!0));return}let r=t.getPromptCounter(s.id);t.close();try{p.dataIn("HOOK","Stop: Requesting summary",{sessionId:s.id,workerPort:s.worker_port,promptNumber:r});let n=await fetch(`http://127.0.0.1:${s.worker_port}/sessions/${s.id}/summarize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({prompt_number:r}),signal:AbortSignal.timeout(2e3)});if(n.ok)p.debug("HOOK","Summary request sent successfully",{sessionId:s.id});else{let u=await n.text();p.failure("HOOK","Failed to generate summary",{sessionId:s.id,status:n.status},u)}}catch(n){p.failure("HOOK","Error requesting summary",{sessionId:s.id},n)}finally{console.log(l("Stop",!0))}}import{stdin as A}from"process";var T="";A.on("data",o=>T+=o);A.on("end",async()=>{try{let o=T.trim()?JSON.parse(T):void 0;await L(o),process.exit(0)}catch(o){console.error(`[claude-mem summary-hook error: ${o.message}]`),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}}); + `).run(e.toISOString(),t).changes}close(){this.db.close()}};function D(o,e,t){return o==="PreCompact"?e?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:t.reason||"Pre-compact operation failed",suppressOutput:!0}:o==="SessionStart"?e&&t.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:t.context}}:{continue:!0,suppressOutput:!0}:o==="UserPromptSubmit"||o==="PostToolUse"?{continue:!0,suppressOutput:!0}:o==="Stop"?{continue:!0,suppressOutput:!0}:{continue:e,suppressOutput:!0,...t.reason&&!e?{stopReason:t.reason}:{}}}function l(o,e,t={}){let s=D(o,e,t);return JSON.stringify(s)}async function A(o){if(!o)throw new Error("summaryHook requires input");let{session_id:e}=o,t=new m,s=t.findActiveSDKSession(e);if(!s){t.close(),console.log(l("Stop",!0));return}if(!s.worker_port){t.close(),p.error("HOOK","No worker port for session",{sessionId:s.id}),console.log(l("Stop",!0));return}let r=t.getPromptCounter(s.id);t.close();try{p.dataIn("HOOK","Stop: Requesting summary",{sessionId:s.id,workerPort:s.worker_port,promptNumber:r});let n=await fetch(`http://127.0.0.1:${s.worker_port}/sessions/${s.id}/summarize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({prompt_number:r}),signal:AbortSignal.timeout(2e3)});if(n.ok)p.debug("HOOK","Summary request sent successfully",{sessionId:s.id});else{let u=await n.text();p.failure("HOOK","Failed to generate summary",{sessionId:s.id,status:n.status},u)}}catch(n){p.failure("HOOK","Error requesting summary",{sessionId:s.id},n)}finally{console.log(l("Stop",!0))}}import{stdin as I}from"process";var T="";I.on("data",o=>T+=o);I.on("end",async()=>{try{let o=T.trim()?JSON.parse(T):void 0;await A(o),process.exit(0)}catch(o){console.error(`[claude-mem summary-hook error: ${o.message}]`),console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}}); diff --git a/src/hooks/cleanup.ts b/src/hooks/cleanup.ts index 86064931..7a795d37 100644 --- a/src/hooks/cleanup.ts +++ b/src/hooks/cleanup.ts @@ -1,4 +1,4 @@ -import { HooksDatabase } from '../services/sqlite/HooksDatabase.js'; +import { SessionStore } from '../services/sqlite/SessionStore.js'; export interface SessionEndInput { session_id: string; @@ -46,7 +46,7 @@ export async function cleanupHook(input?: SessionEndInput): Promise { console.error('[claude-mem cleanup] Searching for active SDK session', { session_id, reason }); // Find active SDK session - const db = new HooksDatabase(); + const db = new SessionStore(); const session = db.findActiveSDKSession(session_id); if (!session) { diff --git a/src/hooks/context.ts b/src/hooks/context.ts index cb0cf74b..f3c57d3e 100644 --- a/src/hooks/context.ts +++ b/src/hooks/context.ts @@ -1,5 +1,5 @@ import path from 'path'; -import { HooksDatabase } from '../services/sqlite/HooksDatabase.js'; +import { SessionStore } from '../services/sqlite/SessionStore.js'; export interface SessionStartInput { session_id?: string; @@ -20,7 +20,7 @@ export function contextHook(input?: SessionStartInput): void { const cwd = input?.cwd ?? process.cwd(); const project = cwd ? path.basename(cwd) : 'unknown-project'; - const db = new HooksDatabase(); + const db = new SessionStore(); try { const sessions = db.getRecentSessionsWithStatus(project, 3); diff --git a/src/hooks/new.ts b/src/hooks/new.ts index 8893ae88..5374d209 100644 --- a/src/hooks/new.ts +++ b/src/hooks/new.ts @@ -1,5 +1,5 @@ import path from 'path'; -import { HooksDatabase } from '../services/sqlite/HooksDatabase.js'; +import { SessionStore } from '../services/sqlite/SessionStore.js'; import { createHookResponse } from './hook-response.js'; export interface UserPromptSubmitInput { @@ -42,7 +42,7 @@ export async function newHook(input?: UserPromptSubmitInput): Promise { const { session_id, cwd, prompt } = input; const project = path.basename(cwd); - const db = new HooksDatabase(); + const db = new SessionStore(); try { // Check for any existing session (active, failed, or completed) diff --git a/src/hooks/save.ts b/src/hooks/save.ts index 81a614e1..bc022e1a 100644 --- a/src/hooks/save.ts +++ b/src/hooks/save.ts @@ -1,4 +1,4 @@ -import { HooksDatabase } from '../services/sqlite/HooksDatabase.js'; +import { SessionStore } from '../services/sqlite/SessionStore.js'; import { createHookResponse } from './hook-response.js'; import { logger } from '../utils/logger.js'; @@ -32,7 +32,7 @@ export async function saveHook(input?: PostToolUseInput): Promise { return; } - const db = new HooksDatabase(); + const db = new SessionStore(); const session = db.findActiveSDKSession(session_id); if (!session) { diff --git a/src/hooks/summary.ts b/src/hooks/summary.ts index 6799308f..0ea869ce 100644 --- a/src/hooks/summary.ts +++ b/src/hooks/summary.ts @@ -1,4 +1,4 @@ -import { HooksDatabase } from '../services/sqlite/HooksDatabase.js'; +import { SessionStore } from '../services/sqlite/SessionStore.js'; import { createHookResponse } from './hook-response.js'; import { logger } from '../utils/logger.js'; @@ -18,7 +18,7 @@ export async function summaryHook(input?: StopInput): Promise { } const { session_id } = input; - const db = new HooksDatabase(); + const db = new SessionStore(); const session = db.findActiveSDKSession(session_id); if (!session) { diff --git a/src/sdk/worker.ts b/src/sdk/worker.ts index 6292e59e..3ce32842 100644 --- a/src/sdk/worker.ts +++ b/src/sdk/worker.ts @@ -15,7 +15,7 @@ import net from 'net'; import { unlinkSync, existsSync } from 'fs'; import { query } from '@anthropic-ai/claude-agent-sdk'; import type { SDKUserMessage, SDKSystemMessage } from '@anthropic-ai/claude-agent-sdk'; -import { HooksDatabase } from '../services/sqlite/HooksDatabase.js'; +import { SessionStore } from '../services/sqlite/SessionStore.js'; import { getWorkerSocketPath } from '../shared/paths.js'; import { buildInitPrompt, buildObservationPrompt, buildFinalizePrompt } from './prompts.js'; import { parseObservations, parseSummary } from './parser.js'; @@ -60,7 +60,7 @@ export async function main() { */ class SDKWorker { private sessionDbId: number; - private db: HooksDatabase; + private db: SessionStore; private socketPath: string; private server: net.Server | null = null; private sdkSessionId: string | null = null; @@ -72,7 +72,7 @@ class SDKWorker { constructor(sessionDbId: number) { this.sessionDbId = sessionDbId; - this.db = new HooksDatabase(); + this.db = new SessionStore(); this.abortController = new AbortController(); this.socketPath = getWorkerSocketPath(sessionDbId); console.error('[claude-mem worker] Worker instance created', { diff --git a/src/services/sqlite/SessionSearch.ts b/src/services/sqlite/SessionSearch.ts new file mode 100644 index 00000000..b0513377 --- /dev/null +++ b/src/services/sqlite/SessionSearch.ts @@ -0,0 +1,525 @@ +import Database from 'better-sqlite3'; +import { DATA_DIR, DB_PATH, ensureDir } from '../../shared/paths.js'; +import { + ObservationSearchResult, + SessionSummarySearchResult, + SearchOptions, + SearchFilters, + DateRange, + ObservationRow +} from './types.js'; + +/** + * Search interface for session-based memory + * Provides FTS5 full-text search and structured queries for sessions, observations, and summaries + */ +export class SessionSearch { + private db: Database.Database; + + constructor(dbPath?: string) { + if (!dbPath) { + ensureDir(DATA_DIR); + dbPath = DB_PATH; + } + this.db = new Database(dbPath); + this.db.pragma('journal_mode = WAL'); + + // Ensure FTS tables exist + this.ensureFTSTables(); + } + + /** + * Ensure FTS5 tables exist (inline migration) + */ + private ensureFTSTables(): void { + try { + // Check if FTS tables already exist + const tables = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%_fts'").all() as any[]; + const hasFTS = tables.some((t: any) => t.name === 'observations_fts' || t.name === 'session_summaries_fts'); + + if (hasFTS) { + // Already migrated + return; + } + + console.error('[SessionSearch] Creating FTS5 tables...'); + + // Create observations_fts virtual table + this.db.exec(` + CREATE VIRTUAL TABLE IF NOT EXISTS observations_fts USING fts5( + title, + subtitle, + narrative, + text, + facts, + concepts, + content='observations', + content_rowid='id' + ); + `); + + // Populate with existing data + this.db.exec(` + INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts) + SELECT id, title, subtitle, narrative, text, facts, concepts + FROM observations; + `); + + // Create triggers for observations + this.db.exec(` + CREATE TRIGGER IF NOT EXISTS observations_ai AFTER INSERT ON observations BEGIN + INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts) + VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts); + END; + + CREATE TRIGGER IF NOT EXISTS observations_ad AFTER DELETE ON observations BEGIN + INSERT INTO observations_fts(observations_fts, rowid, title, subtitle, narrative, text, facts, concepts) + VALUES('delete', old.id, old.title, old.subtitle, old.narrative, old.text, old.facts, old.concepts); + END; + + CREATE TRIGGER IF NOT EXISTS observations_au AFTER UPDATE ON observations BEGIN + INSERT INTO observations_fts(observations_fts, rowid, title, subtitle, narrative, text, facts, concepts) + VALUES('delete', old.id, old.title, old.subtitle, old.narrative, old.text, old.facts, old.concepts); + INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts) + VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts); + END; + `); + + // Create session_summaries_fts virtual table + this.db.exec(` + CREATE VIRTUAL TABLE IF NOT EXISTS session_summaries_fts USING fts5( + request, + investigated, + learned, + completed, + next_steps, + notes, + content='session_summaries', + content_rowid='id' + ); + `); + + // Populate with existing data + this.db.exec(` + INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes) + SELECT id, request, investigated, learned, completed, next_steps, notes + FROM session_summaries; + `); + + // Create triggers for session_summaries + this.db.exec(` + CREATE TRIGGER IF NOT EXISTS session_summaries_ai AFTER INSERT ON session_summaries BEGIN + INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes) + VALUES (new.id, new.request, new.investigated, new.learned, new.completed, new.next_steps, new.notes); + END; + + CREATE TRIGGER IF NOT EXISTS session_summaries_ad AFTER DELETE ON session_summaries BEGIN + INSERT INTO session_summaries_fts(session_summaries_fts, rowid, request, investigated, learned, completed, next_steps, notes) + VALUES('delete', old.id, old.request, old.investigated, old.learned, old.completed, old.next_steps, old.notes); + END; + + CREATE TRIGGER IF NOT EXISTS session_summaries_au AFTER UPDATE ON session_summaries BEGIN + INSERT INTO session_summaries_fts(session_summaries_fts, rowid, request, investigated, learned, completed, next_steps, notes) + VALUES('delete', old.id, old.request, old.investigated, old.learned, old.completed, old.next_steps, old.notes); + INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes) + VALUES (new.id, new.request, new.investigated, new.learned, new.completed, new.next_steps, new.notes); + END; + `); + + console.error('[SessionSearch] FTS5 tables created successfully'); + } catch (error: any) { + console.error('[SessionSearch] FTS migration error:', error.message); + } + } + + /** + * Escape FTS5 special characters in user input + */ + private escapeFTS5(text: string): string { + // FTS5 special characters: " * ( ) AND OR NOT + // For safety, we'll wrap the entire query in quotes for phrase search + // or let advanced users pass boolean operators directly + return text; + } + + /** + * Build WHERE clause for structured filters + */ + private buildFilterClause( + filters: SearchFilters, + params: any[], + tableAlias: string = 'o' + ): string { + const conditions: string[] = []; + + // Project filter + if (filters.project) { + conditions.push(`${tableAlias}.project = ?`); + params.push(filters.project); + } + + // Type filter (for observations only) + if (filters.type) { + if (Array.isArray(filters.type)) { + const placeholders = filters.type.map(() => '?').join(','); + conditions.push(`${tableAlias}.type IN (${placeholders})`); + params.push(...filters.type); + } else { + conditions.push(`${tableAlias}.type = ?`); + params.push(filters.type); + } + } + + // Date range filter + if (filters.dateRange) { + const { start, end } = filters.dateRange; + if (start) { + const startEpoch = typeof start === 'number' ? start : new Date(start).getTime(); + conditions.push(`${tableAlias}.created_at_epoch >= ?`); + params.push(startEpoch); + } + if (end) { + const endEpoch = typeof end === 'number' ? end : new Date(end).getTime(); + conditions.push(`${tableAlias}.created_at_epoch <= ?`); + params.push(endEpoch); + } + } + + // Concepts filter (JSON array search) + if (filters.concepts) { + const concepts = Array.isArray(filters.concepts) ? filters.concepts : [filters.concepts]; + const conceptConditions = concepts.map(() => { + return `EXISTS (SELECT 1 FROM json_each(${tableAlias}.concepts) WHERE value = ?)`; + }); + if (conceptConditions.length > 0) { + conditions.push(`(${conceptConditions.join(' OR ')})`); + params.push(...concepts); + } + } + + // Files filter (JSON array search) + if (filters.files) { + const files = Array.isArray(filters.files) ? filters.files : [filters.files]; + const fileConditions = files.map(() => { + return `( + EXISTS (SELECT 1 FROM json_each(${tableAlias}.files_read) WHERE value LIKE ?) + OR EXISTS (SELECT 1 FROM json_each(${tableAlias}.files_modified) WHERE value LIKE ?) + )`; + }); + if (fileConditions.length > 0) { + conditions.push(`(${fileConditions.join(' OR ')})`); + files.forEach(file => { + params.push(`%${file}%`, `%${file}%`); + }); + } + } + + return conditions.length > 0 ? conditions.join(' AND ') : ''; + } + + /** + * Build ORDER BY clause + */ + private buildOrderClause(orderBy: SearchOptions['orderBy'] = 'relevance', hasFTS: boolean = true, ftsTable: string = 'observations_fts'): string { + switch (orderBy) { + case 'relevance': + return hasFTS ? `ORDER BY ${ftsTable}.rank ASC` : 'ORDER BY o.created_at_epoch DESC'; + case 'date_desc': + return 'ORDER BY o.created_at_epoch DESC'; + case 'date_asc': + return 'ORDER BY o.created_at_epoch ASC'; + default: + return 'ORDER BY o.created_at_epoch DESC'; + } + } + + /** + * Search observations using FTS5 full-text search + */ + searchObservations(query: string, options: SearchOptions = {}): ObservationSearchResult[] { + const params: any[] = []; + const { limit = 50, offset = 0, orderBy = 'relevance', ...filters } = options; + + // Build FTS5 match query + const ftsQuery = this.escapeFTS5(query); + params.push(ftsQuery); + + // Build filter conditions + const filterClause = this.buildFilterClause(filters, params, 'o'); + const whereClause = filterClause ? `AND ${filterClause}` : ''; + + // Build ORDER BY + const orderClause = this.buildOrderClause(orderBy, true); + + // Main query with FTS5 + const sql = ` + SELECT + o.*, + observations_fts.rank as rank + FROM observations o + JOIN observations_fts ON o.id = observations_fts.rowid + WHERE observations_fts MATCH ? + ${whereClause} + ${orderClause} + LIMIT ? OFFSET ? + `; + + params.push(limit, offset); + + const results = this.db.prepare(sql).all(...params) as ObservationSearchResult[]; + + // Normalize rank to score (0-1, higher is better) + if (results.length > 0) { + const minRank = Math.min(...results.map(r => r.rank || 0)); + const maxRank = Math.max(...results.map(r => r.rank || 0)); + const range = maxRank - minRank || 1; + + results.forEach(r => { + if (r.rank !== undefined) { + // Invert rank (lower rank = better match) and normalize to 0-1 + r.score = 1 - ((r.rank - minRank) / range); + } + }); + } + + return results; + } + + /** + * Search session summaries using FTS5 full-text search + */ + searchSessions(query: string, options: SearchOptions = {}): SessionSummarySearchResult[] { + const params: any[] = []; + const { limit = 50, offset = 0, orderBy = 'relevance', ...filters } = options; + + // Build FTS5 match query + const ftsQuery = this.escapeFTS5(query); + params.push(ftsQuery); + + // Build filter conditions (without type filter - not applicable to summaries) + const filterOptions = { ...filters }; + delete filterOptions.type; + const filterClause = this.buildFilterClause(filterOptions, params, 's'); + const whereClause = filterClause ? `AND ${filterClause}` : ''; + + // Note: session_summaries don't have files_read/files_modified in the same way + // We'll need to adjust the filter clause + const adjustedWhereClause = whereClause.replace(/files_read/g, 'files_read').replace(/files_modified/g, 'files_edited'); + + // Build ORDER BY + const orderClause = orderBy === 'relevance' + ? 'ORDER BY session_summaries_fts.rank ASC' + : orderBy === 'date_asc' + ? 'ORDER BY s.created_at_epoch ASC' + : 'ORDER BY s.created_at_epoch DESC'; + + // Main query with FTS5 + const sql = ` + SELECT + s.*, + session_summaries_fts.rank as rank + FROM session_summaries s + JOIN session_summaries_fts ON s.id = session_summaries_fts.rowid + WHERE session_summaries_fts MATCH ? + ${adjustedWhereClause} + ${orderClause} + LIMIT ? OFFSET ? + `; + + params.push(limit, offset); + + const results = this.db.prepare(sql).all(...params) as SessionSummarySearchResult[]; + + // Normalize rank to score + if (results.length > 0) { + const minRank = Math.min(...results.map(r => r.rank || 0)); + const maxRank = Math.max(...results.map(r => r.rank || 0)); + const range = maxRank - minRank || 1; + + results.forEach(r => { + if (r.rank !== undefined) { + r.score = 1 - ((r.rank - minRank) / range); + } + }); + } + + return results; + } + + /** + * Find observations by concept tag + */ + findByConcept(concept: string, filters: SearchFilters = {}): ObservationSearchResult[] { + const params: any[] = []; + + // Add concept to filters + const conceptFilters = { ...filters, concepts: concept }; + const filterClause = this.buildFilterClause(conceptFilters, params, 'o'); + + const sql = ` + SELECT o.* + FROM observations o + WHERE ${filterClause} + ORDER BY o.created_at_epoch DESC + `; + + return this.db.prepare(sql).all(...params) as ObservationSearchResult[]; + } + + /** + * Find observations and summaries by file path + */ + findByFile(filePath: string, filters: SearchFilters = {}): { + observations: ObservationSearchResult[]; + sessions: SessionSummarySearchResult[]; + } { + const params: any[] = []; + + // Add file to filters + const fileFilters = { ...filters, files: filePath }; + const filterClause = this.buildFilterClause(fileFilters, params, 'o'); + + const observationsSql = ` + SELECT o.* + FROM observations o + WHERE ${filterClause} + ORDER BY o.created_at_epoch DESC + `; + + const observations = this.db.prepare(observationsSql).all(...params) as ObservationSearchResult[]; + + // For session summaries, search files_read and files_edited + const sessionParams: any[] = []; + const sessionFilters = { ...filters }; + delete sessionFilters.type; // Remove type filter for sessions + + const baseConditions: string[] = []; + if (sessionFilters.project) { + baseConditions.push('s.project = ?'); + sessionParams.push(sessionFilters.project); + } + + if (sessionFilters.dateRange) { + const { start, end } = sessionFilters.dateRange; + if (start) { + const startEpoch = typeof start === 'number' ? start : new Date(start).getTime(); + baseConditions.push('s.created_at_epoch >= ?'); + sessionParams.push(startEpoch); + } + if (end) { + const endEpoch = typeof end === 'number' ? end : new Date(end).getTime(); + baseConditions.push('s.created_at_epoch <= ?'); + sessionParams.push(endEpoch); + } + } + + // File condition + baseConditions.push(`( + EXISTS (SELECT 1 FROM json_each(s.files_read) WHERE value LIKE ?) + OR EXISTS (SELECT 1 FROM json_each(s.files_edited) WHERE value LIKE ?) + )`); + sessionParams.push(`%${filePath}%`, `%${filePath}%`); + + const sessionsSql = ` + SELECT s.* + FROM session_summaries s + WHERE ${baseConditions.join(' AND ')} + ORDER BY s.created_at_epoch DESC + `; + + const sessions = this.db.prepare(sessionsSql).all(...sessionParams) as SessionSummarySearchResult[]; + + return { observations, sessions }; + } + + /** + * Find observations by type + */ + findByType( + type: ObservationRow['type'] | ObservationRow['type'][], + filters: SearchFilters = {} + ): ObservationSearchResult[] { + const params: any[] = []; + + // Add type to filters + const typeFilters = { ...filters, type }; + const filterClause = this.buildFilterClause(typeFilters, params, 'o'); + + const sql = ` + SELECT o.* + FROM observations o + WHERE ${filterClause} + ORDER BY o.created_at_epoch DESC + `; + + return this.db.prepare(sql).all(...params) as ObservationSearchResult[]; + } + + /** + * Advanced search combining FTS5 and structured filters + */ + advancedSearch(options: { + textQuery?: string; + searchSessions?: boolean; + } & SearchOptions): { + observations: ObservationSearchResult[]; + sessions: SessionSummarySearchResult[]; + } { + const { textQuery, searchSessions = true, ...searchOptions } = options; + + let observations: ObservationSearchResult[] = []; + let sessions: SessionSummarySearchResult[] = []; + + if (textQuery) { + // Use FTS5 search + observations = this.searchObservations(textQuery, searchOptions); + if (searchSessions) { + sessions = this.searchSessions(textQuery, searchOptions); + } + } else { + // Pure structured query (no FTS) + const params: any[] = []; + const filterClause = this.buildFilterClause(searchOptions, params, 'o'); + + if (filterClause) { + const obsSql = ` + SELECT o.* + FROM observations o + WHERE ${filterClause} + ${this.buildOrderClause(searchOptions.orderBy, false)} + LIMIT ? OFFSET ? + `; + params.push(searchOptions.limit || 50, searchOptions.offset || 0); + observations = this.db.prepare(obsSql).all(...params) as ObservationSearchResult[]; + } + + if (searchSessions) { + const sessionParams: any[] = []; + const sessionFilters = { ...searchOptions }; + delete sessionFilters.type; + const sessionFilterClause = this.buildFilterClause(sessionFilters, sessionParams, 's'); + + if (sessionFilterClause) { + const sessSql = ` + SELECT s.* + FROM session_summaries s + WHERE ${sessionFilterClause} + ORDER BY s.created_at_epoch DESC + LIMIT ? OFFSET ? + `; + sessionParams.push(searchOptions.limit || 50, searchOptions.offset || 0); + sessions = this.db.prepare(sessSql).all(...sessionParams) as SessionSummarySearchResult[]; + } + } + } + + return { observations, sessions }; + } + + /** + * Close the database connection + */ + close(): void { + this.db.close(); + } +} diff --git a/src/services/sqlite/HooksDatabase.ts b/src/services/sqlite/SessionStore.ts similarity index 92% rename from src/services/sqlite/HooksDatabase.ts rename to src/services/sqlite/SessionStore.ts index 47578a79..e615f75a 100644 --- a/src/services/sqlite/HooksDatabase.ts +++ b/src/services/sqlite/SessionStore.ts @@ -3,11 +3,10 @@ import { DATA_DIR, DB_PATH, ensureDir } from '../../shared/paths.js'; import { logger } from '../../utils/logger.js'; /** - * Lightweight database interface for hooks - * Provides simple, synchronous operations for hook commands - * No complex logic - just basic CRUD operations + * Session data store for SDK sessions, observations, and summaries + * Provides simple, synchronous CRUD operations for session-based memory */ -export class HooksDatabase { +export class SessionStore { private db: Database; constructor() { @@ -38,10 +37,10 @@ export class HooksDatabase { if (!hasWorkerPort) { this.db.exec('ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER'); - console.error('[HooksDatabase] Added worker_port column to sdk_sessions table'); + console.error('[SessionStore] Added worker_port column to sdk_sessions table'); } } catch (error: any) { - console.error('[HooksDatabase] Migration error:', error.message); + console.error('[SessionStore] Migration error:', error.message); } } @@ -56,7 +55,7 @@ export class HooksDatabase { if (!hasPromptCounter) { this.db.exec('ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0'); - console.error('[HooksDatabase] Added prompt_counter column to sdk_sessions table'); + console.error('[SessionStore] Added prompt_counter column to sdk_sessions table'); } // Check observations for prompt_number @@ -65,7 +64,7 @@ export class HooksDatabase { if (!obsHasPromptNumber) { this.db.exec('ALTER TABLE observations ADD COLUMN prompt_number INTEGER'); - console.error('[HooksDatabase] Added prompt_number column to observations table'); + console.error('[SessionStore] Added prompt_number column to observations table'); } // Check session_summaries for prompt_number @@ -74,7 +73,7 @@ export class HooksDatabase { if (!sumHasPromptNumber) { this.db.exec('ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER'); - console.error('[HooksDatabase] Added prompt_number column to session_summaries table'); + console.error('[SessionStore] Added prompt_number column to session_summaries table'); } // Remove UNIQUE constraint on session_summaries.sdk_session_id @@ -83,7 +82,7 @@ export class HooksDatabase { const hasUniqueConstraint = (summariesIndexes as any[]).some((idx: any) => idx.unique === 1); } catch (error: any) { - console.error('[HooksDatabase] Prompt tracking migration error:', error.message); + console.error('[SessionStore] Prompt tracking migration error:', error.message); } } @@ -101,7 +100,7 @@ export class HooksDatabase { return; } - console.error('[HooksDatabase] Removing UNIQUE constraint from session_summaries.sdk_session_id...'); + console.error('[SessionStore] Removing UNIQUE constraint from session_summaries.sdk_session_id...'); // Begin transaction this.db.exec('BEGIN TRANSACTION'); @@ -153,14 +152,14 @@ export class HooksDatabase { // Commit transaction this.db.exec('COMMIT'); - console.error('[HooksDatabase] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id'); + console.error('[SessionStore] Successfully removed UNIQUE constraint from session_summaries.sdk_session_id'); } catch (error: any) { // Rollback on error this.db.exec('ROLLBACK'); throw error; } } catch (error: any) { - console.error('[HooksDatabase] Migration error (remove UNIQUE constraint):', error.message); + console.error('[SessionStore] Migration error (remove UNIQUE constraint):', error.message); } } @@ -178,7 +177,7 @@ export class HooksDatabase { return; } - console.error('[HooksDatabase] Adding hierarchical fields to observations table...'); + console.error('[SessionStore] Adding hierarchical fields to observations table...'); // Add new columns this.db.exec(` @@ -191,9 +190,9 @@ export class HooksDatabase { ALTER TABLE observations ADD COLUMN files_modified TEXT; `); - console.error('[HooksDatabase] Successfully added hierarchical fields to observations table'); + console.error('[SessionStore] Successfully added hierarchical fields to observations table'); } catch (error: any) { - console.error('[HooksDatabase] Migration error (add hierarchical fields):', error.message); + console.error('[SessionStore] Migration error (add hierarchical fields):', error.message); } } @@ -212,7 +211,7 @@ export class HooksDatabase { return; } - console.error('[HooksDatabase] Making observations.text nullable...'); + console.error('[SessionStore] Making observations.text nullable...'); // Begin transaction this.db.exec('BEGIN TRANSACTION'); @@ -266,14 +265,14 @@ export class HooksDatabase { // Commit transaction this.db.exec('COMMIT'); - console.error('[HooksDatabase] Successfully made observations.text nullable'); + console.error('[SessionStore] Successfully made observations.text nullable'); } catch (error: any) { // Rollback on error this.db.exec('ROLLBACK'); throw error; } } catch (error: any) { - console.error('[HooksDatabase] Migration error (make text nullable):', error.message); + console.error('[SessionStore] Migration error (make text nullable):', error.message); } } diff --git a/src/services/sqlite/index.ts b/src/services/sqlite/index.ts index 5cdc19a0..7ebe5def 100644 --- a/src/services/sqlite/index.ts +++ b/src/services/sqlite/index.ts @@ -1,8 +1,11 @@ // Export main components export { DatabaseManager, getDatabase, initializeDatabase } from './Database.js'; -// Export hooks database -export { HooksDatabase } from './HooksDatabase.js'; +// Export session store (CRUD operations for sessions, observations, summaries) +export { SessionStore } from './SessionStore.js'; + +// Export session search (FTS5 and structured search) +export { SessionSearch } from './SessionSearch.js'; // Export types export * from './types.js'; diff --git a/src/services/sqlite/migrations.ts b/src/services/sqlite/migrations.ts index 5fa82978..0cfeb79a 100644 --- a/src/services/sqlite/migrations.ts +++ b/src/services/sqlite/migrations.ts @@ -362,6 +362,115 @@ export const migration005: Migration = { } }; +/** + * Migration 006 - Add FTS5 full-text search tables + * Creates virtual tables for fast text search on observations and session_summaries + */ +export const migration006: Migration = { + version: 6, + up: (db: Database) => { + // FTS5 virtual table for observations + // Note: This assumes the hierarchical fields (title, subtitle, etc.) already exist + // from the inline migrations in SessionStore constructor + db.run(` + CREATE VIRTUAL TABLE IF NOT EXISTS observations_fts USING fts5( + title, + subtitle, + narrative, + text, + facts, + concepts, + content='observations', + content_rowid='id' + ); + `); + + // Populate FTS table with existing data + db.run(` + INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts) + SELECT id, title, subtitle, narrative, text, facts, concepts + FROM observations; + `); + + // Triggers to keep observations_fts in sync + db.run(` + CREATE TRIGGER IF NOT EXISTS observations_ai AFTER INSERT ON observations BEGIN + INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts) + VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts); + END; + + CREATE TRIGGER IF NOT EXISTS observations_ad AFTER DELETE ON observations BEGIN + INSERT INTO observations_fts(observations_fts, rowid, title, subtitle, narrative, text, facts, concepts) + VALUES('delete', old.id, old.title, old.subtitle, old.narrative, old.text, old.facts, old.concepts); + END; + + CREATE TRIGGER IF NOT EXISTS observations_au AFTER UPDATE ON observations BEGIN + INSERT INTO observations_fts(observations_fts, rowid, title, subtitle, narrative, text, facts, concepts) + VALUES('delete', old.id, old.title, old.subtitle, old.narrative, old.text, old.facts, old.concepts); + INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts) + VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts); + END; + `); + + // FTS5 virtual table for session_summaries + db.run(` + CREATE VIRTUAL TABLE IF NOT EXISTS session_summaries_fts USING fts5( + request, + investigated, + learned, + completed, + next_steps, + notes, + content='session_summaries', + content_rowid='id' + ); + `); + + // Populate FTS table with existing data + db.run(` + INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes) + SELECT id, request, investigated, learned, completed, next_steps, notes + FROM session_summaries; + `); + + // Triggers to keep session_summaries_fts in sync + db.run(` + CREATE TRIGGER IF NOT EXISTS session_summaries_ai AFTER INSERT ON session_summaries BEGIN + INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes) + VALUES (new.id, new.request, new.investigated, new.learned, new.completed, new.next_steps, new.notes); + END; + + CREATE TRIGGER IF NOT EXISTS session_summaries_ad AFTER DELETE ON session_summaries BEGIN + INSERT INTO session_summaries_fts(session_summaries_fts, rowid, request, investigated, learned, completed, next_steps, notes) + VALUES('delete', old.id, old.request, old.investigated, old.learned, old.completed, old.next_steps, old.notes); + END; + + CREATE TRIGGER IF NOT EXISTS session_summaries_au AFTER UPDATE ON session_summaries BEGIN + INSERT INTO session_summaries_fts(session_summaries_fts, rowid, request, investigated, learned, completed, next_steps, notes) + VALUES('delete', old.id, old.request, old.investigated, old.learned, old.completed, old.next_steps, old.notes); + INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes) + VALUES (new.id, new.request, new.investigated, new.learned, new.completed, new.next_steps, new.notes); + END; + `); + + console.log('✅ Created FTS5 virtual tables and triggers for full-text search'); + }, + + down: (db: Database) => { + db.run(` + DROP TRIGGER IF EXISTS observations_au; + DROP TRIGGER IF EXISTS observations_ad; + DROP TRIGGER IF EXISTS observations_ai; + DROP TABLE IF EXISTS observations_fts; + + DROP TRIGGER IF EXISTS session_summaries_au; + DROP TRIGGER IF EXISTS session_summaries_ad; + DROP TRIGGER IF EXISTS session_summaries_ai; + DROP TABLE IF EXISTS session_summaries_fts; + `); + } +}; + /** * All migrations in order */ @@ -370,5 +479,6 @@ export const migrations: Migration[] = [ migration002, migration003, migration004, - migration005 + migration005, + migration006 ]; \ No newline at end of file diff --git a/src/services/sqlite/types.ts b/src/services/sqlite/types.ts index cab8c12d..2f115552 100644 --- a/src/services/sqlite/types.ts +++ b/src/services/sqlite/types.ts @@ -182,3 +182,88 @@ export function normalizeTimestamp(timestamp: string | Date | number | undefined epoch: date.getTime() }; } + +/** + * SDK Hooks Database Types + */ +export interface SDKSessionRow { + id: number; + claude_session_id: string; + sdk_session_id: string | null; + project: string; + user_prompt: string | null; + started_at: string; + started_at_epoch: number; + completed_at: string | null; + completed_at_epoch: number | null; + status: 'active' | 'completed' | 'failed'; + worker_port?: number; + prompt_counter?: number; +} + +export interface ObservationRow { + id: number; + sdk_session_id: string; + project: string; + text: string | null; + type: 'decision' | 'bugfix' | 'feature' | 'refactor' | 'discovery' | 'change'; + title: string | null; + subtitle: string | null; + facts: string | null; // JSON array + narrative: string | null; + concepts: string | null; // JSON array + files_read: string | null; // JSON array + files_modified: string | null; // JSON array + prompt_number: number | null; + created_at: string; + created_at_epoch: number; +} + +export interface SessionSummaryRow { + id: number; + sdk_session_id: string; + project: string; + request: string | null; + investigated: string | null; + learned: string | null; + completed: string | null; + next_steps: string | null; + files_read: string | null; // JSON array + files_edited: string | null; // JSON array + notes: string | null; + prompt_number: number | null; + created_at: string; + created_at_epoch: number; +} + +/** + * Search and Filter Types + */ +export interface DateRange { + start?: string | number; // ISO string or epoch + end?: string | number; // ISO string or epoch +} + +export interface SearchFilters { + project?: string; + type?: ObservationRow['type'] | ObservationRow['type'][]; + concepts?: string | string[]; + files?: string | string[]; + dateRange?: DateRange; +} + +export interface SearchOptions extends SearchFilters { + limit?: number; + offset?: number; + orderBy?: 'relevance' | 'date_desc' | 'date_asc'; +} + +export interface ObservationSearchResult extends ObservationRow { + rank?: number; // FTS5 relevance score (lower is better) + score?: number; // Normalized score (higher is better, 0-1) +} + +export interface SessionSummarySearchResult extends SessionSummaryRow { + rank?: number; // FTS5 relevance score (lower is better) + score?: number; // Normalized score (higher is better, 0-1) +} diff --git a/src/services/worker-service.ts b/src/services/worker-service.ts index 07ea1897..d1ed9d12 100644 --- a/src/services/worker-service.ts +++ b/src/services/worker-service.ts @@ -6,7 +6,7 @@ import express, { Request, Response } from 'express'; import { query } from '@anthropic-ai/claude-agent-sdk'; import type { SDKUserMessage, SDKSystemMessage } from '@anthropic-ai/claude-agent-sdk'; -import { HooksDatabase } from './sqlite/HooksDatabase.js'; +import { SessionStore } from './sqlite/SessionStore.js'; import { buildInitPrompt, buildObservationPrompt, buildFinalizePrompt } from '../sdk/prompts.js'; import { parseObservations, parseSummary } from '../sdk/parser.js'; import type { SDKSession } from '../sdk/prompts.js'; @@ -77,7 +77,7 @@ class WorkerService { this.port = port; // Clean up orphaned sessions from previous worker instances - const db = new HooksDatabase(); + const db = new SessionStore(); const cleanedCount = db.cleanupOrphanedSessions(); db.close(); @@ -148,14 +148,14 @@ class WorkerService { this.sessions.set(sessionDbId, session); // Update port in database - const db = new HooksDatabase(); + const db = new SessionStore(); db.setWorkerPort(sessionDbId, this.port!); db.close(); // Start SDK agent in background session.generatorPromise = this.runSDKAgent(session).catch(err => { logger.failure('WORKER', 'SDK agent error', { sessionId: sessionDbId }, err); - const db = new HooksDatabase(); + const db = new SessionStore(); db.markSessionFailed(sessionDbId); db.close(); this.sessions.delete(sessionDbId); @@ -278,7 +278,7 @@ class WorkerService { } // Mark as failed since we're aborting - const db = new HooksDatabase(); + const db = new SessionStore(); db.markSessionFailed(sessionDbId); db.close(); @@ -313,7 +313,7 @@ class WorkerService { const systemMsg = message as SDKSystemMessage; if (systemMsg.session_id) { // Update in database first, check if it succeeded - const db = new HooksDatabase(); + const db = new SessionStore(); const updated = db.updateSDKSessionId(session.sessionDbId, systemMsg.session_id); db.close(); @@ -354,7 +354,7 @@ class WorkerService { duration: `${(sessionDuration / 1000).toFixed(1)}s` }); - const db = new HooksDatabase(); + const db = new SessionStore(); db.markSessionCompleted(session.sessionDbId); db.close(); @@ -411,7 +411,7 @@ class WorkerService { if (message.type === 'summarize') { session.lastPromptNumber = message.prompt_number; - const db = new HooksDatabase(); + const db = new SessionStore(); const dbSession = db.getSessionById(session.sessionDbId) as SDKSession | undefined; db.close(); @@ -487,7 +487,7 @@ class WorkerService { }); } - const db = new HooksDatabase(); + const db = new SessionStore(); for (const obs of observations) { if (session.sdkSessionId) { db.storeObservation(session.sdkSessionId, session.project, obs, promptNumber);