@karmaniverous/jeeves-watcher 0.4.4 → 0.5.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- !function(e,t,r,i,n,o,s,a,c,l,h,d,u,f,g,p,m,y,w,b,v,M,S,F,k,x,P,z,j,C,E){"use strict";function R(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var T=R(k);function D(e){if(e instanceof Error)return e;if("string"==typeof e)return new Error(e);const t=String("object"==typeof e&&null!==e&&"message"in e?e.message:e),r=new Error(t);return r.cause=e,r}function A(e){const t=e.replace(/\\/g,"/"),r=t.search(/[*?\[]/);if(-1===r)return i.resolve(e);const n=t.slice(0,r),o=n.endsWith("/")?n.slice(0,-1):i.dirname(n);return i.resolve(o)}async function*I(e){let t;try{t=(await r.readdir(e,{withFileTypes:!0})).map((e=>({name:e.name,isDirectory:e.isDirectory()})))}catch{return}for(const n of t){const t=i.resolve(e,n.name);if(n.isDirectory)yield*I(t);else try{(await r.stat(t)).isFile()&&(yield t)}catch{}}}async function W(e,t,r,i){const o=await async function(e,t=[]){const r=e.map((e=>e.replace(/\\/g,"/"))),i=t.map((e=>e.replace(/\\/g,"/"))),o=n(r,{dot:!0}),s=i.length?n(i,{dot:!0}):()=>!1,a=Array.from(new Set(e.map(A))),c=new Set;for(const e of a)for await(const t of I(e)){const e=t.replace(/\\/g,"/");s(e)||o(e)&&c.add(t)}return Array.from(c)}(e,t);for(const e of o)await r[i](e);return o.length}function N(e,t=!1){let r=e.replace(/\\/g,"/").toLowerCase();return t&&(r=r.replace(/^([a-z]):/,((e,t)=>t))),r}function H(e,t){const r=N(e,!0),n=s.createHash("sha256").update(r,"utf8").digest("hex");return i.join(t,`${n}.meta.json`)}async function O(e,t){try{const i=await r.readFile(H(e,t),"utf8");return JSON.parse(i)}catch{return null}}async function L(e,t,n){const o=H(e,t);await r.mkdir(i.dirname(o),{recursive:!0}),await r.writeFile(o,JSON.stringify(n,null,2),"utf8")}async function _(e,t){try{await r.rm(H(e,t))}catch{}}const $=["file_path","chunk_index","total_chunks","content_hash","chunk_text"];function q(e){const{processor:r,vectorStore:i,embeddingProvider:n,logger:s,config:a}=e,c=t({logger:!1});var l;return c.get("/status",(l={vectorStore:i,config:a},async()=>{const e=await l.vectorStore.getCollectionInfo();return{status:"ok",uptime:process.uptime(),collection:{name:l.config.vectorStore.collectionName,pointCount:e.pointCount,dimensions:e.dimensions},payloadFields:e.payloadFields}})),c.post("/metadata",function(e){return async(t,r)=>{try{const{path:r,metadata:i}=t.body;return await e.processor.processMetadataUpdate(r,i),{ok:!0}}catch(t){return e.logger.error({err:D(t)},"Metadata update failed"),r.status(500).send({error:"Internal server error"})}}}({processor:r,logger:s})),c.post("/search",function(e){return async(t,r)=>{try{const{query:r,limit:i=10,filter:n}=t.body,o=await e.embeddingProvider.embed([r]);return await e.vectorStore.search(o[0],i,n)}catch(t){return e.logger.error({err:D(t)},"Search failed"),r.status(500).send({error:"Internal server error"})}}}({embeddingProvider:n,vectorStore:i,logger:s})),c.post("/reindex",function(e){return async(t,r)=>{try{const t=await W(e.config.watch.paths,e.config.watch.ignored,e.processor,"processFile");return await r.status(200).send({ok:!0,filesIndexed:t})}catch(t){return e.logger.error({err:D(t)},"Reindex failed"),await r.status(500).send({error:"Internal server error"})}}}({config:a,processor:r,logger:s})),c.post("/rebuild-metadata",function(e){return async(t,r)=>{try{const t=e.config.metadataDir??".jeeves-metadata",i=[...$];for await(const r of e.vectorStore.scroll()){const e=r.payload,n=e.file_path;if("string"!=typeof n||0===n.length)continue;const s=o.omit(e,i);await L(n,t,s)}return await r.status(200).send({ok:!0})}catch(t){return e.logger.error({err:D(t)},"Rebuild metadata failed"),await r.status(500).send({error:"Internal server error"})}}}({config:a,vectorStore:i,logger:s})),c.post("/config-reindex",function(e){return async(t,r)=>{try{const i=t.body.scope??"rules";return(async()=>{try{if("rules"===i){const t=await W(e.config.watch.paths,e.config.watch.ignored,e.processor,"processRulesUpdate");e.logger.info({scope:i,filesProcessed:t},"Config reindex (rules) completed")}else{const t=await W(e.config.watch.paths,e.config.watch.ignored,e.processor,"processFile");e.logger.info({scope:i,filesProcessed:t},"Config reindex (full) completed")}}catch(t){e.logger.error({err:D(t),scope:i},"Config reindex failed")}})(),await r.status(200).send({status:"started",scope:i})}catch(t){return e.logger.error({err:D(t)},"Config reindex request failed"),await r.status(500).send({error:"Internal server error"})}}}({config:a,processor:r,logger:s})),c}function Q(e){let t=i.resolve(e);const r=i.resolve("/");for(;t!==r;){if(a.existsSync(i.join(t,".git"))&&a.statSync(i.join(t,".git")).isDirectory())return t;const e=i.dirname(t);if(e===t)break;t=e}}function G(e){const t=i.resolve(e);try{return a.statSync(t).isDirectory()?t:i.dirname(t)}catch{}const r=/[*?[{]/.exec(e);if(!r)return;const n=e.slice(0,r.index).trim(),o=0===n.length?".":n.endsWith("/")||n.endsWith("\\")?n:i.dirname(n),s=i.resolve(o);return a.existsSync(s)?s:void 0}function J(e){const t=[],r=i.join(e,".gitignore");let n;a.existsSync(r)&&t.push(r);try{n=a.readdirSync(e)}catch{return t}for(const r of n){if(".git"===r||"node_modules"===r)continue;const n=i.join(e,r);try{a.statSync(n).isDirectory()&&t.push(...J(n))}catch{}}return t}function B(e){const t=a.readFileSync(e,"utf8");return c().add(t)}class K{repos=new Map;constructor(e){this.scan(e)}scan(e){this.repos.clear();const t=new Set;for(const r of e){const e=G(r);if(!e)continue;if(t.has(e))continue;t.add(e);const n=Q(e);if(!n)continue;if(this.repos.has(n))continue;const o=J(n).map((e=>({dir:i.dirname(e),ig:B(e)})));o.sort(((e,t)=>t.dir.length-e.dir.length)),this.repos.set(n,{root:n,entries:o})}}isIgnored(e){const t=i.resolve(e);for(const[,e]of this.repos){const r=i.relative(e.root,t);if(!(r.startsWith("..")||r.startsWith(i.resolve("/"))||/^[a-zA-Z]:/.test(r)))for(const r of e.entries){const e=i.relative(r.dir,t);if(e.startsWith("..")||/^[a-zA-Z]:/.test(e))continue;const n=e.replace(/\\/g,"/");if(r.ig.ignores(n))return!0}}return!1}invalidate(e){const t=i.resolve(e),r=i.dirname(t);for(const[,e]of this.repos){if(!i.relative(e.root,r).startsWith(".."))return e.entries=e.entries.filter((e=>e.dir!==r)),void(a.existsSync(t)&&(e.entries.push({dir:r,ig:B(t)}),e.entries.sort(((e,t)=>t.dir.length-e.dir.length))))}const n=Q(r);if(n&&a.existsSync(t)){const e=[{dir:r,ig:B(t)}];if(this.repos.has(n)){const t=this.repos.get(n);t.entries.push(e[0]),t.entries.sort(((e,t)=>t.dir.length-e.dir.length))}else this.repos.set(n,{root:n,entries:e})}}}function U(e,t){return"string"!=typeof e?e:e.replace(/\$\{([^}]+)\}/g,((e,r)=>{const i=o.get(t,r);return null==i?"":"string"==typeof i?i:JSON.stringify(i)}))}function V(e,t){const r={};for(const[i,n]of Object.entries(e))r[i]=U(n,t);return r}async function Y(e,t){const r={};for(const n of e){const e=i.resolve(t,n),o=await import(l.pathToFileURL(e).href),s="object"==typeof o.default&&null!==o.default?o.default:o;for(const[e,t]of Object.entries(s))"function"==typeof t&&(r[e]=t)}return r}async function Z(e,t,r,n,s,c,l){const d=function(e,t){const r=new Map,n=t=>{const n=e?i.resolve(e,t):t;if(!r.has(n)){const e=a.readFileSync(n,"utf-8");r.set(n,JSON.parse(e))}return r.get(n)};return{split:(e,t)=>e.split(t),slice:(e,t,r)=>e.slice(t,r),join:(e,t)=>e.join(t),toLowerCase:e=>e.toLowerCase(),replace:(e,t,r)=>e.replace(t,r),get:(e,t)=>o.get(e,t),lookupJson:(e,t,r)=>{const i=n(e)[t];return null==i?null:r?o.get(i,r)??null:i},mapLookup:(e,t,r)=>{if(!Array.isArray(t))return[];const i=n(e),s=[];for(const e of t){if("string"!=typeof e)continue;const t=i[e];if(null==t)continue;const n=o.get(t,r);if(null!=n)if(Array.isArray(n))for(const e of n)s.push(e);else s.push(n)}return s},...t}}(c,l);let u={},f=null;const g=n??console;for(const[n,{rule:o,validate:l}]of e.entries())if(l(t)){const e=V(o.set,t);if(u={...u,...e},o.map){let e;if("string"==typeof o.map){if(o.map.endsWith(".json")&&c)try{const t=i.resolve(c,o.map),r=a.readFileSync(t,"utf-8");e=JSON.parse(r)}catch(e){g.warn(`Failed to load map file "${o.map}": ${e instanceof Error?e.message:String(e)}`);continue}else if(e=r?.[o.map],!e){g.warn(`Map reference "${o.map}" not found in named maps. Skipping map transformation.`);continue}}else e=o.map;try{const r=new h.JsonMap(e,d),i=await r.transform(t);i&&"object"==typeof i&&!Array.isArray(i)?u={...u,...i}:g.warn("JsonMap transformation did not return an object; skipping merge.")}catch(e){g.warn(`JsonMap transformation failed: ${e instanceof Error?e.message:String(e)}`)}}if(o.template&&s){const e=`rule-${String(n)}`,r={...t.json??{},...t,...u};try{const t=s.render(e,r);t&&t.trim()?f=t:g.warn(`Template for rule ${String(n)} rendered empty output. Falling back to raw content.`)}catch(e){g.warn(`Template render failed for rule ${String(n)}: ${e instanceof Error?e.message:String(e)}. Falling back to raw content.`)}}}return{metadata:u,renderedContent:f}}const X=y.unified().use(m,{fragment:!0});function ee(e){e.registerHelper("adfToMarkdown",(function(t){if(!t||"object"!=typeof t)return"";try{const r=g.fromADF(t);return new e.SafeString(p.toMarkdown(r).trim())}catch{return"\x3c!-- ADF conversion failed --\x3e"}})),e.registerHelper("markdownify",(function(t){if("string"!=typeof t||!t.trim())return"";try{const r=X.parse(t),i=f.toMdast(r);return new e.SafeString(p.toMarkdown(i).trim())}catch{return"\x3c!-- HTML conversion failed --\x3e"}})),e.registerHelper("dateFormat",(function(e,t){if(null==e)return"";const r="string"==typeof t?t:"YYYY-MM-DD";return u(e).format(r)})),e.registerHelper("join",(function(e,t){if(!Array.isArray(e))return"";const r="string"==typeof t?t:", ";return e.join(r)})),e.registerHelper("pluck",(function(e,t){return Array.isArray(e)&&"string"==typeof t?e.map((e=>e&&"object"==typeof e?e[t]:void 0)):[]})),e.registerHelper("lowercase",(e=>"string"==typeof e?e.toLowerCase():"")),e.registerHelper("uppercase",(e=>"string"==typeof e?e.toUpperCase():"")),e.registerHelper("capitalize",(e=>"string"==typeof e?o.capitalize(e):"")),e.registerHelper("title",(e=>"string"==typeof e?o.title(e):"")),e.registerHelper("camel",(e=>"string"==typeof e?o.camel(e):"")),e.registerHelper("snake",(e=>"string"==typeof e?o.snake(e):"")),e.registerHelper("dash",(e=>"string"==typeof e?o.dash(e):"")),e.registerHelper("default",(function(e,t){return e??t??""})),e.registerHelper("eq",(function(e,t){return o.isEqual(e,t)})),e.registerHelper("json",(function(t){return new e.SafeString(JSON.stringify(t,null,2))}))}function te(e,t,r,n=new Set){if(e.endsWith(".hbs")||e.endsWith(".handlebars"))return a.readFileSync(i.resolve(r,e),"utf-8");if(void 0!==t?.[e]){if(n.has(e))throw new Error(`Circular template reference detected: ${e}`);return n.add(e),te(t[e],t,r,n)}return e}function re(){const e=d.create();return ee(e),e}async function ie(e,t,r){for(const n of t){const t=i.resolve(r,n),o=await import(l.pathToFileURL(t).href);"function"==typeof o.default&&o.default(e)}}class ne{hbs;compiled=new Map;constructor(e){this.hbs=e}compile(e,t){const r=this.hbs.compile(t);return this.compiled.set(e,r),r}get(e){return this.compiled.get(e)}render(e,t){const r=this.compiled.get(e);return r?r(t):null}}async function oe(e,t,r,i){if(0===e.filter((e=>e.template)).length)return;const n=re();r?.length&&i&&await ie(n,r,i);const o=new ne(n);for(const[r,n]of e.entries()){if(!n.template)continue;const e=te(n.template,t,i??".");o.compile(`rule-${String(r)}`,e)}return o}class se{options;watcher;debounce;constructor(e){this.options=e}start(){this.options.enabled&&(this.watcher=w.watch(this.options.configPath,{ignoreInitial:!0}),this.watcher.on("change",(()=>{this.debounce&&clearTimeout(this.debounce),this.debounce=setTimeout((()=>{this.options.onChange()}),this.options.debounceMs)})),this.watcher.on("error",(e=>{this.options.logger.error({err:D(e)},"Config watcher error")})),this.options.logger.info({configPath:this.options.configPath,debounceMs:this.options.debounceMs},"Config watcher started"))}async stop(){this.debounce&&(clearTimeout(this.debounce),this.debounce=void 0),this.watcher&&(await this.watcher.close(),this.watcher=void 0)}}const ae={metadataDir:".jeeves-watcher",shutdownTimeoutMs:1e4},ce={enabled:!0,debounceMs:1e3},le={host:"127.0.0.1",port:3456},he={level:"info"},de={debounceMs:300,stabilityThresholdMs:500,usePolling:!1,pollIntervalMs:1e3,respectGitignore:!0},ue={chunkSize:1e3,chunkOverlap:200,dimensions:3072,rateLimitPerMinute:300,concurrency:5},fe=v.z.object({paths:v.z.array(v.z.string()).min(1).describe('Glob patterns for files to watch (e.g., "**/*.md"). At least one required.'),ignored:v.z.array(v.z.string()).optional().describe('Glob patterns to exclude from watching (e.g., "**/node_modules/**").'),pollIntervalMs:v.z.number().optional().describe("Polling interval in milliseconds when usePolling is enabled."),usePolling:v.z.boolean().optional().describe("Use polling instead of native file system events (for network drives)."),debounceMs:v.z.number().optional().describe("Debounce delay in milliseconds for file change events."),stabilityThresholdMs:v.z.number().optional().describe("Time in milliseconds a file must remain unchanged before processing."),respectGitignore:v.z.boolean().optional().describe("Skip files ignored by .gitignore in git repositories. Only applies to repos with a .git directory. Default: true.")}),ge=v.z.object({enabled:v.z.boolean().optional().describe("Enable automatic reloading when config file changes."),debounceMs:v.z.number().optional().describe("Debounce delay in milliseconds for config file change detection.")}),pe=v.z.object({provider:v.z.string().default("gemini").describe('Embedding provider name (e.g., "gemini", "openai").'),model:v.z.string().default("gemini-embedding-001").describe('Embedding model identifier (e.g., "gemini-embedding-001", "text-embedding-3-small").'),chunkSize:v.z.number().optional().describe("Maximum chunk size in characters for text splitting."),chunkOverlap:v.z.number().optional().describe("Character overlap between consecutive chunks."),dimensions:v.z.number().optional().describe("Embedding vector dimensions (must match model output)."),apiKey:v.z.string().optional().describe("API key for embedding provider (supports ${ENV_VAR} substitution)."),rateLimitPerMinute:v.z.number().optional().describe("Maximum embedding API requests per minute (rate limiting)."),concurrency:v.z.number().optional().describe("Maximum concurrent embedding requests.")}),me=v.z.object({url:v.z.string().describe('Qdrant server URL (e.g., "http://localhost:6333").'),collectionName:v.z.string().describe("Qdrant collection name for vector storage."),apiKey:v.z.string().optional().describe("Qdrant API key for authentication (supports ${ENV_VAR} substitution).")}),ye=v.z.object({host:v.z.string().optional().describe('Host address for API server (e.g., "127.0.0.1", "0.0.0.0").'),port:v.z.number().optional().describe("Port for API server (e.g., 3456).")}),we=v.z.object({level:v.z.string().optional().describe("Logging level (trace, debug, info, warn, error, fatal)."),file:v.z.string().optional().describe("Path to log file (logs to stdout if omitted).")}),be=v.z.object({match:v.z.record(v.z.string(),v.z.unknown()).describe("JSON Schema object to match against file attributes."),set:v.z.record(v.z.string(),v.z.unknown()).describe("Metadata fields to set when match succeeds."),map:v.z.union([h.jsonMapMapSchema,v.z.string()]).optional().describe("JsonMap transformation (inline definition, named map reference, or .json file path)."),template:v.z.string().optional().describe("Handlebars content template (inline string, named ref, or .hbs/.handlebars file path).")}),ve=v.z.object({watch:fe.describe("File system watch configuration."),configWatch:ge.optional().describe("Configuration file watch settings."),embedding:pe.describe("Embedding model configuration."),vectorStore:me.describe("Qdrant vector store configuration."),metadataDir:v.z.string().optional().describe("Directory for persisted metadata sidecar files."),api:ye.optional().describe("API server configuration."),extractors:v.z.record(v.z.string(),v.z.unknown()).optional().describe("Extractor configurations keyed by name."),inferenceRules:v.z.array(be).optional().describe("Rules for inferring metadata from file attributes."),maps:v.z.record(v.z.string(),h.jsonMapMapSchema.or(v.z.string())).optional().describe("Reusable named JsonMap transformations (inline definition or .json file path resolved relative to config directory)."),templates:v.z.record(v.z.string(),v.z.string()).optional().describe("Named reusable Handlebars templates (inline strings or .hbs/.handlebars file paths)."),templateHelpers:v.z.object({paths:v.z.array(v.z.string()).optional().describe("File paths to custom helper modules.")}).optional().describe("Custom Handlebars helper registration."),mapHelpers:v.z.object({paths:v.z.array(v.z.string()).optional().describe("File paths to JS modules exporting functions to merge into the JsonMap lib.")}).optional().describe("Custom JsonMap lib function registration."),logging:we.optional().describe("Logging configuration."),shutdownTimeoutMs:v.z.number().optional().describe("Timeout in milliseconds for graceful shutdown."),maxRetries:v.z.number().optional().describe("Maximum consecutive system-level failures before triggering fatal error. Default: Infinity."),maxBackoffMs:v.z.number().optional().describe("Maximum backoff delay in milliseconds for system errors. Default: 60000.")}),Me=/\$\{([^}]+)\}/g;function Se(e){if("string"==typeof e)return function(e){return e.replace(Me,((e,t)=>{const r=process.env[t];return void 0===r?e:r}))}(e);if(Array.isArray(e))return e.map((e=>Se(e)));if(null!==e&&"object"==typeof e){const t={};for(const[r,i]of Object.entries(e))t[r]=Se(i);return t}return e}const Fe="jeeves-watcher";async function ke(e){const t=b.cosmiconfig(Fe),r=e?await t.load(e):await t.search();if(!r||r.isEmpty)throw new Error("No jeeves-watcher configuration found. Create a .jeeves-watcherrc or jeeves-watcher.config.{js,ts,json,yaml} file.");try{const e=ve.parse(r.config);if(e.maps){const t=i.dirname(r.filepath);for(const[r,n]of Object.entries(e.maps))if("string"==typeof n){const o=i.resolve(t,n),s=a.readFileSync(o,"utf-8");e.maps[r]=JSON.parse(s)}}return Se((n=e,{...ae,...n,watch:{...de,...n.watch},configWatch:{...ce,...n.configWatch},embedding:{...ue,...n.embedding},api:{...le,...n.api},logging:{...he,...n.logging}}))}catch(e){if(e instanceof v.ZodError){const t=e.issues.map((e=>`${e.path.join(".")}: ${e.message}`)).join("; ");throw new Error(`Invalid jeeves-watcher configuration: ${t}`)}throw e}var n}function xe(e){return e||{warn(e,t){t?console.warn(e,t):console.warn(e)}}}function Pe(e,t){return e<=0?Promise.resolve():new Promise(((r,i)=>{const n=setTimeout((()=>{s(),r()}),e),o=()=>{s(),i(new Error("Retry sleep aborted"))},s=()=>{clearTimeout(n),t&&t.removeEventListener("abort",o)};if(t){if(t.aborted)return void o();t.addEventListener("abort",o,{once:!0})}}))}function ze(e,t,r,i=0){const n=Math.max(0,e-1),o=Math.min(r,t*2**n),s=i>0?1+Math.random()*i:1;return Math.round(o*s)}async function je(e,t){const r=Math.max(1,t.attempts);let i;for(let n=1;n<=r;n++)try{return await e(n)}catch(e){i=e;if(n>=r)break;const o=ze(n,t.baseDelayMs,t.maxDelayMs,t.jitter);t.onRetry?.({attempt:n,attempts:r,delayMs:o,error:e}),await Pe(o,t.signal)}throw i}const Ce=new Map([["mock",function(e){return function(e){return{dimensions:e,embed:t=>Promise.resolve(t.map((t=>{const r=s.createHash("sha256").update(t,"utf8").digest(),i=[];for(let t=0;t<e;t++){const e=r[t%r.length];i.push(e/127.5-1)}return i})))}}(e.dimensions??768)}],["gemini",function(e,t){if(!e.apiKey)throw new Error("Gemini embedding provider requires config.embedding.apiKey");const r=e.dimensions??3072,i=xe(t),n=new M.GoogleGenerativeAIEmbeddings({apiKey:e.apiKey,model:e.model});return{dimensions:r,async embed(t){const o=await je((async r=>(r>1&&i.warn({attempt:r,provider:"gemini",model:e.model},"Retrying embedding request"),n.embedDocuments(t))),{attempts:5,baseDelayMs:500,maxDelayMs:1e4,jitter:.2,onRetry:({attempt:t,delayMs:r,error:n})=>{i.warn({attempt:t,delayMs:r,provider:"gemini",model:e.model,err:D(n)},"Embedding call failed; will retry")}});for(const e of o)if(e.length!==r)throw new Error(`Gemini embedding returned invalid dimensions: expected ${String(r)}, got ${String(e.length)}`);return o}}}]]);function Ee(e,t){const r=Ce.get(e.provider);if(!r)throw new Error(`Unsupported embedding provider: ${e.provider}`);return r(e,t)}function Re(e){const t=e?.level??"info";if(e?.file){const r=S.transport({target:"pino/file",options:{destination:e.file,mkdir:!0}});return S({level:t},r)}return S({level:t})}function Te(e){return s.createHash("sha256").update(e,"utf8").digest("hex")}const De="6a6f686e-6761-4c74-ad6a-656576657321";function Ae(e,t){const r=void 0!==t?`${N(e)}#${String(t)}`:N(e);return F.v5(r,De)}const Ie=["content","body","text","snippet","subject","description","summary","transcript"];function We(e){if(!e||"object"!=typeof e)return JSON.stringify(e);const t=e;for(const e of Ie){const r=t[e];if("string"==typeof r&&r.trim())return r}return JSON.stringify(e)}async function Ne(e){const t=await r.readFile(e,"utf8"),{frontmatter:i,body:n}=function(e){const t=e.replace(/^\uFEFF/,"");if(!/^\s*---/.test(t))return{body:e};const r=/^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/m.exec(t);if(!r)return{body:e};const[,i,n]=r,o=x.load(i);return{frontmatter:o&&"object"==typeof o&&!Array.isArray(o)?o:void 0,body:n}}(t);return{text:n,frontmatter:i}}async function He(e){return{text:(await r.readFile(e,"utf8")).replace(/^\uFEFF/,"")}}async function Oe(e){const t=await r.readFile(e,"utf8"),i=T.load(t.replace(/^\uFEFF/,""));i("script, style").remove();return{text:i("body").text().trim()||i.text().trim()}}const Le=new Map([[".md",Ne],[".markdown",Ne],[".txt",He],[".text",He],[".json",async function(e){const t=await r.readFile(e,"utf8"),i=JSON.parse(t.replace(/^\uFEFF/,"")),n=i&&"object"==typeof i&&!Array.isArray(i)?i:void 0;return{text:We(i),json:n}}],[".pdf",async function(e){const t=await r.readFile(e),i=new Uint8Array(t),{extractText:n}=await import("unpdf"),{text:o}=await n(i);return{text:Array.isArray(o)?o.join("\n\n"):o}}],[".docx",async function(e){const t=await r.readFile(e);return{text:(await P.extractRawText({buffer:t})).value}}],[".html",Oe],[".htm",Oe]]);async function _e(e,t){const r=Le.get(t.toLowerCase());return r?r(e):He(e)}function $e(e,t,r,n){const o=e.replace(/\\/g,"/"),s={file:{path:o,directory:i.dirname(o).replace(/\\/g,"/"),filename:i.basename(o),extension:i.extname(o),sizeBytes:t.size,modified:t.mtime.toISOString()}};return r&&(s.frontmatter=r),n&&(s.json=n),s}function qe(e){const t=function(){const e=new z({allErrors:!0});return j(e),e.addKeyword({keyword:"glob",type:"string",schemaType:"string",validate:(e,t)=>n.isMatch(t,e)}),e}();return e.map(((e,r)=>({rule:e,validate:t.compile({$id:`rule-${String(r)}`,...e.match})})))}async function Qe(e,t,n,o,s,a,c,l){const h=i.extname(e),d=await r.stat(e),u=await _e(e,h),f=$e(e,d,u.frontmatter,u.json),{metadata:g,renderedContent:p}=await Z(t,f,o,s,a,c,l),m=await O(e,n);return{inferred:g,enrichment:m,metadata:{...g,...m??{}},attributes:f,extracted:u,renderedContent:p}}function Ge(e,t){const r=[];for(let i=0;i<t;i++)r.push(Ae(e,i));return r}function Je(e,t=1){if(!e)return t;const r=e.total_chunks;return"number"==typeof r?r:t}class Be{config;embeddingProvider;vectorStore;compiledRules;logger;templateEngine;constructor(e,t,r,i,n,o){this.config=e,this.embeddingProvider=t,this.vectorStore=r,this.compiledRules=i,this.logger=n,this.templateEngine=o}async processFile(e){try{const t=i.extname(e),{metadata:r,extracted:n,renderedContent:o}=await Qe(e,this.compiledRules,this.config.metadataDir,this.config.maps,this.logger,this.templateEngine,this.config.configDir,this.config.customMapLib),s=o??n.text;if(!s.trim())return void this.logger.debug({filePath:e},"Skipping empty file");const a=Te(s),c=Ae(e,0),l=await this.vectorStore.getPayload(c);if(l&&l.content_hash===a)return void this.logger.debug({filePath:e},"Content unchanged, skipping");const h=Je(l),d=this.config.chunkSize??1e3,u=function(e,t,r){const i=e.toLowerCase();return".md"===i||".markdown"===i?new C.MarkdownTextSplitter({chunkSize:t,chunkOverlap:r}):new C.RecursiveCharacterTextSplitter({chunkSize:t,chunkOverlap:r})}(t,d,this.config.chunkOverlap??200),f=await u.splitText(s),g=await this.embeddingProvider.embed(f),p=f.map(((t,i)=>({id:Ae(e,i),vector:g[i],payload:{...r,file_path:e.replace(/\\/g,"/"),chunk_index:i,total_chunks:f.length,content_hash:a,chunk_text:t}})));if(await this.vectorStore.upsert(p),h>f.length){const t=Ge(e,h).slice(f.length);await this.vectorStore.delete(t)}this.logger.info({filePath:e,chunks:f.length},"File processed successfully")}catch(t){this.logger.error({filePath:e,err:D(t)},"Failed to process file")}}async deleteFile(e){try{const t=Ae(e,0),r=await this.vectorStore.getPayload(t),i=Ge(e,Je(r));await this.vectorStore.delete(i),await _(e,this.config.metadataDir),this.logger.info({filePath:e},"File deleted from index")}catch(t){this.logger.error({filePath:e,err:D(t)},"Failed to delete file")}}async processMetadataUpdate(e,t){try{const r={...await O(e,this.config.metadataDir)??{},...t};await L(e,this.config.metadataDir,r);const i=Ae(e,0),n=await this.vectorStore.getPayload(i);if(!n)return null;const o=Je(n),s=Ge(e,o);return await this.vectorStore.setPayload(s,r),this.logger.info({filePath:e,chunks:o},"Metadata updated"),r}catch(t){return this.logger.error({filePath:e,err:D(t)},"Failed to update metadata"),null}}async processRulesUpdate(e){try{const t=Ae(e,0),r=await this.vectorStore.getPayload(t);if(!r)return this.logger.debug({filePath:e},"File not indexed, skipping"),null;const{metadata:i}=await Qe(e,this.compiledRules,this.config.metadataDir,this.config.maps,this.logger,this.templateEngine,this.config.configDir,this.config.customMapLib),n=Je(r),o=Ge(e,n);return await this.vectorStore.setPayload(o,i),this.logger.info({filePath:e,chunks:n},"Rules re-applied"),i}catch(t){return this.logger.error({filePath:e,err:D(t)},"Failed to re-apply rules"),null}}updateRules(e,t,r){this.compiledRules=e,t&&(this.templateEngine=t),void 0!==r&&(this.config={...this.config,customMapLib:r}),this.logger.info({rules:e.length},"Inference rules updated")}}class Ke{debounceMs;concurrency;rateLimitPerMinute;started=!1;active=0;debounceTimers=new Map;latestByKey=new Map;normalQueue=[];lowQueue=[];tokens;lastRefillMs=Date.now();drainWaiters=[];constructor(e){this.debounceMs=e.debounceMs,this.concurrency=e.concurrency,this.rateLimitPerMinute=e.rateLimitPerMinute,this.tokens=this.rateLimitPerMinute??Number.POSITIVE_INFINITY}enqueue(e,t){const r=`${e.priority}:${e.path}`;this.latestByKey.set(r,{event:e,fn:t});const i=this.debounceTimers.get(r);i&&clearTimeout(i);const n=setTimeout((()=>{this.debounceTimers.delete(r);const e=this.latestByKey.get(r);e&&(this.latestByKey.delete(r),this.push(e),this.pump())}),this.debounceMs);this.debounceTimers.set(r,n)}process(){this.started=!0,this.pump()}async drain(){this.isIdle()||await new Promise((e=>{this.drainWaiters.push(e)}))}push(e){"low"===e.event.priority?this.lowQueue.push(e):this.normalQueue.push(e)}refillTokens(e){if(void 0===this.rateLimitPerMinute)return;const t=Math.max(0,e-this.lastRefillMs)*(this.rateLimitPerMinute/6e4);this.tokens=Math.min(this.rateLimitPerMinute,this.tokens+t),this.lastRefillMs=e}takeToken(){const e=Date.now();return this.refillTokens(e),!(this.tokens<1)&&(this.tokens-=1,!0)}nextItem(){return this.normalQueue.shift()??this.lowQueue.shift()}pump(){if(this.started){for(;this.active<this.concurrency;){const e=this.nextItem();if(!e)break;if(!this.takeToken()){"low"===e.event.priority?this.lowQueue.unshift(e):this.normalQueue.unshift(e),setTimeout((()=>{this.pump()}),250);break}this.active+=1,Promise.resolve().then((()=>e.fn(e.event))).finally((()=>{this.active-=1,this.pump(),this.maybeResolveDrain()}))}this.maybeResolveDrain()}}isIdle(){return 0===this.active&&0===this.normalQueue.length&&0===this.lowQueue.length&&0===this.debounceTimers.size&&0===this.latestByKey.size}maybeResolveDrain(){if(!this.isIdle())return;const e=this.drainWaiters;this.drainWaiters=[];for(const t of e)t()}}function Ue(e){return null==e?"keyword":"number"==typeof e?Number.isInteger(e)?"integer":"float":"boolean"==typeof e?"bool":Array.isArray(e)?"keyword[]":"string"==typeof e&&e.length>256?"text":"keyword"}class Ve{client;collectionName;dims;log;constructor(e,t,r){this.client=new E.QdrantClient({url:e.url,apiKey:e.apiKey,checkCompatibility:!1}),this.collectionName=e.collectionName,this.dims=t,this.log=xe(r)}async ensureCollection(){try{const e=await this.client.getCollections();e.collections.some((e=>e.name===this.collectionName))||await this.client.createCollection(this.collectionName,{vectors:{size:this.dims,distance:"Cosine"}})}catch(e){throw new Error(`Failed to ensure collection "${this.collectionName}": ${String(e)}`)}}async upsert(e){0!==e.length&&await je((async t=>{t>1&&this.log.warn({attempt:t,operation:"qdrant.upsert",points:e.length},"Retrying Qdrant upsert"),await this.client.upsert(this.collectionName,{wait:!0,points:e.map((e=>({id:e.id,vector:e.vector,payload:e.payload})))})}),{attempts:5,baseDelayMs:500,maxDelayMs:1e4,jitter:.2,onRetry:({attempt:e,delayMs:t,error:r})=>{this.log.warn({attempt:e,delayMs:t,operation:"qdrant.upsert",err:D(r)},"Qdrant upsert failed; will retry")}})}async delete(e){0!==e.length&&await je((async t=>{t>1&&this.log.warn({attempt:t,operation:"qdrant.delete",ids:e.length},"Retrying Qdrant delete"),await this.client.delete(this.collectionName,{wait:!0,points:e})}),{attempts:5,baseDelayMs:500,maxDelayMs:1e4,jitter:.2,onRetry:({attempt:e,delayMs:t,error:r})=>{this.log.warn({attempt:e,delayMs:t,operation:"qdrant.delete",err:D(r)},"Qdrant delete failed; will retry")}})}async setPayload(e,t){0!==e.length&&await this.client.setPayload(this.collectionName,{wait:!0,points:e,payload:t})}async getPayload(e){try{const t=await this.client.retrieve(this.collectionName,{ids:[e],with_payload:!0,with_vector:!1});return 0===t.length?null:t[0].payload}catch{return null}}async getCollectionInfo(){const e=await this.client.getCollection(this.collectionName),t=e.points_count??0,r=e.config.params.vectors,i=void 0!==r&&"size"in r?r.size:0,n={},o=Object.entries(e.payload_schema);if(o.length>0)for(const[e,t]of o)n[e]={type:t.data_type??"unknown"};else t>0&&await this.discoverPayloadFields(n);return{pointCount:t,dimensions:i,payloadFields:n}}async discoverPayloadFields(e,t=100){const r=await this.client.scroll(this.collectionName,{limit:t,with_payload:!0,with_vector:!1});for(const t of r.points){const r=t.payload;if(r)for(const[t,i]of Object.entries(r))t in e||(e[t]={type:Ue(i)})}}async search(e,t,r){return(await this.client.search(this.collectionName,{vector:e,limit:t,with_payload:!0,...r?{filter:r}:{}})).map((e=>({id:String(e.id),score:e.score,payload:e.payload})))}async*scroll(e,t=100){let r;for(;;){const i=await this.client.scroll(this.collectionName,{limit:t,with_payload:!0,with_vector:!1,...e?{filter:e}:{},...void 0!==r?{offset:r}:{}});for(const e of i.points)yield{id:String(e.id),payload:e.payload};const n=i.next_page_offset;if(null==n)break;if("string"!=typeof n&&"number"!=typeof n)break;r=n}}}class Ye{consecutiveFailures=0;maxRetries;maxBackoffMs;baseDelayMs;onFatalError;logger;constructor(e){this.maxRetries=e.maxRetries??Number.POSITIVE_INFINITY,this.maxBackoffMs=e.maxBackoffMs??6e4,this.baseDelayMs=e.baseDelayMs??1e3,this.onFatalError=e.onFatalError,this.logger=e.logger}recordSuccess(){this.consecutiveFailures>0&&this.logger.info({previousFailures:this.consecutiveFailures},"System health recovered"),this.consecutiveFailures=0}recordFailure(e){if(this.consecutiveFailures+=1,this.logger.error({consecutiveFailures:this.consecutiveFailures,maxRetries:this.maxRetries,err:D(e)},"System-level failure recorded"),this.consecutiveFailures>=this.maxRetries){if(this.logger.fatal({consecutiveFailures:this.consecutiveFailures},"Maximum retries exceeded, triggering fatal error"),this.onFatalError)return this.onFatalError(e),!1;throw e instanceof Error?e:new Error(`Fatal system error: ${String(e)}`)}return!0}get currentBackoffMs(){if(0===this.consecutiveFailures)return 0;const e=Math.max(0,this.consecutiveFailures-1);return Math.min(this.maxBackoffMs,this.baseDelayMs*2**e)}async backoff(e){const t=this.currentBackoffMs;t<=0||(this.logger.warn({delayMs:t,consecutiveFailures:this.consecutiveFailures},"Backing off before next attempt"),await new Promise(((r,i)=>{const n=setTimeout((()=>{s(),r()}),t),o=()=>{s(),i(new Error("Backoff aborted"))},s=()=>{clearTimeout(n),e&&e.removeEventListener("abort",o)};if(e){if(e.aborted)return void o();e.addEventListener("abort",o,{once:!0})}})))}get failures(){return this.consecutiveFailures}}function Ze(e){const t=e.replace(/\\/g,"/").split("/"),r=[];for(const e of t){if(/[*?{[\]]/.test(e))break;r.push(e)}return r.join("/")||"."}function Xe(e){const t=function(e){const t=e.map((e=>e.replace(/\\/g,"/").toLowerCase()));return[...new Set(t)].sort().filter(((e,t,r)=>{const i=e.endsWith("/")?e:e+"/";return!r.some((t=>t!==e&&i.startsWith(t+"/")))}))}(e.map(Ze)),r=function(e){const t=e.map((e=>e.replace(/\\/g,"/"))),r=n(t,{dot:!0,nocase:!0});return e=>{const t=e.replace(/\\/g,"/");return r(t)}}(e);return{roots:t,matches:r}}class et{config;queue;processor;logger;health;gitignoreFilter;globMatches;watcher;constructor(e,t,r,i,n={}){this.config=e,this.queue=t,this.processor=r,this.logger=i,this.gitignoreFilter=n.gitignoreFilter,this.globMatches=()=>!0;const o={maxRetries:n.maxRetries,maxBackoffMs:n.maxBackoffMs,onFatalError:n.onFatalError,logger:i};this.health=new Ye(o)}start(){const{roots:e,matches:t}=Xe(this.config.paths);this.globMatches=t;const r=this.config.ignored?function(e){return e.map((e=>{if("string"!=typeof e)return e;const t=e.replace(/\\/g,"/"),r=n(t,{dot:!0,nocase:!0});return e=>{const t=e.replace(/\\/g,"/");return r(t)}}))}(this.config.ignored):void 0;this.watcher=w.watch(e,{ignored:r,usePolling:this.config.usePolling,interval:this.config.pollIntervalMs,awaitWriteFinish:!!this.config.stabilityThresholdMs&&{stabilityThreshold:this.config.stabilityThresholdMs},ignoreInitial:!1}),this.watcher.on("add",(e=>{this.handleGitignoreChange(e),this.globMatches(e)&&(this.isGitignored(e)||(this.logger.debug({path:e},"File added"),this.queue.enqueue({type:"create",path:e,priority:"normal"},(()=>this.wrapProcessing((()=>this.processor.processFile(e)))))))})),this.watcher.on("change",(e=>{this.handleGitignoreChange(e),this.globMatches(e)&&(this.isGitignored(e)||(this.logger.debug({path:e},"File changed"),this.queue.enqueue({type:"modify",path:e,priority:"normal"},(()=>this.wrapProcessing((()=>this.processor.processFile(e)))))))})),this.watcher.on("unlink",(e=>{this.handleGitignoreChange(e),this.globMatches(e)&&(this.isGitignored(e)||(this.logger.debug({path:e},"File removed"),this.queue.enqueue({type:"delete",path:e,priority:"normal"},(()=>this.wrapProcessing((()=>this.processor.deleteFile(e)))))))})),this.watcher.on("error",(e=>{this.logger.error({err:D(e)},"Watcher error"),this.health.recordFailure(e)})),this.queue.process(),this.logger.info({paths:this.config.paths},"Filesystem watcher started")}async stop(){this.watcher&&(await this.watcher.close(),this.watcher=void 0,this.logger.info("Filesystem watcher stopped"))}get systemHealth(){return this.health}isGitignored(e){if(!this.gitignoreFilter)return!1;const t=this.gitignoreFilter.isIgnored(e);return t&&this.logger.debug({path:e},"Skipping gitignored file"),t}handleGitignoreChange(e){this.gitignoreFilter&&e.endsWith(".gitignore")&&(this.logger.info({path:e},"Gitignore file changed, refreshing filter"),this.gitignoreFilter.invalidate(e))}async wrapProcessing(e){try{await this.health.backoff(),await e(),this.health.recordSuccess()}catch(e){this.health.recordFailure(e)||await this.stop()}}}const tt={loadConfig:ke,createLogger:Re,createEmbeddingProvider:Ee,createVectorStoreClient:(e,t,r)=>new Ve(e,t,r),compileRules:qe,createDocumentProcessor:(e,t,r,i,n,o)=>new Be(e,t,r,i,n,o),createEventQueue:e=>new Ke(e),createFileSystemWatcher:(e,t,r,i,n)=>new et(e,t,r,i,n),createApiServer:q};class rt{config;configPath;factories;runtimeOptions;logger;watcher;queue;server;processor;configWatcher;constructor(e,t,r={},i={}){this.config=e,this.configPath=t,this.factories={...tt,...r},this.runtimeOptions=i}async start(){const e=this.factories.createLogger(this.config.logging);this.logger=e;const{embeddingProvider:t,vectorStore:r}=await this.initEmbeddingAndStore(e),n=this.factories.compileRules(this.config.inferenceRules??[]),o=this.configPath?i.dirname(this.configPath):".",s=await oe(this.config.inferenceRules??[],this.config.templates,this.config.templateHelpers?.paths,o),a=this.config.mapHelpers?.paths?.length&&o?await Y(this.config.mapHelpers.paths,o):void 0,c=this.factories.createDocumentProcessor({metadataDir:this.config.metadataDir??".jeeves-metadata",chunkSize:this.config.embedding.chunkSize,chunkOverlap:this.config.embedding.chunkOverlap,maps:this.config.maps,configDir:o,customMapLib:a},t,r,n,e,s);this.processor=c,this.queue=this.factories.createEventQueue({debounceMs:this.config.watch.debounceMs??2e3,concurrency:this.config.embedding.concurrency??5,rateLimitPerMinute:this.config.embedding.rateLimitPerMinute}),this.watcher=this.createWatcher(this.queue,c,e),this.server=await this.startApiServer(c,r,t,e),this.watcher.start(),this.startConfigWatch(),e.info("jeeves-watcher started")}async stop(){if(await this.stopConfigWatch(),this.watcher&&await this.watcher.stop(),this.queue){const e=this.config.shutdownTimeoutMs??1e4;await Promise.race([this.queue.drain().then((()=>!0)),new Promise((t=>{setTimeout((()=>{t(!1)}),e)}))])||this.logger?.warn({timeoutMs:e},"Queue drain timeout hit, forcing shutdown")}this.server&&await this.server.close(),this.logger?.info("jeeves-watcher stopped")}async initEmbeddingAndStore(e){let t;try{t=this.factories.createEmbeddingProvider(this.config.embedding,e)}catch(t){throw e.fatal({err:D(t)},"Failed to create embedding provider"),t}const r=this.factories.createVectorStoreClient(this.config.vectorStore,t.dimensions,e);return await r.ensureCollection(),{embeddingProvider:t,vectorStore:r}}createWatcher(e,t,r){const i=this.config.watch.respectGitignore??!0?new K(this.config.watch.paths):void 0;return this.factories.createFileSystemWatcher(this.config.watch,e,t,r,{maxRetries:this.config.maxRetries,maxBackoffMs:this.config.maxBackoffMs,onFatalError:this.runtimeOptions.onFatalError,gitignoreFilter:i})}async startApiServer(e,t,r,i){const n=this.factories.createApiServer({processor:e,vectorStore:t,embeddingProvider:r,queue:this.queue,config:this.config,logger:i});return await n.listen({host:this.config.api?.host??"127.0.0.1",port:this.config.api?.port??3456}),n}startConfigWatch(){const e=this.logger;if(!e)return;const t=this.config.configWatch?.enabled??!0;t&&this.configPath?(this.configWatcher=new se({configPath:this.configPath,enabled:t,debounceMs:this.config.configWatch?.debounceMs??1e4,logger:e,onChange:async()=>this.reloadConfig()}),this.configWatcher.start()):this.configPath||e.debug("Config watch enabled, but no config path was provided")}async stopConfigWatch(){this.configWatcher&&(await this.configWatcher.stop(),this.configWatcher=void 0)}async reloadConfig(){const e=this.logger,t=this.processor;if(e&&t&&this.configPath){e.info({configPath:this.configPath},"Config change detected, reloading...");try{const r=await this.factories.loadConfig(this.configPath);this.config=r;const n=this.factories.compileRules(r.inferenceRules??[]),o=i.dirname(this.configPath),s=await oe(r.inferenceRules??[],r.templates,r.templateHelpers?.paths,o),a=r.mapHelpers?.paths?.length&&o?await Y(r.mapHelpers.paths,o):void 0;t.updateRules(n,s,a),e.info({configPath:this.configPath,rules:n.length},"Config reloaded")}catch(t){e.error({err:D(t)},"Failed to reload config")}}}}e.DocumentProcessor=Be,e.EventQueue=Ke,e.FileSystemWatcher=et,e.GitignoreFilter=K,e.JeevesWatcher=rt,e.SystemHealth=Ye,e.TemplateEngine=ne,e.VectorStoreClient=Ve,e.apiConfigSchema=ye,e.applyRules=Z,e.buildAttributes=$e,e.buildTemplateEngine=oe,e.compileRules=qe,e.configWatchConfigSchema=ge,e.contentHash=Te,e.createApiServer=q,e.createEmbeddingProvider=Ee,e.createHandlebarsInstance=re,e.createLogger=Re,e.deleteMetadata=_,e.embeddingConfigSchema=pe,e.extractText=_e,e.inferenceRuleSchema=be,e.jeevesWatcherConfigSchema=ve,e.loadConfig=ke,e.loadCustomHelpers=ie,e.loggingConfigSchema=we,e.metadataPath=H,e.pointId=Ae,e.readMetadata=O,e.registerBuiltinHelpers=ee,e.resolveTemplateSource=te,e.startFromConfig=async function(e){const t=await ke(e),r=new rt(t,e);return function(e){const t=async()=>{await e(),process.exit(0)};process.on("SIGTERM",(()=>{t()})),process.on("SIGINT",(()=>{t()}))}((()=>r.stop())),await r.start(),r},e.vectorStoreConfigSchema=me,e.watchConfigSchema=fe,e.writeMetadata=L}(this["jeeves-watcher"]=this["jeeves-watcher"]||{},Fastify,promises,node_path,picomatch,radash,node_crypto,node_fs,ignore,node_url,jsonmap,Handlebars,dayjs,hastUtilToMdast,mdastUtilFromAdf,mdastUtilToMarkdown,rehypeParse,unified,chokidar,cosmiconfig,zod,googleGenai,pino,uuid,cheerio,yaml,mammoth,Ajv,addFormats,textsplitters,jsClientRest);
1
+ !function(e,t,r,i,n,s,o,a,c,l,u,h,f,d,g,p,m,y,b,w,v,M,S,z,x,k,j,P,F,R,O,E){"use strict";function A(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var C=A(w);function D(e){if(e instanceof Error)return e;if("string"==typeof e)return new Error(e);const t=String("object"==typeof e&&null!==e&&"message"in e?e.message:e),r=new Error(t);return r.cause=e,r}function T(e,t){return e<=0?Promise.resolve():new Promise(((r,i)=>{const n=setTimeout((()=>{o(),r()}),e),s=()=>{o(),i(new Error("Retry sleep aborted"))},o=()=>{clearTimeout(n),t&&t.removeEventListener("abort",s)};if(t){if(t.aborted)return void s();t.addEventListener("abort",s,{once:!0})}}))}function N(e,t,r,i=0){const n=Math.max(0,e-1),s=Math.min(r,t*2**n),o=i>0?1+Math.random()*i:1;return Math.round(s*o)}async function I(e,t){const r=Math.max(1,t.attempts);let i;for(let n=1;n<=r;n++)try{return await e(n)}catch(e){i=e;if(n>=r)break;const s=N(n,t.baseDelayMs,t.maxDelayMs,t.jitter);t.onRetry?.({attempt:n,attempts:r,delayMs:s,error:e}),await T(s,t.signal)}throw i}function H(e){return e.replace(/\\/g,"/")}function $(e){const t=H(e),r=t.search(/[*?[]/);if(-1===r)return i.resolve(e);const n=t.slice(0,r),s=n.endsWith("/")?n.slice(0,-1):i.dirname(n);return i.resolve(s)}async function*_(e){let t;try{t=(await r.readdir(e,{withFileTypes:!0})).map((e=>({name:e.name,isDirectory:e.isDirectory()})))}catch{return}for(const n of t){const t=i.resolve(e,n.name);if(n.isDirectory)yield*_(t);else try{(await r.stat(t)).isFile()&&(yield t)}catch{}}}async function W(e,t,r,i){const s=await async function(e,t=[]){const r=e.map((e=>H(e))),i=t.map((e=>H(e))),s=n(r,{dot:!0}),o=i.length?n(i,{dot:!0}):()=>!1,a=Array.from(new Set(e.map($))),c=new Set;for(const e of a)for await(const t of _(e)){const e=H(t);o(e)||s(e)&&c.add(t)}return Array.from(c)}(e,t);for(const e of s)await r[i](e);return s.length}async function L(e,t,r){await I((async()=>{const r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!r.ok)throw new Error(`Non-OK response: ${String(r.status)}`)}),{attempts:3,baseDelayMs:1e3,maxDelayMs:4e3,onRetry:({attempt:t,error:i})=>{r.warn({attempt:t,err:D(i),url:e},"Reindex callback failed; will retry")}})}async function J(e,t){const{config:r,processor:i,logger:n,reindexTracker:s,valuesManager:o}=e;s?.start(t);const a=Date.now();let c=0,l=0;try{if("full"===t&&o&&o.clearAll(),"issues"===t&&e.issuesManager){const t=e.issuesManager.getAll(),r=Object.keys(t);c=0;for(const e of r)try{await i.processFile(e),c++}catch(t){l++,n.warn({filePath:e,err:D(t)},"Failed to reprocess issue file")}}else c=await W(r.watch.paths,r.watch.ignored,i,"processFile");const u=Date.now()-a;return n.info({scope:t,filesProcessed:c,durationMs:u},`Reindex (${t}) completed`),s?.complete(),r.reindex?.callbackUrl&&await L(r.reindex.callbackUrl,{scope:t,filesProcessed:c,durationMs:u,errors:[]},n),{filesProcessed:c,durationMs:u,errors:l}}catch(e){l=1;const i=Date.now()-a;return n.error({err:D(e),scope:t},"Reindex failed"),s?.complete(),r.reindex?.callbackUrl&&await L(r.reindex.callbackUrl,{scope:t,filesProcessed:0,durationMs:i,errors:[D(e).message]},n),{filesProcessed:0,durationMs:i,errors:l}}}const q=s.z.object({paths:s.z.array(s.z.string()).min(1).describe('Glob patterns for files to watch (e.g., "**/*.md"). At least one required.'),ignored:s.z.array(s.z.string()).optional().describe('Glob patterns to exclude from watching (e.g., "**/node_modules/**").'),pollIntervalMs:s.z.number().optional().describe("Polling interval in milliseconds when usePolling is enabled."),usePolling:s.z.boolean().optional().describe("Use polling instead of native file system events (for network drives)."),debounceMs:s.z.number().optional().describe("Debounce delay in milliseconds for file change events."),stabilityThresholdMs:s.z.number().optional().describe("Time in milliseconds a file must remain unchanged before processing."),respectGitignore:s.z.boolean().optional().describe("Skip files ignored by .gitignore in git repositories. Only applies to repos with a .git directory. Default: true.")}),B=s.z.object({enabled:s.z.boolean().optional().describe("Enable automatic reloading when config file changes."),debounceMs:s.z.number().optional().describe("Debounce delay in milliseconds for config file change detection."),reindex:s.z.union([s.z.literal("issues").describe("Re-process only files with recorded issues."),s.z.literal("full").describe("Full reindex of all watched files.")]).optional().describe("Reindex scope triggered on config change. Default: issues.")}),G=s.z.object({host:s.z.string().optional().describe('Host address for API server (e.g., "127.0.0.1", "0.0.0.0").'),port:s.z.number().optional().describe("Port for API server (e.g., 3456).")}),Q=s.z.object({level:s.z.string().optional().describe("Logging level (trace, debug, info, warn, error, fatal)."),file:s.z.string().optional().describe("Path to log file (logs to stdout if omitted).")}),U=s.z.record(s.z.string(),s.z.unknown()),K=s.z.object({type:s.z.literal("object").optional().describe('JSON Schema type (always "object" for schema definitions).'),properties:s.z.record(s.z.string(),U).optional().describe("Map of property names to JSON Schema property definitions.")}),V=s.z.union([K,s.z.string().describe("File path to a JSON schema file.")]),Y=s.z.union([s.z.string().describe("Named reference to a global schema."),K]),Z=s.z.object({name:s.z.string().min(1).describe("Unique name identifying this inference rule."),description:s.z.string().min(1).describe("Human-readable description of what this rule does."),match:s.z.record(s.z.string(),s.z.unknown()).describe("JSON Schema object to match against file attributes."),schema:s.z.array(Y).optional().describe("Array of schema references (named schema refs or inline objects) merged left-to-right."),map:s.z.union([o.jsonMapMapSchema,s.z.string()]).optional().describe("JsonMap transformation (inline definition, named map reference, or .json file path)."),template:s.z.string().optional().describe("Handlebars content template (inline string, named ref, or .hbs/.handlebars file path).")}),X=s.z.object({provider:s.z.string().default("gemini").describe('Embedding provider name (e.g., "gemini", "openai").'),model:s.z.string().default("gemini-embedding-001").describe('Embedding model identifier (e.g., "gemini-embedding-001", "text-embedding-3-small").'),chunkSize:s.z.number().optional().describe("Maximum chunk size in characters for text splitting."),chunkOverlap:s.z.number().optional().describe("Character overlap between consecutive chunks."),dimensions:s.z.number().optional().describe("Embedding vector dimensions (must match model output)."),apiKey:s.z.string().optional().describe("API key for embedding provider (supports ${ENV_VAR} substitution)."),rateLimitPerMinute:s.z.number().optional().describe("Maximum embedding API requests per minute (rate limiting)."),concurrency:s.z.number().optional().describe("Maximum concurrent embedding requests.")}),ee=s.z.object({url:s.z.string().describe('Qdrant server URL (e.g., "http://localhost:6333").'),collectionName:s.z.string().describe("Qdrant collection name for vector storage."),apiKey:s.z.string().optional().describe("Qdrant API key for authentication (supports ${ENV_VAR} substitution).")}),te=s.z.object({description:s.z.string().optional().describe("Human-readable description of this deployment's organizational strategy and content domains."),schemas:s.z.record(s.z.string(),V).optional().describe("Global named schema definitions (inline objects or file paths) referenced by inference rules."),watch:q.describe("File system watch configuration."),configWatch:B.optional().describe("Configuration file watch settings."),embedding:X.describe("Embedding model configuration."),vectorStore:ee.describe("Qdrant vector store configuration."),metadataDir:s.z.string().optional().describe("Directory for persisted metadata sidecar files."),api:G.optional().describe("API server configuration."),extractors:s.z.record(s.z.string(),s.z.unknown()).optional().describe("Extractor configurations keyed by name."),stateDir:s.z.string().optional().describe("Directory for persistent state files (issues.json, values.json). Defaults to metadataDir."),inferenceRules:s.z.array(Z).optional().describe("Rules for inferring metadata from file attributes."),maps:s.z.record(s.z.string(),s.z.union([o.jsonMapMapSchema,s.z.string(),s.z.object({map:o.jsonMapMapSchema.or(s.z.string()),description:s.z.string().optional()})])).optional().describe("Reusable named JsonMap transformations (inline definition or .json file path resolved relative to config directory)."),templates:s.z.record(s.z.string(),s.z.union([s.z.string(),s.z.object({template:s.z.string(),description:s.z.string().optional()})])).optional().describe("Named reusable Handlebars templates (inline strings or .hbs/.handlebars file paths)."),templateHelpers:s.z.record(s.z.string(),s.z.object({path:s.z.string(),description:s.z.string().optional()})).optional().describe("Custom Handlebars helper registration."),mapHelpers:s.z.record(s.z.string(),s.z.object({path:s.z.string(),description:s.z.string().optional()})).optional().describe("Custom JsonMap lib function registration."),reindex:s.z.object({callbackUrl:s.z.url().optional()}).optional().describe("Reindex configuration."),slots:s.z.record(s.z.string(),s.z.unknown()).optional().describe("Named Qdrant filter patterns for skill-activated behaviors."),search:s.z.object({scoreThresholds:s.z.object({strong:s.z.number().min(-1).max(1),relevant:s.z.number().min(-1).max(1),noise:s.z.number().min(-1).max(1)}).optional()}).optional().describe("Search configuration including score thresholds."),logging:Q.optional().describe("Logging configuration."),shutdownTimeoutMs:s.z.number().optional().describe("Timeout in milliseconds for graceful shutdown."),maxRetries:s.z.number().optional().describe("Maximum consecutive system-level failures before triggering fatal error. Default: Infinity."),maxBackoffMs:s.z.number().optional().describe("Maximum backoff delay in milliseconds for system errors. Default: 60000.")});function re(e,t){let r={...e};if(t){const e=function(e,t){if(!t)return e??[];if(!e)return t;const r=[...e];for(const e of t){const t=e.name;if(!t){r.push(e);continue}const i=r.findIndex((e=>e.name===t));i>=0?r[i]=e:r.push(e)}return r}(r.inferenceRules,t.inferenceRules);r={...r,...t,inferenceRules:e}}const i=te.safeParse(r),n=[];if(!i.success){for(const e of i.error.issues)n.push({path:e.path.join("."),message:e.message});return{candidateRaw:r,errors:n}}return{candidateRaw:r,parsed:i.data,errors:n}}function ie(e,t,r){return async(i,n)=>{try{return await e(i,n)}catch(e){return t.error({err:D(e)},`${r} failed`),n.status(500).send({error:"Internal server error"})}}}function ne(e){!function(e){const t=new Set,r=[];for(const i of e)t.has(i.name)?r.push(i.name):t.add(i.name);if(r.length>0)throw new Error(`Duplicate inference rule names found: ${r.join(", ")}. Rule names must be unique.`)}(e);const t=function(){const e=new a({allErrors:!0});return c(e),e.addKeyword({keyword:"glob",type:"string",schemaType:"string",validate:(e,t)=>n.isMatch(t,e)}),e}();return e.map((e=>({rule:e,validate:t.compile({$id:e.name,...e.match})})))}function se(e,t,r){if(!e)return{};const i={};for(const[t,n]of Object.entries(e))i[t]={...n,...r?.[t]?.exports?{exports:r[t].exports}:{}};return t&&(i._exports=t),i}function oe(e){try{const t=u.readFileSync(e,"utf-8");return e.endsWith(".json")?JSON.parse(t):t}catch{return e}}function ae(e){return async(t,r)=>{try{const{path:r,resolve:i}=t.body;let n=function(e){const{config:t,valuesManager:r,issuesManager:i,helperExports:n,helperIntrospection:s}=e,o=(t.inferenceRules??[]).map((e=>({...e,values:r.getForRule(e.name)})));return{description:t.description??"",search:t.search??{},schemas:t.schemas??{},inferenceRules:o,mapHelpers:se(t.mapHelpers,n?.mapHelpers,s?.mapHelpers),templateHelpers:se(t.templateHelpers,n?.templateHelpers,s?.templateHelpers),maps:t.maps??{},templates:t.templates??{},slots:t.slots??{},issues:i.getAll()}}({config:e.config,valuesManager:e.valuesManager,issuesManager:e.issuesManager,helperIntrospection:e.helperIntrospection});i&&i.length>0&&(n=function(e,t){const r={...e};if(Array.isArray(r.inferenceRules)&&(r.inferenceRules=r.inferenceRules.map((e=>{let i={...e};if(t.includes("files")&&"string"==typeof e.map&&e.map.endsWith(".json")&&(i={...i,map:oe(e.map)}),t.includes("globals")&&Array.isArray(e.schema)&&"object"==typeof r.schemas){const t=r.schemas,n=e.schema.map((e=>"string"==typeof e&&t[e]?t[e]:e));i={...i,schema:n}}return i}))),t.includes("files")&&r.maps&&"object"==typeof r.maps){const e={...r.maps};for(const[t,r]of Object.entries(e))"string"==typeof r&&(e[t]=oe(r));r.maps=e}if(t.includes("files")&&r.templates&&"object"==typeof r.templates){const e={...r.templates};for(const[t,r]of Object.entries(e))"string"==typeof r&&(e[t]=oe(r));r.templates=e}return r}(n,i));const s=l.JSONPath({path:r,json:n});return{result:s,count:s.length}}catch(t){const i=D(t);return e.logger.error({err:i},"Config query failed"),r.status(400).send({error:i.message||"Query failed"})}}}const ce=Z.extend({values:s.z.record(s.z.string(),s.z.array(s.z.unknown())).optional()}),le=s.z.object({description:s.z.string().optional(),search:s.z.object({scoreThresholds:s.z.object({strong:s.z.number(),relevant:s.z.number(),noise:s.z.number()}).optional()}).optional(),schemas:s.z.array(s.z.unknown()),inferenceRules:s.z.array(ce),maps:s.z.record(s.z.string(),s.z.unknown()).optional(),templates:s.z.record(s.z.string(),s.z.unknown()).optional(),templateHelpers:s.z.record(s.z.string(),s.z.unknown()).optional(),mapHelpers:s.z.record(s.z.string(),s.z.unknown()).optional(),slots:s.z.record(s.z.string(),s.z.unknown()).optional(),issues:s.z.record(s.z.string(),s.z.array(s.z.unknown())).optional()});async function ue(e,t,r){const n={};for(const[s,{path:o}]of Object.entries(e)){const e=i.resolve(t,o),a=await import(f.pathToFileURL(e).href),c="object"==typeof a.default&&null!==a.default?a.default:a,l={};for(const[e,t]of Object.entries(c))r&&!r(t)||(l[e]=t);n[s]=l}return n}function he(e,t){return"string"!=typeof e?e:e.replace(/\$\{([^}]+)\}/g,((e,r)=>{const i=h.get(t,r);return null==i?"":"string"==typeof i?i:JSON.stringify(i)}))}function fe(e,t){if("string"==typeof e){const r=t?i.resolve(t,e):e,n=u.readFileSync(r,"utf-8");return JSON.parse(n)}return e}function de(e,t={}){const{globalSchemas:r={},configDir:i}=t,n={properties:{}};for(const t of e){let e;if("string"==typeof t){const n=r[t];if(!n)throw new Error(`Schema reference "${t}" not found in global schemas`);e=fe(n,i)}else e=t;if(e.properties)for(const[t,r]of Object.entries(e.properties)){const e=n.properties[t];n.properties[t]=e?{...e,...r}:r}}return n}function ge(e,t){if(null!=e)switch(t){case"string":return"string"==typeof e?e:"number"==typeof e||"boolean"==typeof e?String(e):"object"==typeof e?JSON.stringify(e):void 0;case"integer":if(""===e)return;if("string"==typeof e){const t=e.trim(),r=parseInt(t,10);return Number.isInteger(r)&&r.toString()===t?r:void 0}return"number"==typeof e&&Number.isInteger(e)?e:void 0;case"number":{if(""===e)return;const t="string"==typeof e?parseFloat(e):Number(e);return Number.isFinite(t)?t:void 0}case"boolean":if(""===e)return;if("boolean"==typeof e)return e;if("string"==typeof e){const t=e.toLowerCase();if("true"===t)return!0;if("false"===t)return!1}return;case"array":if(""===e)return;if(Array.isArray(e))return e;if("string"==typeof e)try{const t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return;case"object":if(""===e)return;if("string"==typeof e){try{const t=JSON.parse(e);if("object"==typeof t&&null!==t&&!Array.isArray(t))return t}catch{}return}return"object"!=typeof e||Array.isArray(e)?void 0:e;default:return e}}function pe(e,t){const r={};for(const[i,n]of Object.entries(e.properties)){const e=n.set;if(void 0===e)continue;const s=ge(he(e,t),n.type);void 0!==s&&(r[i]=s)}return r}function me(e,t){for(const[r,i]of Object.entries(e.properties))if(!i.type)throw new Error(`Property "${r}" in rule "${t}" has no declared type. Every property must have a type.`)}async function ye(e,t,r,n,s,a,c,l){const f=function(e,t){const r=new Map,n=t=>{const n=e?i.resolve(e,t):t;if(!r.has(n)){const e=u.readFileSync(n,"utf-8");r.set(n,JSON.parse(e))}return r.get(n)};return{split:(e,t)=>e.split(t),slice:(e,t,r)=>e.slice(t,r),join:(e,t)=>e.join(t),toLowerCase:e=>e.toLowerCase(),replace:(e,t,r)=>e.replace(t,r),get:(e,t)=>h.get(e,t),lookupJson:(e,t,r)=>{const i=n(e)[t];return null==i?null:r?h.get(i,r)??null:i},mapLookup:(e,t,r)=>{if(!Array.isArray(t))return[];const i=n(e),s=[];for(const e of t){if("string"!=typeof e)continue;const t=i[e];if(null==t)continue;const n=h.get(t,r);if(null!=n)if(Array.isArray(n))for(const e of n)s.push(e);else s.push(n)}return s},...t}}(a,c);let d={},g=null;const p=[],m=n??console;for(const[,{rule:n,validate:c}]of e.entries())if(c(t)){if(p.push(n.name),n.schema&&n.schema.length>0)try{const e=de(n.schema,{globalSchemas:l,configDir:a});me(e,n.name);const r=pe(e,t);d={...d,...r}}catch(e){m.warn(`Schema processing failed for rule "${n.name}": ${e instanceof Error?e.message:String(e)}`);continue}if(n.map){let e;if("string"==typeof n.map){if(n.map.endsWith(".json")&&a)try{const t=i.resolve(a,n.map),r=u.readFileSync(t,"utf-8");e=JSON.parse(r)}catch(e){m.warn(`Failed to load map file "${n.map}": ${e instanceof Error?e.message:String(e)}`);continue}else if(e=r?.[n.map],!e){m.warn(`Map reference "${n.map}" not found in named maps. Skipping map transformation.`);continue}}else e=n.map;try{const r=new o.JsonMap(e,f),i=await r.transform(t);i&&"object"==typeof i&&!Array.isArray(i)?d={...d,...i}:m.warn("JsonMap transformation did not return an object; skipping merge.")}catch(e){m.warn(`JsonMap transformation failed: ${e instanceof Error?e.message:String(e)}`)}}if(n.template&&s){const e=n.name,r={...t.json??{},...t,...d};try{const t=s.render(e,r);t&&t.trim()?g=t:m.warn(`Template for rule "${n.name}" rendered empty output. Falling back to raw content.`)}catch(e){m.warn(`Template render failed for rule "${n.name}": ${e instanceof Error?e.message:String(e)}. Falling back to raw content.`)}}}return{metadata:d,renderedContent:g,matchedRules:p}}function be(e,t,r,n){const s=H(e),o={file:{path:s,directory:H(i.dirname(s)),filename:i.basename(s),extension:i.extname(s),sizeBytes:t.size,modified:t.mtime.toISOString()}};return r&&(o.frontmatter=r),n&&(o.json=n),o}function we(e){return ie((async t=>{const{config:r,testPaths:i}=t.body,{candidateRaw:n,parsed:s,errors:o}=re(e.config,r);if(o.length>0)return{valid:!1,errors:o};const a=function(e){const t=[];for(const r of["mapHelpers","templateHelpers"]){const i=e[r];if(i)for(const[e,n]of Object.entries(i))if(n.path)if(u.existsSync(n.path))try{u.readFileSync(n.path,"utf-8")}catch(i){t.push({path:`${r}.${e}.path`,message:`Failed to read: ${D(i).message}`})}else t.push({path:`${r}.${e}.path`,message:`File not found: ${n.path}`})}return t}(n);if(a.length>0)return{valid:!1,errors:a};if(s?.inferenceRules)for(const e of s.inferenceRules)if(e.schema&&0!==e.schema.length)try{me(de(e.schema,{globalSchemas:s.schemas??{}}),e.name)}catch(t){return{valid:!1,errors:[{path:`inferenceRules[${e.name}]`,message:D(t).message}]}}const c=[];if(i&&s?.inferenceRules){const e=ne(s.inferenceRules);for(const t of i)try{const r=be(t,u.statSync(t)),i=await ye(e,r);c.push({path:t,matchedRules:i.matchedRules,metadata:i.metadata})}catch{c.push({path:t,matchedRules:[],metadata:{},error:"File not found"})}}return{valid:!0,...c.length>0?{testResults:c}:{}}}),e.logger,"Config validate")}function ve(e,t){switch(t){case"string":return"string"==typeof e;case"integer":return"number"==typeof e&&Number.isInteger(e);case"number":return"number"==typeof e&&Number.isFinite(e);case"boolean":return"boolean"==typeof e;case"array":return Array.isArray(e);case"object":return function(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}(e);default:return!0}}function Me(e){return null===e?"null":Array.isArray(e)?"array":"number"==typeof e?Number.isInteger(e)?"integer":"number":typeof e}function Se(e){return ie((async(t,r)=>{const{path:n,metadata:s}=t.body,o=function(e,t,r){const n=ne(e.inferenceRules??[]),s=H(t),o={file:{path:s,directory:H(i.dirname(s)),filename:i.basename(s),extension:i.extname(s),sizeBytes:0,modified:new Date(0).toISOString()}},a=n.filter((e=>e.validate(o))),c=a.map((e=>e.rule.name)),l=a.flatMap((e=>e.rule.schema??[]));if(0===l.length)return{ok:!0,matchedRules:c};const u=de(l,{globalSchemas:e.schemas??{}}),h=[];for(const[t,i]of Object.entries(r)){if(null==i)continue;if(!Object.hasOwn(u.properties,t))continue;const r=u.properties[t].type;if(r&&!ve(i,r)){const n=Me(i),s=a.filter((i=>{if(!i.rule.schema)return!1;const n=de(i.rule.schema,{globalSchemas:e.schemas??{}});return Object.hasOwn(n.properties,t)&&n.properties[t].type===r})),o=s.length>0?s[0].rule.name:c[0]??"unknown";h.push({property:t,expected:r,received:n,rule:o,message:`Property '${t}' is declared as ${r} in ${o} schema, received ${n}`})}}return h.length>0?{ok:!1,matchedRules:c,error:"Validation failed",details:h}:{ok:!0,matchedRules:c}}(e.config,n,s);return o.ok?(await e.processor.processMetadataUpdate(n,s),{ok:!0,matched_rules:o.matchedRules}):r.code(400).send({error:o.error,details:o.details})}),e.logger,"Metadata update")}function ze(e,t=!1){let r=e.replace(/\\/g,"/").toLowerCase();return t&&(r=r.replace(/^([a-z]):/,((e,t)=>t))),r}function xe(e,t){const r=ze(e,!0),n=d.createHash("sha256").update(r,"utf8").digest("hex");return i.join(t,`${n}.meta.json`)}async function ke(e,t){try{const i=await r.readFile(xe(e,t),"utf8");return JSON.parse(i)}catch{return null}}async function je(e,t,n){const s=xe(e,t);await r.mkdir(i.dirname(s),{recursive:!0}),await r.writeFile(s,JSON.stringify(n,null,2),"utf8")}async function Pe(e,t){try{await r.rm(xe(e,t))}catch{}}const Fe=["file_path","chunk_index","total_chunks","content_hash","chunk_text"],Re="file_path",Oe="chunk_index",Ee="total_chunks",Ae="content_hash",Ce="chunk_text";class De{_active=!1;_scope;_startedAt;start(e){this._active=!0,this._scope=e,this._startedAt=(new Date).toISOString()}complete(){this._active=!1,this._scope=void 0,this._startedAt=void 0}getStatus(){return this._active?{active:!0,scope:this._scope,startedAt:this._startedAt}:{active:!1}}}function Te(e){const{processor:o,vectorStore:a,embeddingProvider:c,logger:l,config:u,issuesManager:f,valuesManager:d,configPath:g,helperIntrospection:p}=e,m=e.reindexTracker??new De,y=t({logger:!1});var b;return y.get("/status",(b={vectorStore:a,collectionName:u.vectorStore.collectionName,reindexTracker:m},async()=>{const e=await b.vectorStore.getCollectionInfo();return{status:"ok",uptime:process.uptime(),collection:{name:b.collectionName,pointCount:e.pointCount,dimensions:e.dimensions},reindex:b.reindexTracker.getStatus()}})),y.post("/metadata",Se({processor:o,config:u,logger:l})),y.post("/search",function(e){return ie((async t=>{const{query:r,limit:i=10,offset:n,filter:s}=t.body,o=await e.embeddingProvider.embed([r]);return await e.vectorStore.search(o[0],i,s,n)}),e.logger,"Search")}({embeddingProvider:c,vectorStore:a,logger:l})),y.post("/reindex",function(e){return ie((async(t,r)=>{const i=await W(e.watch.paths,e.watch.ignored,e.processor,"processFile");return await r.status(200).send({ok:!0,filesIndexed:i})}),e.logger,"Reindex")}({watch:u.watch,processor:o,logger:l})),y.post("/rebuild-metadata",function(e){return ie((async(t,r)=>{const i=e.metadataDir??".jeeves-metadata",n=[...Fe];for await(const t of e.vectorStore.scroll()){const e=t.payload,r=e[Re];if("string"!=typeof r||0===r.length)continue;const s=h.omit(e,n);await je(r,i,s)}return await r.status(200).send({ok:!0})}),e.logger,"Rebuild metadata")}({metadataDir:u.metadataDir,vectorStore:a,logger:l})),y.post("/config-reindex",function(e){return ie((async(t,r)=>{const i=t.body.scope??"issues";return J({config:e.config,processor:e.processor,logger:e.logger,reindexTracker:e.reindexTracker},i),await r.status(200).send({status:"started",scope:i})}),e.logger,"Config reindex request")}({config:u,processor:o,logger:l,reindexTracker:m})),y.get("/issues",function(e){return()=>{const t=e.issuesManager.getAll();return{count:Object.keys(t).length,issues:t}}}({issuesManager:f})),y.get("/config/schema",(async(e,t)=>{const r=s.z.toJSONSchema(le);t.send(r)})),y.post("/config/match",function(e){const{config:t,logger:r}=e,s=ne(t.inferenceRules??[]),o=n(t.watch.paths,{dot:!0}),a=t.watch.ignored?.length?n(t.watch.ignored,{dot:!0}):null;return ie((async(e,t)=>{const r=e.body;if(!Array.isArray(r.paths))return void t.code(400).send({error:'Request body must include "paths" array'});const n={matches:r.paths.map((e=>{const t=H(e),r={file:{path:t,directory:H(i.dirname(t)),filename:i.basename(t),extension:i.extname(t),sizeBytes:0,modified:new Date(0).toISOString()}},n=[];for(const e of s)e.validate(r)&&n.push(e.rule.name);return{rules:n,watched:o(t)&&!a?.(t)}}))};t.send(n)}),r,"Config match")}({config:u,logger:l})),y.post("/config/query",ae({config:u,valuesManager:d,issuesManager:f,logger:l,helperIntrospection:p})),y.post("/config/validate",we({config:u,logger:l})),y.post("/config/apply",function(e){return ie((async(t,i)=>{const{config:n}=t.body,{candidateRaw:s,errors:o}=re(e.config,n);if(o.length>0)return await i.status(400).send({valid:!1,errors:o});await r.writeFile(e.configPath,JSON.stringify(s,null,2),"utf-8");const a=e.config.configWatch?.reindex??"issues";return e.triggerReindex&&e.triggerReindex(a),{applied:!0,reindexTriggered:!!e.triggerReindex,scope:a}}),e.logger,"Config apply")}({config:u,configPath:g,reindexTracker:m,logger:l,triggerReindex:e=>{J({config:u,processor:o,logger:l,reindexTracker:m,valuesManager:d,issuesManager:f},e)}})),y}class Ne{filePath;cache=null;logger;constructor(e){this.filePath=e.filePath,this.logger=e.logger,u.mkdirSync(i.dirname(this.filePath),{recursive:!0})}load(){if(this.cache)return this.cache;try{if(u.existsSync(this.filePath)){const e=u.readFileSync(this.filePath,"utf-8");this.cache=JSON.parse(e)}else this.cache=this.createEmpty()}catch{this.logger.warn({filePath:this.filePath},"Failed to read JSON store file, starting fresh"),this.cache=this.createEmpty()}return this.cache}save(){u.writeFileSync(this.filePath,JSON.stringify(this.cache,null,2),"utf-8")}}class Ie extends Ne{constructor(e,t){super({filePath:i.join(e,"issues.json"),logger:t})}createEmpty(){return{}}record(e,t,r,i){const n=this.load(),s={type:t,message:r,timestamp:Math.floor(Date.now()/1e3),...i};n[e]||(n[e]=[]),n[e].push(s),this.save(),this.logger.debug({filePath:e,type:t},"Issue recorded")}clear(e){const t=this.load();e in t&&(Reflect.deleteProperty(t,e),this.save(),this.logger.debug({filePath:e},"Issue cleared"))}clearAll(){this.cache={},this.save(),this.logger.debug("All issues cleared")}getAll(){return{...this.load()}}}const He=s.z.object({type:s.z.union([s.z.literal("type_collision").describe("Conflicting metadata types from multiple rules."),s.z.literal("interpolation_error").describe("Template variable resolution failure.")]).describe("Error category: type_collision (conflicting metadata types), interpolation_error (template rendering failure)."),property:s.z.string().optional(),rules:s.z.array(s.z.string()).optional(),rule:s.z.string().optional(),types:s.z.array(s.z.string()).optional(),message:s.z.string(),timestamp:s.z.union([s.z.number(),s.z.string()])});class $e extends Ne{constructor(e,t){super({filePath:i.join(e,"values.json"),logger:t})}createEmpty(){return{}}isTrackable(e){const t=typeof e;return"string"===t||"number"===t||"boolean"===t}update(e,t){const r=this.load();r[e]??={};const i=r[e];for(const[e,r]of Object.entries(t)){if(!this.isTrackable(r))continue;i[e]??=[];const t=i[e];t.includes(r)||(t.push(r),t.sort(((e,t)=>typeof e==typeof t?String(e).localeCompare(String(t)):typeof e<typeof t?-1:1)))}this.save()}clearAll(){this.cache={},this.save(),this.logger.debug("All values cleared")}getAll(){return{...this.load()}}getForRule(e){return{...this.load()[e]}}}class _e{options;watcher;debounce;constructor(e){this.options=e}start(){this.options.enabled&&(this.watcher=g.watch(this.options.configPath,{ignoreInitial:!0}),this.watcher.on("change",(()=>{this.debounce&&clearTimeout(this.debounce),this.debounce=setTimeout((()=>{this.options.onChange()}),this.options.debounceMs)})),this.watcher.on("error",(e=>{this.options.logger.error({err:D(e)},"Config watcher error")})),this.options.logger.info({configPath:this.options.configPath,debounceMs:this.options.debounceMs},"Config watcher started"))}async stop(){this.debounce&&(clearTimeout(this.debounce),this.debounce=void 0),this.watcher&&(await this.watcher.close(),this.watcher=void 0)}}const We={metadataDir:".jeeves-watcher",shutdownTimeoutMs:1e4},Le={enabled:!0,debounceMs:1e3},Je={host:"127.0.0.1",port:3456},qe={level:"info"},Be={debounceMs:300,stabilityThresholdMs:500,usePolling:!1,pollIntervalMs:1e3,respectGitignore:!0},Ge={chunkSize:1e3,chunkOverlap:200,dimensions:3072,rateLimitPerMinute:300,concurrency:5},Qe=/\$\{([^}]+)\}/g;function Ue(e){if("string"==typeof e)return function(e){return e.replace(Qe,((e,t)=>{const r=process.env[t];return void 0===r?e:r}))}(e);if(Array.isArray(e))return e.map((e=>Ue(e)));if(null!==e&&"object"==typeof e){const t={};for(const[r,i]of Object.entries(e))t[r]=Ue(i);return t}return e}const Ke="jeeves-watcher";async function Ve(e){const t=p.cosmiconfig(Ke),r=e?await t.load(e):await t.search();if(!r||r.isEmpty)throw new Error("No jeeves-watcher configuration found. Create a .jeeves-watcherrc or jeeves-watcher.config.{js,ts,json,yaml} file.");try{const e=te.parse(r.config);if(e.maps){const t=i.dirname(r.filepath);for(const[r,n]of Object.entries(e.maps))if("string"==typeof n){const s=i.resolve(t,n),o=u.readFileSync(s,"utf-8");e.maps[r]=JSON.parse(o)}}return Ue((n=e,{...We,...n,watch:{...Be,...n.watch},configWatch:{...Le,...n.configWatch},embedding:{...Ge,...n.embedding},api:{...Je,...n.api},logging:{...qe,...n.logging}}))}catch(e){if(e instanceof s.ZodError){const t=e.issues.map((e=>`${e.path.join(".")}: ${e.message}`)).join("; ");throw new Error(`Invalid jeeves-watcher configuration: ${t}`)}throw e}var n}function Ye(e){return e||{warn(e,t){t?console.warn(e,t):console.warn(e)}}}const Ze=new Map([["mock",function(e){return function(e){return{dimensions:e,embed:t=>Promise.resolve(t.map((t=>{const r=d.createHash("sha256").update(t,"utf8").digest(),i=[];for(let t=0;t<e;t++){const e=r[t%r.length];i.push(e/127.5-1)}return i})))}}(e.dimensions??768)}],["gemini",function(e,t){if(!e.apiKey)throw new Error("Gemini embedding provider requires config.embedding.apiKey");const r=e.dimensions??3072,i=Ye(t),n=new m.GoogleGenerativeAIEmbeddings({apiKey:e.apiKey,model:e.model});return{dimensions:r,async embed(t){const s=await I((async r=>(r>1&&i.warn({attempt:r,provider:"gemini",model:e.model},"Retrying embedding request"),n.embedDocuments(t))),{attempts:5,baseDelayMs:500,maxDelayMs:1e4,jitter:.2,onRetry:({attempt:t,delayMs:r,error:n})=>{i.warn({attempt:t,delayMs:r,provider:"gemini",model:e.model,err:D(n)},"Embedding call failed; will retry")}});for(const e of s)if(e.length!==r)throw new Error(`Gemini embedding returned invalid dimensions: expected ${String(r)}, got ${String(e.length)}`);return s}}}]]);function Xe(e,t,r){const i=new Map(Ze);if(r)for(const[e,t]of r)i.set(e,t);const n=i.get(e.provider);if(!n)throw new Error(`Unsupported embedding provider: ${e.provider}`);return n(e,t)}function et(e){const t=e?.level??"info";if(e?.file){const r=y.transport({target:"pino/file",options:{destination:e.file,mkdir:!0}});return y({level:t},r)}return y({level:t})}function tt(e){return d.createHash("sha256").update(e,"utf8").digest("hex")}const rt="6a6f686e-6761-4c74-ad6a-656576657321";function it(e,t){const r=void 0!==t?`${ze(e)}#${String(t)}`:ze(e);return b.v5(r,rt)}function nt(e,t,r,i){if("string"==typeof r){const n=r,s=i??{};return void e.error({...s,err:D(t)},n)}const n=r,s="string"==typeof i?i:"";e.error({...n,err:D(t)},s)}const st=["content","body","text","snippet","subject","description","summary","transcript"];function ot(e){if(!e||"object"!=typeof e)return JSON.stringify(e);const t=e;for(const e of st){const r=t[e];if("string"==typeof r&&r.trim())return r}return JSON.stringify(e)}async function at(e){const t=await r.readFile(e,"utf8"),{frontmatter:i,body:n}=function(e){const t=e.replace(/^\uFEFF/,"");if(!/^\s*---/.test(t))return{body:e};const r=/^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/m.exec(t);if(!r)return{body:e};const[,i,n]=r,s=v.load(i);return{frontmatter:s&&"object"==typeof s&&!Array.isArray(s)?s:void 0,body:n}}(t);return{text:n,frontmatter:i}}async function ct(e){return{text:(await r.readFile(e,"utf8")).replace(/^\uFEFF/,"")}}async function lt(e){const t=await r.readFile(e,"utf8"),i=C.load(t.replace(/^\uFEFF/,""));i("script, style").remove();return{text:i("body").text().trim()||i.text().trim()}}const ut=new Map([[".md",at],[".markdown",at],[".txt",ct],[".text",ct],[".json",async function(e){const t=await r.readFile(e,"utf8"),i=JSON.parse(t.replace(/^\uFEFF/,"")),n=i&&"object"==typeof i&&!Array.isArray(i)?i:void 0;return{text:ot(i),json:n}}],[".pdf",async function(e){const t=await r.readFile(e),i=new Uint8Array(t),{extractText:n}=await import("unpdf"),{text:s}=await n(i);return{text:Array.isArray(s)?s.join("\n\n"):s}}],[".docx",async function(e){const t=await r.readFile(e);return{text:(await M.extractRawText({buffer:t})).value}}],[".html",lt],[".htm",lt]]);async function ht(e,t,r){const i=new Map(ut);if(r)for(const[e,t]of r)i.set(e,t);const n=i.get(t.toLowerCase());return n?n(e):ct(e)}async function ft(e){const{filePath:t,compiledRules:n,metadataDir:s,maps:o,logger:a,templateEngine:c,configDir:l,customMapLib:u,globalSchemas:h}=e,f=i.extname(t),d=await r.stat(t),g=await ht(t,f),p=be(t,d,g.frontmatter,g.json),{metadata:m,renderedContent:y,matchedRules:b}=await ye(n,p,o,a,c,l,u,h),w=await ke(t,s);return{inferred:m,enrichment:w,metadata:{...m,...w??{}},attributes:p,extracted:g,renderedContent:y,matchedRules:b}}function dt(e,t){const r=[];for(let i=0;i<t;i++)r.push(it(e,i));return r}function gt(e,t=1){if(!e)return t;const r=e[Ee];return"number"==typeof r?r:t}class pt{config;embeddingProvider;vectorStore;compiledRules;logger;templateEngine;issuesManager;valuesManager;constructor({config:e,embeddingProvider:t,vectorStore:r,compiledRules:i,logger:n,templateEngine:s,issuesManager:o,valuesManager:a}){this.config=e,this.embeddingProvider=t,this.vectorStore=r,this.compiledRules=i,this.logger=n,this.templateEngine=s,this.issuesManager=o,this.valuesManager=a}async processFile(e){try{const t=i.extname(e),{metadata:r,extracted:n,renderedContent:s,matchedRules:o}=await ft({filePath:e,compiledRules:this.compiledRules,metadataDir:this.config.metadataDir,maps:this.config.maps,logger:this.logger,templateEngine:this.templateEngine,configDir:this.config.configDir,customMapLib:this.config.customMapLib,globalSchemas:this.config.globalSchemas}),a=s??n.text;if(!a.trim())return void this.logger.debug({filePath:e},"Skipping empty file");const c=tt(a),l=it(e,0),u=await this.vectorStore.getPayload(l);if(u&&u.content_hash===c)return void this.logger.debug({filePath:e},"Content unchanged, skipping");const h=this.config.chunkSize??1e3,f=function(e,t,r){const i=e.toLowerCase();return".md"===i||".markdown"===i?new S.MarkdownTextSplitter({chunkSize:t,chunkOverlap:r}):new S.RecursiveCharacterTextSplitter({chunkSize:t,chunkOverlap:r})}(t,h,this.config.chunkOverlap??200),d={...r,matched_rules:o};if(await async function(e,t,r,i,n){const{embeddingProvider:s,vectorStore:o,splitter:a,logger:c}=e,l=gt(n),u=tt(t),h=await a.splitText(t),f=await s.embed(h),d=h.map(((e,t)=>({id:it(r,t),vector:f[t],payload:{...i,[Re]:H(r),[Oe]:t,[Ee]:h.length,[Ae]:u,[Ce]:e}})));if(await o.upsert(d),l>h.length){const e=dt(r,l).slice(h.length);await o.delete(e)}c.info({filePath:r,chunks:h.length},"File processed successfully")}({embeddingProvider:this.embeddingProvider,vectorStore:this.vectorStore,splitter:f,logger:this.logger},a,e,d,u),this.issuesManager?.clear(e),this.valuesManager)for(const e of o)this.valuesManager.update(e,r)}catch(t){nt(this.logger,t,{filePath:e},"Failed to process file")}}async deleteFile(e){try{const t=it(e,0),r=await this.vectorStore.getPayload(t),i=dt(e,gt(r));await this.vectorStore.delete(i),await Pe(e,this.config.metadataDir),this.logger.info({filePath:e},"File deleted from index")}catch(t){nt(this.logger,t,{filePath:e},"Failed to delete file")}}async processMetadataUpdate(e,t){try{const r={...await ke(e,this.config.metadataDir)??{},...t};await je(e,this.config.metadataDir,r);const i=it(e,0),n=await this.vectorStore.getPayload(i);if(!n)return null;const s=gt(n),o=dt(e,s);return await this.vectorStore.setPayload(o,r),this.logger.info({filePath:e,chunks:s},"Metadata updated"),r}catch(t){return nt(this.logger,t,{filePath:e},"Failed to update metadata"),null}}async processRulesUpdate(e){try{const t=it(e,0),r=await this.vectorStore.getPayload(t);if(!r)return this.logger.debug({filePath:e},"File not indexed, skipping"),null;const{metadata:i,matchedRules:n}=await ft({filePath:e,compiledRules:this.compiledRules,metadataDir:this.config.metadataDir,maps:this.config.maps,logger:this.logger,templateEngine:this.templateEngine,configDir:this.config.configDir,customMapLib:this.config.customMapLib,globalSchemas:this.config.globalSchemas}),s={...i,matched_rules:n},o=gt(r),a=dt(e,o);return await this.vectorStore.setPayload(a,s),this.issuesManager?.clear(e),this.logger.info({filePath:e,chunks:o},"Rules re-applied"),s}catch(t){return nt(this.logger,t,{filePath:e},"Failed to re-apply rules"),null}}updateRules(e,t,r){this.compiledRules=e,t&&(this.templateEngine=t),void 0!==r&&(this.config={...this.config,customMapLib:r}),this.logger.info({rules:e.length},"Inference rules updated")}}class mt{debounceMs;concurrency;rateLimitPerMinute;started=!1;active=0;debounceTimers=new Map;latestByKey=new Map;normalQueue=[];lowQueue=[];tokens;lastRefillMs=Date.now();drainWaiters=[];constructor(e){this.debounceMs=e.debounceMs,this.concurrency=e.concurrency,this.rateLimitPerMinute=e.rateLimitPerMinute,this.tokens=this.rateLimitPerMinute??Number.POSITIVE_INFINITY}enqueue(e,t){const r=`${e.priority}:${e.path}`;this.latestByKey.set(r,{event:e,fn:t});const i=this.debounceTimers.get(r);i&&clearTimeout(i);const n=setTimeout((()=>{this.debounceTimers.delete(r);const e=this.latestByKey.get(r);e&&(this.latestByKey.delete(r),this.push(e),this.pump())}),this.debounceMs);this.debounceTimers.set(r,n)}process(){this.started=!0,this.pump()}async drain(){this.isIdle()||await new Promise((e=>{this.drainWaiters.push(e)}))}push(e){"low"===e.event.priority?this.lowQueue.push(e):this.normalQueue.push(e)}refillTokens(e){if(void 0===this.rateLimitPerMinute)return;const t=Math.max(0,e-this.lastRefillMs)*(this.rateLimitPerMinute/6e4);this.tokens=Math.min(this.rateLimitPerMinute,this.tokens+t),this.lastRefillMs=e}takeToken(){const e=Date.now();return this.refillTokens(e),!(this.tokens<1)&&(this.tokens-=1,!0)}nextItem(){return this.normalQueue.shift()??this.lowQueue.shift()}pump(){if(this.started){for(;this.active<this.concurrency;){const e=this.nextItem();if(!e)break;if(!this.takeToken()){"low"===e.event.priority?this.lowQueue.unshift(e):this.normalQueue.unshift(e),setTimeout((()=>{this.pump()}),250);break}this.active+=1,Promise.resolve().then((()=>e.fn(e.event))).finally((()=>{this.active-=1,this.pump(),this.maybeResolveDrain()}))}this.maybeResolveDrain()}}isIdle(){return 0===this.active&&0===this.normalQueue.length&&0===this.lowQueue.length&&0===this.debounceTimers.size&&0===this.latestByKey.size}maybeResolveDrain(){if(!this.isIdle())return;const e=this.drainWaiters;this.drainWaiters=[];for(const t of e)t()}}function yt(e){return null==e?"keyword":"number"==typeof e?Number.isInteger(e)?"integer":"float":"boolean"==typeof e?"bool":Array.isArray(e)?"keyword[]":"string"==typeof e&&e.length>256?"text":"keyword"}class bt{client;collectionName;dims;log;constructor(e,t,r){this.client=new z.QdrantClient({url:e.url,apiKey:e.apiKey,checkCompatibility:!1}),this.collectionName=e.collectionName,this.dims=t,this.log=Ye(r)}async ensureCollection(){try{const e=await this.client.getCollections();e.collections.some((e=>e.name===this.collectionName))||await this.client.createCollection(this.collectionName,{vectors:{size:this.dims,distance:"Cosine"}})}catch(e){throw new Error(`Failed to ensure collection "${this.collectionName}": ${String(e)}`)}}async retryOperation(e,t){await I((async r=>{r>1&&this.log.warn({attempt:r,operation:`qdrant.${e}`},`Retrying Qdrant ${e}`),await t()}),{attempts:5,baseDelayMs:500,maxDelayMs:1e4,jitter:.2,onRetry:({attempt:t,delayMs:r,error:i})=>{this.log.warn({attempt:t,delayMs:r,operation:`qdrant.${e}`,err:D(i)},`Qdrant ${e} failed; will retry`)}})}async upsert(e){0!==e.length&&await this.retryOperation("upsert",(async()=>{await this.client.upsert(this.collectionName,{wait:!0,points:e.map((e=>({id:e.id,vector:e.vector,payload:e.payload})))})}))}async delete(e){0!==e.length&&await this.retryOperation("delete",(async()=>{await this.client.delete(this.collectionName,{wait:!0,points:e})}))}async setPayload(e,t){0!==e.length&&await this.client.setPayload(this.collectionName,{wait:!0,points:e,payload:t})}async getPayload(e){try{const t=await this.client.retrieve(this.collectionName,{ids:[e],with_payload:!0,with_vector:!1});return 0===t.length?null:t[0].payload}catch{return null}}async getCollectionInfo(){const e=await this.client.getCollection(this.collectionName),t=e.points_count??0,r=e.config.params.vectors,i=void 0!==r&&"size"in r?r.size:0,n={},s=Object.entries(e.payload_schema);if(s.length>0)for(const[e,t]of s)n[e]={type:t.data_type??"unknown"};else t>0&&await this.discoverPayloadFields(n);return{pointCount:t,dimensions:i,payloadFields:n}}async discoverPayloadFields(e,t=100){const r=await this.client.scroll(this.collectionName,{limit:t,with_payload:!0,with_vector:!1});for(const t of r.points){const r=t.payload;if(r)for(const[t,i]of Object.entries(r))t in e||(e[t]={type:yt(i)})}}async search(e,t,r,i){return(await this.client.search(this.collectionName,{vector:e,limit:t,with_payload:!0,...r?{filter:r}:{},...void 0!==i?{offset:i}:{}})).map((e=>({id:String(e.id),score:e.score,payload:e.payload})))}async*scroll(e,t=100){let r;for(;;){const i=await this.client.scroll(this.collectionName,{limit:t,with_payload:!0,with_vector:!1,...e?{filter:e}:{},...void 0!==r?{offset:r}:{}});for(const e of i.points)yield{id:String(e.id),payload:e.payload};const n=i.next_page_offset;if(null==n)break;if("string"!=typeof n&&"number"!=typeof n)break;r=n}}}class wt{consecutiveFailures=0;maxRetries;maxBackoffMs;baseDelayMs;onFatalError;logger;constructor(e){this.maxRetries=e.maxRetries??Number.POSITIVE_INFINITY,this.maxBackoffMs=e.maxBackoffMs??6e4,this.baseDelayMs=e.baseDelayMs??1e3,this.onFatalError=e.onFatalError,this.logger=e.logger}recordSuccess(){this.consecutiveFailures>0&&this.logger.info({previousFailures:this.consecutiveFailures},"System health recovered"),this.consecutiveFailures=0}recordFailure(e){if(this.consecutiveFailures+=1,this.logger.error({consecutiveFailures:this.consecutiveFailures,maxRetries:this.maxRetries,err:D(e)},"System-level failure recorded"),this.consecutiveFailures>=this.maxRetries){if(this.logger.fatal({consecutiveFailures:this.consecutiveFailures},"Maximum retries exceeded, triggering fatal error"),this.onFatalError)return this.onFatalError(e),!1;throw e instanceof Error?e:new Error(`Fatal system error: ${String(e)}`)}return!0}get currentBackoffMs(){if(0===this.consecutiveFailures)return 0;const e=Math.max(0,this.consecutiveFailures-1);return Math.min(this.maxBackoffMs,this.baseDelayMs*2**e)}async backoff(e){const t=this.currentBackoffMs;t<=0||(this.logger.warn({delayMs:t,consecutiveFailures:this.consecutiveFailures},"Backing off before next attempt"),await new Promise(((r,i)=>{const n=setTimeout((()=>{o(),r()}),t),s=()=>{o(),i(new Error("Backoff aborted"))},o=()=>{clearTimeout(n),e&&e.removeEventListener("abort",s)};if(e){if(e.aborted)return void s();e.addEventListener("abort",s,{once:!0})}})))}get failures(){return this.consecutiveFailures}}function vt(e){const t=H(e).split("/"),r=[];for(const e of t){if(/[*?{[\]]/.test(e))break;r.push(e)}return r.join("/")||"."}function Mt(e){const t=function(e){const t=e.map((e=>H(e).toLowerCase()));return[...new Set(t)].sort().filter(((e,t,r)=>{const i=e.endsWith("/")?e:e+"/";return!r.some((t=>t!==e&&i.startsWith(t+"/")))}))}(e.map(vt)),r=function(e){const t=e.map((e=>H(e))),r=n(t,{dot:!0,nocase:!0});return e=>{const t=H(e);return r(t)}}(e);return{roots:t,matches:r}}class St{config;queue;processor;logger;health;gitignoreFilter;globMatches;watcher;constructor(e,t,r,i,n={}){this.config=e,this.queue=t,this.processor=r,this.logger=i,this.gitignoreFilter=n.gitignoreFilter,this.globMatches=()=>!0;const s={maxRetries:n.maxRetries,maxBackoffMs:n.maxBackoffMs,onFatalError:n.onFatalError,logger:i};this.health=new wt(s)}start(){const{roots:e,matches:t}=Mt(this.config.paths);this.globMatches=t;const r=this.config.ignored?function(e){return e.map((e=>{if("string"!=typeof e)return e;const t=H(e),r=n(t,{dot:!0,nocase:!0});return e=>{const t=H(e);return r(t)}}))}(this.config.ignored):void 0;this.watcher=g.watch(e,{ignored:r,usePolling:this.config.usePolling,interval:this.config.pollIntervalMs,awaitWriteFinish:!!this.config.stabilityThresholdMs&&{stabilityThreshold:this.config.stabilityThresholdMs},ignoreInitial:!1}),this.watcher.on("add",(e=>{this.handleGitignoreChange(e),this.globMatches(e)&&(this.isGitignored(e)||(this.logger.debug({path:e},"File added"),this.queue.enqueue({type:"create",path:e,priority:"normal"},(()=>this.wrapProcessing((()=>this.processor.processFile(e)))))))})),this.watcher.on("change",(e=>{this.handleGitignoreChange(e),this.globMatches(e)&&(this.isGitignored(e)||(this.logger.debug({path:e},"File changed"),this.queue.enqueue({type:"modify",path:e,priority:"normal"},(()=>this.wrapProcessing((()=>this.processor.processFile(e)))))))})),this.watcher.on("unlink",(e=>{this.handleGitignoreChange(e),this.globMatches(e)&&(this.isGitignored(e)||(this.logger.debug({path:e},"File removed"),this.queue.enqueue({type:"delete",path:e,priority:"normal"},(()=>this.wrapProcessing((()=>this.processor.deleteFile(e)))))))})),this.watcher.on("error",(e=>{this.logger.error({err:D(e)},"Watcher error"),this.health.recordFailure(e)})),this.queue.process(),this.logger.info({paths:this.config.paths},"Filesystem watcher started")}async stop(){this.watcher&&(await this.watcher.close(),this.watcher=void 0,this.logger.info("Filesystem watcher stopped"))}get systemHealth(){return this.health}isGitignored(e){if(!this.gitignoreFilter)return!1;const t=this.gitignoreFilter.isIgnored(e);return t&&this.logger.debug({path:e},"Skipping gitignored file"),t}handleGitignoreChange(e){this.gitignoreFilter&&e.endsWith(".gitignore")&&(this.logger.info({path:e},"Gitignore file changed, refreshing filter"),this.gitignoreFilter.invalidate(e))}async wrapProcessing(e){try{await this.health.backoff(),await e(),this.health.recordSuccess()}catch(e){this.health.recordFailure(e)||await this.stop()}}}const zt={loadConfig:Ve,createLogger:et,createEmbeddingProvider:Xe,createVectorStoreClient:(e,t,r)=>new bt(e,t,r),compileRules:ne,createDocumentProcessor:e=>new pt(e),createEventQueue:e=>new mt(e),createFileSystemWatcher:(e,t,r,i,n)=>new St(e,t,r,i,n),createApiServer:Te};function xt(e){let t=i.resolve(e);const r=i.resolve("/");for(;t!==r;){if(u.existsSync(i.join(t,".git"))&&u.statSync(i.join(t,".git")).isDirectory())return t;const e=i.dirname(t);if(e===t)break;t=e}}function kt(e){const t=i.resolve(e);try{return u.statSync(t).isDirectory()?t:i.dirname(t)}catch{}const r=/[*?[{]/.exec(e);if(!r)return;const n=e.slice(0,r.index).trim(),s=0===n.length?".":n.endsWith("/")||n.endsWith("\\")?n:i.dirname(n),o=i.resolve(s);return u.existsSync(o)?o:void 0}function jt(e){const t=[],r=i.join(e,".gitignore");let n;u.existsSync(r)&&t.push(r);try{n=u.readdirSync(e)}catch{return t}for(const r of n){if(".git"===r||"node_modules"===r)continue;const n=i.join(e,r);try{u.statSync(n).isDirectory()&&t.push(...jt(n))}catch{}}return t}function Pt(e){const t=u.readFileSync(e,"utf8");return x().add(t)}class Ft{repos=new Map;constructor(e){this.scan(e)}scan(e){this.repos.clear();const t=new Set;for(const r of e){const e=kt(r);if(!e)continue;if(t.has(e))continue;t.add(e);const n=xt(e);if(!n)continue;if(this.repos.has(n))continue;const s=jt(n).map((e=>({dir:i.dirname(e),ig:Pt(e)})));s.sort(((e,t)=>t.dir.length-e.dir.length)),this.repos.set(n,{root:n,entries:s})}}isIgnored(e){const t=i.resolve(e);for(const[,e]of this.repos){const r=i.relative(e.root,t);if(!(r.startsWith("..")||r.startsWith(i.resolve("/"))||/^[a-zA-Z]:/.test(r)))for(const r of e.entries){const e=i.relative(r.dir,t);if(e.startsWith("..")||/^[a-zA-Z]:/.test(e))continue;const n=e.replace(/\\/g,"/");if(r.ig.ignores(n))return!0}}return!1}invalidate(e){const t=i.resolve(e),r=i.dirname(t);for(const[,e]of this.repos){if(!i.relative(e.root,r).startsWith(".."))return e.entries=e.entries.filter((e=>e.dir!==r)),void(u.existsSync(t)&&(e.entries.push({dir:r,ig:Pt(t)}),e.entries.sort(((e,t)=>t.dir.length-e.dir.length))))}const n=xt(r);if(n&&u.existsSync(t)){const e=[{dir:r,ig:Pt(t)}];if(this.repos.has(n)){const t=this.repos.get(n);t.entries.push(e[0]),t.entries.sort(((e,t)=>t.dir.length-e.dir.length))}else this.repos.set(n,{root:n,entries:e})}}}function Rt(e){const t={},r=/\/\*\*([\s\S]*?)\*\/\s*export\s+(?:function|const)\s+(\w+)/g;let i;for(;null!==(i=r.exec(e));){const[,e,r]=i;if(!r||!e)continue;const n=e.split("\n").map((e=>e.replace(/^\s*\*\s?/,"").trim())).filter((e=>e.length>0&&!e.startsWith("@")));t[r]=n.join(" ")}return t}async function Ot(e,t){const r={},i=await ue({[t]:{path:e}},"",(e=>"function"==typeof e));let n={};for(const t of[".ts",".js",""]){const r=e.replace(/\.[jt]s$/,"")+t;try{if(n=Rt(u.readFileSync(""===t?e:r,"utf-8")),Object.keys(n).length>0)break}catch{}}const s=i[t]??{};for(const e of Object.keys(s))r[`${t}_${e}`]=n[e]??"";return{exports:r}}const Et=E.unified().use(O,{fragment:!0});function At(e){e.registerHelper("adfToMarkdown",(function(t){if(!t||"object"!=typeof t)return"";try{const r=F.fromADF(t);return new e.SafeString(R.toMarkdown(r).trim())}catch{return"\x3c!-- ADF conversion failed --\x3e"}})),e.registerHelper("markdownify",(function(t){if("string"!=typeof t||!t.trim())return"";try{const r=Et.parse(t),i=P.toMdast(r);return new e.SafeString(R.toMarkdown(i).trim())}catch{return"\x3c!-- HTML conversion failed --\x3e"}})),e.registerHelper("dateFormat",(function(e,t){if(null==e)return"";const r="string"==typeof t?t:"YYYY-MM-DD";return j(e).format(r)})),e.registerHelper("join",(function(e,t){if(!Array.isArray(e))return"";const r="string"==typeof t?t:", ";return e.join(r)})),e.registerHelper("pluck",(function(e,t){return Array.isArray(e)&&"string"==typeof t?e.map((e=>e&&"object"==typeof e?e[t]:void 0)):[]})),e.registerHelper("lowercase",(e=>"string"==typeof e?e.toLowerCase():"")),e.registerHelper("uppercase",(e=>"string"==typeof e?e.toUpperCase():"")),e.registerHelper("capitalize",(e=>"string"==typeof e?h.capitalize(e):"")),e.registerHelper("title",(e=>"string"==typeof e?h.title(e):"")),e.registerHelper("camel",(e=>"string"==typeof e?h.camel(e):"")),e.registerHelper("snake",(e=>"string"==typeof e?h.snake(e):"")),e.registerHelper("dash",(e=>"string"==typeof e?h.dash(e):"")),e.registerHelper("default",(function(e,t){return e??t??""})),e.registerHelper("eq",(function(e,t){return h.isEqual(e,t)})),e.registerHelper("json",(function(t){return new e.SafeString(JSON.stringify(t,null,2))}))}function Ct(e,t,r,n=new Set){if(e.endsWith(".hbs")||e.endsWith(".handlebars"))return u.readFileSync(i.resolve(r,e),"utf-8");if(void 0!==t?.[e]){if(n.has(e))throw new Error(`Circular template reference detected: ${e}`);return n.add(e),Ct(t[e],t,r,n)}return e}function Dt(){const e=k.create();return At(e),e}async function Tt(e,t,r){for(const[n,{path:s}]of Object.entries(t)){const t=i.resolve(r,s),o=await import(f.pathToFileURL(t).href);if("function"==typeof o.default){const t=new Set(Object.keys(e.helpers));o.default(e,n);const r=Object.keys(e.helpers);for(const i of r)if(!t.has(i)&&!i.startsWith(`${n}_`)){const t=e.helpers[i];e.registerHelper(`${n}_${i}`,t),e.unregisterHelper(i)}}}}class Nt{hbs;compiled=new Map;constructor(e){this.hbs=e}compile(e,t){const r=this.hbs.compile(t);return this.compiled.set(e,r),r}get(e){return this.compiled.get(e)}render(e,t){const r=this.compiled.get(e);return r?r(t):null}}async function It(e,t,r,i){if(0===e.filter((e=>e.template)).length)return;const n=Dt();r&&Object.keys(r).length>0&&i&&await Tt(n,r,i);const s=new Nt(n),o=t?Object.fromEntries(Object.entries(t).map((([e,t])=>{return[e,(r=t,"string"==typeof r?r:r.template)];var r}))):void 0;for(const t of e){if(!t.template)continue;const e=Ct(t.template,o,i??".");s.compile(t.name,e)}return s}function Ht(e){if(!e)return;const t={};for(const[r,i]of Object.entries(e))t[r]="string"==typeof i?i:i&&"object"==typeof i&&"map"in i?i.map:i;return t}async function $t(e,t){const r=await It(e.inferenceRules??[],e.templates,e.templateHelpers,t),i=e.mapHelpers&&t?await async function(e,t){const r=await ue(e,t,(e=>"function"==typeof e)),i={};for(const[e,t]of Object.entries(r))for(const[r,n]of Object.entries(t))i[`${e}_${r}`]=n;return i}(e.mapHelpers,t):void 0;return{templateEngine:r,customMapLib:i}}async function _t(e,t){return await async function(e,t){const r={mapHelpers:{},templateHelpers:{}};if(e.mapHelpers)for(const[n,{path:s}]of Object.entries(e.mapHelpers)){const e=i.resolve(t,s);r.mapHelpers[n]=await Ot(e,n)}if(e.templateHelpers)for(const[n,{path:s}]of Object.entries(e.templateHelpers)){const e=i.resolve(t,s);r.templateHelpers[n]=await Ot(e,n)}return r}({mapHelpers:e.mapHelpers,templateHelpers:e.templateHelpers},t)}function Wt(e){return e?i.dirname(e):"."}class Lt{config;configPath;factories;runtimeOptions;logger;watcher;queue;server;processor;configWatcher;issuesManager;valuesManager;helperIntrospection;constructor(e,t,r={},i={}){this.config=e,this.configPath=t,this.factories={...zt,...r},this.runtimeOptions=i}async start(){const e=this.factories.createLogger(this.config.logging);this.logger=e;const{embeddingProvider:t,vectorStore:r}=await async function(e,t,r){let i;try{i=t.createEmbeddingProvider(e.embedding,r)}catch(e){throw r.fatal({err:D(e)},"Failed to create embedding provider"),e}const n=t.createVectorStoreClient(e.vectorStore,i.dimensions,r);return await n.ensureCollection(),{embeddingProvider:i,vectorStore:n}}(this.config,this.factories,e),i=this.factories.compileRules(this.config.inferenceRules??[]),n=Wt(this.configPath),{templateEngine:s,customMapLib:o}=await $t(this.config,n);this.helperIntrospection=await _t(this.config,n);const a=function(e,t,r){return{metadataDir:e.metadataDir??".jeeves-metadata",chunkSize:e.embedding.chunkSize,chunkOverlap:e.embedding.chunkOverlap,maps:Ht(e.maps),configDir:t,customMapLib:r,globalSchemas:e.schemas}}(this.config,n,o),c=this.factories.createDocumentProcessor({config:a,embeddingProvider:t,vectorStore:r,compiledRules:i,logger:e,templateEngine:s});this.processor=c,this.queue=this.factories.createEventQueue({debounceMs:this.config.watch.debounceMs??2e3,concurrency:this.config.embedding.concurrency??5,rateLimitPerMinute:this.config.embedding.rateLimitPerMinute}),this.watcher=function(e,t,r,i,n,s){const o=e.watch.respectGitignore??1?new Ft(e.watch.paths):void 0;return t.createFileSystemWatcher(e.watch,r,i,n,{maxRetries:e.maxRetries??s.maxRetries,maxBackoffMs:e.maxBackoffMs??s.maxBackoffMs,onFatalError:s.onFatalError,gitignoreFilter:o})}(this.config,this.factories,this.queue,c,e,this.runtimeOptions);const l=this.config.stateDir??this.config.metadataDir??".jeeves-metadata";this.issuesManager=new Ie(l,e),this.valuesManager=new $e(l,e),this.server=await this.startApiServer(c,r,t,e,this.issuesManager,this.valuesManager,this.helperIntrospection),this.watcher.start(),this.startConfigWatch(),e.info("jeeves-watcher started")}async stop(){if(await this.stopConfigWatch(),this.watcher&&await this.watcher.stop(),this.queue){const e=this.config.shutdownTimeoutMs??1e4;await Promise.race([this.queue.drain().then((()=>!0)),new Promise((t=>{setTimeout((()=>{t(!1)}),e)}))])||this.logger?.warn({timeoutMs:e},"Queue drain timeout hit, forcing shutdown")}this.server&&await this.server.close(),this.logger?.info("jeeves-watcher stopped")}async startApiServer(e,t,r,i,n,s,o){const a=this.factories.createApiServer({processor:e,vectorStore:t,embeddingProvider:r,queue:this.queue,config:this.config,logger:i,issuesManager:n,valuesManager:s,configPath:this.configPath??"",helperIntrospection:o});return await a.listen({host:this.config.api?.host??"127.0.0.1",port:this.config.api?.port??3456}),a}startConfigWatch(){const e=this.logger;if(!e)return;const t=this.config.configWatch?.enabled??!0;t&&this.configPath?(this.configWatcher=new _e({configPath:this.configPath,enabled:t,debounceMs:this.config.configWatch?.debounceMs??1e4,logger:e,onChange:async()=>this.reloadConfig()}),this.configWatcher.start()):this.configPath||e.debug("Config watch enabled, but no config path was provided")}async stopConfigWatch(){this.configWatcher&&(await this.configWatcher.stop(),this.configWatcher=void 0)}async reloadConfig(){const e=this.logger,t=this.processor;if(e&&t&&this.configPath){e.info({configPath:this.configPath},"Config change detected, reloading...");try{const r=await this.factories.loadConfig(this.configPath);this.config=r;const i=this.factories.compileRules(r.inferenceRules??[]),n=Wt(this.configPath),{templateEngine:s,customMapLib:o}=await $t(r,n);t.updateRules(i,s,o),e.info({configPath:this.configPath,rules:i.length},"Config reloaded");const a=r.configWatch?.reindex??"issues";e.info({scope:a},`Config watch triggering ${a} reindex`),await J({config:r,processor:t,logger:e,valuesManager:this.valuesManager,issuesManager:this.issuesManager},a)}catch(t){e.error({err:D(t)},"Failed to reload config")}}}}e.DocumentProcessor=pt,e.EventQueue=mt,e.FileSystemWatcher=St,e.GitignoreFilter=Ft,e.IssuesManager=Ie,e.JeevesWatcher=Lt,e.ReindexTracker=De,e.SystemHealth=wt,e.TemplateEngine=Nt,e.ValuesManager=$e,e.VectorStoreClient=bt,e.apiConfigSchema=G,e.applyRules=ye,e.buildAttributes=be,e.buildTemplateEngine=It,e.compileRules=ne,e.configWatchConfigSchema=B,e.contentHash=tt,e.createApiServer=Te,e.createEmbeddingProvider=Xe,e.createHandlebarsInstance=Dt,e.createLogger=et,e.deleteMetadata=Pe,e.embeddingConfigSchema=X,e.extractText=ht,e.inferenceRuleSchema=Z,e.issueRecordSchema=He,e.jeevesWatcherConfigSchema=te,e.loadConfig=Ve,e.loadCustomHelpers=Tt,e.loggingConfigSchema=Q,e.metadataPath=xe,e.pointId=it,e.readMetadata=ke,e.registerBuiltinHelpers=At,e.resolveTemplateSource=Ct,e.startFromConfig=async function(e){const t=await Ve(e),r=new Lt(t,e);return function(e){const t=async()=>{await e(),process.exit(0)};process.on("SIGTERM",(()=>{t()})),process.on("SIGINT",(()=>{t()}))}((()=>r.stop())),await r.start(),r},e.vectorStoreConfigSchema=ee,e.watchConfigSchema=q,e.writeMetadata=je}(this["jeeves-watcher"]=this["jeeves-watcher"]||{},Fastify,promises,node_path,picomatch,zod,jsonmap,Ajv,addFormats,jsonpathPlus,node_fs,radash,node_url,node_crypto,chokidar,cosmiconfig,googleGenai,pino,uuid,cheerio,yaml,mammoth,textsplitters,jsClientRest,ignore,Handlebars,dayjs,hastUtilToMdast,mdastUtilFromAdf,mdastUtilToMarkdown,rehypeParse,unified);