ko-qmd 2.8.3-ko.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +1937 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +184 -0
  4. package/README.md +292 -0
  5. package/bin/qmd +192 -0
  6. package/dist/ast.d.ts +65 -0
  7. package/dist/ast.js +51 -0
  8. package/dist/bench/bench.d.ts +41 -0
  9. package/dist/bench/bench.js +12 -0
  10. package/dist/bench/score.d.ts +33 -0
  11. package/dist/bench/score.js +1 -0
  12. package/dist/bench/types.d.ts +101 -0
  13. package/dist/bench/types.js +1 -0
  14. package/dist/cli/build-info.json +4 -0
  15. package/dist/cli/embed-lock.d.ts +24 -0
  16. package/dist/cli/embed-lock.js +2 -0
  17. package/dist/cli/formatter.d.ts +120 -0
  18. package/dist/cli/formatter.js +60 -0
  19. package/dist/cli/mcp-pid.d.ts +33 -0
  20. package/dist/cli/mcp-pid.js +1 -0
  21. package/dist/cli/qmd.d.ts +101 -0
  22. package/dist/cli/qmd.js +165 -0
  23. package/dist/cli/version.d.ts +42 -0
  24. package/dist/cli/version.js +1 -0
  25. package/dist/collections.d.ts +162 -0
  26. package/dist/collections.js +1 -0
  27. package/dist/db.d.ts +63 -0
  28. package/dist/db.js +2 -0
  29. package/dist/filters.d.ts +46 -0
  30. package/dist/filters.js +1 -0
  31. package/dist/grep.d.ts +85 -0
  32. package/dist/grep.js +9 -0
  33. package/dist/hangul.d.ts +102 -0
  34. package/dist/hangul.js +1 -0
  35. package/dist/index.d.ts +270 -0
  36. package/dist/index.js +1 -0
  37. package/dist/llm.d.ts +584 -0
  38. package/dist/llm.js +40 -0
  39. package/dist/maintenance.d.ts +33 -0
  40. package/dist/maintenance.js +1 -0
  41. package/dist/mcp/daemon-health.d.ts +17 -0
  42. package/dist/mcp/daemon-health.js +1 -0
  43. package/dist/mcp/origin-guard.d.ts +67 -0
  44. package/dist/mcp/origin-guard.js +1 -0
  45. package/dist/mcp/server.d.ts +131 -0
  46. package/dist/mcp/server.js +35 -0
  47. package/dist/memory.d.ts +74 -0
  48. package/dist/memory.js +13 -0
  49. package/dist/metadata-filter.d.ts +74 -0
  50. package/dist/metadata-filter.js +1 -0
  51. package/dist/metadata-store.d.ts +45 -0
  52. package/dist/metadata-store.js +68 -0
  53. package/dist/metadata.d.ts +61 -0
  54. package/dist/metadata.js +1 -0
  55. package/dist/paths.d.ts +1 -0
  56. package/dist/paths.js +1 -0
  57. package/dist/query-log.d.ts +156 -0
  58. package/dist/query-log.js +2 -0
  59. package/dist/refresh.d.ts +60 -0
  60. package/dist/refresh.js +1 -0
  61. package/dist/rerank-input.d.ts +46 -0
  62. package/dist/rerank-input.js +5 -0
  63. package/dist/store.d.ts +1267 -0
  64. package/dist/store.js +421 -0
  65. package/dist/trust.d.ts +152 -0
  66. package/dist/trust.js +2 -0
  67. package/package.json +124 -0
  68. package/scripts/build.mjs +130 -0
  69. package/scripts/check-package-grammars.mjs +29 -0
  70. package/scripts/package-smoke.mjs +65 -0
  71. package/scripts/test-all.mjs +42 -0
  72. package/skills/qmd/SKILL.md +333 -0
  73. package/skills/qmd/references/mcp-setup.md +122 -0
  74. package/skills/release/SKILL.md +141 -0
  75. package/skills/release/scripts/install-hooks.sh +38 -0
  76. package/skills/release/scripts/release-context.sh +129 -0
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ var Eo=Object.defineProperty;var a=(e,t)=>Eo(e,"name",{value:t,configurable:!0});import{isBun as So}from"../db.js";import Co from"fast-glob";import{spawn as xt}from"child_process";import{isQmdMcpPid as Ye,mcpDaemonStateFiles as Do,openDaemonLogFile as qo}from"./mcp-pid.js";import{embedLockPathForDb as Mo,tryAcquireEmbedLock as _o,EMBED_LOCK_BUSY_MESSAGE as Po}from"./embed-lock.js";import{fileURLToPath as ge}from"url";import{basename as vt,dirname as X,join as A,relative as kt,resolve as _e}from"path";import{parseArgs as Ro}from"util";import{buildDocumentFilter as Lo,describeFilter as pe}from"../filters.js";import{compileGrepPattern as To,grepDocuments as Io}from"../grep.js";import{readFileSync as F,readdirSync as me,realpathSync as se,statSync as fe,existsSync as R,unlinkSync as re,writeFileSync as wt,closeSync as No,mkdirSync as Pe,lstatSync as Ke,rmSync as Oo,symlinkSync as Ao,readlinkSync as Fo,copyFileSync as Uo}from"fs";import{createInterface as Qo}from"readline/promises";import{getPwd as W,getRealPath as Re,isPathInsideDir as Bo,homedir as Z,resolve as q,enableProductionMode as jo,searchFTS as Go,countFilteredDocuments as Et,extractSnippet as he,getContextForFile as Wo,getContextForPath as Ho,listCollections as ze,removeCollection as Vo,renameCollection as Yo,findDocument as Ko,resolveCommaListName as zo,matchFilesByGlob as Jo,getHashesNeedingEmbedding as $e,hashContent as Xo,extractTitle as St,formatDocForEmbedding as Zo,getEmbeddingFingerprint as en,chunkDocumentByTokens as tn,clearCache as Ct,getIndexHealth as on,parseVirtualPath as le,buildVirtualPath as Dt,isVirtualPath as Je,isDocid as nn,resolveVirtualPath as Le,insertContent as qt,insertDocument as sn,findOrMigrateLegacyDocument as rn,updateDocumentTitle as ln,updateDocument as cn,deactivateDocument as an,getActiveDocumentPaths as dn,cleanupOrphanedContent as un,countOrphanedVectors as Mt,previewCleanup as mn,runCleanup as fn,escapeLikePattern as gn,hybridQuery as pn,vectorSearchQuery as hn,validateLexQuery as $n,structuredSearch as bn,addLineNumbers as ee,DEFAULT_EMBED_MODEL as Te,DEFAULT_EMBED_MAX_BATCH_BYTES as yn,DEFAULT_EMBED_MAX_DOCS_PER_BATCH as xn,DEFAULT_RERANK_MODEL as Xe,DEFAULT_QUERY_MODEL as _t,DEFAULT_GLOB as Pt,splitGlobMask as vn,DEFAULT_MULTI_GET_MAX_BYTES as Rt,createStore as Lt,getDefaultDbPath as Tt,reindexCollection as kn,generateEmbeddings as wn,maybeAdoptLegacyEmbeddingFingerprint as En,syncConfigToDb as Ze}from"../store.js";import{syncDocumentMetadata as Sn,countDocumentsPendingMetadata as It}from"../metadata-store.js";import{parseMetadataFilter as Cn}from"../metadata-filter.js";import{disposeDefaultLlamaCpp as Dn,getDefaultLlamaCpp as qn,setDefaultLlamaCpp as Mn,LlamaCpp as _n,withLLMSession as et,pullModels as Pn,DEFAULT_MODEL_CACHE_DIR as Ie,resolveModels as be,inspectGgufFile as Nt,isDarwinMetalMitigationActive as Rn}from"../llm.js";import{escapeXml as H,escapeCSV as Ne}from"./formatter.js";import{resolveCommit as Ln}from"./version.js";import{latestQueryLogFile as Tn}from"../query-log.js";import{getCollection as N,listCollections as ye,getDefaultCollectionNames as In,addContext as Ot,removeContext as At,removeCollection as Nn,renameCollection as On,setGlobalContext as Ft,listAllContexts as Ut,setConfigIndexName as Qt,loadConfig as ie,saveConfig as Bt,setConfigSource as Oe,findLocalConfigPath as An,getLocalDbPath as Fn,getConfigPath as ce,configExists as Un}from"../collections.js";import{decideLocalConfigGate as Qn,gatedItems as Bn,hasGatedItems as tt,isCollectionPathInsideProject as jn,isLocalConfigPath as xe,isLocalConfigTrustOptedIn as Gn,isTrusted as Wn,listTrusted as Hn,recordTrust as ot,revokeTrust as Vn,sensitiveDigest as Yn}from"../trust.js";let V=null,ve,jt="index";function Y(){if(!V){V=Lt(ve);try{const e=de(),t=ie();Ze(V.db,t);const o=Kt()?e:be(),s=new _n({embedModel:o.embed,generateModel:o.generate,rerankModel:o.rerank});Mn(s),V.llm=s}catch{}}return V}a(Y,"getStore");function P(){return Y().db}a(P,"getDb");function ke(){const e=Y();try{const t=ie();e.db.prepare("DELETE FROM store_config WHERE key = 'config_hash'").run(),Ze(e.db,t)}catch{}}a(ke,"resyncConfig");function k(){V&&(V.close(),V=null)}a(k,"closeDb");function te(){return V?.dbPath??ve??Tt()}a(te,"getDbPath");function Gt(){return jt}a(Gt,"getActiveIndexName");function Wt(){const e=process.env.XDG_CACHE_HOME?q(process.env.XDG_CACHE_HOME,"qmd"):q(Z(),".cache","qmd"),{pidFile:t,logFile:o}=Do(Gt());return{cacheDir:e,pidPath:q(e,t),logPath:q(e,o)}}a(Wt,"mcpDaemonPaths");const Kn=8181;function zn(e){if(e===void 0)return Kn;const t=Number(e);if(!Number.isInteger(t)||t<1||t>65535)throw new Error(`Invalid --port ${JSON.stringify(String(e))}: expected an integer between 1 and 65535.`);return t}a(zn,"resolveMcpPort");async function Jn(e,t,o=15e3){let s=e.exitCode!==null;e.on("exit",()=>{s=!0});const r=Date.now()+o;for(;;){let l="";try{l=F(t,"utf-8")}catch{}if(/listening on /i.test(l))return{ok:!0};if(s||e.exitCode!==null){const i=l.match(/^.*(?:already in use|EADDRINUSE).*$/gim);return i?{ok:!1,message:(i[i.length-1]??"Port already in use.").trim()}:{ok:!1,message:`Daemon exited before listening (code ${e.exitCode??"?"}). See logs: ${t}`}}if(Date.now()>=r){try{e.kill("SIGTERM")}catch{}return{ok:!1,message:`Timed out waiting for the daemon to listen. See logs: ${t}`}}await new Promise(i=>setTimeout(i,100))}}a(Jn,"waitForDaemonListening");function Ht(e){let t=e;if(e){const o=/^[a-zA-Z]:[\\/]/.test(e)||/^\\/.test(e);(o||/[\\/]/.test(e))&&(t=(o?e:_e(process.cwd(),e)).replace(/[:\\/]+/g,"_").replace(/^_+/,""))}jt=t||"index",ve=t?Tt(t):void 0,k()}a(Ht,"setIndexName");function Wr(e,t){Y().ensureVecTable(t)}a(Wr,"ensureVecTable");const U=!process.env.NO_COLOR&&process.stdout.isTTY,n={reset:U?"\x1B[0m":"",dim:U?"\x1B[2m":"",bold:U?"\x1B[1m":"",cyan:U?"\x1B[36m":"",yellow:U?"\x1B[33m":"",green:U?"\x1B[32m":"",magenta:U?"\x1B[35m":"",blue:U?"\x1B[34m":""},Ae={hide(){process.stderr.write("\x1B[?25l")},show(){process.stderr.write("\x1B[?25h")}};async function Vt(e){await new Promise(t=>{e.write("",()=>t())})}a(Vt,"flushWritable");async function Xn(e){const t=e.stderr??process.stderr;await Vt(e.stdout??process.stdout);try{await(e.cleanup??Dn)()}catch(o){t.write(`QMD Warning: cleanup after successful output failed (${o instanceof Error?o.message:String(o)}); exiting 0 because command output completed.
3
+ `)}if(await Vt(t),e.exit){e.exit(0);return}process.exitCode=0}a(Xn,"finishSuccessfulCliCommand"),process.on("SIGINT",()=>{Ae.show(),process.exit(130)}),process.on("SIGTERM",()=>{Ae.show(),process.exit(143)});const ae=process.stderr.isTTY,L={set(e){ae&&process.stderr.write(`\x1B]9;4;1;${Math.round(e)}\x07`)},clear(){ae&&process.stderr.write("\x1B]9;4;0\x07")},indeterminate(){ae&&process.stderr.write("\x1B]9;4;3\x07")},error(){ae&&process.stderr.write("\x1B]9;4;2\x07")}};function Fe(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.floor(e/60)}m ${Math.round(e%60)}s`:`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`}a(Fe,"formatETA");function Yt(e,t=at()){const{needsEmbedding:o,totalDocs:s,daysStale:r}=on(e,t);if(o>0){const l=Math.round(o/s*100);l>=10?process.stderr.write(`${n.yellow}Warning: ${o} documents (${l}%) need embeddings. Run 'qmd embed' for better results.${n.reset}
4
+ `):process.stderr.write(`${n.dim}Tip: ${o} documents need embeddings. Run 'qmd embed' to index them.${n.reset}
5
+ `)}r!==null&&r>=14&&process.stderr.write(`${n.dim}Tip: Index last updated ${r} days ago. Run 'qmd update' to refresh.${n.reset}
6
+ `)}a(Yt,"checkIndexHealth");function Hr(e,t,o){const s=t.replace(/\/$/,""),r=s.split("/").pop()||"";let l;e.startsWith(s+"/")?l=r+e.slice(s.length):l=e;const i=l.split("/").filter($=>$.length>0),m=Math.min(2,i.length);for(let $=i.length-m;$>=0;$--){const p=i.slice($).join("/");if(!o.has(p))return p}return e}a(Hr,"computeDisplayPath");function Ue(e){const t=Math.floor((Date.now()-e.getTime())/1e3);if(t<60)return`${t}s ago`;const o=Math.floor(t/60);if(o<60)return`${o}m ago`;const s=Math.floor(o/60);return s<24?`${s}h ago`:`${Math.floor(s/24)}d ago`}a(Ue,"formatTimeAgo");function we(e){return e<1e3?`${e}ms`:`${(e/1e3).toFixed(1)}s`}a(we,"formatMs");function Q(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:e<1024*1024*1024?`${(e/(1024*1024)).toFixed(1)} MB`:`${(e/(1024*1024*1024)).toFixed(1)} GB`}a(Q,"formatBytes");function Zn(e,t){try{return se(e)===se(t)}catch{return _e(e)===_e(t)}}a(Zn,"sameDirectory");function es(){const e=W();if(Zn(e,Z()))throw new Error("Refusing to initialize a local index in $HOME. The global index is automatically created; run `qmd collection add <path>` for the global index, or run `qmd init` inside a project folder.");const t=A(e,".qmd"),o=A(t,"index.yml"),s=A(t,"index.yaml"),r=R(s)?s:o,l=A(t,"index.sqlite");Pe(t,{recursive:!0}),Oe({configPath:r}),ve=l,k(),R(r)?de():Bt({collections:{},models:be()});const i=Lt(l);Ze(i.db,ie()),i.close(),console.log("ready to go with new local index")}a(es,"initLocalIndex");function ts(){const e=process.env.QMD_FORCE_CPU;return!!e&&!["false","off","none","disable","disabled","0"].includes(e.trim().toLowerCase())}a(ts,"isForceCpuEnabled");function os(){return ts()?"CPU forced (QMD_FORCE_CPU)":process.env.QMD_LLAMA_GPU?.trim()||"auto"}a(os,"configuredGpuModeLabel");function ns(e){const t=new Map;for(const o of e)t.set(o,(t.get(o)||0)+1);return Array.from(t.entries()).map(([o,s])=>s>1?`${s}\xD7 ${o}`:o).join(", ")}a(ns,"summarizeDeviceNames");function oe(e){const t=Z();return e.replaceAll(t,"~").replaceAll(process.cwd(),".").split(`
7
+ `).map(o=>o.trim()).filter(Boolean).slice(0,3).join("; ")}a(oe,"sanitizeDiagnosticMessage");const ss=.1;function rs(e,t){const o=t>0?Math.round(e/t*100):0;return`${e} orphaned embedding chunks (${o}% of vectors) \u2014 run 'qmd cleanup' to reclaim space`}a(rs,"formatOrphanedVectorHint");async function ls(){const e=te(),t=P();let o=0;try{o=fe(e).size}catch{}const s=ze(t),r=t.prepare("SELECT COUNT(*) as count FROM documents WHERE active = 1").get(),l=t.prepare("SELECT COUNT(*) as count FROM content_vectors").get(),i=at(),m=$e(t,void 0,i),$=t.prepare("SELECT MAX(modified_at) as latest FROM documents WHERE active = 1").get();console.log(`${n.bold}QMD Status${n.reset}
8
+ `),console.log(`Index: ${e}`),console.log(`Size: ${Q(o)}`);const{pidPath:p}=Wt();if(R(p)){const y=parseInt(F(p,"utf-8").trim());if(Ye(y))console.log(`MCP: ${n.green}running${n.reset} (PID ${y})`);else try{re(p)}catch{}}const u=Tn();u.kind==="file"?console.log(`Query log: ${vt(u.path)} (last write ${Ue(u.modified)})`):u.kind==="error"?console.log(`Query log: ${n.yellow}unreadable \u2014 ${u.message}${n.reset}`):console.log(`Query log: ${n.dim}none (daemon writes it when started with QMD_QUERY_LOG=1)${n.reset}`),console.log("");const c=Mt(t);if(console.log(`${n.bold}Documents${n.reset}`),console.log(` Total: ${r.count} files indexed`),console.log(` Vectors: ${l.count} embedded`),c>0){const y=l.count>0?Math.round(c/l.count*100):0;console.log(` ${n.yellow}Orphaned: ${c} embedding chunks (${y}%)${n.reset} \u2014 run 'qmd cleanup'`)}m>0&&console.log(` ${n.yellow}Pending: ${m} need embedding${n.reset} (run 'qmd embed')`);const d=It(t);if(d>0&&console.log(` ${n.yellow}Metadata: ${d} need extraction${n.reset} (run 'qmd update'; excluded from --filter searches)`),$.latest){const y=new Date($.latest);console.log(` Updated: ${Ue(y)}`)}const h=Ut(),f=new Map;for(const y of h)f.has(y.collection)||f.set(y.collection,[]),f.get(y.collection).push({path_prefix:y.path,context:y.context});try{const{getASTStatus:y}=await import("../ast.js"),w=await y();if(console.log(`
9
+ ${n.bold}AST Chunking${n.reset}`),w.available){const S=w.languages.filter(E=>E.available).map(E=>E.language),v=w.languages.filter(E=>!E.available);if(console.log(` Status: ${n.green}active${n.reset}`),console.log(` Languages: ${S.join(", ")}`),v.length>0)for(const E of v)console.log(` ${n.yellow}Unavailable: ${E.language} (${E.error})${n.reset}`)}else{console.log(` Status: ${n.yellow}unavailable${n.reset} (falling back to regex chunking)`);for(const S of w.languages)S.error&&console.log(` ${n.dim}${S.language}: ${S.error}${n.reset}`)}}catch{console.log(`
10
+ ${n.bold}AST Chunking${n.reset}`),console.log(` Status: ${n.dim}not available${n.reset}`)}if(s.length>0){console.log(`
11
+ ${n.bold}Collections${n.reset}`);for(const y of s){const w=y.last_modified?Ue(new Date(y.last_modified)):"never",S=f.get(y.name)||[];if(console.log(` ${n.cyan}${y.name}${n.reset} ${n.dim}(qmd://${y.name}/)${n.reset}`),console.log(` ${n.dim}Pattern:${n.reset} ${y.glob_pattern}`),console.log(` ${n.dim}Files:${n.reset} ${y.active_count} (updated ${w})`),S.length>0){console.log(` ${n.dim}Contexts:${n.reset} ${S.length}`);for(const v of S){const E=v.path_prefix===""||v.path_prefix==="/"?"/":`/${v.path_prefix}`,T=v.context.length>60?v.context.substring(0,57)+"...":v.context;console.log(` ${n.dim}${E}:${n.reset} ${T}`)}}}console.log(`
12
+ ${n.bold}Examples${n.reset}`),console.log(` ${n.dim}# List files in a collection${n.reset}`),s.length>0&&s[0]&&console.log(` qmd ls ${s[0].name}`),console.log(` ${n.dim}# Get a document${n.reset}`),s.length>0&&s[0]&&console.log(` qmd get qmd://${s[0].name}/path/to/file.md`),console.log(` ${n.dim}# Search within a collection${n.reset}`),s.length>0&&s[0]&&console.log(` qmd search "query" -c ${s[0].name}`)}else console.log(`
13
+ ${n.dim}No collections. Run 'qmd collection add .' to index markdown files.${n.reset}`);{const y=a(S=>{const v=S.match(/^hf:([^/]+\/[^/]+)\//);return v?`https://huggingface.co/${v[1]}`:S},"hfLink"),w=so();console.log(`
14
+ ${n.bold}Models${n.reset}`),console.log(` Embedding: ${y(w.embed)}`),console.log(` Reranking: ${y(w.rerank)}`),console.log(` Generation: ${y(w.generate)}`)}const g=[],b=s.filter(y=>(f.get(y.name)||[]).length===0);if(b.length>0){const y=b.map(S=>S.name).slice(0,3).join(", "),w=b.length>3?` +${b.length-3} more`:"";g.push(`Add context to collections for better search results: ${y}${w}`),g.push(` ${n.dim}qmd context add qmd://<name>/ "What this collection contains"${n.reset}`),g.push(` ${n.dim}qmd context add qmd://<name>/meeting-notes "Weekly team meeting notes"${n.reset}`)}const x=s.filter(y=>!N(y.name)?.update);if(x.length>0&&s.length>1){const y=x.map(S=>S.name).slice(0,3).join(", "),w=x.length>3?` +${x.length-3} more`:"";g.push(`Add update commands to keep collections fresh: ${y}${w}`),g.push(` ${n.dim}qmd collection update-cmd <name> 'git stash && git pull --rebase --ff-only && git stash pop'${n.reset}`)}if(g.length>0){console.log(`
15
+ ${n.bold}Tips${n.reset}`);for(const y of g)console.log(` ${y}`)}k()}a(ls,"showStatus");function nt(){return{embed:Te,rerank:Xe,generate:_t}}a(nt,"builtinModels");function Qe(){const e=ie();return{hooks:Object.entries(e.collections??{}).filter(([,t])=>!!t.update).map(([t,o])=>({collection:t,command:o.update})),paths:Object.entries(e.collections??{}).map(([t,o])=>({collection:t,path:o.path})),models:{embed:e.models?.embed,rerank:e.models?.rerank,generate:e.models?.generate}}}a(Qe,"collectSensitiveSnapshot");function st(e,t){return Yn(t,e,nt())}a(st,"localConfigDigest");function rt(e,t){return Bn(e,t,nt())}a(rt,"localConfigGated");function Kt(){const e=ce();if(!xe(e)||Gn())return!0;const t=Qe(),o=rt(e,t);return tt(o)?Wn(e,st(e,t)):!0}a(Kt,"localConfigIsFullyTrusted");function zt(){const e=ce();xe(e)&&ot(e,st(e,Qe()))}a(zt,"trustCurrentConfig");async function is(e){const{createInterface:t}=await import("node:readline/promises"),o=t({input:process.stdin,output:process.stdout});try{const s=(await o.question(e)).trim().toLowerCase();return s==="y"||s==="yes"}finally{o.close()}}a(is,"confirmOnTty");function Jt(e){if(e.hooks.length>0){console.log(`${n.yellow}This project's config defines update commands:${n.reset}`);for(const t of e.hooks)console.log(` ${n.bold}${t.collection}${n.reset}: ${t.command}`)}if(e.paths.length>0){console.log(`${n.yellow}Collection paths outside this project:${n.reset}`);for(const t of e.paths)console.log(` ${n.bold}${t.collection}${n.reset}: ${t.path}`)}if(e.models.length>0){console.log(`${n.yellow}Custom models:${n.reset}`);for(const t of e.models)console.log(` ${n.bold}${t.slot}${n.reset}: ${t.uri}`)}}a(Jt,"printGatedItems");async function Ee(){const e=ce(),t=Qe(),o=rt(e,t);if(!tt(o))return!0;const s=Qn({configPath:e,snapshot:t,builtins:nt(),isInteractive:!!process.stdin.isTTY&&!!process.stdout.isTTY});return s.action==="run"?!0:(Jt(o),console.log(`${n.dim}Config that came with a checkout is not trusted by default.${n.reset}`),s.action==="skip"?(console.log(`${n.yellow}Skipping them \u2014 no terminal to confirm on. Indexing of this project continues.${n.reset}`),console.log(`${n.dim}Approve with 'qmd trust', or set QMD_TRUST_LOCAL_CONFIG=1 for unattended runs.${n.reset}
16
+ `),!1):await is("Trust this project's .qmd config? [y/N] ")?(ot(e,s.digest),console.log(`${n.green}Trusted ${e}.${n.reset} ${n.dim}Editing a hook, path, or model will ask again.${n.reset}
17
+ `),!0):(console.log(`${n.yellow}Skipped. Indexing of this project continues.${n.reset}
18
+ `),!1))}a(Ee,"resolveLocalConfigTrust");function cs(e){const t=ce();if(e==="list"){const r=Hn();if(r.length===0){console.log(`${n.dim}No trusted project configs.${n.reset}`);return}for(const l of r){const i=typeof l.hooks=="string"?l.hooks:"",m=i.length>12?`${i.slice(0,12)}\u2026`:i;console.log(`${l.path} ${n.dim}(trusted ${l.trustedAt}, digest ${m})${n.reset}`)}return}if(e==="revoke"){if(!xe(t)){console.log(`${n.dim}No project-local .qmd config in scope \u2014 ${t} is your own config and is never gated.${n.reset}`),console.log(`${n.dim}Run this from inside the project, or see 'qmd trust list'.${n.reset}`);return}Vn(t)?console.log(`${n.green}\u2713 Revoked trust for ${t}${n.reset}`):console.log(`${n.dim}${t} was not trusted.${n.reset}`);return}if(e&&(console.error("Usage: qmd trust [list|revoke]"),process.exit(1)),!xe(t)){console.log(`${n.dim}${t} is your own config \u2014 it is never gated. Nothing to trust.${n.reset}`);return}const o=Qe(),s=rt(t,o);if(!tt(s)){console.log(`${n.dim}${t} defines no update commands, out-of-project collection paths, or custom models. Nothing to trust.${n.reset}`);return}Jt(s),ot(t,st(t,o)),console.log(`${n.green}\u2713 Trusted ${t}${n.reset}`),console.log(`${n.dim}Editing a hook, out-of-project path, or custom model will ask again. Revoke with 'qmd trust revoke'.${n.reset}`)}a(cs,"manageTrust");async function as(){const e=await Ee(),t=P(),o=Y(),s=dt().embed;Ct(t);const r=ze(t);if(r.length===0)return console.log(`${n.dim}No collections found. Run 'qmd collection add .' to index markdown files.${n.reset}`),k(),0;const l=e,i=ce();console.log(`${n.bold}Updating ${r.length} collection(s)...${n.reset}
19
+ `);let m=0;for(let c=0;c<r.length;c++){const d=r[c];if(!d)continue;console.log(`${n.cyan}[${c+1}/${r.length}]${n.reset} ${n.bold}${d.name}${n.reset} ${n.dim}(${d.glob_pattern})${n.reset}`);const h=N(d.name),f=h?.path??d.pwd;if(!l&&xe(i)&&!jn(i,f)){console.log(`${n.yellow}Skipping collection '${d.name}' \u2014 path ${f} is outside this project and this .qmd config is not trusted.${n.reset}`),console.log(`${n.dim}Approve with 'qmd trust'.${n.reset}
20
+ `),m++;continue}if(h?.update&&l){console.log(`${n.dim} Running update command: ${h.update}${n.reset}`);try{const x=xt("bash",["-c",h.update],{cwd:d.pwd,stdio:["ignore","pipe","pipe"]}),[y,w,S]=await new Promise((v,E)=>{let T="",M="";x.stdout?.on("data",O=>{T+=O.toString()}),x.stderr?.on("data",O=>{M+=O.toString()}),x.on("error",E),x.on("close",O=>v([T,M,O??1]))});y.trim()&&console.log(y.trim().split(`
21
+ `).map(v=>` ${v}`).join(`
22
+ `)),w.trim()&&console.log(w.trim().split(`
23
+ `).map(v=>` ${v}`).join(`
24
+ `)),S!==0&&(console.log(`${n.yellow}\u2717 Update command failed with exit code ${S}${n.reset}`),process.exit(S))}catch(x){console.log(`${n.yellow}\u2717 Update command failed: ${x}${n.reset}`),process.exit(1)}}const g=Date.now();console.log(`Collection: ${d.pwd} (${d.glob_pattern})`),L.indeterminate();const b=await kn(o,d.pwd,d.glob_pattern,d.name,{ignorePatterns:h?.ignore,onProgress:a(x=>{L.set(x.current/x.total*100);const y=(Date.now()-g)/1e3,w=x.current/y,S=(x.total-x.current)/w,v=x.current>2?` ETA: ${Fe(S)}`:"";ae&&process.stderr.write(`\rIndexing: ${x.current}/${x.total}${v} `)},"onProgress")});L.clear(),console.log(`
25
+ Indexed: ${b.indexed} new, ${b.updated} updated, ${b.unchanged} unchanged, ${b.removed} removed`),eo(b.skippedFiles),Zt(b.metadataErrors),b.orphanedCleaned>0&&console.log(`Cleaned up ${b.orphanedCleaned} orphaned content hash(es)`),console.log("")}const $=$e(t,void 0,s),p=t.prepare("SELECT COUNT(*) as count FROM content_vectors").get().count,u=Mt(t);return k(),m>0?console.log(`${n.yellow}Updated ${r.length-m} of ${r.length} collection(s), skipped ${m} (not trusted \u2014 run 'qmd trust').${n.reset}`):console.log(`${n.green}\u2713 All collections updated.${n.reset}`),$>0&&console.log(`
26
+ Run 'qmd embed' to update embeddings (${$} unique hashes need vectors)`),p>0&&u/p>=ss&&console.log(`
27
+ ${rs(u,p)}`),m}a(as,"updateCollections");function Xt(e,t){const o=Re(t),s=ye();let r=null;for(const i of s)(o.startsWith(i.path+"/")||o===i.path)&&(!r||i.path.length>r.path.length)&&(r={name:i.name,path:i.path});if(!r)return null;let l=o;return l.startsWith(r.path+"/")?l=l.slice(r.path.length+1):l===r.path&&(l=""),{collectionName:r.name,relativePath:l}}a(Xt,"detectCollectionFromPath");async function ds(e,t){const o=P();if(e==="/"){Ft(t),ke(),console.log(`${n.green}\u2713${n.reset} Set global context`),console.log(`${n.dim}Context: ${t}${n.reset}`),k();return}let s=e||".";if(s==="."||s==="./"?s=W():s.startsWith("~/")?s=Z()+s.slice(1):!s.startsWith("/")&&!s.startsWith("qmd://")&&(s=q(W(),s)),Je(s)){const i=le(s);i||(console.error(`${n.yellow}Invalid virtual path: ${s}${n.reset}`),process.exit(1)),N(i.collectionName)||(console.error(`${n.yellow}Collection not found: ${i.collectionName}${n.reset}`),process.exit(1)),Ot(i.collectionName,i.path,t),ke();const $=i.path?`qmd://${i.collectionName}/${i.path}`:`qmd://${i.collectionName}/ (collection root)`;console.log(`${n.green}\u2713${n.reset} Added context for: ${$}`),console.log(`${n.dim}Context: ${t}${n.reset}`),k();return}const r=Xt(o,s);r||(console.error(`${n.yellow}Path is not in any indexed collection: ${s}${n.reset}`),console.error(`${n.dim}Run 'qmd status' to see indexed collections${n.reset}`),process.exit(1)),Ot(r.collectionName,r.relativePath,t),ke();const l=r.relativePath?`qmd://${r.collectionName}/${r.relativePath}`:`qmd://${r.collectionName}/`;console.log(`${n.green}\u2713${n.reset} Added context for: ${l}`),console.log(`${n.dim}Context: ${t}${n.reset}`),k()}a(ds,"contextAdd");function us(){const e=P(),t=Ut();if(t.length===0){console.log(`${n.dim}No contexts configured. Use 'qmd context add' to add one.${n.reset}`),k();return}console.log(`
28
+ ${n.bold}Configured Contexts${n.reset}
29
+ `);let o="";for(const s of t){s.collection!==o&&(console.log(`${n.cyan}${s.collection}${n.reset}`),o=s.collection);const r=s.path?` ${s.path}`:" / (root)";console.log(`${r}`),console.log(` ${n.dim}${s.context}${n.reset}`)}k()}a(us,"contextList");function ms(e){if(e==="/"){Ft(void 0);const l=Y();ke(),k(),console.log(`${n.green}\u2713${n.reset} Removed global context`);return}if(Je(e)){const l=le(e);l||(console.error(`${n.yellow}Invalid virtual path: ${e}${n.reset}`),process.exit(1));const i=N(l.collectionName);i||(console.error(`${n.yellow}Collection not found: ${l.collectionName}${n.reset}`),process.exit(1)),At(i.name,l.path)||(console.error(`${n.yellow}No context found for: ${e}${n.reset}`),process.exit(1)),console.log(`${n.green}\u2713${n.reset} Removed context for: ${e}`);return}let t=e;t==="."||t==="./"?t=W():t.startsWith("~/")?t=Z()+t.slice(1):t.startsWith("/")||(t=q(W(),t));const o=P(),s=Xt(o,t);k(),s||(console.error(`${n.yellow}Path is not in any indexed collection: ${t}${n.reset}`),process.exit(1)),At(s.collectionName,s.relativePath)||(console.error(`${n.yellow}No context found for: qmd://${s.collectionName}/${s.relativePath}${n.reset}`),process.exit(1)),console.log(`${n.green}\u2713${n.reset} Removed context for: qmd://${s.collectionName}/${s.relativePath}`)}a(ms,"contextRemove");function lt(e,t=process.cwd()){let o;try{o=se(e)}catch{return null}const s=(()=>{try{return se(t)}catch{return t}})();if(o===s)return"./";if(o.startsWith(s+"/")){const r=kt(s,o);if(r&&!r.startsWith(".."))return`./${r}`}return o}a(lt,"renderFullPath");function it(e,t){if(e<=0)return;const o=t===1?"the file":`${e} of ${t} results`;console.error(`${n.yellow}warning:${n.reset} --full-path could not resolve ${o} on disk (moved or deleted since indexing); showing qmd:// + docid instead. Run 'qmd update' to refresh the index.`)}a(it,"warnUnresolvedFullPaths");function fs(e,t,o,s,r=!1){let l=e;const i=l.match(/:(\d+):(\d+)$/);if(i)t===void 0&&(t=parseInt(i[1],10)),o===void 0&&(o=parseInt(i[2],10)),l=l.slice(0,-i[0].length);else{const g=l.match(/:(\d+)$/);if(g){const b=g[1];b&&(t===void 0&&(t=parseInt(b,10)),l=l.slice(0,-g[0].length))}}t!==void 0&&(t=Math.max(1,t));const m=Je(l)?le(l):null;m&&(m.indexName&&(Ht(m.indexName),Qt(m.indexName)),l=Dt(m.collectionName,m.path));const $=P(),p=Ko($,l,{includeBody:!0});if("error"in p){if(p.error==="excluded_by_ignore")console.error(`Document is excluded by ignore rule: ${e}`),console.error(`Collection: ${p.collection}`),console.error(`Matched path: ${p.path}`),console.error(`Ignore rule: ${p.rule}`);else if(console.error(`Document not found: ${e}`),p.similarFiles.length>0){console.error("Similar files:");for(const g of p.similarFiles)console.error(` ${g}`)}k(),process.exit(1)}const u=p.docid,c=`qmd://${p.displayPath}`;let d;if(r){const g=Le($,c),b=g&&R(g)?lt(g):null;b?d=b:(d=u?`${c} #${u}`:c,it(1,1))}else d=u?`${c} #${u}`:c;let h=p.body||"";const f=t||1;if(t!==void 0||o!==void 0){const g=h.split(`
30
+ `),b=f-1,x=o!==void 0?b+o:g.length;h=g.slice(b,x).join(`
31
+ `)}s&&(h=ee(h,f)),console.log(d),p.context&&console.log(`Folder Context: ${p.context}`),console.log(`---
32
+ `),console.log(h),k()}a(fs,"getDocument");function gs(e,t,o=Rt,s="cli",r=!0,l=!1){const i=P(),m=e.includes(",")&&!e.includes("*")&&!e.includes("?")&&!e.includes("{"),$=nn(e);let p;if(m||$){const f=m?e.split(",").map(g=>g.trim()).filter(Boolean):[e.trim()].filter(Boolean);p=[];for(const g of f){const b=zo(i,g);b.ok?p.push({filepath:b.match.virtualPath,displayPath:b.match.virtualPath,bodyLength:b.match.bodyLength,collection:b.match.collection,path:b.match.path}):console.error(b.error)}$&&p.length===0&&(k(),process.exit(1))}else p=Jo(i,e).map(f=>({...f,displayPath:f.filepath,collection:void 0,path:void 0})),p.length===0&&(console.error(`No files matched pattern: ${e}`),k(),process.exit(1));const u=[];for(const f of p){let g=f.collection,b=f.path;if(!g||!b){const M=le(f.filepath);M&&(g=M.collectionName,b=M.path)}const x=g&&b?Ho(i,g,b):null,y=g&&b?i.prepare(`
33
+ SELECT d.hash as hash
34
+ FROM documents d
35
+ WHERE d.collection = ? AND d.path = ? AND d.active = 1
36
+ `).get(g,b):null,w=y?.hash?y.hash.slice(0,6):void 0;let S;if(l){const M=Le(i,f.filepath);M&&R(M)&&(S=lt(M)??void 0)}if(f.bodyLength>o){u.push({file:f.filepath,displayPath:f.displayPath,fsPath:S,docid:w,title:f.displayPath.split("/").pop()||f.displayPath,body:"",context:x,skipped:!0,skipReason:`File too large (${Math.round(f.bodyLength/1024)}KB > ${Math.round(o/1024)}KB). Re-run with a larger --max-bytes to retrieve the full content.`});continue}if(!g||!b)continue;const v=i.prepare(`
37
+ SELECT content.doc as body, d.title
38
+ FROM documents d
39
+ JOIN content ON content.hash = d.hash
40
+ WHERE d.collection = ? AND d.path = ? AND d.active = 1
41
+ `).get(g,b);if(!v)continue;let E=v.body,T=null;if(t!==void 0){const M=E.split(`
42
+ `);E=M.slice(0,t).join(`
43
+ `),M.length>t&&(T=`
44
+
45
+ [... truncated ${M.length-t} more lines]`)}r&&(E=ee(E)),T&&(E+=T),u.push({file:f.filepath,displayPath:f.displayPath,fsPath:S,docid:w,title:v.title||f.displayPath.split("/").pop()||f.displayPath,body:E,context:x,skipped:!1})}k();const c=a(f=>l&&f.fsPath?f.fsPath:f.displayPath,"identOf"),d=a(f=>l&&f.fsPath?void 0:f.docid,"docidOf"),h=l?u.filter(f=>!f.fsPath).length:0;if(s==="json"){const f=u.map(g=>{const b=d(g);return{file:c(g),...b&&{docid:`#${b}`},title:g.title,...g.context&&{context:g.context},...g.skipped?{skipped:!0,reason:g.skipReason}:{body:g.body}}});console.log(JSON.stringify(f,null,2))}else if(s==="csv"){const f=a(g=>{if(g==null)return"";const b=String(g);return b.includes(",")||b.includes('"')||b.includes(`
46
+ `)?`"${b.replace(/"/g,'""')}"`:b},"escapeField");console.log("docid,file,title,context,skipped,body");for(const g of u){const b=d(g);console.log([b?`#${b}`:"",c(g),g.title,g.context,g.skipped?"true":"false",g.skipped?g.skipReason:g.body].map(f).join(","))}}else if(s==="files")for(const f of u){const g=d(f),b=g?`#${g},`:"",x=f.context?`,"${f.context.replace(/"/g,'""')}"`:"",y=f.skipped?"[SKIPPED]":"";console.log(`${b}${c(f)}${x}${y?`,${y}`:""}`)}else if(s==="md")for(const f of u){const g=d(f);console.log(`## ${c(f)}
47
+ `),g&&console.log(`**docid:** \`#${g}\`
48
+ `),f.title&&f.title!==f.displayPath&&console.log(`**Title:** ${f.title}
49
+ `),f.context&&console.log(`**Context:** ${f.context}
50
+ `),f.skipped?console.log(`> ${f.skipReason}
51
+ `):(console.log("```"),console.log(f.body),console.log("```\n"))}else if(s==="xml"){console.log('<?xml version="1.0" encoding="UTF-8"?>'),console.log("<documents>");for(const f of u){const g=d(f),b=g?` docid="#${g}"`:"";console.log(` <document${b}>`),console.log(` <file>${H(c(f))}</file>`),console.log(` <title>${H(f.title)}</title>`),f.context&&console.log(` <context>${H(f.context)}</context>`),f.skipped?(console.log(" <skipped>true</skipped>"),console.log(` <reason>${H(f.skipReason||"")}</reason>`)):console.log(` <body>${H(f.body)}</body>`),console.log(" </document>")}console.log("</documents>")}else for(const f of u){const g=d(f),b=g?` #${g}`:"";if(console.log(`
52
+ ${"=".repeat(60)}`),console.log(`File: ${c(f)}${b}`),console.log(`${"=".repeat(60)}
53
+ `),f.skipped){console.log(`[SKIPPED: ${f.skipReason}]`);continue}f.context&&console.log(`Folder Context: ${f.context}
54
+ ---
55
+ `),console.log(f.body)}it(h,u.length)}a(gs,"multiGet");function ps(e){const t=P();if(!e){const u=ye();if(u.length===0){console.log("No collections found. Run 'qmd collection add .' to index files."),k();return}const c=u.map(d=>{const h=t.prepare(`
56
+ SELECT COUNT(*) as file_count
57
+ FROM documents d
58
+ WHERE d.collection = ? AND d.active = 1
59
+ `).get(d.name);return{name:d.name,file_count:h?.file_count||0}});console.log(`${n.bold}Collections:${n.reset}
60
+ `);for(const d of c)console.log(` ${n.dim}qmd://${n.reset}${n.cyan}${d.name}/${n.reset} ${n.dim}(${d.file_count} files)${n.reset}`);k();return}let o,s=null;const r=e.startsWith("qmd://")?e.slice(6):null;if(r!==null&&r.startsWith("/")){const u=r.replace(/\/$/,""),d=ye().filter(h=>u===h.name||u.startsWith(h.name+"/")).sort((h,f)=>f.name.length-h.name.length)[0];if(d)o=d.name,s=u.slice(d.name.length).replace(/^\//,"")||null;else{const h=le(e);h||(console.error(`Invalid virtual path: ${e}`),k(),process.exit(1)),o=h.collectionName,s=h.path}}else if(r!==null){const u=le(e);u||(console.error(`Invalid virtual path: ${e}`),k(),process.exit(1)),o=u.collectionName,s=u.path}else if(e.startsWith("/")){const u=e.replace(/\/$/,""),d=ye().filter(h=>u===h.name||u.startsWith(h.name+"/")).sort((h,f)=>f.name.length-h.name.length)[0];d?(o=d.name,s=u.slice(d.name.length).replace(/^\//,"")||null):o=u}else{const u=e.split("/");o=u[0]||"",u.length>1&&(s=u.slice(1).join("/"))}const l=N(o);l||(console.error(`Collection not found: ${o}`),console.error("Run 'qmd ls' to see available collections."),k(),process.exit(1));let i,m;s?(i=`
61
+ SELECT d.path, d.title, d.modified_at, LENGTH(ct.doc) as size
62
+ FROM documents d
63
+ JOIN content ct ON d.hash = ct.hash
64
+ WHERE d.collection = ? AND d.path LIKE ? ESCAPE '#' AND d.active = 1
65
+ ORDER BY d.path
66
+ `,m=[l.name,`${gn(s)}%`]):(i=`
67
+ SELECT d.path, d.title, d.modified_at, LENGTH(ct.doc) as size
68
+ FROM documents d
69
+ JOIN content ct ON d.hash = ct.hash
70
+ WHERE d.collection = ? AND d.active = 1
71
+ ORDER BY d.path
72
+ `,m=[l.name]);const $=t.prepare(i).all(...m);if($.length===0){console.log(s?`No files found under qmd://${o}/${s}`:`No files found in collection: ${o}`),k();return}const p=Math.max(...$.map(u=>Q(u.size).length));for(const u of $){const c=Q(u.size).padStart(p),d=new Date(u.modified_at),h=hs(d);console.log(`${c} ${h} ${n.dim}qmd://${o}/${n.reset}${n.cyan}${u.path}${n.reset}`)}k()}a(ps,"listFiles");function hs(e){const t=new Date,o=new Date(t.getTime()-4320*60*60*1e3),r=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][e.getMonth()],l=e.getDate().toString().padStart(2," ");if(e<o){const i=e.getFullYear();return`${r} ${l} ${i}`}else{const i=e.getHours().toString().padStart(2,"0"),m=e.getMinutes().toString().padStart(2,"0");return`${r} ${l} ${i}:${m}`}}a(hs,"formatLsTime");function $s(){const e=P(),t=ze(e);if(t.length===0){console.log("No collections found. Run 'qmd collection add .' to create one."),k();return}console.log(`${n.bold}Collections (${t.length}):${n.reset}
73
+ `);for(const o of t){const s=o.last_modified?new Date(o.last_modified):new Date,r=Ue(s),l=N(o.name),m=l?.includeByDefault===!1?` ${n.yellow}[excluded]${n.reset}`:"";console.log(`${n.cyan}${o.name}${n.reset} ${n.dim}(qmd://${o.name}/)${n.reset}${m}`),console.log(` ${n.dim}Pattern:${n.reset} ${o.glob_pattern}`),l?.ignore?.length&&console.log(` ${n.dim}Ignore:${n.reset} ${l.ignore.join(", ")}`),console.log(` ${n.dim}Files:${n.reset} ${o.active_count}`),console.log(` ${n.dim}Updated:${n.reset} ${r}`),console.log()}k()}a($s,"collectionList");function bs(e){const t=typeof e.mask=="string"&&e.mask.length>0?e.mask:void 0,o=typeof e.glob=="string"&&e.glob.length>0?e.glob:void 0;return t??o??Pt}a(bs,"collectionGlobFromCli");async function ys(e,t,o){let s=o;if(!s){const p=e.split("/").filter(Boolean);s=p[p.length-1]||"root"}N(s)&&(console.error(`${n.yellow}Collection '${s}' already exists.${n.reset}`),console.error("Use a different name with --name <name>"),process.exit(1));const i=ye().find(p=>Re(p.path)===e&&p.pattern===t);i&&(console.error(`${n.yellow}A collection already exists for this path and pattern:${n.reset}`),console.error(` Name: ${i.name} (qmd://${i.name}/)`),console.error(` Pattern: ${t}`),console.error(`
74
+ Use 'qmd update' to re-index it, or remove it first with 'qmd collection remove ${i.name}'`),process.exit(1));const{addCollection:m}=await import("../collections.js");m(s,e,t),zt(),ke(),console.log(`Creating collection '${s}'...`);const $=N(s);await ks(e,t,s,!1,$?.ignore),console.log(`${n.green}\u2713${n.reset} Collection '${s}' created successfully`)}a(ys,"collectionAdd");function xs(e){N(e)||(console.error(`${n.yellow}Collection not found: ${e}${n.reset}`),console.error("Run 'qmd collection list' to see available collections."),process.exit(1));const o=P(),s=Vo(o,e);Nn(e),k(),console.log(`${n.green}\u2713${n.reset} Removed collection '${e}'`),console.log(` Deleted ${s.deletedDocs} documents`),s.cleanedHashes>0&&console.log(` Cleaned up ${s.cleanedHashes} orphaned content hashes`)}a(xs,"collectionRemove");function vs(e,t){N(e)||(console.error(`${n.yellow}Collection not found: ${e}${n.reset}`),console.error("Run 'qmd collection list' to see available collections."),process.exit(1)),N(t)&&(console.error(`${n.yellow}Collection name already exists: ${t}${n.reset}`),console.error("Choose a different name or remove the existing collection first."),process.exit(1));const r=P();Yo(r,e,t),On(e,t),k(),console.log(`${n.green}\u2713${n.reset} Renamed collection '${e}' to '${t}'`),console.log(` Virtual paths updated: ${n.cyan}qmd://${e}/${n.reset} \u2192 ${n.cyan}qmd://${t}/${n.reset}`)}a(vs,"collectionRename");async function ks(e,t=Pt,o,s=!1,r){const l=P(),i=e||W(),m=new Date().toISOString(),$=["node_modules",".git",".cache","vendor","dist","build"];if(Ct(l),!o)throw new Error("Collection name is required. Collections must be defined in ~/.config/qmd/index.yml");console.log(`Collection: ${i} (${t})`),L.indeterminate();const p=[...$.map(_=>`**/${_}/**`),...r||[]],c=(await Co(vn(t),{cwd:i,onlyFiles:!0,followSymbolicLinks:!1,dot:!1,ignore:p})).filter(_=>!_.split("/").some(z=>z.startsWith("."))),d=c.length;d===0&&(L.clear(),console.log("No files found matching pattern."));let f=0,g=0,b=0,x=0,y=0;const w=[],S=new Set,v=new Set(c.map(_=>_.replace(/\\/g,"/"))),E=Date.now();for(const _ of c){const ne=Re(q(i,_)),z=_.replace(/\\/g,"/");if(!Bo(i,ne)){x++,w.push({file:_,code:"OUTSIDE_COLLECTION"}),L.set(x/d*100);continue}S.add(z);let D;try{D=F(ne,"utf-8")}catch(G){x++,w.push({file:_,code:ws(G)}),L.set(x/d*100);continue}if(!D.trim()){x++;continue}const j=await Xo(D),J=St(D,_),ue=rn(l,o,z,v);let Ve,yt=!0;if(ue)if(Ve=ue.id,ue.hash===j)yt=!1,ue.title!==J?(ln(l,ue.id,J,m),g++):b++;else{qt(l,j,D,m);const G=fe(ne);cn(l,ue.id,J,j,G?new Date(G.mtime).toISOString():m),g++}else{f++,qt(l,j,D,m);const G=fe(ne);Ve=sn(l,o,z,J,j,G?new Date(G.birthtime).toISOString():m,G?new Date(G.mtime).toISOString():m)}Sn(l,Ve,D,z,yt?void 0:{onlyIfStale:!0})?.error&&y++,x++,L.set(x/d*100);const xo=(Date.now()-E)/1e3,vo=x/xo,ko=(d-x)/vo,wo=x>2?` ETA: ${Fe(ko)}`:"";ae&&process.stderr.write(`\rIndexing: ${x}/${d}${wo} `)}const T=dn(l,o);let M=0;for(const _ of T)S.has(_)||(an(l,o,_),M++);const O=un(l),Me=$e(l);L.clear(),console.log(`
75
+ Indexed: ${f} new, ${g} updated, ${b} unchanged, ${M} removed`),eo(w),Zt(y),O>0&&console.log(`Cleaned up ${O} orphaned content hash(es)`),Me>0&&!s&&console.log(`
76
+ Run 'qmd embed' to update embeddings (${Me} unique hashes need vectors)`),k()}a(ks,"indexFiles");function ws(e){if(e&&typeof e=="object"&&"code"in e){const t=e.code;if(typeof t=="string"&&t.length>0)return t}return"ERROR"}a(ws,"fsErrorCode");function Zt(e){e!==0&&console.warn(`\u26A0 ${e} file(s) have invalid qmd.metadata frontmatter and are excluded from filtered search`)}a(Zt,"reportMetadataErrors");function eo(e){if(e.length===0)return;for(const s of e)s.code==="OUTSIDE_COLLECTION"?console.warn(`\u26A0 Skipped file outside collection: ${s.file}`):console.warn(`\u26A0 Skipped unreadable file: ${s.file} (${s.code})`);const t=e.filter(s=>s.code==="OUTSIDE_COLLECTION").length,o=e.length-t;t&&console.warn(`Skipped ${t} file(s) outside the collection root`),o&&console.warn(`Skipped ${o} unreadable file(s)`)}a(eo,"reportSkippedReads");function to(e,t=30){const o=Math.round(e/100*t),s=t-o;return"\u2588".repeat(o)+"\u2591".repeat(s)}a(to,"renderProgressBar");function oo(e,t){if(t===void 0)return;const o=Number(t);if(!Number.isInteger(o)||o<1)throw new Error(`${e} must be a positive integer`);return o}a(oo,"parseEmbedBatchOption");function Es(e){if(e===void 0)return;const t=Number(e);if(!Number.isInteger(t)||t<1)throw new Error(`--candidate-limit must be a positive integer (got "${String(e)}")`);return t}a(Es,"parseCandidateLimit");function Ss(e){if(e===void 0)return;const t=Number(e);if(!Number.isFinite(t)||t<=0)throw new Error("--max-batch-mb must be a positive number");return t}a(Ss,"parseEmbedBatchMbOption");function no(e){if(e===void 0)return;const t=String(e);if(t==="auto"||t==="regex")return t;throw new Error(`--chunk-strategy must be "auto" or "regex" (got "${t}")`)}a(no,"parseChunkStrategy");function Cs(e){if(e===void 0)return;const t=Number(e);if(!Number.isFinite(t)||t<0)throw new Error("--timeout must be a non-negative number of minutes (0 = no limit)");return t*60*1e3}a(Cs,"parseEmbedTimeoutOption");function Ds(e,t){if(e===void 0||e==="")return t;const o=parseInt(String(e),10);if(!Number.isInteger(o)||o<1)throw new Error(`-n must be a positive integer (got "${String(e)}")`);return o}a(Ds,"parseLimitOption");function ct(e,t){if(t===void 0||t==="")return;const o=parseInt(String(t),10);if(!Number.isInteger(o)||o<1)throw new Error(`${e} must be a positive integer (got "${String(t)}")`);return o}a(ct,"parseGetLineOption");function qs(e){const t=parseFloat(String(e));if(!Number.isFinite(t))throw new Error(`--min-score must be a number (got "${String(e)}")`);return t}a(qs,"parseMinScoreOption");function de(){try{const e=ie(),t=be(e.models),o=e.models??{};return(o.embed!==t.embed||o.generate!==t.generate||o.rerank!==t.rerank)&&Bt({...e,models:{...o,embed:t.embed,generate:t.generate,rerank:t.rerank}}),t}catch{return be()}}a(de,"ensureModelsConfiguredForCli");function at(){return de().embed}a(at,"resolveEmbedModelForCli");function Vr(){return de().generate}a(Vr,"resolveGenerateModelForCli");function Yr(){return de().rerank}a(Yr,"resolveRerankModelForCli");function so(){return de()}a(so,"resolveModelsForCli");function dt(){const e=de();return Kt()?e:be()}a(dt,"resolveModelsForRuntime");async function Ms(e=at(),t=!1,o,s){const r=Y(),l=r.db,i=s?.runEmbeddings??wn,m=_o(Mo(te()));m||(console.log(Po),k(),process.exit(1));try{if(t&&console.log(`${n.yellow}Force re-indexing: clearing all vectors...${n.reset}`),$e(l,o?.collection,e)===0&&!t){console.log(`${n.green}\u2713 All content hashes already have embeddings.${n.reset}`),k();return}if(console.log(`${n.dim}Model: ${$t(e)}${n.reset}
77
+ `),o?.maxDocsPerBatch!==void 0||o?.maxBatchBytes!==void 0){const d=o.maxDocsPerBatch??xn,h=o.maxBatchBytes??yn;console.log(`${n.dim}Batch: ${d} docs / ${Q(h)}${n.reset}
78
+ `)}Ae.hide(),L.indeterminate();const p=Date.now(),u=await i(r,{force:t,model:e,collection:o?.collection,maxDocsPerBatch:o?.maxDocsPerBatch,maxBatchBytes:o?.maxBatchBytes,chunkStrategy:o?.chunkStrategy,maxDurationMs:o?.maxDurationMs,onProgress:a(d=>{if(d.totalBytes===0)return;const h=Math.min(100,d.bytesProcessed/d.totalBytes*100);L.set(h);const f=(Date.now()-p)/1e3,g=f>0?d.bytesProcessed/f:0,b=Math.max(0,d.totalBytes-d.bytesProcessed),x=g>0?b/g:Number.POSITIVE_INFINITY,y=to(h),w=h.toFixed(0).padStart(3),S=g>0?`${Q(g)}/s`:".../s",v=f>2&&Number.isFinite(x)?Fe(x):"...",E=`${Q(d.bytesProcessed)}/${Q(d.totalBytes)} input`,T=`${I(d.chunksEmbedded)} chunks`,M=d.errors>0?` ${n.yellow}${I(d.errors)} err${n.reset}`:"";ae&&process.stderr.write(`\r${n.cyan}${y}${n.reset} ${n.bold}${w}% input${n.reset} ${n.dim}${T}${M} \xB7 ${E} \xB7 ${S} \xB7 ETA ${v}${n.reset} `)},"onProgress")}).finally(()=>{L.clear(),Ae.show()}),c=u.durationMs/1e3;if(u.chunksEmbedded===0&&u.docsProcessed===0)console.log(`${n.green}\u2713 No non-empty documents to embed.${n.reset}`);else if(console.log(`\r${n.green}${to(100)}${n.reset} ${n.bold}100%${n.reset} `),console.log(`
79
+ ${n.green}\u2713 Done!${n.reset} Embedded ${n.bold}${u.chunksEmbedded}${n.reset} chunks from ${n.bold}${u.docsProcessed}${n.reset} documents in ${n.bold}${Fe(c)}${n.reset}`),u.errors>0){console.log(`${n.yellow}\u26A0 ${I(u.errors)} chunks still failed after retries${n.reset}`);for(const d of(u.failures??[]).slice(0,8))console.log(` ${n.dim}${d.path}#${d.seq} (${d.attempts} attempts): ${d.reason}${n.reset}`);(u.failures?.length??0)>8&&console.log(` ${n.dim}...and ${I((u.failures?.length??0)-8)} more${n.reset}`)}k()}finally{m.release()}}a(Ms,"vectorIndex");function _s(e){return e.replace(/[^\w']/g,"").trim()}a(_s,"sanitizeFTS5Term");function Kr(e){const t=e.replace(/[^\w\s']/g,"").trim(),o=e.split(/\s+/).map(_s).filter(m=>m.length>=2);if(o.length===0)return"";if(o.length===1)return`"${o[0].replace(/"/g,'""')}"`;const s=`"${t.replace(/"/g,'""')}"`,r=o.map(m=>`"${m.replace(/"/g,'""')}"`),l=`NEAR(${r.join(" ")}, 10)`,i=r.join(" OR ");return`(${s}) OR (${l}) OR (${i})`}a(Kr,"buildFTS5Query");function zr(e){const t=Math.abs(e);return 1/(1+Math.exp(-(t-5)/3))}a(zr,"normalizeBM25");function Ps(e){try{return Lo({path:e.path,since:e.since,until:e.until})}catch(t){console.error(`qmd: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}}a(Ps,"parseDocumentFilter");function Rs(e){if(e.length===0)return[];const t=e.slice().sort((s,r)=>r.rrfContribution-s.rrfContribution),o=[` Sub-query ranks (${t.length} of the expansion's lists placed this document):`];for(const s of t){const r=s.query.replace(/\s+/g," ").trim(),l=r.length>56?`${r.slice(0,53)}...`:r,i=`${s.source}/${s.queryType}`.padEnd(12),m=`#${s.rank}`.padStart(4);o.push(` ${i} ${m} rrf=${B(s.rrfContribution)} backend=${B(s.backendScore)}${l?` ${l}`:""}`)}return o}a(Rs,"explainGroupLines");function Ls(e){for(const t of Rs(e))console.log(`${n.dim}${t}${n.reset}`)}a(Ls,"printExplainGroups");function Ts(e,t){if(!U)return e;const o=t.toLowerCase().split(/\s+/).filter(r=>r.length>=3);let s=e;for(const r of o){const l=new RegExp(`(${r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")})`,"gi");s=s.replace(l,`${n.yellow}${n.bold}$1${n.reset}`)}return s}a(Ts,"highlightTerms");function Is(e){const t=(e*100).toFixed(2).padStart(6);return U?e>=.7?`${n.green}${t}%${n.reset}`:e>=.4?`${n.yellow}${t}%${n.reset}`:`${n.dim}${t}%${n.reset}`:`${t}%`}a(Is,"formatScore");function B(e){return e.toFixed(4)}a(B,"formatExplainNumber");function Jr(e){const t=Z();return e.startsWith(t)?"~"+e.slice(t.length):e}a(Jr,"shortPath");function ut(e,t,o){if(!t.scope||t.format==="json"||t.format==="csv"||t.format==="xml"||t.format==="md"||t.format==="files"){ro(t.format);return}const{kept:s,total:r}=Et(e,t.scope,Ce(o));if(s===0){console.log(`No results found \u2014 ${pe(t.scope)} matched 0 of ${r} documents.`);return}console.log(`No results found in the ${s} of ${r} documents matching ${pe(t.scope)}.`)}a(ut,"reportEmptyFilteredSearch");function Ns(e,t,o){if(!t.scope)return;const{kept:s,total:r}=Et(e,t.scope,Ce(o));return s===0?`\u2014 ${pe(t.scope)} matched 0 of ${r} documents`:`in the ${s} of ${r} documents matching ${pe(t.scope)}`}a(Ns,"describeScopeCounts");function mt(e,t,o,s){if(!(!o.scope||t.some(r=>r.score>=o.minScore)))return Ns(e,o,s)}a(mt,"minScoreScopeNote");function ro(e,t="no_results",o){if(e==="json"||e==="csv"||e==="xml"||e==="md"||e==="files"){if(t==="min_score"&&process.stderr.write(o?`Note: no results above --min-score threshold ${o}.
80
+ `:`Note: no results above --min-score threshold.
81
+ `),e==="json"){console.log("[]");return}if(e==="csv"){console.log("docid,score,file,title,context,line,snippet");return}if(e==="xml"){console.log("<results></results>");return}if(e==="md"||e==="files")return}if(t==="min_score"){console.log(o?`No results found above minimum score threshold ${o}.`:"No results found above minimum score threshold.");return}console.log("No results found.")}a(ro,"printEmptySearchResults");const Os="vscode://file/{path}:{line}:{col}";function As(e){return encodeURI(e).replace(/\?/g,"%3F").replace(/#/g,"%23")}a(As,"encodePathForEditorUri");function Fs(){const e=process.env.QMD_EDITOR_URI?.trim();if(e)return e;try{const t=ie(),o=(t.editor_uri||t.editor_uri_template||t.editorUri||t["editor-uri"])?.trim();if(o)return o}catch{}return Os}a(Fs,"getEditorUriTemplate");function Us(e,t,o,s){const r=Number.isFinite(o)&&o>0?Math.floor(o):1,l=Number.isFinite(s)&&s>0?Math.floor(s):1,i=As(t);return e.replace(/\{path\}/g,i).replace(/\{line\}/g,String(r)).replace(/\{col\}/g,String(l)).replace(/\{column\}/g,String(l))}a(Us,"buildEditorUri");function Qs(e,t,o=!!process.stdout.isTTY){return o?`\x1B]8;;${t}\x07${e}\x1B]8;;\x07`:e}a(Qs,"termLink");function Bs(e){return e??process.env.QMD_HOST??"localhost"}a(Bs,"resolveDaemonHost");function ft(e,t,o,s){const r=e.filter(c=>c.score>=o.minScore).slice(0,o.limit);if(r.length===0){ro(o.format,"min_score",s);return}const l=a(c=>{const[d,...h]=c.split("/");if(!d||h.length===0)return`qmd://${c}`;const f=Gt();return Dt(d,h.join("/"),f==="index"?void 0:f)},"toQmdPath"),i=o.fullPath?P():null,m=new Map;for(const c of r){const d=l(c.displayPath);let h={ident:d,resolved:!1};if(o.fullPath&&i){const f=Le(i,d);if(f&&R(f)){const g=lt(f);g&&(h={ident:g,resolved:!0})}}m.set(c,h)}const $=o.fullPath?r.filter(c=>!m.get(c)?.resolved).length:0,p=a(c=>m.get(c)?.ident??l(c.displayPath),"displayPathFor"),u=a(c=>!o.fullPath||!m.get(c)?.resolved,"showDocid");if(o.format==="json"){const c=r.map(d=>{const h=d.docid||(d.hash?d.hash.slice(0,6):void 0),f=he(d.body,t,300,d.chunkPos,d.chunkLen,o.intent);let g=o.full?d.body:void 0,b=o.full?void 0:f.snippet;return o.lineNumbers&&(g&&(g=ee(g)),b&&(b=ee(b))),{...h&&u(d)&&{docid:`#${h}`},score:Math.round(d.score*1e4)/1e4,file:p(d),line:f.line,title:d.title,...d.context&&{context:d.context},...d.metadata&&Object.keys(d.metadata).length>0&&{metadata:d.metadata},...g&&{body:g},...b&&{snippet:b},...o.explain&&d.explain&&{explain:d.explain}}});console.log(JSON.stringify(c,null,2))}else if(o.format==="files")for(const c of r){const d=c.docid||(c.hash?c.hash.slice(0,6):""),h=c.context?`,"${c.context.replace(/"/g,'""')}"`:"";o.fullPath?console.log(`${c.score.toFixed(4)},${p(c)}${h}`):console.log(`#${d},${c.score.toFixed(4)},${p(c)}${h}`)}else if(o.format==="cli"){const c=Fs(),d=P();for(let h=0;h<r.length;h++){const f=r[h];if(!f)continue;const{line:g,snippet:b}=he(f.body,t,500,f.chunkPos,f.chunkLen,o.intent),x=f.docid||(f.hash?f.hash.slice(0,6):void 0),y=l(f.displayPath),w=le(y),S=Le(d,y),v=p(f),E=b.split(`
82
+ `).slice(1).join(`
83
+ `).toLowerCase(),T=t.toLowerCase().split(/\s+/).some(D=>D.length>0&&E.includes(D)),M=T?`:${g}`:"",O=x&&u(f)?` ${n.dim}#${x}${n.reset}`:"";if(process.stdout.isTTY&&S&&w?.path){const j=Us(c,S,T?g:1,1),J=Qs(`${v}${M}`,j);console.log(`${n.cyan}${J}${n.reset}${O}`)}else console.log(`${n.cyan}${v}${n.dim}${M}${n.reset}${O}`);f.title&&console.log(`${n.bold}Title: ${f.title}${n.reset}`),f.context&&console.log(`${n.dim}Context: ${f.context}${n.reset}`);const Me=Is(f.score);if(console.log(`Score: ${n.bold}${Me}${n.reset}`),o.explain&&f.explain){const D=f.explain,j=D.ftsScores.length>0?D.ftsScores.map(B).join(", "):"none",J=D.vectorScores.length>0?D.vectorScores.map(B).join(", "):"none";console.log(`${n.dim}Explain: fts=[${j}] vec=[${J}]${n.reset}`),console.log(`${n.dim} RRF: total=${B(D.rrf.totalScore)} base=${B(D.rrf.baseScore)} bonus=${B(D.rrf.topRankBonus)} rank=${D.rrf.rank}${n.reset}`),console.log(`${n.dim} Blend: ${Math.round(D.rrf.weight*100)}%*${B(D.rrf.positionScore)} + ${Math.round((1-D.rrf.weight)*100)}%*${B(D.rerankScore)} = ${B(D.blendedScore)}${n.reset}`),Ls(D.rrf.contributions)}console.log();const _=o.full?f.body:b,ne=o.lineNumbers?ee(_,o.full?1:g):_,z=Ts(ne,t);console.log(z),h<r.length-1&&console.log(`
84
+ `)}}else if(o.format==="md")for(let c=0;c<r.length;c++){const d=r[c];if(!d)continue;const h=p(d),f=d.title||h,g=d.docid||(d.hash?d.hash.slice(0,6):void 0);let b=o.full?d.body:he(d.body,t,500,d.chunkPos,d.chunkLen,o.intent).snippet;o.lineNumbers&&(b=ee(b));const x=`**file:** \`${h}\`
85
+ `,y=g&&u(d)?`**docid:** \`#${g}\`
86
+ `:"",w=d.context?`**context:** ${d.context}
87
+ `:"";console.log(`---
88
+ # ${f}
89
+ ${x}${y}${w}
90
+ ${b}
91
+ `)}else if(o.format==="xml")for(const c of r){const d=c.title?` title="${H(c.title)}"`:"",h=c.context?` context="${H(c.context)}"`:"",f=c.docid||(c.hash?c.hash.slice(0,6):"");let g=o.full?c.body:he(c.body,t,500,c.chunkPos,c.chunkLen,o.intent).snippet;o.lineNumbers&&(g=ee(g));const b=u(c)?` docid="#${f}"`:"";console.log(`<file${b} name="${H(p(c))}"${d}${h}>
92
+ ${H(g)}
93
+ </file>
94
+ `)}else{console.log("docid,score,file,title,context,line,snippet");for(const c of r){const{line:d,snippet:h}=he(c.body,t,500,c.chunkPos,c.chunkLen,o.intent);let f=o.full?c.body:h;o.lineNumbers&&(f=ee(f,o.full?1:d));const g=c.docid||(c.hash?c.hash.slice(0,6):""),b=f||"",y=`${Ne(p(c))},${Ne(c.title||"")},${Ne(c.context||"")},${d},${Ne(b)}`,w=g&&u(c)?`#${g}`:"";console.log(`${w},${c.score.toFixed(4)},${y}`)}}it($,r.length)}a(ft,"outputResults");function Se(e,t=!1){if(!e&&t)return In();if(!e)return[];const o=Array.isArray(e)?e:[e],s=[];for(const r of o)N(r)||(console.error(`Collection not found: ${r}`),k(),process.exit(1)),s.push(r);return s}a(Se,"resolveCollectionFilter");function Ce(e){if(e.length!==0)return e.length===1?e[0]:e}a(Ce,"collectionSearchFilter");function js(e){const t=e.split(`
95
+ `).map((m,$)=>({raw:m,trimmed:m.trim(),number:$+1})).filter(m=>m.trimmed.length>0);if(t.length===0)return null;const o=/^(lex|vec|hyde):\s*/i,s=/^expand:\s*/i,r=/^intent:\s*/i,l=[];let i;for(const m of t){if(s.test(m.trimmed)){if(t.length>1)throw new Error(`Line ${m.number} starts with expand:, but query documents cannot mix expand with typed lines. Submit a single expand query instead.`);if(!m.trimmed.replace(s,"").trim())throw new Error("expand: query must include text.");return null}if(r.test(m.trimmed)){if(i!==void 0)throw new Error(`Line ${m.number}: only one intent: line is allowed per query document.`);const p=m.trimmed.replace(r,"").trim();if(!p)throw new Error(`Line ${m.number}: intent: must include text.`);i=p;continue}const $=m.trimmed.match(o);if($){const p=$[1].toLowerCase(),u=m.trimmed.slice($[0].length).trim();if(!u)throw new Error(`Line ${m.number} (${p}:) must include text.`);if(/\r|\n/.test(u))throw new Error(`Line ${m.number} (${p}:) contains a newline. Keep each query on a single line.`);l.push({type:p,query:u,line:m.number});continue}if(t.length===1)return null;throw new Error(`Line ${m.number} is missing a lex:/vec:/hyde:/intent: prefix. Each line in a query document must start with one.`)}if(i&&l.length===0)throw new Error("intent: cannot appear alone. Add at least one lex:, vec:, or hyde: line.");return l.length>0?{searches:l,intent:i}:null}a(js,"parseStructuredQuery");function Be(e){if(e===void 0)return;let t;try{t=JSON.parse(String(e))}catch(o){console.error(`Invalid --filter JSON: ${o instanceof Error?o.message:String(o)}`),console.error(`Example: --filter '{"key":"status","operator":"eq","value":"published"}'`),process.exit(1)}try{return Cn(t)}catch(o){console.error(o instanceof Error?o.message:String(o)),process.exit(1)}}a(Be,"parseCliMetadataFilter");function je(e){const t=It(e);t!==0&&process.stderr.write(`${n.yellow}Warning: ${t} document(s) lack current metadata extraction and are excluded from filtered results. Run 'qmd update'.${n.reset}
96
+ `)}a(je,"warnPendingMetadata");function Gs(e,t){t.explain&&process.stderr.write(`${n.yellow}Warning: --explain is only supported for query; ignoring it for search.${n.reset}
97
+ `);const o=$n(e);o&&(console.error(o),process.exit(1));const s=P(),r=Se(t.collection,!0);t.filter&&je(s);const l=t.all?1e5:Math.max(50,t.limit*2);let i=!1;const $=Go(s,e,l,Ce(r),t.filter,t.scope,()=>{i=!0}).map(u=>({file:u.filepath,displayPath:u.displayPath,title:u.title,body:u.body||"",score:u.score,context:u.context??Wo(s,u.filepath),hash:u.hash,docid:u.docid,metadata:u.metadata}));if($.length===0){ut(s,t,r),k();return}i&&process.stderr.write(`${n.yellow}Warning: filtered search hit the 50,000-candidate scan cap before narrowing, so results may be incomplete. Narrow the query text, or run unfiltered and filter the output instead.${n.reset}
98
+ `);const p=mt(s,$,t,r);k(),ft($,e,t,p)}a(Gs,"search");function Ws(e,t,o){const s=o["case-sensitive"]?!0:o["ignore-case"]?!1:void 0;let r;try{r=To(e,{caseSensitive:s,fixedString:!!(o["fixed-strings"]||o["fixed-string"])})}catch(u){console.error(`qmd: ${u instanceof Error?u.message:String(u)}`),process.exit(1)}const l=P(),i=Se(t.collection,!0);t.filter&&je(l);const m=o["max-lines"],$=t.all?1e5:o.n&&parseInt(String(o.n),10)||20,p=Io(l,r,{collections:i,filter:t.scope,metadataFilter:t.filter,limit:$,maxLinesPerFile:m?Math.max(1,parseInt(String(m),10)||20):void 0});if(k(),t.format==="json"){console.log(JSON.stringify({files:p.files.map(u=>({docid:`#${u.docid}`,file:t.fullPath?u.displayPath:u.filepath,title:u.title,matchCount:u.matchCount,lines:u.lines})),scanned:p.scanned,truncated:p.truncated},null,2));return}if(t.format==="files"){for(const u of p.files)console.log(t.fullPath?u.displayPath:u.filepath);return}if(p.files.length===0){const u=t.scope?` matching ${pe(t.scope)}`:"";console.log(`No matches in ${p.scanned} document${p.scanned===1?"":"s"}${u}.`);return}Hs(p.files,t),p.truncated&&(console.log(""),console.log(`${n.dim}Stopped at ${p.files.length} files \u2014 raise -n or use --all for more.${n.reset}`))}a(Ws,"grepCommand");function Hs(e,t){for(const o of e){const s=o.lines.length,r=o.matchCount-s,l=r>0?`${n.dim} (+${r} more)${n.reset}`:"";console.log(`${n.cyan}${t.fullPath?o.displayPath:o.filepath}${n.reset} ${n.dim}#${o.docid}${n.reset}${l}`);for(const{line:i,text:m}of o.lines){const $=m.length>300?`${m.slice(0,300)}\u2026`:m;console.log(` ${n.dim}${String(i).padStart(5)}:${n.reset} ${$}`)}console.log("")}}a(Hs,"printGrepMatches");function lo(e,t){const o=[];o.push(`${n.dim}\u251C\u2500 ${e}${n.reset}`);for(const s of t){let r=s.query.replace(/\n/g," ");r.length>72&&(r=r.substring(0,69)+"..."),o.push(`${n.dim}\u251C\u2500 ${s.type}: ${r}${n.reset}`)}o.length>0&&(o[o.length-1]=o[o.length-1].replace("\u251C\u2500","\u2514\u2500"));for(const s of o)process.stderr.write(s+`
99
+ `)}a(lo,"logExpansionTree");async function Vs(e,t,o=Te){t.explain&&process.stderr.write(`${n.yellow}Warning: --explain is only supported for query; ignoring it for vsearch.${n.reset}
100
+ `);const s=Y(),r=Se(t.collection,!0);Yt(s.db),t.filter&&je(s.db),await et(async()=>{let l=await hn(s,e,{collection:Ce(r),filter:t.filter,limit:t.all?500:t.limit||10,minScore:t.minScore||.3,intent:t.intent,scope:t.scope,hooks:{onExpand:a((m,$)=>{lo(m,$),process.stderr.write(`${n.dim}Searching ${$.length+1} vector queries...${n.reset}
101
+ `)},"onExpand")}});if(l.length===0){ut(s.db,t,r),k();return}const i=mt(s.db,l,t,r);k(),ft(l.map(m=>({file:m.file,displayPath:m.displayPath,title:m.title,body:m.body,score:m.score,context:m.context,docid:m.docid,metadata:m.metadata})),e,{...t,limit:l.length},i)},{maxDuration:600*1e3,name:"vectorSearch"})}a(Vs,"vectorSearch");async function Ys(e,t,o=Te,s=Xe){const r=Y(),l=Se(t.collection,!0);Yt(r.db),t.filter&&je(r.db);const i=js(e),m=t.intent||i?.intent;await et(async()=>{let $;if(i){const d=i.searches,h=d.map(f=>f.type).join("+");process.stderr.write(`${n.dim}Structured search: ${d.length} queries (${h})${n.reset}
102
+ `),m&&process.stderr.write(`${n.dim}\u251C\u2500 intent: ${m}${n.reset}
103
+ `);for(const f of d){let g=f.query.replace(/\n/g," ");g.length>72&&(g=g.substring(0,69)+"..."),process.stderr.write(`${n.dim}\u251C\u2500 ${f.type}: ${g}${n.reset}
104
+ `)}process.stderr.write(`${n.dim}\u2514\u2500 Searching...${n.reset}
105
+ `),$=await bn(r,d,{collections:l.length>0?l:void 0,filter:t.filter,limit:t.all?500:t.limit||10,minScore:t.minScore||0,candidateLimit:t.candidateLimit,skipRerank:t.skipRerank,explain:!!t.explain,intent:m,chunkStrategy:t.chunkStrategy,scope:t.scope,hooks:{onEmbedStart:a(f=>{process.stderr.write(`${n.dim}Embedding ${f} ${f===1?"query":"queries"}...${n.reset}`)},"onEmbedStart"),onEmbedDone:a(f=>{process.stderr.write(`${n.dim} (${we(f)})${n.reset}
106
+ `)},"onEmbedDone"),onRerankStart:a(f=>{process.stderr.write(`${n.dim}Reranking ${f} chunks...${n.reset}`),L.indeterminate()},"onRerankStart"),onRerankDone:a(f=>{L.clear(),process.stderr.write(`${n.dim} (${we(f)})${n.reset}
107
+ `)},"onRerankDone")}})}else $=await pn(r,e,{collection:Ce(l),filter:t.filter,limit:t.all?500:t.limit||10,minScore:t.minScore||0,candidateLimit:t.candidateLimit,skipRerank:t.skipRerank,explain:!!t.explain,intent:m,chunkStrategy:t.chunkStrategy,scope:t.scope,hooks:{onStrongSignal:a(d=>{process.stderr.write(`${n.dim}Strong BM25 signal (${d.toFixed(2)}) \u2014 skipping expansion${n.reset}
108
+ `)},"onStrongSignal"),onExpandStart:a(()=>{process.stderr.write(`${n.dim}Expanding query...${n.reset}`)},"onExpandStart"),onExpand:a((d,h,f)=>{process.stderr.write(`${n.dim} (${we(f)})${n.reset}
109
+ `),lo(d,h),process.stderr.write(`${n.dim}Searching ${h.length+1} queries...${n.reset}
110
+ `)},"onExpand"),onEmbedStart:a(d=>{process.stderr.write(`${n.dim}Embedding ${d} ${d===1?"query":"queries"}...${n.reset}`)},"onEmbedStart"),onEmbedDone:a(d=>{process.stderr.write(`${n.dim} (${we(d)})${n.reset}
111
+ `)},"onEmbedDone"),onRerankStart:a(d=>{process.stderr.write(`${n.dim}Reranking ${d} chunks...${n.reset}`),L.indeterminate()},"onRerankStart"),onRerankDone:a(d=>{L.clear(),process.stderr.write(`${n.dim} (${we(d)})${n.reset}
112
+ `)},"onRerankDone")}});if($.length===0){ut(r.db,t,l),k();return}const p=mt(r.db,$,t,l);k();const u=i?.searches,c=u&&(u.find(d=>d.type==="lex")?.query||u.find(d=>d.type==="vec")?.query)||e;ft($.map(d=>({file:d.file,displayPath:d.displayPath,title:d.title,body:d.body,chunkPos:d.bestChunkPos,chunkLen:d.bestChunk.length,score:d.score,context:d.context,docid:d.docid,metadata:d.metadata,explain:d.explain})),c,{...t,limit:$.length},p)},{maxDuration:600*1e3,name:"querySearch"})}a(Ys,"querySearch");const gt={index:{type:"string"},context:{type:"string"},help:{type:"boolean",short:"h"},version:{type:"boolean",short:"v"},skill:{type:"boolean"},global:{type:"boolean"},yes:{type:"boolean"},n:{type:"string"},"min-score":{type:"string"},all:{type:"boolean"},full:{type:"boolean"},format:{type:"string"},csv:{type:"boolean"},md:{type:"boolean"},xml:{type:"boolean"},files:{type:"boolean"},json:{type:"boolean"},explain:{type:"boolean"},collection:{type:"string",short:"c",multiple:!0},filter:{type:"string"},name:{type:"string"},mask:{type:"string"},glob:{type:"string"},force:{type:"boolean",short:"f"},"max-docs-per-batch":{type:"string"},"max-batch-mb":{type:"string"},timeout:{type:"string"},pull:{type:"boolean"},refresh:{type:"boolean"},progress:{type:"boolean"},"dry-run":{type:"boolean"},l:{type:"string"},from:{type:"string"},"max-bytes":{type:"string"},"line-numbers":{type:"boolean"},"no-line-numbers":{type:"boolean"},"full-path":{type:"boolean"},"candidate-limit":{type:"string",short:"C"},"no-rerank":{type:"boolean",default:!1},"no-gpu":{type:"boolean",default:!1},intent:{type:"string"},path:{type:"string",multiple:!0},"ignore-case":{type:"boolean",short:"i"},"case-sensitive":{type:"boolean",short:"S"},"fixed-strings":{type:"boolean",short:"F"},"fixed-string":{type:"boolean"},"max-lines":{type:"string"},since:{type:"string"},until:{type:"string"},"chunk-strategy":{type:"string"},http:{type:"boolean"},daemon:{type:"boolean"},port:{type:"string"},host:{type:"string"}};function Ks(){const{values:e,positionals:t,tokens:o}=Ro({args:process.argv.slice(2),options:gt,allowPositionals:!0,strict:!1,tokens:!0}),s=new Set(Object.keys(gt)),r=new Set(Object.values(gt).flatMap(h=>h.short?[h.short]:[])),l=[];for(const h of o)h.kind==="option"&&(s.has(h.name)||r.has(h.name)||(l.includes(h.rawName)||l.push(h.rawName),delete e[h.name]));l.length>0&&console.error(`Warning: ignoring unknown option(s): ${l.join(", ")} (did you misspell a flag?)`),e["no-gpu"]&&(process.env.QMD_FORCE_CPU="1");const i=e.index;if(i)Ht(i),Qt(i),Oe();else{const h=An();h?(Oe({configPath:h}),ve=Fn(h),k()):Oe()}let m="cli";const $=typeof e.format=="string"?e.format.toLowerCase().trim():"",p=["cli","json","csv","md","xml","files"];$?p.includes($)?m=$:(console.error(`Unknown --format value: ${e.format}`),console.error(`Valid: ${p.join(", ")}`),process.exit(1)):e.csv?m="csv":e.md?m="md":e.xml?m="xml":e.files?m="files":e.json&&(m="json");const u=m==="files"||m==="json"?20:5,c=!!e.all,d={format:m,full:!!e.full,limit:c?1e5:Ds(e.n,u),minScore:e["min-score"]?qs(e["min-score"]):0,all:c,collection:e.collection,lineNumbers:!!e["line-numbers"],candidateLimit:e["candidate-limit"]?Es(e["candidate-limit"]):void 0,skipRerank:!!e["no-rerank"],explain:!!e.explain,intent:e.intent,chunkStrategy:no(e["chunk-strategy"]),fullPath:!!e["full-path"],scope:Ps(e)};return{command:t[0]||"",args:t.slice(1),query:t.slice(1).join(" "),opts:d,values:e}}a(Ks,"parseCLI");function zs(e){return e?q(Z(),".agents","skills","qmd"):q(W(),".agents","skills","qmd")}a(zs,"getSkillInstallDir");function Js(e){return e?q(Z(),".claude","skills","qmd"):q(W(),".claude","skills","qmd")}a(Js,"getClaudeSkillLinkPath");function pt(e){try{return Ke(e),!0}catch{return!1}}a(pt,"pathExists");function io(e){const t=Ke(e);t.isDirectory()&&!t.isSymbolicLink()?Oo(e,{recursive:!0,force:!0}):re(e)}a(io,"removePath");const co="skills";function Xs(){if(process.env.QMD_SKILLS_DIR)return null;let t=X(ge(import.meta.url));for(;;){if(R(q(t,co)))return t;const o=X(t);if(o===t)break;t=o}return null}a(Xs,"findPackageRoot");function ao(e=!1){if(process.env.QMD_SKILLS_DIR)return[process.env.QMD_SKILLS_DIR];const t=Xs();if(!t)return[];const o=q(t,co);return R(o)?[o]:[]}a(ao,"getSkillSearchDirs");function Zs(e){const t=e.trimStart();if(!t.startsWith("---"))return null;const o=t.slice(3).indexOf(`
113
+ ---`);if(o<0)return null;const s=t.slice(3,3+o);let r="",l="",i=!1;const m=s.split(/\r?\n/);for(let $=0;$<m.length;$++){const p=m[$];if(p.startsWith("name:"))r=p.slice(5).trim();else if(p.startsWith("description:")){const u=[p.slice(12).trim()];for(;$+1<m.length&&/^\s+\S/.test(m[$+1]);)$++,u.push(m[$].trim());l=u.join(" ")}else if(p.startsWith("hidden:")){const u=p.slice(7).trim().toLowerCase();i=u==="true"||u==="yes"}}return r?{name:r,description:l,hidden:i}:null}a(Zs,"parseSkillFrontmatter");function uo(e=!1){const t=[];for(const o of ao(e)){let s=[];try{s=me(o)}catch{continue}for(const r of s){const l=q(o,r),i=q(l,"SKILL.md");if(!R(i))continue;let m="";try{m=F(i,"utf-8")}catch{continue}const $=Zs(m);$&&t.push({...$,dir:l})}}return t.sort((o,s)=>o.name.localeCompare(s.name))}a(uo,"discoverSkills");function Ge(e,t=!1){return uo(t).find(o=>o.name===e)??null}a(Ge,"findSkill");function ht(e){return F(q(e.dir,"SKILL.md"),"utf-8")}a(ht,"readSkillContent");function mo(e){const t=[];for(const o of["references","templates","scripts"]){const s=q(e.dir,o);if(R(s))for(const r of me(s).sort()){const l=q(s,r);try{if(!fe(l).isFile())continue;t.push({relativePath:`${o}/${vt(l)}`,content:F(l,"utf-8")})}catch{}}}return t}a(mo,"collectSkillFiles");function fo(){const e=Ge("qmd");if(!e)throw new Error("QMD skill not found. Reinstall qmd or set QMD_SKILLS_DIR.");console.log("QMD Skill"),console.log("");const t=ht(e);process.stdout.write(t.endsWith(`
114
+ `)?t:t+`
115
+ `)}a(fo,"showSkill");function go(e,t){Pe(t,{recursive:!0});for(const o of me(e)){const s=q(e,o),r=q(t,o),l=fe(s);l.isDirectory()?go(s,r):l.isFile()&&Uo(s,r)}}a(go,"copyDirectoryContents");function er(){return`---
116
+ name: qmd
117
+ description: Bootstrap QMD search instructions from the installed qmd CLI. Use when users ask to find notes, retrieve documents, inspect a wiki, or answer from indexed local markdown.
118
+ license: MIT
119
+ compatibility: Requires qmd CLI. Run \`qmd skill show\` for version-matched instructions.
120
+ allowed-tools: Bash(qmd:*), mcp__qmd__*
121
+ ---
122
+
123
+ # QMD - Query Markdown Documents
124
+
125
+ This installed skill is intentionally a small bootstrap so it does not go stale
126
+ when the qmd package updates.
127
+
128
+ Load the full, version-matched QMD instructions from the CLI:
129
+
130
+ !\`qmd skill show\`
131
+
132
+ If your agent does not support bang-command expansion, run:
133
+
134
+ \`\`\`bash
135
+ qmd skill show
136
+ \`\`\`
137
+
138
+ Then follow those instructions. In short: search first, fetch full sources with
139
+ \`qmd get\` or \`qmd multi-get\`, and answer from retrieved text rather than snippets.
140
+ `}a(er,"installedSkillStubContent");function tr(e,t){if(pt(e)){if(!t)throw new Error(`Skill already exists: ${e} (use --force to replace it)`);io(e)}const o=Ge("qmd");if(!o)throw new Error("QMD skill not found. Reinstall qmd or set QMD_SKILLS_DIR.");go(o.dir,e),wt(q(e,"SKILL.md"),er(),"utf-8")}a(tr,"writeSkillInstall");function De(e){console.log(JSON.stringify(e))}a(De,"outputSkillsJson");function or(e,t,o=!1,s=!1){const r=e[0]??"list",l=a(()=>uo(!0).filter(i=>!i.hidden),"runtimeSkills");switch(r){case"list":{const i=l();if(t){De({success:!0,data:i.map(({name:$,description:p})=>({name:$,description:p}))});return}if(i.length===0){console.log("No skills found");return}const m=Math.max(...i.map($=>$.name.length));for(const $ of i)console.log(` ${$.name.padEnd(m)} ${$.description}`);return}case"get":{const i=o||e.includes("--full"),m=s||e.includes("--all"),$=e.slice(1).filter(u=>u!=="--full"&&u!=="--all"),p=m?l():$.map(u=>{const c=Ge(u,!0);if(!c)throw new Error(`Skill not found: ${u}`);return c});if(p.length===0)throw new Error("No skill name provided. Usage: qmd skills get <name>");if(t){De({success:!0,data:p.map(u=>({name:u.name,content:ht(u),...i?{files:mo(u).map(c=>({path:c.relativePath,content:c.content}))}:{}}))});return}p.forEach((u,c)=>{c>0&&console.log(`
141
+ ---
142
+ `);const d=ht(u);if(process.stdout.write(d.endsWith(`
143
+ `)?d:d+`
144
+ `),i)for(const h of mo(u))console.log(`
145
+ --- ${h.relativePath} ---
146
+ `),process.stdout.write(h.content.endsWith(`
147
+ `)?h.content:h.content+`
148
+ `)});return}case"path":{const i=e[1];if(!i){const $=ao(!0);t?De({success:!0,data:{paths:$}}):$.forEach(p=>console.log(p));return}const m=Ge(i,!0);if(!m)throw new Error(`Skill not found: ${i}`);t?De({success:!0,data:{name:m.name,path:m.dir}}):console.log(m.dir);return}case"help":{po();return}default:throw new Error(`Unknown skills subcommand: ${r}`)}}a(or,"runSkillsCommand");function po(){console.log("Usage: qmd skills <list|get|path> [options]"),console.log(""),console.log("Commands:"),console.log(" list List bundled runtime skills"),console.log(" get <name> Print a bundled runtime skill"),console.log(" get <name> --full Include references/templates/scripts"),console.log(" get --all Print all bundled runtime skills"),console.log(" path [name] Print runtime skill directory path(s)"),console.log(""),console.log("Options:"),console.log(" --json Print structured JSON")}a(po,"showSkillsHelp");function nr(e,t,o){const s=X(e);if(pt(s)){const l=se(X(t)),i=se(s);if(l===i)return!1}const r=kt(s,t)||".";if(Pe(s,{recursive:!0}),pt(e)){if(Ke(e).isSymbolicLink()&&Fo(e)===r)return!0;if(!o)throw new Error(`Claude skill path already exists: ${e} (use --force to replace it)`);io(e)}return Ao(r,e,"dir"),!0}a(nr,"ensureClaudeSymlink");async function sr(e,t){if(t)return!0;if(!process.stdin.isTTY||!process.stdout.isTTY)return console.log(`Tip: create a Claude symlink manually at ${e}`),!1;const o=Qo({input:process.stdin,output:process.stdout});try{const r=(await o.question(`Create a symlink in ${e}? [y/N] `)).trim().toLowerCase();return r==="y"||r==="yes"}finally{o.close()}}a(sr,"shouldCreateClaudeSymlink");async function rr(e,t,o){const s=zs(e);tr(s,t),console.log(`\u2713 Installed QMD skill to ${s}`);const r=Js(e);if(!await sr(r,o))return;const l=nr(r,s,t);console.log(l?`\u2713 Linked Claude skill at ${r}`:`\u2713 Claude already sees the skill via ${X(r)}`)}a(rr,"installSkill");function lr(){console.log("qmd \u2014 Quick Markdown Search"),console.log(""),console.log("Usage:"),console.log(" qmd <command> [options]"),console.log(""),console.log("Primary commands:"),console.log(" qmd query <query> - Hybrid search with auto expansion + reranking (recommended)"),console.log(" qmd query 'lex:..\\nvec:...' - Structured query document (you provide lex/vec/hyde lines)"),console.log(" qmd search <query> - Full-text BM25 keywords (no LLM)"),console.log(" qmd vsearch <query> - Vector similarity only"),console.log(" qmd grep <pattern> - Exact/regex match over indexed bodies (no ranking)"),console.log(" qmd get <file>[:from[:count]] - Show a document (line-numbered; #docid in header)"),console.log(" qmd multi-get <pattern> - Batch fetch via glob or comma-separated list"),console.log(" qmd skills list/get/path - List and retrieve bundled runtime skills"),console.log(" qmd skill show/install - Show or install the QMD skill"),console.log(" qmd mcp - Start the MCP server (stdio transport for AI agents)"),console.log(" qmd bench <fixture.json> - Run search quality benchmarks against a fixture file"),console.log(""),console.log("Collections & context:"),console.log(" qmd collection add/list/remove/rename/show - Manage indexed folders"),console.log(" qmd context add/list/rm - Attach human-written summaries"),console.log(" qmd ls [collection[/path]] - Inspect indexed files"),console.log(""),console.log("Maintenance:"),console.log(" qmd init - Create a project-local .qmd index"),console.log(" qmd status - View index + collection health"),console.log(" qmd update [--pull] - Re-index collections (optionally git pull first)"),console.log(" qmd trust [list|revoke] - Approve a checked-in .qmd config's hooks/paths/models"),console.log(" qmd embed [-f] [-c <name>] - Generate/refresh vector embeddings"),console.log(" --max-docs-per-batch <n> - Cap docs loaded into memory per embedding batch"),console.log(" --max-batch-mb <n> - Cap UTF-8 MB loaded into memory per embedding batch"),console.log(" --timeout <minutes> - Embed session cap in minutes (0 = no limit; default 30)"),console.log(" qmd pull [--refresh] [--progress] - Download embedding/generation/rerank models"),console.log(" qmd cleanup [--dry-run] - Drop inactive docs/orphans, compact FTS, vacuum"),console.log(""),console.log("Query syntax (qmd query):"),console.log(" QMD queries are either a single expand query (no prefix) or a multi-line"),console.log(" document where every line is typed with lex:, vec:, or hyde:. This grammar"),console.log(" matches the docs in docs/SYNTAX.md and is enforced in the CLI."),console.log("");const e=["query = expand_query | query_document ;","expand_query = text | explicit_expand ;",'explicit_expand= "expand:" text ;',"query_document = [ intent_line ] { typed_line } ;",'intent_line = "intent:" text newline ;','typed_line = type ":" text newline ;','type = "lex" | "vec" | "hyde" ;',"text = quoted_phrase | plain_text ;",`quoted_phrase = '"' { character } '"' ;`,"plain_text = { character } ;",'newline = "\\n" ;'];console.log(" Grammar:");for(const t of e)console.log(` ${t}`);console.log(""),console.log(" Examples:"),console.log(' qmd query "how does auth work" # single-line \u2192 implicit expand'),console.log(" qmd query $'lex: CAP theorem\\nvec: consistency' # typed query document"),console.log(` qmd query $'lex: "exact matches" sports -baseball' # phrase + negation lex search`),console.log(" qmd query $'hyde: Hypothetical answer text' # hyde-only document"),console.log(""),console.log(" Constraints:"),console.log(" - Standalone expand queries cannot mix with typed lines."),console.log(" - Query documents allow only lex:, vec:, hyde:, or intent: prefixes."),console.log(" - Each typed line must be single-line text with balanced quotes."),console.log(""),console.log("AI agents & integrations:"),console.log(" - Run `qmd mcp` to expose the MCP server (stdio) to agents/IDEs."),console.log(" - Run `qmd skills get qmd --full` for version-matched agent instructions."),console.log(" - `qmd skill install` installs the QMD skill into ./.agents/skills/qmd."),console.log(" - Use `qmd skill install --global` for ~/.agents/skills/qmd."),console.log(" - `qmd --skill` is kept as an alias for `qmd skill show`."),console.log(" - Advanced: `qmd mcp --http ...` and `qmd mcp --http --daemon` are optional for custom transports."),console.log(""),console.log("Global options:"),console.log(" --index <name> - Use a named index (default: index)"),console.log(" QMD_EDITOR_URI - Editor link template for clickable TTY search output"),console.log(""),console.log("Search options:"),console.log(" -n <num> - Max results (default 5, or 20 for --format files|json)"),console.log(" --all - Return all matches (pair with --min-score)"),console.log(" --min-score <num> - Minimum similarity score"),console.log(" --full - Output full document instead of snippet"),console.log(" -C, --candidate-limit <n> - Max candidates to rerank (default 40, lower = faster)"),console.log(" --no-rerank - Skip LLM reranking (use RRF scores only, much faster on CPU)"),console.log(" --no-gpu - Force CPU mode for llama.cpp operations (same as QMD_FORCE_CPU=1)"),console.log(" --line-numbers - Include line numbers (search; get/multi-get are on by default)"),console.log(" --no-line-numbers - Disable line numbers for get/multi-get"),console.log(" --full-path - Show on-disk paths instead of qmd:// + docid (get/multi-get/search/query)"),console.log(" Paths are ./-prefixed when under $PWD, absolute otherwise"),console.log(" Results whose file is gone keep qmd:// + docid and warn on stderr"),console.log(" --explain - Include retrieval score traces (query, CLI/--format json)"),console.log(" --format <kind> - Output format: cli (default) | json | csv | md | xml | files"),console.log(" -c, --collection <name> - Filter by one or more collections"),console.log(" --path <glob> - Only documents matching the glob; repeatable, '!' excludes"),console.log(" Matched against collection/path, as printed in results"),console.log(" --since <when> - Only documents modified at or after (7d, 3h, 2w, 2026-09-01)"),console.log(" --until <when> - Only documents modified at or before (same formats)"),console.log(" --filter <json> - Metadata filter (recursive JSON AST; search/vsearch/query/grep)"),console.log(` e.g. '{"key":"status","operator":"eq","value":"published"}'`),console.log(""),console.log("Grep options:"),console.log(" -i, --ignore-case - Match either case (default: smart case)"),console.log(" -S, --case-sensitive - Match case exactly"),console.log(" -F, --fixed-strings - Treat the pattern as a literal string, not a regex"),console.log(" --max-lines <num> - Max reported lines per file (default 20)"),console.log(" -n <num> - Max files (default 20); --all for no cap"),console.log(""),console.log("Embed/query options:"),console.log(" --chunk-strategy <auto|regex> - Chunking mode (default: regex; auto uses AST for code files)"),console.log(" --timeout <minutes> - Embed session cap in minutes (0 = no limit; default 30)"),console.log(""),console.log("Multi-get options:"),console.log(" -l <num> - Maximum lines per file"),console.log(" --max-bytes <num> - Skip files larger than N bytes (default 65536)"),console.log(" --format <kind> - Same formats as search"),console.log(""),console.log(`Index: ${te()}`)}a(lr,"showHelp");function C(e,t,o){const s=t?`${n.green}\u2713${n.reset}`:`${n.yellow}\u26A0${n.reset}`;console.log(`${s} ${e}: ${o}`)}a(C,"doctorCheck");function I(e){return e.toLocaleString("en-US")}a(I,"formatCount");function $t(e){return e.startsWith("hf:")?e.split("/").pop()||e:e.length>56?`${e.slice(0,53)}...`:e}a($t,"shortModelName");function ir(e){const t=Array.from(new Set(e));return t.some(s=>s.includes("qmd embed --force"))?t.filter(s=>!s.includes("qmd embed")||s.startsWith("Run `qmd embed --force`")):t}a(ir,"normalizedDoctorNextSteps");function We(e){const t=e.lastIndexOf("_");return t<0?e.length>18?`${e.slice(0,18)}...`:e:`${e.slice(0,12)}_${e.slice(t+1)}`}a(We,"shortHashSeq");function cr(e){return new Float32Array(e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength))}a(cr,"decodeStoredEmbedding");function ar(e,t){if(e.length!==t.length||e.length===0)return Number.POSITIVE_INFINITY;let o=0,s=0,r=0;for(let l=0;l<e.length;l++){const i=e[l]??0,m=t[l]??0;o+=i*m,s+=i*i,r+=m*m}return s===0||r===0?Number.POSITIVE_INFINITY:1-o/(Math.sqrt(s)*Math.sqrt(r))}a(ar,"cosineDistance");function ho(e){return oe(e)}a(ho,"formatModelDiagnosticPath");function dr(e){const t=[];if(e.startsWith("hf:")){const s=e.split("/").pop();if(!s||!R(Ie))return{path:null,invalid:t};const r=me(Ie,{withFileTypes:!0});for(const l of r){if(!l.isFile()||!l.name.endsWith(".gguf")||!l.name.includes(s))continue;const i=A(Ie,l.name),m=Nt(i);if(m.valid)return{path:i,invalid:t};t.push(`${ho(i)}: ${m.details}`)}return{path:null,invalid:t}}const o=Nt(e);return o.valid?{path:e,invalid:t}:(o.exists&&t.push(`${ho(e)}: ${o.details}`),{path:null,invalid:t})}a(dr,"findCachedModelInspection");function $o(e){const t=oe(e);return t.length>96?`${t.slice(0,93)}...`:t}a($o,"envValueForDisplay");function ur(e,t={}){const o=[],s=a((l,i)=>{const m=process.env[l]?.trim();m&&o.push({name:l,value:$o(m),consequence:i})},"add"),r=a((l,i,m)=>{const $=process.env[l]?.trim();if(!$)return;const p=t[i],u=p&&p!==$?`set but ignored because index models.${i} is configured as ${p}`:`sets the active ${i} model to ${m}; changes embedding/search semantics and may require \`qmd pull\` plus \`qmd embed\``;o.push({name:l,value:$o($),consequence:u})},"addModel");return s("INDEX_PATH","overrides the SQLite index path; QMD reads/writes a different database"),s("QMD_SQLITE_BUSY_TIMEOUT","overrides the SQLite busy-timeout in ms (default 120000, 0 = fail-fast); too low can surface SQLITE_BUSY under concurrent writers"),s("QMD_CONFIG_DIR","overrides the QMD config directory and takes precedence over XDG_CONFIG_HOME"),s("XDG_CONFIG_HOME","moves QMD config to $XDG_CONFIG_HOME/qmd when QMD_CONFIG_DIR is not set"),s("XDG_CACHE_HOME","moves the default index cache, model cache, MCP daemon PID files, and query logs"),s("QMD_QUERY_LOG","1/true/yes makes the HTTP daemon append each search to queries-YYYY-MM.jsonl in the cache dir"),s("QMD_HOST","overrides the MCP HTTP server bind host (default localhost); 0.0.0.0 accepts off-host connections"),r("QMD_EMBED_MODEL","embed",e.embed),r("QMD_GENERATE_MODEL","generate",e.generate),r("QMD_RERANK_MODEL","rerank",e.rerank),s("QMD_FORCE_CPU","forces llama.cpp to bypass GPU backends; embeddings/query will be slower but GPU crashes are avoided"),s("QMD_LLAMA_GPU","selects llama.cpp GPU backend (metal/cuda/vulkan) or disables GPU when set to false/off/0"),s("QMD_DOCTOR_DEVICE_PROBE","controls qmd doctor native device probing; 0/off skips GPU probing"),s("QMD_EMBED_PARALLELISM","overrides embedding parallel context count; too high can exhaust RAM/VRAM"),s("QMD_LLM_IDLE_TIMEOUT_MS","ms of idle before models unload (0 = never); keeping them loaded holds their memory"),s("QMD_LLM_LOAD_TIMEOUT_MS","caps the model-load wait per stage (default 120000, 0 = wait forever); past it the stage is skipped"),s("QMD_RERANK_CASCADE","0/false/off/no disables head-first cascade rerank and scores all candidates at once"),s("QMD_EXPAND_CONTEXT_SIZE","overrides query expansion context size; larger values use more memory"),s("QMD_RERANK_CONTEXT_SIZE","overrides reranker context size; larger values use more memory"),s("QMD_RERANK_MAX_DOC_TOKENS","caps tokens per document sent to the reranker; lower is faster but scores less text"),s("QMD_EMBED_CONTEXT_SIZE","overrides embed context size; larger values use more memory"),s("QMD_EDITOR_URI","overrides clickable editor link template in terminal output"),s("QMD_SKILLS_DIR","overrides where qmd skills are discovered from"),s("QMD_METAL_KEEP_RESIDENCY","opts back into libggml-metal residency sets on darwin; restores ~0ms perf wins for long-lived processes but re-exposes the static-destructor backtrace dump at process exit (ggml-org/llama.cpp#22593)"),s("GGML_METAL_NO_RESIDENCY","set automatically by the launcher on darwin to disable Metal residency sets (avoids ggml-org/llama.cpp#22593); override via QMD_METAL_KEEP_RESIDENCY=1"),s("NO_COLOR","disables colored terminal output"),s("CI","disables real LLM operations inside QMD's LlamaCpp wrapper"),s("HF_ENDPOINT","changes Hugging Face download endpoint used when pulling models"),s("QMD_WRAPPER_CAPTURE","test/debug hook for the qmd shell wrapper; should not be set in normal use"),s("QMD_TRUST_LOCAL_CONFIG","trusts project-local .qmd config hooks/paths/models without prompting; runs unreviewed commands on update/query"),s("QMD_TRUST_UPDATE_HOOKS","runs project-local update hooks without prompting; runs unreviewed commands on update"),s("WSL_DISTRO_NAME","enables WSL path handling heuristics"),s("WSL_INTEROP","enables WSL path handling heuristics"),o}a(ur,"collectEnvironmentOverrides");function mr(e){try{const t=ie(),o=Object.keys(t.collections??{}).length;return o===0?(C("index config",!1,"no collections configured. Next: `qmd collection add .`"),e.push("Run `qmd collection add . --name <name>` from the folder you want to index, or edit .qmd/index.yml manually.")):C("index config",!0,`${I(o)} ${o===1?"collection":"collections"} configured`),{config:t,valid:!0}}catch(t){const o=t instanceof Error?oe(t.message):oe(String(t)),s=ce();return C("index config",!1,`invalid index.yml at ${s}: ${o}. Next: fix the YAML and rerun \`qmd doctor\``),e.push(`Fix invalid YAML in ${s}, then rerun \`qmd doctor\`.`),{config:null,valid:!1}}}a(mr,"checkDoctorIndexConfig");function fr(e,t={}){const o=ur(e,t);if(o.length===0){C("environment overrides",!0,"none");return}C("environment overrides",!1,`${o.length} set`);for(const s of o)console.log(` - ${s.name}=${s.value}: ${s.consequence}`)}a(fr,"checkEnvironmentOverrides");function gr(e,t={}){const o=[{role:"embedding",key:"embed",active:e.embed,configured:t.embed,defaultModel:Te,envName:"QMD_EMBED_MODEL",envValue:process.env.QMD_EMBED_MODEL},{role:"generation",key:"generate",active:e.generate,configured:t.generate,defaultModel:_t,envName:"QMD_GENERATE_MODEL",envValue:process.env.QMD_GENERATE_MODEL},{role:"reranking",key:"rerank",active:e.rerank,configured:t.rerank,defaultModel:Xe,envName:"QMD_RERANK_MODEL",envValue:process.env.QMD_RERANK_MODEL}],s=[];for(const r of o){const l=r.envValue?.trim();l&&r.active===l?s.push(`${r.role}: env ${r.envName}=${r.active} (default ${r.defaultModel}; might be ok)`):r.configured&&r.configured!==r.defaultModel?s.push(`${r.role}: index ${r.configured} (default ${r.defaultModel}; might be ok)`):l&&r.active!==l&&s.push(`${r.role}: ${r.envName} is set to ${l} but index config uses ${r.active}`)}if(s.length===0){C("model defaults",!0,"using QMD codebase defaults");return}C("model defaults",!1,`non-default model configuration: ${s.join("; ")}`)}a(gr,"checkModelDefaults");function pr(e,t){const o=[["embedding",e.embed],["generation",e.generate],["reranking",e.rerank]],s=new Map;for(const[p,u]of o)s.set(u,[...s.get(u)??[],p]);const r=[],l=[],i=[];for(const[p,u]of s){const c=`${u.join("+")}: ${p}`,d=dr(p);i.push(...d.invalid.map(h=>`${c} (${h})`)),d.path?l.push(c):r.push(c)}if(r.length===0&&i.length===0){C("model cache",!0,`${l.length} active ${l.length===1?"model is":"models are"} downloaded and valid GGUF`);return}const m=[];i.length>0&&m.push(`invalid ${i.length}: ${i.join("; ")}`),r.length>0&&m.push(`missing ${r.length}/${s.size}: ${r.join("; ")}`);const $=i.length>0?"Next: run `qmd pull --refresh` (or remove the bad cached file)":"Next: run `qmd pull`";C("model cache",!1,`${m.join("; ")}. ${$}`),i.length>0?t.push("Run `qmd pull --refresh` to replace invalid cached model files, or delete the listed file and rerun `qmd pull`."):t.push("Run `qmd pull` to download missing embedding/generation/reranking models before `qmd embed` or `qmd query`.")}a(pr,"checkModelCache");async function hr(e,t,o,s=3){if(e.prepare("SELECT COUNT(*) AS count FROM documents WHERE active = 1").get().count===0)return{ok:!0,details:"no active documents indexed",empty:!0};if(!e.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='vectors_vec'").get())return{ok:!1,details:"no vector table to test; please run qmd embed again",empty:!0};const i=e.prepare(`
149
+ SELECT cv.hash, cv.seq, c.doc AS body, MIN(d.path) AS path
150
+ FROM content_vectors cv
151
+ JOIN documents d ON d.hash = cv.hash AND d.active = 1
152
+ JOIN content c ON c.hash = cv.hash
153
+ WHERE cv.model = ? AND cv.embed_fingerprint = ?
154
+ GROUP BY cv.hash, cv.seq, c.doc
155
+ ORDER BY random()
156
+ LIMIT ?
157
+ `).all(t,o,s);if(i.length===0)return{ok:!1,details:"no current embedded chunks to test; please run qmd embed again",empty:!0};const m=1e-4,$=[];return await et(async p=>{for(const u of i){const c=`${u.hash}_${u.seq}`,h=(await tn(u.body,void 0,void 0,void 0,u.path,void 0,p.signal))[u.seq];if(!h){$.push(`${We(c)}: chunk no longer exists`);continue}const f=St(u.body,u.path),g=await p.embed(Zo(h.text,f,t),{model:t});if(!g){$.push(`${We(c)}: embedding failed`);continue}const b=e.prepare("SELECT embedding FROM vectors_vec WHERE hash_seq = ?").get(c);if(!b){$.push(`${We(c)}: stored vector missing`);continue}const x=ar(g.embedding,cr(b.embedding));x>m&&$.push(`${We(c)}: stored vector distance ${x.toFixed(6)}`)}},{maxDuration:600*1e3,name:"doctorEmbeddingVectorSample"}),$.length>0?{ok:!1,details:`${$.length}/${i.length} sampled chunks differ from stored vectors (${$[0]}). Rebuild with \`qmd embed --force\``,empty:!1}:{ok:!0,details:`${i.length} sampled ${i.length===1?"chunk":"chunks"} reproduce stored vectors`,empty:!1}}a(hr,"checkEmbeddingVectorSamples");function bt(e,t){for(const o of t)if(!(!o||!R(o)))try{for(const s of me(o))if(s===e||s.startsWith(`${e}.`))return!0}catch{}return!1}a(bt,"hasLibraryInDirs");function $r(){if(process.platform!=="linux")return null;const e=new Set;for(const l of[process.env.LD_LIBRARY_PATH,process.env.CUDA_PATH])for(const i of(l??"").split(":"))i&&e.add(i);process.env.CUDA_PATH&&(e.add(A(process.env.CUDA_PATH,"lib64")),e.add(A(process.env.CUDA_PATH,"targets","x86_64-linux","lib")));for(const l of["/usr/lib","/usr/lib64","/usr/lib/x86_64-linux-gnu","/usr/local/cuda/lib64","/usr/local/cuda/targets/x86_64-linux/lib"])e.add(l);try{for(const l of me("/usr/local")){if(!l.toLowerCase().startsWith("cuda-"))continue;const i=A("/usr/local",l);e.add(A(i,"lib64")),e.add(A(i,"targets","x86_64-linux","lib"))}}catch{}const t=[...e];if(!(bt("libcuda.so",t)||bt("libnvidia-ml.so",t)))return null;const r=[["libcudart.so","CUDA runtime"],["libcublas.so","cuBLAS"],["libcublasLt.so","cuBLASLt"]].filter(([l])=>!bt(l,t)).map(([,l])=>l);return r.length===0?null:`NVIDIA driver libraries are visible, but CUDA user-space libraries are missing from loader paths (${r.join(", ")})`}a($r,"linuxCudaRuntimeDiagnostic");async function br(e){const t=os();if(C("device mode",!0,t),["0","false","off","no","skip"].includes((process.env.QMD_DOCTOR_DEVICE_PROBE??"").trim().toLowerCase())){C("device probe",!1,"skipped by QMD_DOCTOR_DEVICE_PROBE=0. Next: unset it and rerun `qmd doctor` to verify GPU/CPU acceleration"),e.push("Unset `QMD_DOCTOR_DEVICE_PROBE` and rerun `qmd doctor` when you want to verify llama.cpp device acceleration.");return}const s="Probing native llama backend now. If qmd crashes here, rerun with `QMD_FORCE_CPU=1 qmd doctor` (or `QMD_DOCTOR_DEVICE_PROBE=0 qmd doctor` to skip this probe).";process.stdout.isTTY&&process.stdout.write(`${n.dim}${s}${n.reset}`);try{const r=await qn().getDeviceInfo({allowBuild:!1});if(process.stdout.isTTY&&process.stdout.write(`\r${" ".repeat(s.length)}\r`),r.gpu){const i=[`GPU ${r.gpu==="metal"&&process.platform==="darwin"?"metal (macOS Metal backend)":String(r.gpu)}`,`offloading ${r.gpuOffloading?"enabled":"disabled"}`];r.gpuDevices.length>0&&i.push(`devices: ${ns(r.gpuDevices)}`),r.vram&&i.push(`VRAM ${Q(r.vram.free)} free / ${Q(r.vram.total)} total`),i.push(`${r.cpuCores} CPU math cores`),C("device probe",r.gpuOffloading,r.gpuOffloading?i.join("; "):`${i.join("; ")}. Next: check QMD_LLAMA_GPU and llama.cpp backend support`),r.gpuOffloading||e.push("GPU was detected but offloading is disabled; check `QMD_LLAMA_GPU=metal|cuda|vulkan` and rerun `qmd doctor`."),r.gpu==="metal"&&process.platform==="darwin"&&(Rn()?C("darwin metal residency",!0,"GGML_METAL_NO_RESIDENCY=1 set by launcher; clean process exit (avoids ggml-org/llama.cpp#22593). Opt back in with QMD_METAL_KEEP_RESIDENCY=1 if you run long-lived qmd processes."):(C("darwin metal residency",!1,"residency sets active (QMD_METAL_KEEP_RESIDENCY=1 or launcher bypassed); llama-using commands may dump a libggml-metal backtrace at exit (ggml-org/llama.cpp#22593) even when output succeeded."),e.push("Unset `QMD_METAL_KEEP_RESIDENCY` so the launcher can disable Metal residency sets; without this, query/vsearch/embed dump a stack trace at exit even on success.")))}else{const l=$r(),i=l?` ${l}.`:"";C("device probe",!1,`running on CPU (${r.cpuCores} math cores).${i} Next: install/configure Metal, CUDA, or Vulkan for faster embeddings, or set QMD_FORCE_CPU=1 to make CPU mode explicit`),l?e.push(`${l}; install CUDA runtime/cuBLAS libraries or add their directory to LD_LIBRARY_PATH, then rerun \`qmd doctor\`.`):e.push("Vector operations are running on CPU; install/configure Metal, CUDA, or Vulkan if embedding/query performance is too slow.")}}catch(r){process.stdout.isTTY&&process.stdout.write(`\r${" ".repeat(s.length)}\r`);const l=r instanceof Error?oe(r.message):oe(String(r));C("device probe",!1,`probe failed: ${l}. Next: run with QMD_FORCE_CPU=1 to bypass GPU probing, or set QMD_LLAMA_GPU=metal|cuda|vulkan and retry`),e.push("GPU probe failed; try `QMD_FORCE_CPU=1 qmd doctor` to confirm CPU fallback, then fix GPU drivers/backend if acceleration is expected.")}}a(br,"runDoctorDeviceChecks");async function yr(){const e=Y(),t=e.db,o=bo(),s=so(),r=s.embed,l=en(r),i=[];console.log(`${n.bold}QMD Doctor${n.reset}
158
+ `),console.log(`Index: ${te()}`),console.log(`Runtime: ${So?"bun:sqlite":"better-sqlite3"}`);try{const c=t.prepare("SELECT sqlite_version() AS version").get();C("SQLite runtime",!0,c.version)}catch(c){C("SQLite runtime",!1,c instanceof Error?c.message:String(c))}const m=o.dependencies?.["better-sqlite3"]??o.devDependencies?.["better-sqlite3"]??"not declared";C("better-sqlite3 package",!0,String(m));try{const c=t.prepare("SELECT vec_version() AS version").get();C("sqlite-vec",!0,c.version)}catch(c){C("sqlite-vec",!1,c instanceof Error?c.message:String(c))}const p=mr(i).config?.models??{};fr(s,p),gr(s,p),pr(s,i),await br(i);try{const c=await En(e,r);(c.checked||c.adopted>0)&&C("legacy fingerprint adoption",c.adopted>0,c.adopted>0?`adopted ${c.adopted} legacy chunks; ${c.reason}`:c.reason)}catch(c){C("legacy fingerprint adoption",!1,c instanceof Error?c.message:String(c))}try{const c=$e(t,void 0,r);C("embedding freshness",c===0,c===0?"all active documents match current fingerprint":`${I(c)} active documents need embeddings. Next: \`qmd embed\``),c>0&&i.push(`Run \`qmd embed\` to generate ${I(c)} missing/stale document embeddings.`)}catch(c){C("embedding freshness",!1,c instanceof Error?c.message:String(c))}try{const c=t.prepare(`
159
+ SELECT model, embed_fingerprint AS fingerprint, COUNT(DISTINCT hash) AS docs, COUNT(*) AS chunks
160
+ FROM content_vectors
161
+ GROUP BY model, embed_fingerprint
162
+ ORDER BY chunks DESC, model, embed_fingerprint
163
+ `).all(),d=new Set(c.map(v=>v.fingerprint)),h=c.filter(v=>v.model===r&&v.fingerprint!==l),f=c.length===0||d.size===1&&c[0]?.fingerprint===l&&h.length===0,g=c.filter(v=>v.model===r&&v.fingerprint===l).reduce((v,E)=>v+E.docs,0),b=c.reduce((v,E)=>v+E.docs,0)-g,x=c.map(v=>{const E=v.fingerprint===l?"current":v.fingerprint||"legacy";return`${$t(v.model)}:${E} ${I(v.docs)} docs/${I(v.chunks)} chunks`}).join("; "),y=c.filter(v=>v.fingerprint),w=[...new Set(y.map(v=>v.fingerprint))];if(w.length>1){const v=y.map(E=>`${E.fingerprint}${E.fingerprint===l?" (current)":""}: ${$t(E.model)} ${I(E.docs)} docs/${I(E.chunks)} chunks`).join("; ");C("mixed named embedding fingerprints",!1,`content_vectors contains ${w.length} named fingerprints: ${v}. Next: \`qmd embed\` or \`qmd embed --force\``),i.push("Run `qmd embed` to converge mixed named embedding fingerprints; use `qmd embed --force` if old named fingerprints or vector sample mismatches remain.")}const S=c.length===0?`no vectors yet; current fingerprint ${l}`:f?`${I(g)} docs on current fingerprint (${l})`:`${I(g)} docs current, ${I(b)} docs legacy/stale. ${x}. Next: \`qmd embed\``;C("embedding fingerprints",f,S),f||i.push("Run `qmd embed` to migrate active documents to the current embedding fingerprint; use `qmd embed --force` if vector samples still fail afterward.")}catch(c){C("embedding fingerprints",!1,c instanceof Error?c.message:String(c))}try{const c=await hr(t,r,l);C("embedding vector sample",c.ok,c.details),!c.ok&&!c.empty&&i.push("Run `qmd embed --force` to rebuild existing vectors that no longer reproduce under the current embedding pipeline.")}catch(c){const d=c instanceof Error?oe(c.message):oe(String(c));C("embedding vector sample",!1,`${d}; rebuild with \`qmd embed --force\``),i.push("Run `qmd embed --force` to rebuild existing vectors, then rerun `qmd doctor`.")}const u=ir(i);if(u.length>0){console.log(`
164
+ ${n.bold}Recommended next step${u.length===1?"":"s"}${n.reset}`);for(const c of u)console.log(` - ${c}`)}k()}a(yr,"showDoctor");function He(){console.error("If qmd still behaves unexpectedly, run 'qmd doctor' for diagnostics.")}a(He,"printDoctorHint");function K(e,t=1){console.error(e instanceof Error?e.message:String(e)),He(),process.exit(t)}a(K,"exitWithError");function bo(){const e=X(ge(import.meta.url)),t=q(e,"..","..","package.json");return JSON.parse(F(t,"utf-8"))}a(bo,"readPackageJson");function xr(){const e=X(ge(import.meta.url)),t=bo(),o=Ln(e,_e(e,"..","..")),s=o?`${t.version} (${o})`:t.version;console.log(`qmd ${s}`)}a(xr,"showVersion");const yo=ge(import.meta.url),qe=process.argv[1],vr=qe===yo||qe?.endsWith("/qmd.ts")||qe?.endsWith("/qmd.js")||qe!=null&&se(qe)===yo;if(vr){jo();const e=Ks();switch(e.values.version&&(xr(),process.exit(0)),e.values.skill&&(fo(),process.exit(0)),e.values.help&&e.command==="skill"&&(console.log("Usage: qmd skill <show|install> [options]"),console.log(""),console.log("Commands:"),console.log(" show Print the QMD skill"),console.log(" install Install QMD skill into ./.agents/skills/qmd"),console.log(""),console.log("Options:"),console.log(" --global Install into ~/.agents/skills/qmd"),console.log(" --yes Also create the .claude/skills/qmd symlink"),console.log(" -f, --force Replace existing install or symlink"),process.exit(0)),(!e.command||e.values.help)&&(lr(),process.exit(e.values.help?0:1)),e.command){case"context":{const t=e.args[0];switch(t||(console.error("Usage: qmd context <add|list|rm>"),console.error(""),console.error("Commands:"),console.error(' qmd context add [path] "text" - Add context (defaults to current dir)'),console.error(' qmd context add / "text" - Add global context to all collections'),console.error(" qmd context list - List all contexts"),console.error(" qmd context rm <path> - Remove context"),process.exit(1)),t){case"add":{e.args.length<2&&(console.error('Usage: qmd context add [path] "text"'),console.error(""),console.error("Examples:"),console.error(' qmd context add "Context for current directory"'),console.error(' qmd context add . "Context for current directory"'),console.error(' qmd context add /subfolder "Context for subfolder"'),console.error(' qmd context add / "Global context for all collections"'),console.error(""),console.error(" Using virtual paths:"),console.error(' qmd context add qmd://journals/ "Context for entire journals collection"'),console.error(' qmd context add qmd://journals/2024 "Context for 2024 journals"'),process.exit(1));let o,s;const r=e.args[1]||"";e.args[2]?(o=r,s=e.args.slice(2).join(" ")):(o=void 0,s=r),await ds(o,s);break}case"list":{us();break}case"rm":case"remove":{(e.args.length<2||!e.args[1])&&(console.error("Usage: qmd context rm <path>"),console.error("Examples:"),console.error(" qmd context rm /"),console.error(" qmd context rm qmd://journals/2024"),process.exit(1)),ms(e.args[1]);break}default:console.error(`Unknown subcommand: ${t}`),console.error("Available: add, list, rm"),process.exit(1)}break}case"get":{e.args[0]||(console.error("Usage: qmd get <filepath>[:from[:count]] [--from <line>] [-l <lines>] [--no-line-numbers] [--full-path]"),process.exit(1));const t=!e.values["no-line-numbers"];let o,s;try{o=ct("--from",e.values.from),s=ct("-l",e.values.l)}catch(r){K(r)}fs(e.args[0],o,s,t,!!e.values["full-path"]);break}case"multi-get":{e.args[0]||(console.error("Usage: qmd multi-get <pattern> [-l <lines>] [--max-bytes <bytes>] [--no-line-numbers] [--full-path] [--format json|csv|md|xml|files]"),console.error(" pattern: glob (e.g., 'journals/2025-05*.md') or comma-separated list"),process.exit(1));let t;try{t=oo("--max-bytes",e.values["max-bytes"])??Rt}catch(r){K(r)}const o=!e.values["no-line-numbers"];let s;try{s=ct("-l",e.values.l)}catch(r){K(r)}gs(e.args[0],s,t,e.opts.format,o,!!e.values["full-path"]);break}case"ls":{ps(e.args[0]);break}case"collection":{const t=e.args[0];switch(t){case"list":{$s();break}case"add":{const o=e.args[1];o||(console.error("Usage: qmd collection add <path> [--name NAME] [--mask GLOB]"),console.error(" Pass '.' to index the current directory."),console.error(" --mask / --glob: glob (default **/*.md), brace group, or comma-separated list"),process.exit(1));const s=Re(o==="."?W():q(o)),r=bs(e.values),l=e.values.name;R(s)||(console.error(`${n.yellow}Collection path does not exist.${n.reset}`),console.error(` Received: ${o}`),console.error(` Resolved: ${s}`),console.error("Provide an existing directory and run 'qmd collection add <path>' again."),process.exit(1)),fe(s).isDirectory()||(console.error(`${n.yellow}Collection path is not a directory.${n.reset}`),console.error(` Received: ${o}`),console.error(` Resolved: ${s}`),console.error("Choose a directory and run 'qmd collection add <path>' again."),process.exit(1)),await ys(s,r,l);break}case"remove":case"rm":{e.args[1]||(console.error("Usage: qmd collection remove <name>"),console.error(" Use 'qmd collection list' to see available collections"),process.exit(1)),xs(e.args[1]);break}case"rename":case"mv":{(!e.args[1]||!e.args[2])&&(console.error("Usage: qmd collection rename <old-name> <new-name>"),console.error(" Use 'qmd collection list' to see available collections"),process.exit(1)),vs(e.args[1],e.args[2]);break}case"set-update":case"update-cmd":{const o=e.args[1],s=e.args.slice(2).join(" ")||null;o||(console.error("Usage: qmd collection update-cmd <name> [command]"),console.error(" Set the command to run before indexing (e.g., 'git pull')"),console.error(" Omit command to clear it"),process.exit(1));const{updateCollectionSettings:r,getCollection:l}=await import("../collections.js");l(o)||(console.error(`Collection not found: ${o}`),process.exit(1)),r(o,{update:s}),zt(),console.log(s?`\u2713 Set update command for '${o}': ${s}`:`\u2713 Cleared update command for '${o}'`);break}case"include":case"exclude":{const o=e.args[1];o||(console.error(`Usage: qmd collection ${t} <name>`),console.error(` ${t==="include"?"Include":"Exclude"} collection in default queries`),process.exit(1));const{updateCollectionSettings:s,getCollection:r}=await import("../collections.js");r(o)||(console.error(`Collection not found: ${o}`),process.exit(1));const i=t==="include";s(o,{includeByDefault:i}),console.log(`\u2713 Collection '${o}' ${i?"included in":"excluded from"} default queries`);break}case"show":case"info":{const o=e.args[1];o||(console.error("Usage: qmd collection show <name>"),process.exit(1));const{getCollection:s}=await import("../collections.js"),r=s(o);if(r||(console.error(`Collection not found: ${o}`),process.exit(1)),console.log(`Collection: ${o}`),console.log(` Path: ${r.path}`),console.log(` Pattern: ${r.pattern}`),console.log(` Include: ${r.includeByDefault!==!1?"yes (default)":"no"}`),r.update&&console.log(` Update: ${r.update}`),r.context){const l=Object.keys(r.context).length;console.log(` Contexts: ${l}`)}break}case"help":case void 0:console.log("Usage: qmd collection <command> [options]"),console.log(""),console.log("Commands:"),console.log(" list List all collections"),console.log(" add <path> [--name NAME] [--mask|--glob GLOB] Add a collection"),console.log(" remove <name> Remove a collection"),console.log(" rename <old> <new> Rename a collection"),console.log(" show <name> Show collection details"),console.log(" update-cmd <name> [cmd] Set pre-update command (e.g., 'git pull')"),console.log(" include <name> Include in default queries"),console.log(" exclude <name> Exclude from default queries"),console.log(""),console.log("Examples:"),console.log(" qmd collection add ~/notes --name notes"),console.log(" qmd collection add ~/notes --name notes --mask 'a.md,journals/*.md'"),console.log(" qmd collection update-cmd brain 'git pull'"),console.log(" qmd collection exclude archive"),process.exit(0);default:console.error(`Unknown subcommand: ${t}`),console.error("Run 'qmd collection help' for usage"),He(),process.exit(1)}break}case"init":try{es()}catch(t){K(t)}break;case"status":await ls();break;case"doctor":await yr();break;case"update":{await as()>0&&process.exit(1);break}case"trust":cs(e.args[0]);break;case"embed":try{await Ee();const t=oo("maxDocsPerBatch",e.values["max-docs-per-batch"]),o=Ss(e.values["max-batch-mb"]),s=no(e.values["chunk-strategy"]),r=Cs(e.values.timeout),i=Se(e.opts.collection,!1)[0],m=o===void 0?void 0:Math.round(o*1024*1024);if(m!==void 0&&m<1)throw new Error("--max-batch-mb is too small (rounds to 0 bytes)");await Ms(dt().embed,!!e.values.force,{maxDocsPerBatch:t,maxBatchBytes:m,chunkStrategy:s,collection:i,maxDurationMs:r})}catch(t){K(t)}break;case"pull":{try{await Ee();const t=e.values.refresh===void 0?!1:!!e.values.refresh,o=dt(),s=[o.embed,o.generate,o.rerank];console.log(`${n.bold}Pulling models${n.reset}`);const r=await Pn(s,{refresh:t,cacheDir:Ie,cli:!!e.values.progress});for(const l of r){const i=Q(l.sizeBytes),m=l.refreshed?"refreshed":"cached/checked";console.log(`- ${l.model} -> ${l.path} (${i}, ${m})`)}}catch(t){K(t)}break}case"search":e.query||(console.error("Usage: qmd search [options] <query>"),process.exit(1)),e.opts.filter=Be(e.values.filter),Gs(e.query,e.opts);break;case"grep":e.query||(console.error("Usage: qmd grep [options] <pattern>"),process.exit(1)),e.opts.filter=Be(e.values.filter),Ws(e.query,e.opts,e.values);break;case"vsearch":case"vector-search":e.query||(console.error("Usage: qmd vsearch [options] <query>"),process.exit(1));try{e.values["min-score"]||(e.opts.minScore=.3),e.opts.filter=Be(e.values.filter),await Ee(),await Vs(e.query,e.opts)}catch(t){K(t)}break;case"query":case"deep-search":e.query||(console.error("Usage: qmd query [options] <query>"),process.exit(1)),e.opts.filter=Be(e.values.filter),await Ee();try{await Ys(e.query,e.opts)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}break;case"bench":{const t=e.args[0];t||(console.error("Usage: qmd bench <fixture.json> [--json] [-c collection]"),console.error(""),console.error("Run search quality benchmarks against a fixture file."),console.error("See src/bench/fixtures/example.json for the fixture format."),process.exit(1));const{runBenchmark:o}=await import("../bench/bench.js"),s=e.opts.collection;Array.isArray(s)&&s.length>1&&(console.error(`qmd bench accepts only one -c/--collection; got: ${s.join(", ")}`),process.exit(1));try{await o(t,{json:!!e.values.json,collection:Array.isArray(s)?s[0]:s,dbPath:te(),configPath:Un()?ce():void 0})}catch(r){K(r)}break}case"mcp":{const t=e.args[0],{cacheDir:o,pidPath:s,logPath:r}=Wt();if(t==="stop"){R(s)||(console.log("Not running (no PID file)."),process.exit(0));const l=parseInt(F(s,"utf-8").trim());if(!Ye(l)){try{re(s)}catch{}console.log("Cleaned up stale PID file (server was not running)."),process.exit(0)}try{process.kill(l,"SIGTERM"),re(s),console.log(`Stopped QMD MCP server (PID ${l}).`)}catch{try{re(s)}catch{}console.log("Cleaned up stale PID file (server was not running).")}process.exit(0)}if(e.values.http){let l;try{l=zn(e.values.port)}catch(u){console.error(u instanceof Error?u.message:String(u)),process.exit(1)}const i=e.values.host?String(e.values.host):void 0,m=Bs(i);if(e.values.daemon){if(R(s)){const x=parseInt(F(s,"utf-8").trim());Ye(x)&&(console.error(`Already running (PID ${x}). Run 'qmd mcp stop' first.`),process.exit(1));try{re(s)}catch{}}Pe(o,{recursive:!0});const u=qo(r),c=ge(import.meta.url),d=e.values.index?["--index",String(e.values.index)]:[],h=["--host",m],f=c.endsWith(".ts")?["--import",A(X(c),"..","..","node_modules","tsx","dist","esm","index.mjs"),c,...d,"mcp","--http","--port",String(l),...h]:[c,...d,"mcp","--http","--port",String(l),...h],g=xt(process.execPath,f,{stdio:["ignore",u,u],detached:!0,env:{...process.env,INDEX_PATH:te()}});g.unref(),No(u);const b=await Jn(g,r);b.ok||(console.error(b.message),process.exit(1)),wt(s,String(g.pid)),console.log(`Started on http://${m}:${l}/mcp (PID ${g.pid})`),console.log(`Logs: ${r}`),process.exit(0)}process.removeAllListeners("SIGTERM"),process.removeAllListeners("SIGINT");const $=a(()=>{try{if(!R(s))return;parseInt(F(s,"utf-8").trim())===process.pid&&re(s)}catch{}},"unlinkOwnPidfile");process.on("exit",$);const{startMcpHttpServer:p}=await import("../mcp/server.js");try{await p(l,{dbPath:te(),host:m})}catch(u){throw typeof u=="object"&&u!==null&&"code"in u&&u.code==="EADDRINUSE"&&(console.error(`Port ${l} already in use. Try a different port with --port.`),process.exit(1)),u}}else{process.removeAllListeners("SIGTERM"),process.removeAllListeners("SIGINT");const{startMcpServer:l}=await import("../mcp/server.js");await l({dbPath:te()})}break}case"skills":{try{e.values.help||e.args[0]==="help"?po():or(e.args,!!e.values.json,!!e.values.full,!!e.values.all)}catch(t){e.values.json?De({success:!1,error:t instanceof Error?t.message:String(t)}):console.error(t instanceof Error?t.message:String(t)),process.exit(1)}break}case"skill":{const t=e.args[0];switch(t){case"show":{fo();break}case"install":{try{await rr(!!e.values.global,!!e.values.force,!!e.values.yes)}catch(o){K(o)}break}case"help":case void 0:console.log("Usage: qmd skill <show|install> [options]"),console.log(""),console.log("Commands:"),console.log(" show Print the QMD skill"),console.log(" install Install QMD skill into ./.agents/skills/qmd"),console.log(""),console.log("Options:"),console.log(" --global Install into ~/.agents/skills/qmd"),console.log(" --yes Also create the .claude/skills/qmd symlink"),console.log(" -f, --force Replace existing install or symlink"),process.exit(0);default:console.error(`Unknown subcommand: ${t}`),console.error("Run 'qmd skill help' for usage"),He(),process.exit(1)}break}case"cleanup":{const t=P();if(!!e.values["dry-run"]){const r=mn(t);console.log(`Dry run \u2014 no changes made.
165
+ `),console.log(`Would clear ${r.cacheCount} cached API responses`),r.orphanedVectors>0?console.log(`Would remove ${r.orphanedVectors} orphaned embedding chunks`):console.log(`${n.dim}No orphaned embeddings to remove${n.reset}`),r.inactiveDocs>0&&console.log(`Would remove ${r.inactiveDocs} inactive document records`),r.orphanedContent>0&&console.log(`Would remove ${r.orphanedContent} orphaned content hashes`),console.log("Would compact FTS and vacuum the database"),k();break}const s=fn(t);console.log(`${n.green}\u2713${n.reset} Cleared ${s.cacheCount} cached API responses`),s.orphanedVectors>0?console.log(`${n.green}\u2713${n.reset} Removed ${s.orphanedVectors} orphaned embedding chunks`):console.log(`${n.dim}No orphaned embeddings to remove${n.reset}`),s.inactiveDocs>0&&console.log(`${n.green}\u2713${n.reset} Removed ${s.inactiveDocs} inactive document records`),s.orphanedContent>0&&console.log(`${n.green}\u2713${n.reset} Removed ${s.orphanedContent} orphaned content hashes`),console.log(`${n.green}\u2713${n.reset} FTS compacted, database vacuumed`),k();break}default:console.error(`Unknown command: ${e.command}`),console.error("Run 'qmd --help' for usage."),He(),process.exit(1)}e.command!=="mcp"&&await Xn({command:e.command,format:e.opts.format})}export{Kn as DEFAULT_MCP_PORT,Us as buildEditorUri,Rs as explainGroupLines,Xn as finishSuccessfulCliCommand,Is as formatScore,Ss as parseEmbedBatchMbOption,lt as renderFullPath,Bs as resolveDaemonHost,at as resolveEmbedModelForCli,Vr as resolveGenerateModelForCli,zn as resolveMcpPort,Yr as resolveRerankModelForCli,Qs as termLink,Ms as vectorIndex,Jn as waitForDaemonListening};
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Build/commit identification for `qmd --version`.
3
+ *
4
+ * The commit is *stamped at build time* (scripts/build.mjs writes
5
+ * build-info.json next to the compiled CLI) rather than discovered at runtime.
6
+ * A published tarball carries no git history of its own, so a runtime lookup
7
+ * can only ever find some *other* repository's HEAD: `git -C <dir> rev-parse`
8
+ * walks up the tree, and a global install under a git-managed prefix (e.g.
9
+ * Homebrew's /opt/homebrew) reported that prefix's commit as qmd's.
10
+ *
11
+ * Running from a source checkout has no stamp, so the git lookup remains as a
12
+ * fallback — but only after confirming the enclosing repository is the package
13
+ * we are actually running from.
14
+ */
15
+ /** Written next to the compiled CLI (dist/cli/) by scripts/build.mjs. */
16
+ export declare const BUILD_INFO_FILENAME = "build-info.json";
17
+ export type BuildInfo = {
18
+ commit: string;
19
+ builtAt?: string;
20
+ };
21
+ /**
22
+ * Read the commit stamped into this build, or "" when there is none.
23
+ *
24
+ * Deliberately looks beside the running script rather than in the package's
25
+ * dist/ directory: a source run (src/cli/) must not pick up the stamp left by
26
+ * an earlier, possibly unrelated, build in dist/.
27
+ */
28
+ export declare function readStampedCommit(scriptDir: string): string;
29
+ /**
30
+ * Short HEAD of the checkout we are running from, or "" when we are not
31
+ * running from one.
32
+ *
33
+ * The guard is the whole point: an enclosing repository is only qmd's if its
34
+ * top level *is* this package's root. Without that check, any install nested
35
+ * inside an unrelated repository reports that repository's HEAD.
36
+ */
37
+ export declare function gitCommitForCheckout(scriptDir: string, packageRoot: string): string;
38
+ /**
39
+ * The commit to report for this invocation: the build stamp when there is one,
40
+ * otherwise the verified checkout HEAD, otherwise nothing.
41
+ */
42
+ export declare function resolveCommit(scriptDir: string, packageRoot: string): string;
@@ -0,0 +1 @@
1
+ var p=Object.defineProperty;var e=(t,r)=>p(t,"name",{value:r,configurable:!0});import{execFileSync as m}from"node:child_process";import{readFileSync as u,realpathSync as c}from"node:fs";import{join as s}from"node:path";const f="build-info.json";function a(t){try{const r=u(s(t,f),"utf-8"),o=JSON.parse(r);return typeof o.commit=="string"?o.commit:""}catch{return""}}e(a,"readStampedCommit");function n(t,r){return m("git",t,{cwd:r,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}e(n,"git");function d(t,r){try{const o=n(["rev-parse","--show-toplevel"],t);if(c(o)!==c(r))return"";const i=n(["rev-parse","--short","HEAD"],o);return i?n(["status","--porcelain"],o)?`${i}-dirty`:i:""}catch{return""}}e(d,"gitCommitForCheckout");function F(t,r){return a(t)||d(t,r)}e(F,"resolveCommit");export{f as BUILD_INFO_FILENAME,d as gitCommitForCheckout,a as readStampedCommit,F as resolveCommit};