pando-ai 0.1.3 → 0.1.5

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 (151) hide show
  1. package/dist/cli.js +158 -158
  2. package/dist/watcher-process.js +411 -411
  3. package/dist/workers/chunk-Z7LW7C4Z.mjs +518 -0
  4. package/dist/workers/indexer-worker.mjs +1 -1
  5. package/dist/workers/snapshot-worker.mjs +8 -4
  6. package/dist/workers/sqlite-writer-worker.mjs +3 -3
  7. package/package.json +6 -5
  8. package/resources/tools/{pando-tools.json → generated_pando-tools.json} +7 -46
  9. package/resources/tools/generated_tools.md +93 -0
  10. package/tools/clojure-editor/lib/pando-clojure-editor-standalone.jar +0 -0
  11. package/tools/clojure-indexer/lib/pando-clojure-indexer-standalone.jar +0 -0
  12. package/tools/csharp-indexer/CSharpIndexer.csproj +1 -1
  13. package/tools/csharp-indexer/bin/pando-csharp-indexer +81 -23
  14. package/tools/csharp-indexer/bin/pando-csharp-indexer.cmd +82 -14
  15. package/tools/csharp-indexer/src/Program.cs +1860 -0
  16. package/dist/workers/chunk-LGZQCDFH.mjs +0 -522
  17. package/tools/csharp-indexer/bin/Release/net10.0/CSharpIndexer +0 -0
  18. package/tools/csharp-indexer/bin/Release/net10.0/CSharpIndexer.deps.json +0 -383
  19. package/tools/csharp-indexer/bin/Release/net10.0/CSharpIndexer.dll +0 -0
  20. package/tools/csharp-indexer/bin/Release/net10.0/CSharpIndexer.pdb +0 -0
  21. package/tools/csharp-indexer/bin/Release/net10.0/CSharpIndexer.runtimeconfig.json +0 -13
  22. package/tools/csharp-indexer/bin/Release/net10.0/Humanizer.dll +0 -0
  23. package/tools/csharp-indexer/bin/Release/net10.0/Microsoft.CodeAnalysis.CSharp.Workspaces.dll +0 -0
  24. package/tools/csharp-indexer/bin/Release/net10.0/Microsoft.CodeAnalysis.CSharp.dll +0 -0
  25. package/tools/csharp-indexer/bin/Release/net10.0/Microsoft.CodeAnalysis.Workspaces.dll +0 -0
  26. package/tools/csharp-indexer/bin/Release/net10.0/Microsoft.CodeAnalysis.dll +0 -0
  27. package/tools/csharp-indexer/bin/Release/net10.0/System.Composition.AttributedModel.dll +0 -0
  28. package/tools/csharp-indexer/bin/Release/net10.0/System.Composition.Convention.dll +0 -0
  29. package/tools/csharp-indexer/bin/Release/net10.0/System.Composition.Hosting.dll +0 -0
  30. package/tools/csharp-indexer/bin/Release/net10.0/System.Composition.Runtime.dll +0 -0
  31. package/tools/csharp-indexer/bin/Release/net10.0/System.Composition.TypedParts.dll +0 -0
  32. package/tools/csharp-indexer/bin/Release/net10.0/cs/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  33. package/tools/csharp-indexer/bin/Release/net10.0/cs/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  34. package/tools/csharp-indexer/bin/Release/net10.0/cs/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  35. package/tools/csharp-indexer/bin/Release/net10.0/cs/Microsoft.CodeAnalysis.resources.dll +0 -0
  36. package/tools/csharp-indexer/bin/Release/net10.0/de/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  37. package/tools/csharp-indexer/bin/Release/net10.0/de/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  38. package/tools/csharp-indexer/bin/Release/net10.0/de/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  39. package/tools/csharp-indexer/bin/Release/net10.0/de/Microsoft.CodeAnalysis.resources.dll +0 -0
  40. package/tools/csharp-indexer/bin/Release/net10.0/es/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  41. package/tools/csharp-indexer/bin/Release/net10.0/es/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  42. package/tools/csharp-indexer/bin/Release/net10.0/es/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  43. package/tools/csharp-indexer/bin/Release/net10.0/es/Microsoft.CodeAnalysis.resources.dll +0 -0
  44. package/tools/csharp-indexer/bin/Release/net10.0/fr/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  45. package/tools/csharp-indexer/bin/Release/net10.0/fr/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  46. package/tools/csharp-indexer/bin/Release/net10.0/fr/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  47. package/tools/csharp-indexer/bin/Release/net10.0/fr/Microsoft.CodeAnalysis.resources.dll +0 -0
  48. package/tools/csharp-indexer/bin/Release/net10.0/it/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  49. package/tools/csharp-indexer/bin/Release/net10.0/it/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  50. package/tools/csharp-indexer/bin/Release/net10.0/it/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  51. package/tools/csharp-indexer/bin/Release/net10.0/it/Microsoft.CodeAnalysis.resources.dll +0 -0
  52. package/tools/csharp-indexer/bin/Release/net10.0/ja/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  53. package/tools/csharp-indexer/bin/Release/net10.0/ja/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  54. package/tools/csharp-indexer/bin/Release/net10.0/ja/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  55. package/tools/csharp-indexer/bin/Release/net10.0/ja/Microsoft.CodeAnalysis.resources.dll +0 -0
  56. package/tools/csharp-indexer/bin/Release/net10.0/ko/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  57. package/tools/csharp-indexer/bin/Release/net10.0/ko/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  58. package/tools/csharp-indexer/bin/Release/net10.0/ko/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  59. package/tools/csharp-indexer/bin/Release/net10.0/ko/Microsoft.CodeAnalysis.resources.dll +0 -0
  60. package/tools/csharp-indexer/bin/Release/net10.0/pl/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  61. package/tools/csharp-indexer/bin/Release/net10.0/pl/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  62. package/tools/csharp-indexer/bin/Release/net10.0/pl/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  63. package/tools/csharp-indexer/bin/Release/net10.0/pl/Microsoft.CodeAnalysis.resources.dll +0 -0
  64. package/tools/csharp-indexer/bin/Release/net10.0/pt-BR/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  65. package/tools/csharp-indexer/bin/Release/net10.0/pt-BR/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  66. package/tools/csharp-indexer/bin/Release/net10.0/pt-BR/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  67. package/tools/csharp-indexer/bin/Release/net10.0/pt-BR/Microsoft.CodeAnalysis.resources.dll +0 -0
  68. package/tools/csharp-indexer/bin/Release/net10.0/ru/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  69. package/tools/csharp-indexer/bin/Release/net10.0/ru/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  70. package/tools/csharp-indexer/bin/Release/net10.0/ru/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  71. package/tools/csharp-indexer/bin/Release/net10.0/ru/Microsoft.CodeAnalysis.resources.dll +0 -0
  72. package/tools/csharp-indexer/bin/Release/net10.0/tr/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  73. package/tools/csharp-indexer/bin/Release/net10.0/tr/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  74. package/tools/csharp-indexer/bin/Release/net10.0/tr/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  75. package/tools/csharp-indexer/bin/Release/net10.0/tr/Microsoft.CodeAnalysis.resources.dll +0 -0
  76. package/tools/csharp-indexer/bin/Release/net10.0/zh-Hans/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  77. package/tools/csharp-indexer/bin/Release/net10.0/zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  78. package/tools/csharp-indexer/bin/Release/net10.0/zh-Hans/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  79. package/tools/csharp-indexer/bin/Release/net10.0/zh-Hans/Microsoft.CodeAnalysis.resources.dll +0 -0
  80. package/tools/csharp-indexer/bin/Release/net10.0/zh-Hant/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  81. package/tools/csharp-indexer/bin/Release/net10.0/zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  82. package/tools/csharp-indexer/bin/Release/net10.0/zh-Hant/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  83. package/tools/csharp-indexer/bin/Release/net10.0/zh-Hant/Microsoft.CodeAnalysis.resources.dll +0 -0
  84. package/tools/csharp-indexer/bin/Release/net8.0/CSharpIndexer +0 -0
  85. package/tools/csharp-indexer/bin/Release/net8.0/CSharpIndexer.deps.json +0 -400
  86. package/tools/csharp-indexer/bin/Release/net8.0/CSharpIndexer.dll +0 -0
  87. package/tools/csharp-indexer/bin/Release/net8.0/CSharpIndexer.pdb +0 -0
  88. package/tools/csharp-indexer/bin/Release/net8.0/CSharpIndexer.runtimeconfig.json +0 -13
  89. package/tools/csharp-indexer/bin/Release/net8.0/Humanizer.dll +0 -0
  90. package/tools/csharp-indexer/bin/Release/net8.0/Microsoft.CodeAnalysis.CSharp.Workspaces.dll +0 -0
  91. package/tools/csharp-indexer/bin/Release/net8.0/Microsoft.CodeAnalysis.CSharp.dll +0 -0
  92. package/tools/csharp-indexer/bin/Release/net8.0/Microsoft.CodeAnalysis.Workspaces.dll +0 -0
  93. package/tools/csharp-indexer/bin/Release/net8.0/Microsoft.CodeAnalysis.dll +0 -0
  94. package/tools/csharp-indexer/bin/Release/net8.0/System.Composition.AttributedModel.dll +0 -0
  95. package/tools/csharp-indexer/bin/Release/net8.0/System.Composition.Convention.dll +0 -0
  96. package/tools/csharp-indexer/bin/Release/net8.0/System.Composition.Hosting.dll +0 -0
  97. package/tools/csharp-indexer/bin/Release/net8.0/System.Composition.Runtime.dll +0 -0
  98. package/tools/csharp-indexer/bin/Release/net8.0/System.Composition.TypedParts.dll +0 -0
  99. package/tools/csharp-indexer/bin/Release/net8.0/System.IO.Pipelines.dll +0 -0
  100. package/tools/csharp-indexer/bin/Release/net8.0/cs/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  101. package/tools/csharp-indexer/bin/Release/net8.0/cs/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  102. package/tools/csharp-indexer/bin/Release/net8.0/cs/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  103. package/tools/csharp-indexer/bin/Release/net8.0/cs/Microsoft.CodeAnalysis.resources.dll +0 -0
  104. package/tools/csharp-indexer/bin/Release/net8.0/de/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  105. package/tools/csharp-indexer/bin/Release/net8.0/de/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  106. package/tools/csharp-indexer/bin/Release/net8.0/de/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  107. package/tools/csharp-indexer/bin/Release/net8.0/de/Microsoft.CodeAnalysis.resources.dll +0 -0
  108. package/tools/csharp-indexer/bin/Release/net8.0/es/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  109. package/tools/csharp-indexer/bin/Release/net8.0/es/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  110. package/tools/csharp-indexer/bin/Release/net8.0/es/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  111. package/tools/csharp-indexer/bin/Release/net8.0/es/Microsoft.CodeAnalysis.resources.dll +0 -0
  112. package/tools/csharp-indexer/bin/Release/net8.0/fr/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  113. package/tools/csharp-indexer/bin/Release/net8.0/fr/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  114. package/tools/csharp-indexer/bin/Release/net8.0/fr/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  115. package/tools/csharp-indexer/bin/Release/net8.0/fr/Microsoft.CodeAnalysis.resources.dll +0 -0
  116. package/tools/csharp-indexer/bin/Release/net8.0/it/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  117. package/tools/csharp-indexer/bin/Release/net8.0/it/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  118. package/tools/csharp-indexer/bin/Release/net8.0/it/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  119. package/tools/csharp-indexer/bin/Release/net8.0/it/Microsoft.CodeAnalysis.resources.dll +0 -0
  120. package/tools/csharp-indexer/bin/Release/net8.0/ja/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  121. package/tools/csharp-indexer/bin/Release/net8.0/ja/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  122. package/tools/csharp-indexer/bin/Release/net8.0/ja/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  123. package/tools/csharp-indexer/bin/Release/net8.0/ja/Microsoft.CodeAnalysis.resources.dll +0 -0
  124. package/tools/csharp-indexer/bin/Release/net8.0/ko/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  125. package/tools/csharp-indexer/bin/Release/net8.0/ko/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  126. package/tools/csharp-indexer/bin/Release/net8.0/ko/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  127. package/tools/csharp-indexer/bin/Release/net8.0/ko/Microsoft.CodeAnalysis.resources.dll +0 -0
  128. package/tools/csharp-indexer/bin/Release/net8.0/pl/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  129. package/tools/csharp-indexer/bin/Release/net8.0/pl/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  130. package/tools/csharp-indexer/bin/Release/net8.0/pl/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  131. package/tools/csharp-indexer/bin/Release/net8.0/pl/Microsoft.CodeAnalysis.resources.dll +0 -0
  132. package/tools/csharp-indexer/bin/Release/net8.0/pt-BR/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  133. package/tools/csharp-indexer/bin/Release/net8.0/pt-BR/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  134. package/tools/csharp-indexer/bin/Release/net8.0/pt-BR/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  135. package/tools/csharp-indexer/bin/Release/net8.0/pt-BR/Microsoft.CodeAnalysis.resources.dll +0 -0
  136. package/tools/csharp-indexer/bin/Release/net8.0/ru/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  137. package/tools/csharp-indexer/bin/Release/net8.0/ru/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  138. package/tools/csharp-indexer/bin/Release/net8.0/ru/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  139. package/tools/csharp-indexer/bin/Release/net8.0/ru/Microsoft.CodeAnalysis.resources.dll +0 -0
  140. package/tools/csharp-indexer/bin/Release/net8.0/tr/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  141. package/tools/csharp-indexer/bin/Release/net8.0/tr/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  142. package/tools/csharp-indexer/bin/Release/net8.0/tr/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  143. package/tools/csharp-indexer/bin/Release/net8.0/tr/Microsoft.CodeAnalysis.resources.dll +0 -0
  144. package/tools/csharp-indexer/bin/Release/net8.0/zh-Hans/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  145. package/tools/csharp-indexer/bin/Release/net8.0/zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  146. package/tools/csharp-indexer/bin/Release/net8.0/zh-Hans/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  147. package/tools/csharp-indexer/bin/Release/net8.0/zh-Hans/Microsoft.CodeAnalysis.resources.dll +0 -0
  148. package/tools/csharp-indexer/bin/Release/net8.0/zh-Hant/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
  149. package/tools/csharp-indexer/bin/Release/net8.0/zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
  150. package/tools/csharp-indexer/bin/Release/net8.0/zh-Hant/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
  151. package/tools/csharp-indexer/bin/Release/net8.0/zh-Hant/Microsoft.CodeAnalysis.resources.dll +0 -0
@@ -1 +1 @@
1
- import{b as B,c as O,d as q,e as A,f as z,g as F,j as C}from"./chunk-LGZQCDFH.mjs";import"./chunk-ODST7O2H.mjs";import{c as L}from"./chunk-AYCBSZ56.mjs";import{parentPort as h,threadId as te}from"worker_threads";import U from"fs";import $ from"path";import{promises as K}from"fs";import X from"ignore";import{createHash as re}from"crypto";var Z=Math.max(1,Number(process.env.PANDO_BATCH_INDEX_MAX_FILES||"64")),ee=Math.max(1,Number(process.env.PANDO_BATCH_INDEX_MAX_BYTES||`${1024*1024}`)),ae=Math.max(1,Number(process.env.PANDO_BATCH_INDEX_MAX_WAIT_MS||"15")),oe=Math.max(Z,Number(process.env.PANDO_BATCH_INDEX_MAX_PENDING_FILES||"256")),de=Math.max(ee,Number(process.env.PANDO_BATCH_INDEX_MAX_PENDING_BYTES||`${8*1024*1024}`));var Ie=1*1024*1024,xe=Math.max(3e4,Number(process.env.PANDO_WORKER_INIT_TIMEOUT_MS||12e4)),Pe=q();function N(e,r){return Buffer.from(e).toString(r)}function M(e,r,c,t,d,p){let m=Buffer.from(e),n=re("sha1").update(m).digest("hex"),i=p??m.toString(d),l=i?i.split(/\r?\n/).length:0;return{relPath:r,size:c,mtime:t,objectId:n,lineCount:l,encoding:d}}if(!h)throw new Error("Indexer worker must be spawned as a worker thread");L();function u(e,r){try{if(r===void 0){console.error(`[${new Date().toISOString()}] [IndexerWorker] ${e}`);return}console.error(`[${new Date().toISOString()}] [IndexerWorker] ${e} ${JSON.stringify({pid:process.pid,threadId:te,...r&&typeof r=="object"&&!Array.isArray(r)?r:{details:r}})}`)}catch{}}u("module loaded",{cwd:process.cwd(),hasParentPort:!!h,envWorkerRoot:process.env.PANDO_WORKER_SCRIPT_DIR??null,envRuntimeRoot:process.env.PANDO_RUNTIME_ROOT??null});var G=new Map,D="",T="index",x=new Map,v=new Set;function H(e,r){return $.relative(e,r).replace(/\\/g,"/")}function se(e,r){let c=(r||[]).map(t=>typeof t=="string"?t.trim():"").filter(Boolean).map(t=>t.replace(/^[\\/]+/,"").replace(/[\\/]+$/,"")).map(t=>t.endsWith("/")?t:`${t}/`);return c.length?t=>{let d=H(e,t);if(!d||d.startsWith(".."))return!1;let p=d.endsWith("/")?d:`${d}/`;return c.some(m=>p.startsWith(m))}:null}async function ie(e){await new Promise(r=>{x.set(e,r)})}h.on("message",async e=>{if(e.cmd==="scan-ack"){let r=x.get(e.requestId);if(r){x.delete(e.requestId);try{r()}catch{}}return}if(e.cmd==="scan-cancel"){v.add(e.requestId);let r=x.get(e.requestId);if(r){x.delete(e.requestId);try{r()}catch{}}return}if(e.cmd==="init"){try{u("init received",{mode:e.mode??"index",projectRoot:typeof e.projectRoot=="string"?e.projectRoot:null}),typeof e.projectRoot=="string"&&(D=e.projectRoot),T=e.mode??"index",u("init completed",{mode:T,projectRoot:D}),h.postMessage({type:"ready"})}catch(r){u("init failed",{error:r?.message||String(r),stack:r?.stack??null}),h.postMessage({type:"error",message:`init failed: ${r?.message||r}`,stack:r?.stack})}return}if(e.cmd==="scan"){let r=e.requestId,c=typeof e.projectRoot=="string"?e.projectRoot:D;if(u("scan received",{requestId:r,projectRoot:c||null,batchSize:e.batchSize??null,maxFileBytes:e.maxFileBytes??null,excludeDirs:Array.isArray(e.excludeDirs)?e.excludeDirs.slice(0,20):[]}),!c){h.postMessage({type:"error",requestId:r,message:"worker not initialized"});return}let t=Math.max(1,Math.min(500,Number(e.batchSize||100))),d=Math.max(1,Number(e.maxFileBytes||1*1024*1024)),p=e.languageSupport,m=F(p),n=se(c,e.excludeDirs??[]),i=new Set(["node_modules",".git",".pando-data"]),l=o=>o.replace(/\\/g,"/"),f=await C(c,""),I=X().add(f),g=[{dir:c,relDir:"",rules:f,ig:I}],y=0,a=0,s=[],k=async()=>{s.length&&(h.postMessage({type:"scan:batch",requestId:r,files:s}),s=[],await ie(r))};try{for(;g.length&&!v.has(r);){let o=g.pop(),P=[];try{P=await K.readdir(o.dir,{withFileTypes:!0})}catch{a+=1;continue}for(let S of P){if(v.has(r))break;let w=$.join(o.dir,S.name);if(S.isSymbolicLink?.()){a+=1;continue}if(S.isDirectory()){if(i.has(S.name)){a+=1;continue}if(n?.(w)){a+=1;continue}let J=o.relDir?`${o.relDir}/${S.name}`:S.name,R=l(J);if(o.ig.ignores(R)){a+=1;continue}let E=o.rules.slice(),j=await C(w,R);j.length&&E.push(...j);let Q=X().add(E);g.push({dir:w,relDir:R,rules:E,ig:Q});continue}if(!S.isFile()){a+=1;continue}if(n?.(w)){a+=1;continue}let b=H(c,w);if(!b||b.startsWith("..")){a+=1;continue}if(o.ig.ignores(b)){a+=1;continue}let Y=$.extname(S.name).toLowerCase();if(!m.has(Y)){a+=1;continue}let _=A(b);if(!_){a+=1;continue}let W;try{W=await K.stat(w)}catch{a+=1;continue}if(W.size>d){a+=1;continue}s.push({relPath:b,absPath:w,mtimeMs:Math.floor(W.mtimeMs),size:W.size,lang:_}),y+=1,s.length>=t&&await k()}}v.has(r)||await k(),h.postMessage({type:"scan:done",requestId:r,discovered:y,skipped:a,cancelled:v.has(r)}),u("scan complete",{requestId:r,discovered:y,skipped:a,cancelled:v.has(r)})}catch(o){u("scan failed",{requestId:r,error:o?.message||String(o),stack:o?.stack??null}),h.postMessage({type:"error",requestId:r,message:o?.message||String(o),stack:o?.stack})}finally{v.delete(r),x.delete(r)}return}if(e.cmd==="process"){let r=e.role??T,c=typeof e.projectRoot=="string"?e.projectRoot:D;if(!c){h.postMessage({type:"error",requestId:e.requestId,message:"worker not initialized"});return}let{file:t}=e,d=t.encoding??"utf8",p=t.sharedBuffer,m={size:t.size,mtime:t.mtime};try{let n=t.lang??"ts",i,l,f=()=>{if(l&&typeof i=="string")return{content:i,sharedBuffer:l};if(p instanceof SharedArrayBuffer)return l=p,i=N(p,d),{content:i,sharedBuffer:l};if(p instanceof ArrayBuffer){let o=Buffer.from(p),P=new SharedArrayBuffer(o.byteLength);return new Uint8Array(P).set(o),l=P,i=o.toString(d),{content:i,sharedBuffer:l}}let s=U.readFileSync(t.absPath),k=new SharedArrayBuffer(s.byteLength);return new Uint8Array(k).set(s),l=k,i=s.toString(d),{content:i,sharedBuffer:l}},I=()=>{let s=B(n,t.relPath,m),k=f();h.postMessage({type:"result",requestId:e.requestId,role:"index",relPath:t.relPath,result:{payload:s.payload,meta:{size:s.fileSize,mtime:s.mtime},snapshotSummary:M(k.sharedBuffer,t.relPath,t.size,t.mtime,d,k.content)}})},g=`${c}:${n}`,y=G.get(g);if(!y)try{u("creating language indexer",{role:r,requestId:e.requestId,lang:n,projectRoot:c});let s=z(n);if(!O(s))throw new Error(`${n} is not a worker-indexed language`);y=s.createIndexer(c),G.set(g,y),u("language indexer ready",{role:r,requestId:e.requestId,lang:n,projectRoot:c})}catch(s){u("language indexer create failed",{role:r,requestId:e.requestId,lang:n,error:s?.message||String(s),stack:s?.stack??null}),I();return}({content:i,sharedBuffer:l}=f());let a;try{a=await y.process({absPath:t.absPath,relPath:t.relPath,content:i,meta:m,preDeleted:!!t.preDeleted,lang:n,indexAllNodes:t.indexAllNodes})}catch(s){u("process failed",{role:r,requestId:e.requestId,lang:n,relPath:t.relPath,error:s?.message||String(s),stack:s?.stack??null}),I();return}h.postMessage({type:"result",requestId:e.requestId,role:"index",relPath:t.relPath,result:{payload:a.payload,meta:{size:a.fileSize,mtime:a.mtime},snapshotSummary:M(l,t.relPath,t.size,t.mtime,d,i)}})}catch(n){u("process wrapper failed",{role:r,requestId:e.requestId,relPath:t.relPath,error:n?.message||String(n),stack:n?.stack??null});try{let i=t.lang??"ts",l=U.readFileSync(t.absPath),f=new SharedArrayBuffer(l.byteLength);new Uint8Array(f).set(l);let I=l.toString(d),g=B(i,t.relPath,m);h.postMessage({type:"result",requestId:e.requestId,role:"index",relPath:t.relPath,result:{payload:g.payload,meta:{size:g.fileSize,mtime:g.mtime},snapshotSummary:M(f,t.relPath,t.size,t.mtime,d,I)}})}catch(i){h.postMessage({type:"error",requestId:e.requestId,message:i?.message||n?.message||String(i??n),stack:i?.stack??n?.stack})}}return}e.cmd==="close"&&h.postMessage({type:"closed"})});process.on("uncaughtException",e=>{try{h.postMessage({type:"error",message:e?.message||String(e),stack:e?.stack})}catch{}});process.on("unhandledRejection",e=>{try{h.postMessage({type:"error",message:String(e)})}catch{}});
1
+ import{a as B,b as O,c as q,d as A,e as z,f as F,i as C}from"./chunk-Z7LW7C4Z.mjs";import"./chunk-ODST7O2H.mjs";import{c as L}from"./chunk-AYCBSZ56.mjs";import{parentPort as h,threadId as te}from"worker_threads";import U from"fs";import $ from"path";import{promises as K}from"fs";import X from"ignore";import{createHash as re}from"crypto";var Z=Math.max(1,Number(process.env.PANDO_BATCH_INDEX_MAX_FILES||"64")),ee=Math.max(1,Number(process.env.PANDO_BATCH_INDEX_MAX_BYTES||`${1024*1024}`)),ae=Math.max(1,Number(process.env.PANDO_BATCH_INDEX_MAX_WAIT_MS||"15")),oe=Math.max(Z,Number(process.env.PANDO_BATCH_INDEX_MAX_PENDING_FILES||"256")),de=Math.max(ee,Number(process.env.PANDO_BATCH_INDEX_MAX_PENDING_BYTES||`${8*1024*1024}`));var ve=1*1024*1024,xe=Math.max(3e4,Number(process.env.PANDO_WORKER_INIT_TIMEOUT_MS||12e4)),Pe=q();function N(e,r){return Buffer.from(e).toString(r)}function M(e,r,l,t,d,p){let m=Buffer.from(e),n=re("sha1").update(m).digest("hex"),i=p??m.toString(d),c=i?i.split(/\r?\n/).length:0;return{relPath:r,size:l,mtime:t,objectId:n,lineCount:c,encoding:d}}if(!h)throw new Error("Indexer worker must be spawned as a worker thread");L();function u(e,r){try{if(r===void 0){console.error(`[${new Date().toISOString()}] [IndexerWorker] ${e}`);return}console.error(`[${new Date().toISOString()}] [IndexerWorker] ${e} ${JSON.stringify({pid:process.pid,threadId:te,...r&&typeof r=="object"&&!Array.isArray(r)?r:{details:r}})}`)}catch{}}u("module loaded",{cwd:process.cwd(),hasParentPort:!!h,envWorkerRoot:process.env.PANDO_WORKER_SCRIPT_DIR??null,envRuntimeRoot:process.env.PANDO_RUNTIME_ROOT??null});var G=new Map,D="",T="index",x=new Map,I=new Set;function H(e,r){return $.relative(e,r).replace(/\\/g,"/")}function se(e,r){let l=(r||[]).map(t=>typeof t=="string"?t.trim():"").filter(Boolean).map(t=>t.replace(/^[\\/]+/,"").replace(/[\\/]+$/,"")).map(t=>t.endsWith("/")?t:`${t}/`);return l.length?t=>{let d=H(e,t);if(!d||d.startsWith(".."))return!1;let p=d.endsWith("/")?d:`${d}/`;return l.some(m=>p.startsWith(m))}:null}async function ie(e){await new Promise(r=>{x.set(e,r)})}h.on("message",async e=>{if(e.cmd==="scan-ack"){let r=x.get(e.requestId);if(r){x.delete(e.requestId);try{r()}catch{}}return}if(e.cmd==="scan-cancel"){I.add(e.requestId);let r=x.get(e.requestId);if(r){x.delete(e.requestId);try{r()}catch{}}return}if(e.cmd==="init"){try{u("init received",{mode:e.mode??"index",projectRoot:typeof e.projectRoot=="string"?e.projectRoot:null}),typeof e.projectRoot=="string"&&(D=e.projectRoot),T=e.mode??"index",u("init completed",{mode:T,projectRoot:D}),h.postMessage({type:"ready"})}catch(r){u("init failed",{error:r?.message||String(r),stack:r?.stack??null}),h.postMessage({type:"error",message:`init failed: ${r?.message||r}`,stack:r?.stack})}return}if(e.cmd==="scan"){let r=e.requestId,l=typeof e.projectRoot=="string"?e.projectRoot:D;if(u("scan received",{requestId:r,projectRoot:l||null,batchSize:e.batchSize??null,maxFileBytes:e.maxFileBytes??null,excludeDirs:Array.isArray(e.excludeDirs)?e.excludeDirs.slice(0,20):[]}),!l){h.postMessage({type:"error",requestId:r,message:"worker not initialized"});return}let t=Math.max(1,Math.min(500,Number(e.batchSize||100))),d=Math.max(1,Number(e.maxFileBytes||1*1024*1024)),p=e.languageSupport,m=F(p),n=se(l,e.excludeDirs??[]),i=new Set(["node_modules",".git",".pando-data"]),c=o=>o.replace(/\\/g,"/"),f=await C(l,""),v=X().add(f),g=[{dir:l,relDir:"",rules:f,ig:v}],y=0,a=0,s=[],k=async()=>{s.length&&(h.postMessage({type:"scan:batch",requestId:r,files:s}),s=[],await ie(r))};try{for(;g.length&&!I.has(r);){let o=g.pop(),P=[];try{P=await K.readdir(o.dir,{withFileTypes:!0})}catch{a+=1;continue}for(let S of P){if(I.has(r))break;let w=$.join(o.dir,S.name);if(S.isSymbolicLink?.()){a+=1;continue}if(S.isDirectory()){if(i.has(S.name)){a+=1;continue}if(n?.(w)){a+=1;continue}let Y=o.relDir?`${o.relDir}/${S.name}`:S.name,R=c(Y);if(o.ig.ignores(R)){a+=1;continue}let E=o.rules.slice(),j=await C(w,R);j.length&&E.push(...j);let Q=X().add(E);g.push({dir:w,relDir:R,rules:E,ig:Q});continue}if(!S.isFile()){a+=1;continue}if(n?.(w)){a+=1;continue}let b=H(l,w);if(!b||b.startsWith("..")){a+=1;continue}if(o.ig.ignores(b)){a+=1;continue}let J=$.extname(S.name).toLowerCase();if(!m.has(J)){a+=1;continue}let _=A(b);if(!_){a+=1;continue}let W;try{W=await K.stat(w)}catch{a+=1;continue}if(W.size>d){a+=1;continue}s.push({relPath:b,absPath:w,mtimeMs:Math.floor(W.mtimeMs),size:W.size,lang:_}),y+=1,s.length>=t&&await k()}}I.has(r)||await k(),h.postMessage({type:"scan:done",requestId:r,discovered:y,skipped:a,cancelled:I.has(r)}),u("scan complete",{requestId:r,discovered:y,skipped:a,cancelled:I.has(r)})}catch(o){u("scan failed",{requestId:r,error:o?.message||String(o),stack:o?.stack??null}),h.postMessage({type:"error",requestId:r,message:o?.message||String(o),stack:o?.stack})}finally{I.delete(r),x.delete(r)}return}if(e.cmd==="process"){let r=e.role??T,l=typeof e.projectRoot=="string"?e.projectRoot:D;if(!l){h.postMessage({type:"error",requestId:e.requestId,message:"worker not initialized"});return}let{file:t}=e,d=t.encoding??"utf8",p=t.sharedBuffer,m={size:t.size,mtime:t.mtime};try{let n=t.lang??"ts",i,c,f=()=>{if(c&&typeof i=="string")return{content:i,sharedBuffer:c};if(p instanceof SharedArrayBuffer)return c=p,i=N(p,d),{content:i,sharedBuffer:c};if(p instanceof ArrayBuffer){let o=Buffer.from(p),P=new SharedArrayBuffer(o.byteLength);return new Uint8Array(P).set(o),c=P,i=o.toString(d),{content:i,sharedBuffer:c}}let s=U.readFileSync(t.absPath),k=new SharedArrayBuffer(s.byteLength);return new Uint8Array(k).set(s),c=k,i=s.toString(d),{content:i,sharedBuffer:c}},v=()=>{let s=B(n,t.relPath,m),k=f();h.postMessage({type:"result",requestId:e.requestId,role:"index",relPath:t.relPath,result:{payload:s.payload,meta:{size:s.fileSize,mtime:s.mtime},snapshotSummary:M(k.sharedBuffer,t.relPath,t.size,t.mtime,d,k.content)}})},g=`${l}:${n}`,y=G.get(g);if(!y)try{u("creating language indexer",{role:r,requestId:e.requestId,lang:n,projectRoot:l});let s=z(n);if(!O(s))throw new Error(`${n} is not a worker-indexed language`);y=s.createIndexer(l),G.set(g,y),u("language indexer ready",{role:r,requestId:e.requestId,lang:n,projectRoot:l})}catch(s){u("language indexer create failed",{role:r,requestId:e.requestId,lang:n,error:s?.message||String(s),stack:s?.stack??null}),v();return}({content:i,sharedBuffer:c}=f());let a;try{a=await y.process({absPath:t.absPath,relPath:t.relPath,content:i,meta:m,preDeleted:!!t.preDeleted,lang:n})}catch(s){u("process failed",{role:r,requestId:e.requestId,lang:n,relPath:t.relPath,error:s?.message||String(s),stack:s?.stack??null}),v();return}h.postMessage({type:"result",requestId:e.requestId,role:"index",relPath:t.relPath,result:{payload:a.payload,meta:{size:a.fileSize,mtime:a.mtime},snapshotSummary:M(c,t.relPath,t.size,t.mtime,d,i)}})}catch(n){u("process wrapper failed",{role:r,requestId:e.requestId,relPath:t.relPath,error:n?.message||String(n),stack:n?.stack??null});try{let i=t.lang??"ts",c=U.readFileSync(t.absPath),f=new SharedArrayBuffer(c.byteLength);new Uint8Array(f).set(c);let v=c.toString(d),g=B(i,t.relPath,m);h.postMessage({type:"result",requestId:e.requestId,role:"index",relPath:t.relPath,result:{payload:g.payload,meta:{size:g.fileSize,mtime:g.mtime},snapshotSummary:M(f,t.relPath,t.size,t.mtime,d,v)}})}catch(i){h.postMessage({type:"error",requestId:e.requestId,message:i?.message||n?.message||String(i??n),stack:i?.stack??n?.stack})}}return}e.cmd==="close"&&h.postMessage({type:"closed"})});process.on("uncaughtException",e=>{try{h.postMessage({type:"error",message:e?.message||String(e),stack:e?.stack})}catch{}});process.on("unhandledRejection",e=>{try{h.postMessage({type:"error",message:String(e)})}catch{}});
@@ -1,6 +1,10 @@
1
- import{a as _,h as x,i as K}from"./chunk-LGZQCDFH.mjs";import{a as Y,b as it,c as V,e as R}from"./chunk-ODST7O2H.mjs";import{a as J,b as Tt}from"./chunk-Z5RGEDVQ.mjs";import{a as Dt,c as st}from"./chunk-AYCBSZ56.mjs";import{parentPort as j}from"worker_threads";import rt from"path";import*as o from"fs";import*as I from"path";import*as g from"isomorphic-git";import{execFileSync as v}from"child_process";V();import*as Q from"path";function nt(i){let t=Y(i);return{root:t,historyGit:Q.join(t,"history.git"),workdir:Q.join(t,"workdir")}}function f(i,t){try{_.info(i,t)}catch{}}function ot(i,t){try{_.warn(i,t)}catch{}}var F=class{constructor(t){this.repoDir=t;this.stack=[{name:"",entries:[],dirNames:new Set,fileNames:new Set}]}currentDirs(){return this.stack.slice(1).map(t=>t.name)}lcpLen(t,e){let n=0;for(;n<t.length&&n<e.length&&t[n]===e[n];)n++;return n}async flushTop(){if(this.stack.length<=1)return;let t=this.stack.pop();t.entries.sort((r,s)=>r.path.localeCompare(s.path));let e=await g.writeTree({fs:o,dir:this.repoDir,tree:t.entries}),n=this.stack[this.stack.length-1];n.entries.push({mode:"040000",path:t.name,oid:e,type:"tree"}),n.dirNames.add(t.name)}async addFile(t,e){let n=t.replace(/^\.\//,"").replace(/\\/g,"/"),r=n.split("/").filter(Boolean);if(!r.length)return;let s=r.slice(0,-1),a=r[r.length-1],p=this.currentDirs(),m=this.lcpLen(p,s);for(let b=p.length;b>m;b--)await this.flushTop();for(let b=m;b<s.length;b++){let l=s[b];if(this.stack[this.stack.length-1].fileNames.has(l))throw new Error(`Path conflict: file exists where directory expected: ${s.slice(0,b+1).join("/")}`);this.stack.push({name:l,entries:[],dirNames:new Set,fileNames:new Set})}let u=this.stack[this.stack.length-1];if(u.dirNames.has(a))throw new Error(`Path conflict: directory exists where file expected: ${n}`);u.entries.push({mode:"100644",path:a,oid:e,type:"blob"}),u.fileNames.add(a)}async finish(){for(;this.stack.length>1;)await this.flushTop();let t=this.stack[0];return t.entries.sort((e,n)=>e.path.localeCompare(n.path)),g.writeTree({fs:o,dir:this.repoDir,tree:t.entries})}},H=class{constructor(t){this.baseDir=t.baseDir;let e=nt(t.shadowDir??t.baseDir);this.repoDir=I.join(e.root,"history")}async ensureInitialized(){o.mkdirSync(this.repoDir,{recursive:!0});let t=I.join(this.repoDir,".git");if(o.existsSync(t)){await this.ensureDefaultGitignore();return}let e=I.join(this.repoDir,".init.lock"),n=s=>new Promise(a=>setTimeout(a,s)),r=null;try{try{r=o.openSync(e,"wx"),o.writeFileSync(r,String(Date.now()))}catch{let s=Date.now(),a=3e4;for(;!o.existsSync(t);){try{let p=o.statSync(e);if(Date.now()-p.mtimeMs>a){try{o.unlinkSync(e)}catch{}break}}catch{}if(Date.now()-s>a)break;await n(200)}if(o.existsSync(t))return;r=o.openSync(e,"wx"),o.writeFileSync(r,String(Date.now()))}if(o.existsSync(t))return;f(`[${new Date().toISOString()}] [GitHistoryStore] Initializing history repo at ${this.repoDir}`),await g.init({fs:o,dir:this.repoDir}),f(`[${new Date().toISOString()}] [GitHistoryStore] git.init OK`),await g.setConfig({fs:o,dir:this.repoDir,path:"user.name",value:"ast-db"}),await g.setConfig({fs:o,dir:this.repoDir,path:"user.email",value:"ast-db@example.com"}),f(`[${new Date().toISOString()}] [GitHistoryStore] git config set (user.name/user.email)`),o.writeFileSync(I.join(this.repoDir,".gitignore"),`# ast history repo
2
- `),f(`[${new Date().toISOString()}] [GitHistoryStore] wrote .gitignore`)}finally{try{r!=null&&o.closeSync(r)}catch{}try{o.existsSync(e)&&o.unlinkSync(e)}catch{}}await this.ensureDefaultGitignore()}async ensureDefaultGitignore(){let t=I.join(this.repoDir,".gitignore");if(!o.existsSync(t))try{o.mkdirSync(I.dirname(t),{recursive:!0}),o.writeFileSync(t,`# ast history repo
3
- `,"utf8");try{await g.add({fs:o,dir:this.repoDir,filepath:".gitignore"})}catch{}f(`[GitHistoryStore] restored missing .gitignore at ${t}`)}catch(e){ot(`[GitHistoryStore] failed to recreate .gitignore: ${e?.message||e}`)}}normalizeLogicalPath(t){return String(t||"").replace(/\\/g,"/").replace(/^(?:\.\/)+/,"").replace(/^\/+/,"")}gitExists(){try{return v("git",["--version"],{cwd:this.repoDir,stdio:"ignore"}),!0}catch{return!1}}createSnapshotNative(t,e,n,r){let a=(typeof n=="string"?n.match(/^AST-Restore-Trace-Id:\s*(.+)$/m):null)?.[1]?.trim()||null,p=e;if(!p)try{p=v("git",["rev-parse","HEAD"],{cwd:this.repoDir,encoding:"utf8"}).trim()}catch{p=void 0}let m=new Map,u=Date.now();try{f("[GitHistoryStore] native snapshot start",{traceId:a,repoDir:this.repoDir,memberCount:t.length,parentOid:p||null})}catch{}for(let h=0;h<t.length;h++){let y=t[h];if(y.content==null)throw new Error(`Direct snapshot requires content for ${y.logicalPath}`);let S=Buffer.isBuffer(y.content)?y.content:Buffer.from(y.content),c=this.normalizeLogicalPath(y.logicalPath);if(!c)throw new Error("Direct snapshot requires non-empty logicalPath");let d=Date.now();try{f("[GitHistoryStore] native hash-object start",{traceId:a,repoDir:this.repoDir,index:h+1,total:t.length,logicalPath:c,bytes:S.length})}catch{}let D;try{D=v("git",["hash-object","-w","--stdin"],{cwd:this.repoDir,input:S}).toString("utf8").trim()}catch(T){try{ot("[GitHistoryStore] native hash-object failed",{traceId:a,repoDir:this.repoDir,index:h+1,total:t.length,logicalPath:c,bytes:S.length,durationMs:Date.now()-d,message:T?.message||String(T),status:T?.status??null,signal:T?.signal??null,stdout:T?.stdout?String(T.stdout).slice(0,500):null,stderr:T?.stderr?String(T.stderr).slice(0,500):null})}catch{}throw T}let E=Date.now()-d;try{(E>1e3||h<3||h===t.length-1)&&f("[GitHistoryStore] native hash-object done",{traceId:a,repoDir:this.repoDir,index:h+1,total:t.length,logicalPath:c,bytes:S.length,durationMs:E,oid:D})}catch{}m.set(c,D)}try{f("[GitHistoryStore] native hash-object phase complete",{traceId:a,repoDir:this.repoDir,memberCount:t.length,durationMs:Date.now()-u})}catch{}let b=I.join(this.repoDir,`.pando-index-${process.pid}-${Date.now()}`),l={...process.env,GIT_INDEX_FILE:b};try{let h=Date.now();try{f("[GitHistoryStore] native read-tree begin",{traceId:a,repoDir:this.repoDir,tmpIndex:b})}catch{}v("git",["read-tree","--empty"],{cwd:this.repoDir,env:l});try{f("[GitHistoryStore] native read-tree complete",{traceId:a,repoDir:this.repoDir,durationMs:Date.now()-h})}catch{}let y=Array.from(m.keys()).sort((k,C)=>k.localeCompare(C)),S=Date.now();for(let k of y){let C=m.get(k);v("git",["update-index","--add","--cacheinfo","100644",C,k],{cwd:this.repoDir,env:l})}try{f("[GitHistoryStore] native update-index complete",{traceId:a,repoDir:this.repoDir,entryCount:y.length,durationMs:Date.now()-S})}catch{}let c=Date.now();try{f("[GitHistoryStore] native write-tree begin",{traceId:a,repoDir:this.repoDir,entryCount:y.length})}catch{}let d=v("git",["write-tree"],{cwd:this.repoDir,env:l}).toString("utf8").trim();try{f("[GitHistoryStore] native write-tree complete",{traceId:a,repoDir:this.repoDir,treeOid:d,durationMs:Date.now()-c})}catch{}let D=["commit-tree",d];p&&D.push("-p",p),n&&D.push("-m",n);let E=Date.now();try{f("[GitHistoryStore] native commit-tree begin",{traceId:a,repoDir:this.repoDir,treeOid:d,parentOid:p||null})}catch{}let T=v("git",D,{cwd:this.repoDir}).toString("utf8").trim();try{f("[GitHistoryStore] native commit-tree complete",{traceId:a,repoDir:this.repoDir,commitOid:T,durationMs:Date.now()-E})}catch{}let $=Date.now();try{f("[GitHistoryStore] native update-ref begin",{traceId:a,repoDir:this.repoDir,commitOid:T})}catch{}v("git",["update-ref","refs/heads/master",T],{cwd:this.repoDir});try{f("[GitHistoryStore] native update-ref complete",{traceId:a,repoDir:this.repoDir,commitOid:T,durationMs:Date.now()-$})}catch{}return{snapshotId:T,parent:p}}finally{try{o.unlinkSync(b)}catch{}try{o.unlinkSync(`${b}.lock`)}catch{}}}async readObject(t){let{object:e}=await g.readObject({fs:o,dir:this.repoDir,oid:t});return Buffer.from(e)}async hasObject(t){try{return await g.readObject({fs:o,dir:this.repoDir,oid:t}),!0}catch{return!1}}async createSnapshot(t,e){x(e,"Snapshot cancelled"),await this.ensureInitialized(),f(`[${new Date().toISOString()}] [GitHistoryStore] Creating snapshot (streaming) with ${t.members.length} members`);let n=[...t.members].map(w=>({...w,logicalPath:this.normalizeLogicalPath(w.logicalPath)})).filter(w=>!!w.logicalPath).sort((w,P)=>w.logicalPath.localeCompare(P.logicalPath)),r=this.gitExists()&&!e;try{r?_.info("[GitHistoryStore] Using native git snapshot path",{members:n.length}):_.info("[GitHistoryStore] Using JS snapshot path",{members:n.length,git:!1,cancellable:!!e})}catch{}if(r)try{return this.createSnapshotNative(n,t.parent,t.message,t.when).snapshotId}catch(w){try{_.warn(`[GitHistoryStore] Native git path failed; falling back to JS path: ${w?.message||w}`)}catch{}}let s=Date.now(),a=w=>w.toString("hex"),p=w=>Dt("crypto").createHash("sha1").update(w).digest(),m=w=>{let P=Buffer.from(`blob ${w.length}\0`,"utf8"),A=Buffer.concat([P,w]);return a(p(A))},u=Math.max(1,Math.min(64,Number(process.env.SNAPSHOT_BLOB_CONCURRENCY||16))),b=String(process.env.SNAPSHOT_PRECOMPUTE_OIDS||"1")!=="0";try{_.info("[GitHistoryStore] JS snapshot settings",{SNAPSHOT_BLOB_CONCURRENCY:u,SNAPSHOT_PRECOMPUTE_OIDS:b})}catch{}let l=new Map,h=0,y=0,S=0,c=n.map(w=>({path:w.logicalPath,buf:Buffer.isBuffer(w.content)?w.content:Buffer.from(w.content)})),d=async()=>{for(;;){x(e,"Snapshot cancelled");let w;if(h<c.length)w=c[h++];else break;let P;if(b)try{let A=m(w.buf);await this.hasObject(A)&&(P=A,S++)}catch{}if(P||(P=await g.writeBlob({fs:o,dir:this.repoDir,blob:w.buf}),y++),x(e,"Snapshot cancelled"),!P)throw new Error("Failed to compute blob object id");l.set(w.path,P)}},D=Array.from({length:Math.min(u,c.length)},()=>d());await Promise.all(D),x(e,"Snapshot cancelled"),f(`[GitHistoryStore] Blobs ready wrote=${y} skipped=${S} in ${Date.now()-s}ms`);let E=new F(this.repoDir),T=Array.from(l.keys()).sort((w,P)=>w.localeCompare(P));for(let w of T)x(e,"Snapshot cancelled"),await E.addFile(w,l.get(w));x(e,"Snapshot cancelled");let $=Date.now(),k=await E.finish();f(`[GitHistoryStore] Wrote tree(s). root=${k} in ${Date.now()-$}ms`);let C=t.parent;if(!C)try{C=await g.resolveRef({fs:o,dir:this.repoDir,ref:"HEAD"})}catch{}x(e,"Snapshot cancelled");let N=t.when?Math.floor(t.when/1e3):Math.floor(Date.now()/1e3),G=new Date(N*1e3).getTimezoneOffset(),B=await g.commit({fs:o,dir:this.repoDir,message:t.message,parent:C?[C]:[],tree:k,author:{name:"ast-db",email:"ast-db@example.com",timestamp:N,timezoneOffset:G},committer:{name:"ast-db",email:"ast-db@example.com",timestamp:N,timezoneOffset:G}});return await g.writeRef({fs:o,dir:this.repoDir,ref:"refs/heads/master",value:B,force:!0}),f(`[GitHistoryStore] Snapshot commit oid ${B}`),B}async listSnapshotMembers(t){await this.ensureInitialized();let e=s=>Math.round((s||0)/(1024*1024)),n=()=>{let s=process.memoryUsage();return`rss=${e(s.rss)}MB heapUsed=${e(s.heapUsed)}MB heapTotal=${e(s.heapTotal)}MB`},r=[];return f(`[${new Date().toISOString()}] [GitHistoryStore] listSnapshotMembers(${t}) start (${n()})`),await g.walk({fs:o,dir:this.repoDir,trees:[g.TREE({ref:t})],map:async(s,[a])=>{if(!a)return;if(await a.type()==="blob"){let m=await a.oid();r.push({logicalPath:s,objectId:m})}}}),f(`[${new Date().toISOString()}] [GitHistoryStore] listSnapshotMembers(${t}) -> ${r.length} blobs`),r.filter(s=>s.logicalPath&&s.logicalPath!==".").map(s=>({logicalPath:s.logicalPath.replace(/^\.\//,""),objectId:s.objectId}))}async readCommit(t){let{commit:e}=await g.readCommit({fs:o,dir:this.repoDir,oid:t});return{message:e.message,committer:e.committer}}async readCommitParent(t){let{commit:e}=await g.readCommit({fs:o,dir:this.repoDir,oid:t});return Array.isArray(e.parent)&&e.parent.length>0?String(e.parent[0]):void 0}async createSnapshotFromDisk(t,e){x(e,"Snapshot cancelled"),await this.ensureInitialized(),f(`[${new Date().toISOString()}] [GitHistoryStore] Creating snapshot from disk (streaming) with ${t.relPaths.length} members`);let n=[...t.relPaths].map(y=>this.normalizeLogicalPath(y)).filter(Boolean).sort((y,S)=>y.localeCompare(S)),r=Date.now(),s=new F(this.repoDir),a=0;for(let y of n){x(e,"Snapshot cancelled");let S=I.join(this.baseDir,y);try{let c=o.readFileSync(S),d=await g.writeBlob({fs:o,dir:this.repoDir,blob:c});await s.addFile(y,d),a++}catch{}}f(`[GitHistoryStore] Wrote ${a} blobs (disk) in ${Date.now()-r}ms`),x(e,"Snapshot cancelled");let p=Date.now(),m=await s.finish();f(`[GitHistoryStore] Wrote tree(s) (disk). root=${m} in ${Date.now()-p}ms`);let u=t.parent;if(!u)try{u=await g.resolveRef({fs:o,dir:this.repoDir,ref:"HEAD"})}catch{}x(e,"Snapshot cancelled");let b=t.when?Math.floor(t.when/1e3):Math.floor(Date.now()/1e3),l=new Date(b*1e3).getTimezoneOffset(),h=await g.commit({fs:o,dir:this.repoDir,message:t.message,parent:u?[u]:[],tree:m,author:{name:"ast-db",email:"ast-db@example.com",timestamp:b,timezoneOffset:l},committer:{name:"ast-db",email:"ast-db@example.com",timestamp:b,timezoneOffset:l}});return await g.writeRef({fs:o,dir:this.repoDir,ref:"refs/heads/master",value:h,force:!0}),f(`[GitHistoryStore] Snapshot commit oid ${h}`),h}async createSnapshotFromDiskAndCapturedIfChanged(t){await this.ensureInitialized();let e=new Map;for(let c of t.capturedMembers||[]){let d=this.normalizeLogicalPath(c.logicalPath);!d||c.content==null||e.has(d)||e.set(d,Buffer.isBuffer(c.content)?c.content:Buffer.from(c.content))}f(`[${new Date().toISOString()}] [GitHistoryStore] Creating snapshot from disk+captured (diff) with ${t.relPaths.length} members, captured=${e.size}`);let n=[...t.relPaths].map(c=>this.normalizeLogicalPath(c)).filter(Boolean).sort((c,d)=>c.localeCompare(d)),r=Date.now(),s=new F(this.repoDir),a=0,p=0,m=0;for(let c of n)try{let d=e.get(c),D=d??o.readFileSync(I.join(this.baseDir,c)),E=await g.writeBlob({fs:o,dir:this.repoDir,blob:D});await s.addFile(c,E),a++,d?p++:m++}catch{}f(`[GitHistoryStore] Wrote ${a} blobs (captured=${p}, disk=${m}) in ${Date.now()-r}ms`);let u=Date.now(),b=await s.finish();f(`[GitHistoryStore] Wrote tree(s) (disk+captured). root=${b} in ${Date.now()-u}ms`);let l=t.parent;if(!l)try{l=await g.resolveRef({fs:o,dir:this.repoDir,ref:"HEAD"})}catch{}if(l)try{let{commit:c}=await g.readCommit({fs:o,dir:this.repoDir,oid:l});if(c?.tree===b){f("[GitHistoryStore] Snapshot identical to parent; skipping commit",{parentOid:l,tree:b});let d=await this.readCommitParent(l);return{snapshotId:l,identical:!0,parent:d}}}catch(c){f("[GitHistoryStore] Parent read failed; proceeding with commit",{error:c?.message||String(c)})}let h=t.when?Math.floor(t.when/1e3):Math.floor(Date.now()/1e3),y=new Date(h*1e3).getTimezoneOffset(),S=await g.commit({fs:o,dir:this.repoDir,message:t.message,parent:l?[l]:[],tree:b,author:{name:"ast-db",email:"ast-db@example.com",timestamp:h,timezoneOffset:y},committer:{name:"ast-db",email:"ast-db@example.com",timestamp:h,timezoneOffset:y}});return await g.writeRef({fs:o,dir:this.repoDir,ref:"refs/heads/master",value:S,force:!0}),f(`[GitHistoryStore] Snapshot commit oid ${S}`),{snapshotId:S,identical:!1,parent:l}}async createSnapshotFromDiskIfChanged(t){await this.ensureInitialized(),f(`[${new Date().toISOString()}] [GitHistoryStore] Creating snapshot from disk (diff) with ${t.relPaths.length} members`);let e=[...t.relPaths].map(h=>this.normalizeLogicalPath(h)).filter(Boolean).sort((h,y)=>h.localeCompare(y)),n=Date.now(),r=new F(this.repoDir),s=0;for(let h of e){let y=I.join(this.baseDir,h);try{let S=o.readFileSync(y),c=await g.writeBlob({fs:o,dir:this.repoDir,blob:S});await r.addFile(h,c),s++}catch{}}f(`[GitHistoryStore] Wrote ${s} blobs (disk) in ${Date.now()-n}ms`);let a=Date.now(),p=await r.finish();f(`[GitHistoryStore] Wrote tree(s) (disk). root=${p} in ${Date.now()-a}ms`);let m=t.parent;if(!m)try{m=await g.resolveRef({fs:o,dir:this.repoDir,ref:"HEAD"})}catch{}if(m)try{let{commit:h}=await g.readCommit({fs:o,dir:this.repoDir,oid:m});if(h?.tree===p){f("[GitHistoryStore] Snapshot identical to parent; skipping commit",{parentOid:m,tree:p});let y=await this.readCommitParent(m);return{snapshotId:m,identical:!0,parent:y}}}catch(h){f("[GitHistoryStore] Parent read failed; proceeding with commit",{error:h?.message||String(h)})}let u=t.when?Math.floor(t.when/1e3):Math.floor(Date.now()/1e3),b=new Date(u*1e3).getTimezoneOffset(),l=await g.commit({fs:o,dir:this.repoDir,message:t.message,parent:m?[m]:[],tree:p,author:{name:"ast-db",email:"ast-db@example.com",timestamp:u,timezoneOffset:b},committer:{name:"ast-db",email:"ast-db@example.com",timestamp:u,timezoneOffset:b}});return await g.writeRef({fs:o,dir:this.repoDir,ref:"refs/heads/master",value:l,force:!0}),f(`[GitHistoryStore] Snapshot commit oid ${l}`),{snapshotId:l,identical:!1,parent:m}}};function Z(i){let t={},e=i.split(/\r?\n/);for(let n of e){let r=n.match(/^([A-Za-z0-9-]+):\s*(.*)$/);r&&(t[r[1]]=r[2])}return t}import Et from"fs";import L from"path";import at from"ignore";import{Project as Wt}from"ts-morph";var Pt=new Set(["node_modules",".git",".pando-data",".clj-kondo"]);function lt(i,t){if(!t?.length)return null;let e=t.map(r=>r.replace(/^\/+/,"").replace(/\/+$/,"")).filter(Boolean).map(r=>`${r}/`);if(!e.length)return null;let n=r=>r.replace(/\\/g,"/");return r=>{let s=n(L.relative(i,r));if(!s||s.startsWith(".."))return!1;let a=s.endsWith("/")?s:`${s}/`;return e.some(p=>a.startsWith(p))}}function ht(i,t){return xt(i,t,null)}function xt(i,t,e){let n=t?.shouldExclude||null,r=[],s=L.resolve(t?.gitignoreRoot??i),a=K(s,""),p=at().add(a),m=[{dir:i,relDir:"",rules:a,ig:p}];for(;m.length;){let u=m.pop(),b=[];try{b=Et.readdirSync(u.dir,{withFileTypes:!0})}catch{continue}for(let l of b){let h=L.join(u.dir,l.name);if(!(typeof l.isSymbolicLink=="function"&&l.isSymbolicLink())){if(l.isDirectory()){if(Pt.has(l.name)||n?.(h))continue;let S=u.relDir?`${u.relDir}/${l.name}`:l.name,c=ct(S);if(u.ig.ignores(c))continue;let d=u.rules.slice(),D=K(h,c);D.length&&d.push(...D);let E=D.length?at().add(d):u.ig;m.push({dir:h,relDir:c,rules:d,ig:E})}else if(l.isFile()){if(n?.(h))continue;let S=ct(L.relative(i,h));if(u.ig.ignores(S))continue;if(e===null)r.push(h);else{let c=L.extname(l.name).toLowerCase();e.has(c)&&r.push(h)}}}}}return r}function ct(i){return i.replace(/\\/g,"/")}V();Tt();V();import q from"fs";import It from"path";function pt(i){i.pragma("journal_mode = WAL"),i.pragma("synchronous = NORMAL"),i.pragma("busy_timeout = 10000");try{i.pragma("temp_store = MEMORY")}catch{}i.exec(`
1
+ import{g as P,h as J}from"./chunk-Z7LW7C4Z.mjs";import{a as V,b as nt,c as K,e as R}from"./chunk-ODST7O2H.mjs";import{a as Q,b as Et}from"./chunk-Z5RGEDVQ.mjs";import{a as Tt,c as st}from"./chunk-AYCBSZ56.mjs";import{parentPort as $}from"worker_threads";import it from"path";import*as o from"fs";import*as I from"path";import*as g from"isomorphic-git";function xt(){return new Date().toISOString()}function U(r,t,e){let n=`[${xt()}] [${r.toUpperCase()}] ${t}`;if(!e)return n;try{return n+" "+JSON.stringify(e)}catch{return n}}var _={debug:(r,t)=>{try{process.stderr.write(U("debug",r,t)+`
2
+ `)}catch{}},info:(r,t)=>{try{process.stderr.write(U("info",r,t)+`
3
+ `)}catch{}},warn:(r,t)=>{try{process.stderr.write(U("warn",r,t)+`
4
+ `)}catch{}},error:(r,t)=>{try{process.stderr.write(U("error",r,t)+`
5
+ `)}catch{}}};import{execFileSync as v}from"child_process";K();import*as Z from"path";function ot(r){let t=V(r);return{root:t,historyGit:Z.join(t,"history.git"),workdir:Z.join(t,"workdir")}}function f(r,t){try{_.info(r,t)}catch{}}function at(r,t){try{_.warn(r,t)}catch{}}var F=class{constructor(t){this.repoDir=t;this.stack=[{name:"",entries:[],dirNames:new Set,fileNames:new Set}]}currentDirs(){return this.stack.slice(1).map(t=>t.name)}lcpLen(t,e){let n=0;for(;n<t.length&&n<e.length&&t[n]===e[n];)n++;return n}async flushTop(){if(this.stack.length<=1)return;let t=this.stack.pop();t.entries.sort((i,s)=>i.path.localeCompare(s.path));let e=await g.writeTree({fs:o,dir:this.repoDir,tree:t.entries}),n=this.stack[this.stack.length-1];n.entries.push({mode:"040000",path:t.name,oid:e,type:"tree"}),n.dirNames.add(t.name)}async addFile(t,e){let n=t.replace(/^\.\//,"").replace(/\\/g,"/"),i=n.split("/").filter(Boolean);if(!i.length)return;let s=i.slice(0,-1),a=i[i.length-1],p=this.currentDirs(),m=this.lcpLen(p,s);for(let b=p.length;b>m;b--)await this.flushTop();for(let b=m;b<s.length;b++){let l=s[b];if(this.stack[this.stack.length-1].fileNames.has(l))throw new Error(`Path conflict: file exists where directory expected: ${s.slice(0,b+1).join("/")}`);this.stack.push({name:l,entries:[],dirNames:new Set,fileNames:new Set})}let u=this.stack[this.stack.length-1];if(u.dirNames.has(a))throw new Error(`Path conflict: directory exists where file expected: ${n}`);u.entries.push({mode:"100644",path:a,oid:e,type:"blob"}),u.fileNames.add(a)}async finish(){for(;this.stack.length>1;)await this.flushTop();let t=this.stack[0];return t.entries.sort((e,n)=>e.path.localeCompare(n.path)),g.writeTree({fs:o,dir:this.repoDir,tree:t.entries})}},L=class{constructor(t){this.baseDir=t.baseDir;let e=ot(t.shadowDir??t.baseDir);this.repoDir=I.join(e.root,"history")}async ensureInitialized(){o.mkdirSync(this.repoDir,{recursive:!0});let t=I.join(this.repoDir,".git");if(o.existsSync(t)){await this.ensureDefaultGitignore();return}let e=I.join(this.repoDir,".init.lock"),n=s=>new Promise(a=>setTimeout(a,s)),i=null;try{try{i=o.openSync(e,"wx"),o.writeFileSync(i,String(Date.now()))}catch{let s=Date.now(),a=3e4;for(;!o.existsSync(t);){try{let p=o.statSync(e);if(Date.now()-p.mtimeMs>a){try{o.unlinkSync(e)}catch{}break}}catch{}if(Date.now()-s>a)break;await n(200)}if(o.existsSync(t))return;i=o.openSync(e,"wx"),o.writeFileSync(i,String(Date.now()))}if(o.existsSync(t))return;f(`[${new Date().toISOString()}] [GitHistoryStore] Initializing history repo at ${this.repoDir}`),await g.init({fs:o,dir:this.repoDir}),f(`[${new Date().toISOString()}] [GitHistoryStore] git.init OK`),await g.setConfig({fs:o,dir:this.repoDir,path:"user.name",value:"ast-db"}),await g.setConfig({fs:o,dir:this.repoDir,path:"user.email",value:"ast-db@example.com"}),f(`[${new Date().toISOString()}] [GitHistoryStore] git config set (user.name/user.email)`),o.writeFileSync(I.join(this.repoDir,".gitignore"),`# ast history repo
6
+ `),f(`[${new Date().toISOString()}] [GitHistoryStore] wrote .gitignore`)}finally{try{i!=null&&o.closeSync(i)}catch{}try{o.existsSync(e)&&o.unlinkSync(e)}catch{}}await this.ensureDefaultGitignore()}async ensureDefaultGitignore(){let t=I.join(this.repoDir,".gitignore");if(!o.existsSync(t))try{o.mkdirSync(I.dirname(t),{recursive:!0}),o.writeFileSync(t,`# ast history repo
7
+ `,"utf8");try{await g.add({fs:o,dir:this.repoDir,filepath:".gitignore"})}catch{}f(`[GitHistoryStore] restored missing .gitignore at ${t}`)}catch(e){at(`[GitHistoryStore] failed to recreate .gitignore: ${e?.message||e}`)}}normalizeLogicalPath(t){return String(t||"").replace(/\\/g,"/").replace(/^(?:\.\/)+/,"").replace(/^\/+/,"")}gitExists(){try{return v("git",["--version"],{cwd:this.repoDir,stdio:"ignore"}),!0}catch{return!1}}createSnapshotNative(t,e,n,i){let a=(typeof n=="string"?n.match(/^AST-Restore-Trace-Id:\s*(.+)$/m):null)?.[1]?.trim()||null,p=e;if(!p)try{p=v("git",["rev-parse","HEAD"],{cwd:this.repoDir,encoding:"utf8"}).trim()}catch{p=void 0}let m=new Map,u=Date.now();try{f("[GitHistoryStore] native snapshot start",{traceId:a,repoDir:this.repoDir,memberCount:t.length,parentOid:p||null})}catch{}for(let h=0;h<t.length;h++){let y=t[h];if(y.content==null)throw new Error(`Direct snapshot requires content for ${y.logicalPath}`);let S=Buffer.isBuffer(y.content)?y.content:Buffer.from(y.content),c=this.normalizeLogicalPath(y.logicalPath);if(!c)throw new Error("Direct snapshot requires non-empty logicalPath");let d=Date.now();try{f("[GitHistoryStore] native hash-object start",{traceId:a,repoDir:this.repoDir,index:h+1,total:t.length,logicalPath:c,bytes:S.length})}catch{}let D;try{D=v("git",["hash-object","-w","--stdin"],{cwd:this.repoDir,input:S}).toString("utf8").trim()}catch(T){try{at("[GitHistoryStore] native hash-object failed",{traceId:a,repoDir:this.repoDir,index:h+1,total:t.length,logicalPath:c,bytes:S.length,durationMs:Date.now()-d,message:T?.message||String(T),status:T?.status??null,signal:T?.signal??null,stdout:T?.stdout?String(T.stdout).slice(0,500):null,stderr:T?.stderr?String(T.stderr).slice(0,500):null})}catch{}throw T}let E=Date.now()-d;try{(E>1e3||h<3||h===t.length-1)&&f("[GitHistoryStore] native hash-object done",{traceId:a,repoDir:this.repoDir,index:h+1,total:t.length,logicalPath:c,bytes:S.length,durationMs:E,oid:D})}catch{}m.set(c,D)}try{f("[GitHistoryStore] native hash-object phase complete",{traceId:a,repoDir:this.repoDir,memberCount:t.length,durationMs:Date.now()-u})}catch{}let b=I.join(this.repoDir,`.pando-index-${process.pid}-${Date.now()}`),l={...process.env,GIT_INDEX_FILE:b};try{let h=Date.now();try{f("[GitHistoryStore] native read-tree begin",{traceId:a,repoDir:this.repoDir,tmpIndex:b})}catch{}v("git",["read-tree","--empty"],{cwd:this.repoDir,env:l});try{f("[GitHistoryStore] native read-tree complete",{traceId:a,repoDir:this.repoDir,durationMs:Date.now()-h})}catch{}let y=Array.from(m.keys()).sort((k,O)=>k.localeCompare(O)),S=Date.now();for(let k of y){let O=m.get(k);v("git",["update-index","--add","--cacheinfo","100644",O,k],{cwd:this.repoDir,env:l})}try{f("[GitHistoryStore] native update-index complete",{traceId:a,repoDir:this.repoDir,entryCount:y.length,durationMs:Date.now()-S})}catch{}let c=Date.now();try{f("[GitHistoryStore] native write-tree begin",{traceId:a,repoDir:this.repoDir,entryCount:y.length})}catch{}let d=v("git",["write-tree"],{cwd:this.repoDir,env:l}).toString("utf8").trim();try{f("[GitHistoryStore] native write-tree complete",{traceId:a,repoDir:this.repoDir,treeOid:d,durationMs:Date.now()-c})}catch{}let D=["commit-tree",d];p&&D.push("-p",p),n&&D.push("-m",n);let E=Date.now();try{f("[GitHistoryStore] native commit-tree begin",{traceId:a,repoDir:this.repoDir,treeOid:d,parentOid:p||null})}catch{}let T=v("git",D,{cwd:this.repoDir}).toString("utf8").trim();try{f("[GitHistoryStore] native commit-tree complete",{traceId:a,repoDir:this.repoDir,commitOid:T,durationMs:Date.now()-E})}catch{}let j=Date.now();try{f("[GitHistoryStore] native update-ref begin",{traceId:a,repoDir:this.repoDir,commitOid:T})}catch{}v("git",["update-ref","refs/heads/master",T],{cwd:this.repoDir});try{f("[GitHistoryStore] native update-ref complete",{traceId:a,repoDir:this.repoDir,commitOid:T,durationMs:Date.now()-j})}catch{}return{snapshotId:T,parent:p}}finally{try{o.unlinkSync(b)}catch{}try{o.unlinkSync(`${b}.lock`)}catch{}}}async readObject(t){let{object:e}=await g.readObject({fs:o,dir:this.repoDir,oid:t});return Buffer.from(e)}async hasObject(t){try{return await g.readObject({fs:o,dir:this.repoDir,oid:t}),!0}catch{return!1}}async createSnapshot(t,e){P(e,"Snapshot cancelled"),await this.ensureInitialized(),f(`[${new Date().toISOString()}] [GitHistoryStore] Creating snapshot (streaming) with ${t.members.length} members`);let n=[...t.members].map(w=>({...w,logicalPath:this.normalizeLogicalPath(w.logicalPath)})).filter(w=>!!w.logicalPath).sort((w,x)=>w.logicalPath.localeCompare(x.logicalPath)),i=this.gitExists()&&!e;try{i?_.info("[GitHistoryStore] Using native git snapshot path",{members:n.length}):_.info("[GitHistoryStore] Using JS snapshot path",{members:n.length,git:!1,cancellable:!!e})}catch{}if(i)try{return this.createSnapshotNative(n,t.parent,t.message,t.when).snapshotId}catch(w){try{_.warn(`[GitHistoryStore] Native git path failed; falling back to JS path: ${w?.message||w}`)}catch{}}let s=Date.now(),a=w=>w.toString("hex"),p=w=>Tt("crypto").createHash("sha1").update(w).digest(),m=w=>{let x=Buffer.from(`blob ${w.length}\0`,"utf8"),A=Buffer.concat([x,w]);return a(p(A))},u=Math.max(1,Math.min(64,Number(process.env.SNAPSHOT_BLOB_CONCURRENCY||16))),b=String(process.env.SNAPSHOT_PRECOMPUTE_OIDS||"1")!=="0";try{_.info("[GitHistoryStore] JS snapshot settings",{SNAPSHOT_BLOB_CONCURRENCY:u,SNAPSHOT_PRECOMPUTE_OIDS:b})}catch{}let l=new Map,h=0,y=0,S=0,c=n.map(w=>({path:w.logicalPath,buf:Buffer.isBuffer(w.content)?w.content:Buffer.from(w.content)})),d=async()=>{for(;;){P(e,"Snapshot cancelled");let w;if(h<c.length)w=c[h++];else break;let x;if(b)try{let A=m(w.buf);await this.hasObject(A)&&(x=A,S++)}catch{}if(x||(x=await g.writeBlob({fs:o,dir:this.repoDir,blob:w.buf}),y++),P(e,"Snapshot cancelled"),!x)throw new Error("Failed to compute blob object id");l.set(w.path,x)}},D=Array.from({length:Math.min(u,c.length)},()=>d());await Promise.all(D),P(e,"Snapshot cancelled"),f(`[GitHistoryStore] Blobs ready wrote=${y} skipped=${S} in ${Date.now()-s}ms`);let E=new F(this.repoDir),T=Array.from(l.keys()).sort((w,x)=>w.localeCompare(x));for(let w of T)P(e,"Snapshot cancelled"),await E.addFile(w,l.get(w));P(e,"Snapshot cancelled");let j=Date.now(),k=await E.finish();f(`[GitHistoryStore] Wrote tree(s). root=${k} in ${Date.now()-j}ms`);let O=t.parent;if(!O)try{O=await g.resolveRef({fs:o,dir:this.repoDir,ref:"HEAD"})}catch{}P(e,"Snapshot cancelled");let N=t.when?Math.floor(t.when/1e3):Math.floor(Date.now()/1e3),G=new Date(N*1e3).getTimezoneOffset(),B=await g.commit({fs:o,dir:this.repoDir,message:t.message,parent:O?[O]:[],tree:k,author:{name:"ast-db",email:"ast-db@example.com",timestamp:N,timezoneOffset:G},committer:{name:"ast-db",email:"ast-db@example.com",timestamp:N,timezoneOffset:G}});return await g.writeRef({fs:o,dir:this.repoDir,ref:"refs/heads/master",value:B,force:!0}),f(`[GitHistoryStore] Snapshot commit oid ${B}`),B}async listSnapshotMembers(t){await this.ensureInitialized();let e=s=>Math.round((s||0)/(1024*1024)),n=()=>{let s=process.memoryUsage();return`rss=${e(s.rss)}MB heapUsed=${e(s.heapUsed)}MB heapTotal=${e(s.heapTotal)}MB`},i=[];return f(`[${new Date().toISOString()}] [GitHistoryStore] listSnapshotMembers(${t}) start (${n()})`),await g.walk({fs:o,dir:this.repoDir,trees:[g.TREE({ref:t})],map:async(s,[a])=>{if(!a)return;if(await a.type()==="blob"){let m=await a.oid();i.push({logicalPath:s,objectId:m})}}}),f(`[${new Date().toISOString()}] [GitHistoryStore] listSnapshotMembers(${t}) -> ${i.length} blobs`),i.filter(s=>s.logicalPath&&s.logicalPath!==".").map(s=>({logicalPath:s.logicalPath.replace(/^\.\//,""),objectId:s.objectId}))}async readCommit(t){let{commit:e}=await g.readCommit({fs:o,dir:this.repoDir,oid:t});return{message:e.message,committer:e.committer}}async readCommitParent(t){let{commit:e}=await g.readCommit({fs:o,dir:this.repoDir,oid:t});return Array.isArray(e.parent)&&e.parent.length>0?String(e.parent[0]):void 0}async createSnapshotFromDisk(t,e){P(e,"Snapshot cancelled"),await this.ensureInitialized(),f(`[${new Date().toISOString()}] [GitHistoryStore] Creating snapshot from disk (streaming) with ${t.relPaths.length} members`);let n=[...t.relPaths].map(y=>this.normalizeLogicalPath(y)).filter(Boolean).sort((y,S)=>y.localeCompare(S)),i=Date.now(),s=new F(this.repoDir),a=0;for(let y of n){P(e,"Snapshot cancelled");let S=I.join(this.baseDir,y);try{let c=o.readFileSync(S),d=await g.writeBlob({fs:o,dir:this.repoDir,blob:c});await s.addFile(y,d),a++}catch{}}f(`[GitHistoryStore] Wrote ${a} blobs (disk) in ${Date.now()-i}ms`),P(e,"Snapshot cancelled");let p=Date.now(),m=await s.finish();f(`[GitHistoryStore] Wrote tree(s) (disk). root=${m} in ${Date.now()-p}ms`);let u=t.parent;if(!u)try{u=await g.resolveRef({fs:o,dir:this.repoDir,ref:"HEAD"})}catch{}P(e,"Snapshot cancelled");let b=t.when?Math.floor(t.when/1e3):Math.floor(Date.now()/1e3),l=new Date(b*1e3).getTimezoneOffset(),h=await g.commit({fs:o,dir:this.repoDir,message:t.message,parent:u?[u]:[],tree:m,author:{name:"ast-db",email:"ast-db@example.com",timestamp:b,timezoneOffset:l},committer:{name:"ast-db",email:"ast-db@example.com",timestamp:b,timezoneOffset:l}});return await g.writeRef({fs:o,dir:this.repoDir,ref:"refs/heads/master",value:h,force:!0}),f(`[GitHistoryStore] Snapshot commit oid ${h}`),h}async createSnapshotFromDiskAndCapturedIfChanged(t){await this.ensureInitialized();let e=new Map;for(let c of t.capturedMembers||[]){let d=this.normalizeLogicalPath(c.logicalPath);!d||c.content==null||e.has(d)||e.set(d,Buffer.isBuffer(c.content)?c.content:Buffer.from(c.content))}f(`[${new Date().toISOString()}] [GitHistoryStore] Creating snapshot from disk+captured (diff) with ${t.relPaths.length} members, captured=${e.size}`);let n=[...t.relPaths].map(c=>this.normalizeLogicalPath(c)).filter(Boolean).sort((c,d)=>c.localeCompare(d)),i=Date.now(),s=new F(this.repoDir),a=0,p=0,m=0;for(let c of n)try{let d=e.get(c),D=d??o.readFileSync(I.join(this.baseDir,c)),E=await g.writeBlob({fs:o,dir:this.repoDir,blob:D});await s.addFile(c,E),a++,d?p++:m++}catch{}f(`[GitHistoryStore] Wrote ${a} blobs (captured=${p}, disk=${m}) in ${Date.now()-i}ms`);let u=Date.now(),b=await s.finish();f(`[GitHistoryStore] Wrote tree(s) (disk+captured). root=${b} in ${Date.now()-u}ms`);let l=t.parent;if(!l)try{l=await g.resolveRef({fs:o,dir:this.repoDir,ref:"HEAD"})}catch{}if(l)try{let{commit:c}=await g.readCommit({fs:o,dir:this.repoDir,oid:l});if(c?.tree===b){f("[GitHistoryStore] Snapshot identical to parent; skipping commit",{parentOid:l,tree:b});let d=await this.readCommitParent(l);return{snapshotId:l,identical:!0,parent:d}}}catch(c){f("[GitHistoryStore] Parent read failed; proceeding with commit",{error:c?.message||String(c)})}let h=t.when?Math.floor(t.when/1e3):Math.floor(Date.now()/1e3),y=new Date(h*1e3).getTimezoneOffset(),S=await g.commit({fs:o,dir:this.repoDir,message:t.message,parent:l?[l]:[],tree:b,author:{name:"ast-db",email:"ast-db@example.com",timestamp:h,timezoneOffset:y},committer:{name:"ast-db",email:"ast-db@example.com",timestamp:h,timezoneOffset:y}});return await g.writeRef({fs:o,dir:this.repoDir,ref:"refs/heads/master",value:S,force:!0}),f(`[GitHistoryStore] Snapshot commit oid ${S}`),{snapshotId:S,identical:!1,parent:l}}async createSnapshotFromDiskIfChanged(t){await this.ensureInitialized(),f(`[${new Date().toISOString()}] [GitHistoryStore] Creating snapshot from disk (diff) with ${t.relPaths.length} members`);let e=[...t.relPaths].map(h=>this.normalizeLogicalPath(h)).filter(Boolean).sort((h,y)=>h.localeCompare(y)),n=Date.now(),i=new F(this.repoDir),s=0;for(let h of e){let y=I.join(this.baseDir,h);try{let S=o.readFileSync(y),c=await g.writeBlob({fs:o,dir:this.repoDir,blob:S});await i.addFile(h,c),s++}catch{}}f(`[GitHistoryStore] Wrote ${s} blobs (disk) in ${Date.now()-n}ms`);let a=Date.now(),p=await i.finish();f(`[GitHistoryStore] Wrote tree(s) (disk). root=${p} in ${Date.now()-a}ms`);let m=t.parent;if(!m)try{m=await g.resolveRef({fs:o,dir:this.repoDir,ref:"HEAD"})}catch{}if(m)try{let{commit:h}=await g.readCommit({fs:o,dir:this.repoDir,oid:m});if(h?.tree===p){f("[GitHistoryStore] Snapshot identical to parent; skipping commit",{parentOid:m,tree:p});let y=await this.readCommitParent(m);return{snapshotId:m,identical:!0,parent:y}}}catch(h){f("[GitHistoryStore] Parent read failed; proceeding with commit",{error:h?.message||String(h)})}let u=t.when?Math.floor(t.when/1e3):Math.floor(Date.now()/1e3),b=new Date(u*1e3).getTimezoneOffset(),l=await g.commit({fs:o,dir:this.repoDir,message:t.message,parent:m?[m]:[],tree:p,author:{name:"ast-db",email:"ast-db@example.com",timestamp:u,timezoneOffset:b},committer:{name:"ast-db",email:"ast-db@example.com",timestamp:u,timezoneOffset:b}});return await g.writeRef({fs:o,dir:this.repoDir,ref:"refs/heads/master",value:l,force:!0}),f(`[GitHistoryStore] Snapshot commit oid ${l}`),{snapshotId:l,identical:!1,parent:m}}};function q(r){let t={},e=r.split(/\r?\n/);for(let n of e){let i=n.match(/^([A-Za-z0-9-]+):\s*(.*)$/);i&&(t[i[1]]=i[2])}return t}import Pt from"fs";import H from"path";import ct from"ignore";import{Project as Kt}from"ts-morph";var It=new Set(["node_modules",".git",".pando-data",".clj-kondo"]);function ht(r,t){if(!t?.length)return null;let e=t.map(i=>i.replace(/^\/+/,"").replace(/\/+$/,"")).filter(Boolean).map(i=>`${i}/`);if(!e.length)return null;let n=i=>i.replace(/\\/g,"/");return i=>{let s=n(H.relative(r,i));if(!s||s.startsWith(".."))return!1;let a=s.endsWith("/")?s:`${s}/`;return e.some(p=>a.startsWith(p))}}function pt(r,t){return Mt(r,t,null)}function Mt(r,t,e){let n=t?.shouldExclude||null,i=[],s=H.resolve(t?.gitignoreRoot??r),a=J(s,""),p=ct().add(a),m=[{dir:r,relDir:"",rules:a,ig:p}];for(;m.length;){let u=m.pop(),b=[];try{b=Pt.readdirSync(u.dir,{withFileTypes:!0})}catch{continue}for(let l of b){let h=H.join(u.dir,l.name);if(!(typeof l.isSymbolicLink=="function"&&l.isSymbolicLink())){if(l.isDirectory()){if(It.has(l.name)||n?.(h))continue;let S=u.relDir?`${u.relDir}/${l.name}`:l.name,c=lt(S);if(u.ig.ignores(c))continue;let d=u.rules.slice(),D=J(h,c);D.length&&d.push(...D);let E=D.length?ct().add(d):u.ig;m.push({dir:h,relDir:c,rules:d,ig:E})}else if(l.isFile()){if(n?.(h))continue;let S=lt(H.relative(r,h));if(u.ig.ignores(S))continue;if(e===null)i.push(h);else{let c=H.extname(l.name).toLowerCase();e.has(c)&&i.push(h)}}}}}return i}function lt(r){return r.replace(/\\/g,"/")}K();Et();K();import tt from"fs";import Ot from"path";function dt(r){r.pragma("journal_mode = WAL"),r.pragma("synchronous = NORMAL"),r.pragma("busy_timeout = 10000");try{r.pragma("temp_store = MEMORY")}catch{}r.exec(`
4
8
  CREATE TABLE IF NOT EXISTS objects (
5
9
  object_id TEXT PRIMARY KEY,
6
10
  kind TEXT DEFAULT 'blob',
@@ -38,4 +42,4 @@ import{a as _,h as x,i as K}from"./chunk-LGZQCDFH.mjs";import{a as Y,b as it,c a
38
42
 
39
43
  CREATE INDEX IF NOT EXISTS idx_snapshots_timestamp ON snapshots(timestamp);
40
44
  CREATE INDEX IF NOT EXISTS idx_snapshot_meta_kv ON snapshot_meta(key, value);
41
- `)}function tt(i,t){let e=it(i),n=It.dirname(e);q.existsSync(n)||q.mkdirSync(n,{recursive:!0});let r=!!t?.readonly;if(r&&!q.existsSync(e)){let a=new J(e,{});try{pt(a)}finally{try{a.close()}catch{}}}let s=new J(e,r?{readonly:!0}:{});if(!r)pt(s);else try{s.pragma("busy_timeout = 10000")}catch{}return s}var O="",et=[],yt=null;st();function dt(i,t){if(Array.isArray(t)){et=t.slice(),yt=lt(i,et);try{R("SnapshotWorker","exclude state updated",{excludeDirs:et})}catch{}}}function Mt(i){let t=ht(i,{shouldExclude:yt??void 0,gitignoreRoot:i});try{R("SnapshotWorker","gatherSnapshotFiles",{count:t.length,sample:t.slice(0,20).map(e=>rt.relative(i,e).replace(/\\/g,"/"))})}catch{}return t}function gt(i){try{return i.prepare("SELECT snapshot_id FROM snapshots ORDER BY timestamp DESC, rowid DESC LIMIT 1").get()?.snapshot_id}catch{return}}function mt(i,t,e,n,r){let s=r||null;i.prepare("INSERT OR REPLACE INTO snapshots (snapshot_id, parents, timestamp, message) VALUES (?, ?, ?, ?)").run(t,s,Math.floor(e/1e3),n)}async function ft(i,t,e){try{return await i.readCommitParent(t)||e}catch{return e}}function X(i,t){let e=new Map;try{let n=i.prepare("SELECT logical_path, object_id FROM snapshot_members WHERE snapshot_id = ?").all(t);for(let r of n)e.set(r.logical_path,r.object_id)}catch{}return e}function ut(i,t,e){i.transaction(r=>{let s=i.prepare("INSERT OR REPLACE INTO snapshot_members (snapshot_id, logical_path, object_id, lang, encoding) VALUES (?, ?, ?, ?, ?)");for(let a of r)s.run(t,a.logical_path,a.object_id,a.lang??null,a.encoding??null)})(e)}j.on("message",async i=>{if(i.cmd==="init"){O=i.projectRoot,dt(O,i.excludeDirs),j.postMessage({type:"ready"});return}if(i.excludeDirs&&dt(O,i.excludeDirs),i.cmd==="snapshot"){let t=tt(O);try{let e=Date.now(),n=i.payload?.when||Date.now(),r=i.payload?.message||"ast: snapshot",s=i.payload?.parent||gt(t),a=Date.now(),p=i.payload?.files&&i.payload.files.length?i.payload.files:Mt(O);try{R("SnapshotWorker","snapshot start",{when:n,message:r,parent:s,fileCount:p.length,filesPreview:p.slice(0,50).map(D=>rt.relative(O,D).replace(/\\/g,"/"))})}catch{}let m=Date.now()-a,u=p.map(D=>rt.relative(O,D).replace(/\\/g,"/")),b=(i.payload?.captured||[]).map(D=>({logicalPath:D.logicalPath,objectId:"unknown",content:Buffer.from(D.contentB64,"base64")})),l=new H({baseDir:O});await l.ensureInitialized();let h=Date.now(),y=b.length>0?await l.createSnapshotFromDiskAndCapturedIfChanged({message:r,when:n,relPaths:u,capturedMembers:b,parent:s}):await l.createSnapshotFromDiskIfChanged({message:r,when:n,relPaths:u,parent:s}),S=y.snapshotId,c=await ft(l,S,y.parent||s),d=Date.now()-h;if(y.identical){let D=Date.now()-e;try{R("SnapshotWorker","snapshot skipped (identical)",{snapshotId:S,parent:c,files:u.length,timingsMs:{list:m,snapshot:d,total:D}})}catch{}j.postMessage({type:"result",snapshotId:S,parent:c,files:u.length,diff:{added:0,changed:0,deleted:0}})}else{let D=Date.now();mt(t,S,n,r,c);try{let M=Z(r||""),U=t.prepare("INSERT OR REPLACE INTO snapshot_meta (snapshot_id, key, value) VALUES (?, ?, ?)");t.transaction(()=>{for(let[bt,wt]of Object.entries(M))U.run(S,bt,wt)})()}catch{}let E=Date.now()-D,T=Date.now(),$=await l.listSnapshotMembers(S),k=Date.now()-T,C=$.map(M=>({logical_path:M.logicalPath,object_id:M.objectId})),N=Date.now();ut(t,S,C);let G=Date.now()-N,B=c?X(t,c):new Map,w=X(t,S),P=[],A=[],z=[];for(let[M,U]of w){let W=B.get(M);W?W!==U&&A.push(M):P.push(M)}for(let[M]of B)w.has(M)||z.push(M);let St=Date.now()-e;try{R("SnapshotWorker","snapshot complete",{snapshotId:S,parent:c,files:u.length,timingsMs:{list:m,snapshot:d,metadata:E,listMembers:k,membersWrite:G,total:St},diff:{added:P.length,changed:A.length,deleted:z.length}})}catch{}j.postMessage({type:"result",snapshotId:S,parent:c,files:u.length,diff:{added:P.length,changed:A.length,deleted:z.length}})}}catch(e){j.postMessage({type:"error",message:e?.message||String(e)})}finally{t.close()}return}if(i.cmd==="snapshot-captured"){let t=tt(O);try{let e=i.payload?.when||Date.now(),n=i.payload?.message||"ast: snapshot",r=i.payload?.parent||gt(t);try{R("SnapshotWorker","snapshot-captured start",{when:e,message:n,parent:r,members:i.payload.members.length})}catch{}let s=new H({baseDir:O});await s.ensureInitialized();let a=(i.payload.members||[]).map(d=>({logicalPath:d.logicalPath,objectId:"unknown",content:Buffer.from(d.contentB64,"base64")})),p=await s.createSnapshot({message:n,when:e,members:a}),m=await ft(s,p,r);mt(t,p,e,n,m);try{let d=Z(n||""),D=t.prepare("INSERT OR REPLACE INTO snapshot_meta (snapshot_id, key, value) VALUES (?, ?, ?)");t.transaction(()=>{for(let[T,$]of Object.entries(d))D.run(p,T,$)})()}catch{}let u=await s.listSnapshotMembers(p),b=u.map(d=>({logical_path:d.logicalPath,object_id:d.objectId}));ut(t,p,b);let l=m?X(t,m):new Map,h=X(t,p),y=[],S=[],c=[];for(let[d,D]of h){let E=l.get(d);E?E!==D&&S.push(d):y.push(d)}for(let[d]of l)h.has(d)||c.push(d);try{R("SnapshotWorker","snapshot-captured complete",{snapshotId:p,parent:m,members:u.length,diff:{added:y.length,changed:S.length,deleted:c.length}})}catch{}j.postMessage({type:"result",snapshotId:p,parent:m,files:u.length,diff:{added:y.length,changed:S.length,deleted:c.length}})}catch(e){j.postMessage({type:"error",message:e?.message||String(e)})}finally{t.close()}}i.cmd==="close"&&j.postMessage({type:"closed"})});
45
+ `)}function et(r,t){let e=nt(r),n=Ot.dirname(e);tt.existsSync(n)||tt.mkdirSync(n,{recursive:!0});let i=!!t?.readonly;if(i&&!tt.existsSync(e)){let a=new Q(e,{});try{dt(a)}finally{try{a.close()}catch{}}}let s=new Q(e,i?{readonly:!0}:{});if(!i)dt(s);else try{s.pragma("busy_timeout = 10000")}catch{}return s}var C="",rt=[],St=null;st();function gt(r,t){if(Array.isArray(t)){rt=t.slice(),St=ht(r,rt);try{R("SnapshotWorker","exclude state updated",{excludeDirs:rt})}catch{}}}function Ct(r){let t=pt(r,{shouldExclude:St??void 0,gitignoreRoot:r});try{R("SnapshotWorker","gatherSnapshotFiles",{count:t.length,sample:t.slice(0,20).map(e=>it.relative(r,e).replace(/\\/g,"/"))})}catch{}return t}function mt(r){try{return r.prepare("SELECT snapshot_id FROM snapshots ORDER BY timestamp DESC, rowid DESC LIMIT 1").get()?.snapshot_id}catch{return}}function ft(r,t,e,n,i){let s=i||null;r.prepare("INSERT OR REPLACE INTO snapshots (snapshot_id, parents, timestamp, message) VALUES (?, ?, ?, ?)").run(t,s,Math.floor(e/1e3),n)}async function ut(r,t,e){try{return await r.readCommitParent(t)||e}catch{return e}}function X(r,t){let e=new Map;try{let n=r.prepare("SELECT logical_path, object_id FROM snapshot_members WHERE snapshot_id = ?").all(t);for(let i of n)e.set(i.logical_path,i.object_id)}catch{}return e}function yt(r,t,e){r.transaction(i=>{let s=r.prepare("INSERT OR REPLACE INTO snapshot_members (snapshot_id, logical_path, object_id, lang, encoding) VALUES (?, ?, ?, ?, ?)");for(let a of i)s.run(t,a.logical_path,a.object_id,a.lang??null,a.encoding??null)})(e)}$.on("message",async r=>{if(r.cmd==="init"){C=r.projectRoot,gt(C,r.excludeDirs),$.postMessage({type:"ready"});return}if(r.excludeDirs&&gt(C,r.excludeDirs),r.cmd==="snapshot"){let t=et(C);try{let e=Date.now(),n=r.payload?.when||Date.now(),i=r.payload?.message||"ast: snapshot",s=r.payload?.parent||mt(t),a=Date.now(),p=r.payload?.files&&r.payload.files.length?r.payload.files:Ct(C);try{R("SnapshotWorker","snapshot start",{when:n,message:i,parent:s,fileCount:p.length,filesPreview:p.slice(0,50).map(D=>it.relative(C,D).replace(/\\/g,"/"))})}catch{}let m=Date.now()-a,u=p.map(D=>it.relative(C,D).replace(/\\/g,"/")),b=(r.payload?.captured||[]).map(D=>({logicalPath:D.logicalPath,objectId:"unknown",content:Buffer.from(D.contentB64,"base64")})),l=new L({baseDir:C});await l.ensureInitialized();let h=Date.now(),y=b.length>0?await l.createSnapshotFromDiskAndCapturedIfChanged({message:i,when:n,relPaths:u,capturedMembers:b,parent:s}):await l.createSnapshotFromDiskIfChanged({message:i,when:n,relPaths:u,parent:s}),S=y.snapshotId,c=await ut(l,S,y.parent||s),d=Date.now()-h;if(y.identical){let D=Date.now()-e;try{R("SnapshotWorker","snapshot skipped (identical)",{snapshotId:S,parent:c,files:u.length,timingsMs:{list:m,snapshot:d,total:D}})}catch{}$.postMessage({type:"result",snapshotId:S,parent:c,files:u.length,diff:{added:0,changed:0,deleted:0}})}else{let D=Date.now();ft(t,S,n,i,c);try{let M=q(i||""),W=t.prepare("INSERT OR REPLACE INTO snapshot_meta (snapshot_id, key, value) VALUES (?, ?, ?)");t.transaction(()=>{for(let[wt,Dt]of Object.entries(M))W.run(S,wt,Dt)})()}catch{}let E=Date.now()-D,T=Date.now(),j=await l.listSnapshotMembers(S),k=Date.now()-T,O=j.map(M=>({logical_path:M.logicalPath,object_id:M.objectId})),N=Date.now();yt(t,S,O);let G=Date.now()-N,B=c?X(t,c):new Map,w=X(t,S),x=[],A=[],z=[];for(let[M,W]of w){let Y=B.get(M);Y?Y!==W&&A.push(M):x.push(M)}for(let[M]of B)w.has(M)||z.push(M);let bt=Date.now()-e;try{R("SnapshotWorker","snapshot complete",{snapshotId:S,parent:c,files:u.length,timingsMs:{list:m,snapshot:d,metadata:E,listMembers:k,membersWrite:G,total:bt},diff:{added:x.length,changed:A.length,deleted:z.length}})}catch{}$.postMessage({type:"result",snapshotId:S,parent:c,files:u.length,diff:{added:x.length,changed:A.length,deleted:z.length}})}}catch(e){$.postMessage({type:"error",message:e?.message||String(e)})}finally{t.close()}return}if(r.cmd==="snapshot-captured"){let t=et(C);try{let e=r.payload?.when||Date.now(),n=r.payload?.message||"ast: snapshot",i=r.payload?.parent||mt(t);try{R("SnapshotWorker","snapshot-captured start",{when:e,message:n,parent:i,members:r.payload.members.length})}catch{}let s=new L({baseDir:C});await s.ensureInitialized();let a=(r.payload.members||[]).map(d=>({logicalPath:d.logicalPath,objectId:"unknown",content:Buffer.from(d.contentB64,"base64")})),p=await s.createSnapshot({message:n,when:e,members:a}),m=await ut(s,p,i);ft(t,p,e,n,m);try{let d=q(n||""),D=t.prepare("INSERT OR REPLACE INTO snapshot_meta (snapshot_id, key, value) VALUES (?, ?, ?)");t.transaction(()=>{for(let[T,j]of Object.entries(d))D.run(p,T,j)})()}catch{}let u=await s.listSnapshotMembers(p),b=u.map(d=>({logical_path:d.logicalPath,object_id:d.objectId}));yt(t,p,b);let l=m?X(t,m):new Map,h=X(t,p),y=[],S=[],c=[];for(let[d,D]of h){let E=l.get(d);E?E!==D&&S.push(d):y.push(d)}for(let[d]of l)h.has(d)||c.push(d);try{R("SnapshotWorker","snapshot-captured complete",{snapshotId:p,parent:m,members:u.length,diff:{added:y.length,changed:S.length,deleted:c.length}})}catch{}$.postMessage({type:"result",snapshotId:p,parent:m,files:u.length,diff:{added:y.length,changed:S.length,deleted:c.length}})}catch(e){$.postMessage({type:"error",message:e?.message||String(e)})}finally{t.close()}}r.cmd==="close"&&$.postMessage({type:"closed"})});
@@ -1,4 +1,4 @@
1
- import{d as Ne,e as re,f as U}from"./chunk-ODST7O2H.mjs";import{a as ie,b as Ce}from"./chunk-Z5RGEDVQ.mjs";import{c as pe}from"./chunk-AYCBSZ56.mjs";Ce();import{parentPort as S,threadId as Me}from"worker_threads";import B from"path";import ce from"fs";import Ue from"os";function Pe(e){e.exec(`
1
+ import{d as Ne,e as re,f as U}from"./chunk-ODST7O2H.mjs";import{a as ie,b as Ce}from"./chunk-Z5RGEDVQ.mjs";import{c as pe}from"./chunk-AYCBSZ56.mjs";Ce();import{parentPort as S,threadId as Me}from"worker_threads";import B from"path";import Ee from"fs";import{inspect as Ge}from"util";import Ue from"os";function Pe(e){e.exec(`
2
2
  PRAGMA journal_mode=WAL;
3
3
  PRAGMA synchronous=OFF;
4
4
  PRAGMA temp_store=MEMORY;
@@ -230,5 +230,5 @@ import{d as Ne,e as re,f as U}from"./chunk-ODST7O2H.mjs";import{a as ie,b as Ce}
230
230
  CREATE INDEX IF NOT EXISTS idx_resolver_cache_symbol ON resolver_cache(symbol_id);
231
231
  CREATE INDEX IF NOT EXISTS idx_resolver_cache_file ON resolver_cache(file_path);
232
232
 
233
- `)}var Ae=Number(process.env.PANDO_SQLITE_RETRY_MIN_MS||"100"),Le=Number(process.env.PANDO_SQLITE_RETRY_MAX_MS||"500"),be=Math.max(0,Number(process.env.PANDO_SQLITE_RETRY_ATTEMPTS||"5")),L=Ne();if(!S)throw new Error("SQLite writer worker must be spawned as a worker thread");pe();function f(...e){process.env.PANDO_QUIET||console.log(`[${new Date().toISOString()}]`,...e)}function R(...e){L&&console.log(...e)}function Ge(e){L&&re("WriterWorker",e,{threadId:Me})}function Be(e){L&&re("WriterWorker","clojure-source-node",{threadId:Me,...e})}var y=null,ge=null;function Ke(){ge||(ge=setInterval(()=>{if(!y)return;let e=Date.now()-y.startedAt;e>5e3&&f("[WriterWorker] op still running",{cmd:y.cmd,id:y.id,ms:e,fileRel:y.fileRel})},2e3))}function X(e,r,t){y={cmd:e,id:r,startedAt:Date.now(),fileRel:t},Ke()}function b(){y=null}var x=()=>({writeMs:0,writeTrackedMs:0,writePreDeleteMs:0,writeInsertExportsMs:0,writeInsertNodesMs:0,writeInsertReferencesMs:0,writeInsertImportsMs:0,writeInsertImportBindingsMs:0,writeInsertFileMs:0,writeFinalizeMs:0,writeInsertFtsMs:0,writeResidualMs:0}),G=Math.max(0,Math.min(Ae,Le)),Se=Math.max(G,Math.max(Ae,Le)),Ye=e=>new Promise(r=>setTimeout(r,e));function we(e){if(!e)return!1;let r=e.code,t=e.errcode;if(r==="ERR_SQLITE_BUSY"||r==="SQLITE_BUSY"||r==="ERR_SQLITE_ERROR"&&t===5)return!0;let n=e?.message??String(e);return typeof n=="string"&&n.toLowerCase().includes("database is locked")}function ze(){if(Se<=G)return G;let e=Se-G;return G+Math.floor(Math.random()*(e+1))}async function se(e,r){let t=0,n=Date.now();for(;;)try{let i=e();return L&&t>0&&f(`[WriterWorker] ${r} recovered after retry`,{attempts:t,ms:Date.now()-n}),i}catch(i){if(!we(i)||t>=be)throw f(`[WriterWorker] ${r} failed`,{attempts:t,ms:Date.now()-n,error:i?.message??String(i),locked:we(i)}),i;t+=1;let o=ze();f(`[WriterWorker] ${r} retry ${t}/${be} after locked database; waiting ${o}ms`),await Ye(o)}}var A=null,v=null,de=null,_e=null,Te=null,me=null,fe=null,C=null,K=null,w=null,h=null,V=null,q=null,Q=new Map,M=new Map,Y=new Map,le=new Map,ae=Math.max(1e4,Number(process.env.PANDO_DICT_CACHE_MAX_ENTRIES||"200000")),$e=Math.max(64,Number(process.env.PANDO_DICT_CACHE_MAX_KEY_LENGTH||"1024")),he=Math.floor(ae*.7),$=0,j=null,O=null,z=null,J=null,Z=null,ee=null,Ee,W=null,H={reference:1,call:2,new:4,type:8,import:16,export:32};function ue(){if(!A)throw new Error("writer not initialized");return A}function He(e){v||(v=e.prepare("DELETE FROM nodes WHERE file_id = ?"),de=e.prepare("DELETE FROM exports WHERE file_id = ?"),_e=e.prepare("DELETE FROM files WHERE file_id = ?"),Te=e.prepare("DELETE FROM file_imports WHERE file_id = ?"),me=e.prepare("DELETE FROM file_import_bindings WHERE file_id = ?"),fe=e.prepare("DELETE FROM file_symbol_mentions WHERE file_id = ?"))}function te(e){C||(C=e.prepare("INSERT OR IGNORE INTO dict_kinds (text) VALUES (?)"),K=e.prepare("SELECT id FROM dict_kinds WHERE text = ?")),w||(w=e.prepare("INSERT OR IGNORE INTO dict_symbols (text) VALUES (?)"),h=e.prepare("SELECT id FROM dict_symbols WHERE text = ?")),V||(V=e.prepare("INSERT OR IGNORE INTO dict_files (path) VALUES (?)"),q=e.prepare("SELECT id FROM dict_files WHERE path = ?"))}function g(e,r,t,n,i){if(!i)return null;let o=i.length<=$e,l=o?r.get(i):void 0;if(l!=null)return l;t.run(i);let E=n.get(i);if(!E||typeof E.id!="number")return null;if(o){if(r.size>=ae){let T=0;for(let p of r.keys())if(r.delete(p),T+=1,r.size<=he)break;$+=1,($<=10||$%25===0)&&f("[WriterWorker] dictionary cache trimmed",{trimCount:$,removed:T,maxEntries:ae,targetAfterTrim:he,cacheSizeAfter:r.size})}r.set(i,E.id)}return E.id}function Qe(e,r){te(e);let t=Y.get(r);if(t!=null)return t;V.run(r);let n=q.get(r);if(!n||typeof n.id!="number")throw new Error(`Failed to resolve file id for ${r}`);return Y.set(r,n.id),n.id}function je(e,r){te(e);let t=Y.get(r);if(t!=null)return t;let n=q.get(r);return!n||typeof n.id!="number"?null:(Y.set(r,n.id),n.id)}function ve(e,r,t){te(e);let n=new Map;if(Array.isArray(r.symbolMentionRows)&&r.symbolMentionRows.length>0){for(let i of r.symbolMentionRows){let o=typeof i?.[0]=="string"?String(i[0]).trim():"";if(!o)continue;let l=g(e,M,w,h,o);if(l==null)continue;let E=typeof i?.[1]=="string"?String(i[1]).trim().toLowerCase():"",T=H[E]??H.reference,p=typeof i?.[2]=="string"?String(i[2]).trim():"",a=typeof i?.[3]=="string"?String(i[3]).trim():"",s=Number(i?.[4]),I=Number.isFinite(s)&&s>0?Math.floor(s):1,c=`${l}\0${p}\0${a}`,_=n.get(c);if(_){_.mentionKinds|=T,_.mentionCount+=I;continue}n.set(c,{symbolId:l,targetSymbolKey:p,containerQualifiedName:a,mentionKinds:T,mentionCount:I})}return Array.from(n.values()).map(i=>[t,r.lang,i.symbolId,i.targetSymbolKey,i.containerQualifiedName,i.mentionKinds,i.mentionCount])}for(let i of r.referenceRows||[]){let o=typeof i?.[3]=="string"?String(i[3]).trim():"";if(!o)continue;let l=g(e,M,w,h,o);if(l==null)continue;let E=typeof i?.[4]=="string"?String(i[4]).trim().toLowerCase():"",T=H[E]??H.reference,p=typeof i?.[13]=="string"?String(i[13]).trim():"",a=typeof i?.[12]=="string"?String(i[12]).trim():"",s=`${l}\0${p}\0${a}`,I=n.get(s);if(I){I.mentionKinds|=T,I.mentionCount+=1;continue}n.set(s,{symbolId:l,targetSymbolKey:p,containerQualifiedName:a,mentionKinds:T,mentionCount:1})}return Array.from(n.values()).map(i=>[t,r.lang,i.symbolId,i.targetSymbolKey,i.containerQualifiedName,i.mentionKinds,i.mentionCount])}function ke(e,r){let t=r?.journal_mode||"WAL";e.pragma(`journal_mode=${t}`),e.pragma("synchronous=OFF"),e.pragma("temp_store=MEMORY"),e.pragma("cache_size=-20000"),e.pragma("mmap_size=268435456"),e.pragma("journal_size_limit=134217728"),e.pragma("wal_autocheckpoint=1000"),e.pragma("busy_timeout=5000")}function oe(e){try{return ce.statSync(e).size}catch{return null}}function P(e){if(!W)return;let r=`${W}-wal`,t=`${W}-shm`,n=oe(W),i=oe(r),o=oe(t);f("[WriterWorker] db sizes",{reason:e,dbPath:W,dbSize:n,walSize:i,shmSize:o})}function Ve(e){let r=B.dirname(e),t=B.basename(e),n=t.replace(".pando-index-chunk-",".pando-fts-chunk-");return B.join(r,n===t?`${t}.fts`:n)}function De(){if(!j)throw new Error("FTS database path not configured");if(!O){try{ce.mkdirSync(B.dirname(j),{recursive:!0})}catch{}O=new ie(j),ke(O,Ee)}return O}function qe(e){z||(e.exec("CREATE VIRTUAL TABLE IF NOT EXISTS blob_content_fts USING fts5(blob_oid UNINDEXED, content)"),e.exec("CREATE TABLE IF NOT EXISTS blob_fts_presence (blob_oid TEXT PRIMARY KEY)"),z=e.prepare("SELECT 1 FROM blob_fts_presence WHERE blob_oid = ?"),J=e.prepare("INSERT INTO blob_content_fts (blob_oid, content) VALUES (?, ?)"),Z=e.prepare("INSERT OR REPLACE INTO blob_fts_presence (blob_oid) VALUES (?)"),ee=e.prepare("DELETE FROM blob_content_fts WHERE blob_oid = ?"))}function Je(e,r){if(!e||typeof e.blobOid!="string"||e.blobOid.length===0)return;let t=De();qe(t);let n=Date.now();r?.inTransaction||t.exec("BEGIN");try{z.get(e.blobOid)&&ee.run(e.blobOid),J.run(e.blobOid,e.content??""),Z.run(e.blobOid),r?.inTransaction||t.exec("COMMIT")}catch(o){if(!r?.inTransaction)try{t.exec("ROLLBACK")}catch(l){R("[WriterWorker] rollback failed:",l?.message??l)}throw o}let i=Date.now()-n;i>2e3&&f("[WriterWorker] slow fts insert",{blobOid:e.blobOid,ms:i,contentBytes:e.content?e.content.length:0})}function Ze(e,r,t,n){let i=`${r}|${t}|${n}`,o=le.get(i);if(!o){let l=Array.from({length:n},()=>`(${new Array(t).fill("?").join(",")})`).join(","),E=`${r} VALUES ${l}`;o=e.prepare(E),le.set(i,o)}return o}function F(e,r,t,n){if(!n.length||t<=0)return;let i=Date.now(),o=Math.max(1,Math.floor(999/t));for(let E=0;E<n.length;E+=o){let T=n.slice(E,E+o);if(!T.length)continue;let p=Ze(e,r,t,T.length),a=[];for(let c of T)a.push(...c);let s=Date.now();p.run(...a);let I=Date.now()-s;I>500&&f("[WriterWorker] slow insert chunk",{sqlPrefix:r,columnCount:t,rows:T.length,ms:I})}let l=Date.now()-i;l>2e3&&f("[WriterWorker] slow insertRows",{sqlPrefix:r,columnCount:t,rows:n.length,ms:l})}function ye(e,r){He(e);let t=je(e,r);t!=null&&(v.run(t),de.run(t),_e.run(t),Te.run(t),me.run(t),fe.run(t))}function et(e){if(!e.length)return x();let r=ue(),t=x(),n=Date.now();r.exec("BEGIN");try{for(let i of e)ye(r,i);r.exec("COMMIT")}catch(i){try{r.exec("ROLLBACK")}catch(o){R("[WriterWorker] rollback failed:",o?.message??o)}throw i}return t.writePreDeleteMs=Date.now()-n,t.writeTrackedMs=t.writePreDeleteMs,t.writeMs=t.writePreDeleteMs,t}function xe(e,r){let t=ue();te(t);let n=x(),i=Date.now(),o=Qe(t,e.fileRel),l={exports:e.exportRows.length,nodes:e.nodeRows.length,refs:e.referenceRows.length,imports:e.importRows.length,importBindings:e.importBindingRows.length,fileRow:e.fileRow?1:0,fts:e.fts?1:0},E=l.exports+l.nodes+l.refs+l.imports+l.importBindings;r?.inTransaction||t.exec("BEGIN");try{if(t.exec("SAVEPOINT idx_file"),!e.preDeleted){let a=Date.now();ye(t,e.fileRel),n.writePreDeleteMs+=Date.now()-a}let T=(a,s,I,c)=>{let _=Date.now();L&&f("[WriterWorker] section begin",{file:e.fileRel,label:s,count:I});let k=Date.now();c();let d=Date.now()-k;n[a]+=d,L&&f("[WriterWorker] section end",{file:e.fileRel,label:s,count:I,ms:d,elapsedSinceWriteStartMs:Date.now()-_}),d>2e3&&f("[WriterWorker] section slow",{file:e.fileRel,label:s,count:I,ms:d})};T("writeInsertExportsMs","exports",e.exportRows.length,()=>{let a=e.exportRows.map(c=>[o,e.lang,g(t,M,w,h,c[1]),U(c[2]),c[3],c[4]??null,g(t,M,w,h,c[5]),c[6]??null,c[7]??null]),s=[],I=new Map;for(let c of a){let _=c[2];_!=null&&(I.has(_)||(I.set(_,c),s.push(c)))}s.length!==a.length&&R("[WriterWorker] export rows deduped",{file:e.fileRel,lang:e.lang,before:a.length,after:s.length});try{F(t,"INSERT OR REPLACE INTO exports (file_id, lang, export_name_id, node_id, is_reexport, reexport_from, reexport_name_id, export_kind, target_symbol_key)",9,s)}catch(c){try{let _=new Map;for(let d of a){let u=d[2];u!=null&&_.set(u,(_.get(u)??0)+1)}let k=Array.from(_.entries()).filter(([,d])=>d>1);if(k.length){let d=t.prepare("SELECT text FROM dict_symbols WHERE id = ?"),u=k.map(([m,ne])=>{let Fe=d.get(m)?.text??null,We=a.filter(D=>D[2]===m).map(D=>({node_id:D[3],is_reexport:D[4],reexport_from:D[5],reexport_name_id:D[6],export_kind:D[7],target_symbol_key:D[8]}));return{id:m,count:ne,name:Fe,rows:We}});R("[WriterWorker] export duplicates detected",{file:e.fileRel,lang:e.lang,totalExports:a.length,duplicates:u});let N=a.map(m=>{let ne=m[2]!=null?d.get(m[2]):void 0,Ie=m[6]?d.get(m[6]):void 0;return{name_id:m[2],name:ne?.text??null,node_id:m[3],is_reexport:m[4],reexport_from:m[5],reexport_name_id:m[6],reexport_name:Ie?.text??null,export_kind:m[7],target_symbol_key:m[8]}});R("[WriterWorker] export rows dump",{file:e.fileRel,lang:e.lang,rows:N})}}catch(_){R("[WriterWorker] failed to compute export duplicates",_?.message??_)}throw R("[WriterWorker] export insert failed",{file:e.fileRel,lang:e.lang,exportCount:s.length,error:c?.message??c}),c}}),T("writeInsertNodesMs","nodes",e.nodeRows.length,()=>{for(let s of e.nodeRows){let I=s[2],c=s[3],_=s[4];if(!I||!String(I).trim())throw new Error(`[WriterWorker] Missing normalized kind for node in ${e.fileRel}`);if(!c||!String(c).trim())throw new Error(`[WriterWorker] Missing raw kind for node in ${e.fileRel}`);if(!_||!String(_).trim())throw new Error(`[WriterWorker] Missing raw kind source for node in ${e.fileRel}`)}let a=e.nodeRows.map(s=>[U(s[0]),o,e.lang,g(t,M,w,h,s[1]),g(t,Q,C,K,s[2]),s[3],s[4],g(t,Q,C,K,s[5]),s[6],s[7],s[8],g(t,Q,C,K,s[9]),s[10],s[11],s[12],s[13],s[14],s[15],s[16]]);try{F(t,"INSERT OR REPLACE INTO nodes (id, file_id, lang, name_id, kind_id, raw_kind, raw_kind_source, semantic_kind_id, start_pos, end_pos, is_exported, container_kind_id, container_raw_kind, container_raw_kind_source, param_count, qualified_name, scope_chain, symbol_key, metadata)",19,a)}catch(s){if((s?.message??String(s)).includes("UNIQUE constraint failed: nodes.id")){try{let c=new Map;for(let d of e.nodeRows){let u=U(d[0]);if(u==null)continue;let N=u.toString(),m=c.get(N);m?(m.count+=1,m.rawSample.length<3&&m.rawSample.push(d[0])):c.set(N,{count:1,rawSample:[d[0]]})}let _=Array.from(c.entries()).filter(([,d])=>d.count>1).slice(0,5).map(([d,u])=>({id:d,count:u.count,rawSample:u.rawSample})),k=_.map(d=>{let u=e.nodeRows.filter(N=>{let m=U(N[0]);return m!=null&&m.toString()===d.id}).slice(0,3);return{id:d.id,count:d.count,rows:u.map(N=>({rawId:N[0],name:N[1],kind:N[2],rawKind:N[3],semanticKind:N[5],start:N[6],end:N[7],containerKind:N[9],paramCount:N[12]}))}});f("[WriterWorker] UNIQUE nodes.id collision",{file:e.fileRel,lang:e.lang,nodeCount:a.length,duplicateCount:_.length,duplicates:_,duplicateDetails:k})}catch{}try{let c=t.prepare("SELECT id, file_id, lang, start_pos, end_pos FROM nodes WHERE id = ?"),_=t.prepare("SELECT path FROM dict_files WHERE id = ?");for(let k of a){let d=k[0];if(d==null)continue;let u=c.get(d);if(u&&typeof u.file_id=="number"){let N=_.get(u.file_id);f("[WriterWorker] nodes.id collision existing row",{file:e.fileRel,lang:e.lang,nodeId:d?.toString?.()??String(d),existingFileId:u.file_id,existingPath:N?.path,existingLang:u.lang,existingRange:{start:u.start_pos,end:u.end_pos}});break}}}catch{}}throw s}}),T("writeInsertReferencesMs","references",e.referenceRows.length,()=>{let a=ve(t,e,o);L&&e.lang==="clojure"&&a.length>0&&Be({stage:"writer-symbol-mentions",file:e.fileRel,refs:e.referenceRows.length,mentionRows:a.length,sample:a.slice(0,5).map(s=>({symbolId:s[2],mentionKinds:s[3],mentionCount:s[4]}))}),F(t,"INSERT OR REPLACE INTO file_symbol_mentions (file_id, lang, symbol_id, target_symbol_key, container_qualified_name, mention_kinds, mention_count)",7,a)}),T("writeInsertImportsMs","imports",e.importRows.length,()=>{let a=e.importRows.map(s=>[o,e.lang,s[1]??null,s[2]]);F(t,"INSERT INTO file_imports (file_id, lang, module_spec, is_type_only)",4,a)}),T("writeInsertImportBindingsMs","import_bindings",e.importBindingRows.length,()=>{let a=e.importBindingRows.map(s=>[o,e.lang,s[1]??null,g(t,M,w,h,s[2]),g(t,M,w,h,s[3]),g(t,M,w,h,s[4]),s[5]]);F(t,"INSERT INTO file_import_bindings (file_id, lang, module_spec, binding_kind_id, local_name_id, imported_name_id, is_type_only)",7,a)}),T("writeInsertFileMs","files",e.fileRow?1:0,()=>{let a=e.fileRow,s=[o,e.lang,a[1],a[2],a[3],a[4]];F(t,"INSERT OR REPLACE INTO files (file_id, lang, last_modified, file_size, status, indexed_at)",6,[s])}),T("writeInsertFtsMs","fts",e.fts?1:0,()=>Je(e.fts,{inTransaction:r?.inTransaction}));let p=Date.now();t.exec("RELEASE SAVEPOINT idx_file"),r?.inTransaction||t.exec("COMMIT"),n.writeFinalizeMs+=Date.now()-p}catch(T){try{t.exec("ROLLBACK TO SAVEPOINT idx_file")}catch(p){R("[WriterWorker] rollback to savepoint failed:",p?.message??p)}if(!r?.inTransaction)try{t.exec("ROLLBACK")}catch(p){R("[WriterWorker] rollback failed:",p?.message??p)}throw T}return n.writeMs=Date.now()-i,n.writeTrackedMs=n.writePreDeleteMs+n.writeInsertExportsMs+n.writeInsertNodesMs+n.writeInsertImportsMs+n.writeInsertImportBindingsMs+n.writeInsertFileMs+n.writeInsertFtsMs+n.writeFinalizeMs,n.writeResidualMs=Math.max(0,n.writeMs-n.writeTrackedMs),n}function tt(e){if(!e.length)return x();let r=Date.now(),t=x(),n=ue(),i=e.some(l=>l.fts&&typeof l.fts.blobOid=="string"&&l.fts.blobOid.length>0),o=null;n.exec("BEGIN");try{i&&(o=De(),o.exec("BEGIN"));for(let l of e){let E=xe(l,{inTransaction:!0});t.writePreDeleteMs+=E.writePreDeleteMs,t.writeInsertExportsMs+=E.writeInsertExportsMs,t.writeInsertNodesMs+=E.writeInsertNodesMs,t.writeInsertReferencesMs+=E.writeInsertReferencesMs,t.writeInsertImportsMs+=E.writeInsertImportsMs,t.writeInsertImportBindingsMs+=E.writeInsertImportBindingsMs,t.writeInsertFileMs+=E.writeInsertFileMs,t.writeFinalizeMs+=E.writeFinalizeMs,t.writeInsertFtsMs+=E.writeInsertFtsMs}o&&o.exec("COMMIT"),n.exec("COMMIT")}catch(l){if(f("[WriterWorker] handleWriteBatch error",{error:l?.message??l,stack:l?.stack?.split(`
234
- `).slice(0,3).join(" | ")}),o)try{o.exec("ROLLBACK")}catch(E){R("[WriterWorker] fts batch rollback failed:",E?.message??E)}try{n.exec("ROLLBACK")}catch(E){R("[WriterWorker] batch rollback failed:",E?.message??E)}throw l}return t.writeTrackedMs=t.writePreDeleteMs+t.writeInsertExportsMs+t.writeInsertNodesMs+t.writeInsertReferencesMs+t.writeInsertImportsMs+t.writeInsertImportBindingsMs+t.writeInsertFileMs+t.writeInsertFtsMs+t.writeFinalizeMs,t.writeMs=Date.now()-r,t.writeResidualMs=Math.max(0,t.writeMs-t.writeTrackedMs),t}function Xe(){return x()}function Oe(){try{Xe()}catch(e){R("[WriterWorker] backfill on shutdown failed:",e?.message??e)}if(A){try{A.close()}catch(e){R("[WriterWorker] failed to close database:",e?.message??e)}A=null}if(O){try{O.close()}catch(e){R("[WriterWorker] failed to close FTS database:",e?.message??e)}O=null}v=null,de=null,_e=null,Te=null,me=null,fe=null,z=null,J=null,Z=null,ee=null,C=null,K=null,w=null,h=null,V=null,q=null,le.clear(),Q.clear(),M.clear(),Y.clear()}S.on("message",async e=>{let r=(t,n)=>{let i=n instanceof Error?n:new Error(String(n));S.postMessage({type:"error",id:t,message:i.message,stack:i.stack})};if(e.cmd==="init"){try{let t=Date.now();X("init"),A&&Oe();let n=e.dbPath;W=n,Ee=e.pragmas;try{ce.mkdirSync(B.dirname(n),{recursive:!0})}catch{}if(A=new ie(n),ke(A,Ee),Re(A),j=Ve(n),O)try{O.close()}catch(i){R("[WriterWorker] failed to close FTS database:",i?.message??i)}O=null,z=null,J=null,Z=null,ee=null,S.postMessage({type:"ready"}),f("[WriterWorker] init complete",{dbPath:n,ms:Date.now()-t}),P("init"),b()}catch(t){b(),r(void 0,t)}return}if(e.cmd==="write"){try{let t=Date.now(),n=e.payload,i=Array.isArray(n?.fileRow)&&typeof n.fileRow[0]=="string"?n.fileRow[0]:void 0;X("write",e.id,i);let o=await se(()=>xe(n),"write");S.postMessage({type:"response",id:e.id,metrics:o});let l=Date.now()-t;l>2e3&&(f("[WriterWorker] slow write",{id:e.id,ms:l}),P("slow write")),b()}catch(t){b(),r(e.id,t)}return}if(e.cmd==="batchPreDelete"){try{let t=Date.now();X("batchPreDelete",e.id);let n=await se(()=>et(e.files),"batchPreDelete");S.postMessage({type:"response",id:e.id,metrics:n});let i=Date.now()-t;i>2e3&&(f("[WriterWorker] slow batchPreDelete",{id:e.id,ms:i,count:Array.isArray(e.files)?e.files.length:0}),P("slow batchPreDelete")),b()}catch(t){b(),r(e.id,t)}return}if(e.cmd==="writeBatch"){try{let t=Date.now(),n=Array.isArray(e.payloads)?e.payloads:[],i=n.length?n[0].fileRel:void 0;X("writeBatch",e.id,i),Ge(`writeBatch received id=${e.id} count=${n.length} sample=${n[0]?.fileRel??""}`),L&&f("[WriterWorker] writeBatch begin",{id:e.id,count:n.length,sample:n.slice(0,5).map(E=>E.fileRel)});let o=await se(()=>tt(n),"writeBatch");S.postMessage({type:"response",id:e.id,metrics:o});let l=Date.now()-t;L&&f("[WriterWorker] writeBatch end",{id:e.id,ms:l,count:n.length,metrics:o}),l>2e3&&(f("[WriterWorker] slow write batch",{id:e.id,ms:l,count:n.length}),P("slow write batch")),b()}catch(t){b(),r(e.id,t)}return}if(e.cmd==="flush"){try{let t=Date.now();X("flush",e.id);let n=Xe();S.postMessage({type:"response",id:e.id,metrics:n});let i=Date.now()-t;i>2e3&&(f("[WriterWorker] slow flush",{id:e.id,ms:i}),P("slow flush")),b()}catch(t){b(),r(e.id,t)}return}if(e.cmd==="shutdown"){try{X("shutdown",e.id),Oe(),S.postMessage({type:"response",id:e.id,metrics:x()}),b()}catch(t){b(),r(e.id,t)}return}});process.on("uncaughtException",e=>{try{S.postMessage({type:"error",message:e?.message||String(e),stack:e?.stack})}catch(r){R("[WriterWorker] failed to notify parent about uncaughtException:",r?.message??r)}});process.on("unhandledRejection",e=>{try{S.postMessage({type:"error",message:String(e)})}catch(r){R("[WriterWorker] failed to notify parent about unhandledRejection:",r?.message??r)}});
233
+ `)}var Le=Number(process.env.PANDO_SQLITE_RETRY_MIN_MS||"100"),Ae=Number(process.env.PANDO_SQLITE_RETRY_MAX_MS||"500"),ge=Math.max(0,Number(process.env.PANDO_SQLITE_RETRY_ATTEMPTS||"5")),A=Ne();if(!S)throw new Error("SQLite writer worker must be spawned as a worker thread");pe();function f(...e){process.env.PANDO_QUIET||console.log(Be([`[${new Date().toISOString()}]`,...e]))}function Be(e){return e.map(Ke).join(" ")}function Ke(e){if(typeof e=="string")return e;if(e instanceof Error)return e.stack||e.message;try{let r=JSON.stringify(e);if(typeof r=="string")return r}catch{}return Ge(e,{depth:null,breakLength:1/0,compact:!0})}function R(...e){A&&console.log(...e)}function Ye(e){A&&re("WriterWorker",e,{threadId:Me})}function ze(e){A&&re("WriterWorker","clojure-source-node",{threadId:Me,...e})}var D=null,be=null;function $e(){be||(be=setInterval(()=>{if(!D)return;let e=Date.now()-D.startedAt;e>5e3&&f("[WriterWorker] op still running",{cmd:D.cmd,id:D.id,ms:e,fileRel:D.fileRel})},2e3))}function X(e,r,t){D={cmd:e,id:r,startedAt:Date.now(),fileRel:t},$e()}function g(){D=null}var x=()=>({writeMs:0,writeTrackedMs:0,writePreDeleteMs:0,writeInsertExportsMs:0,writeInsertNodesMs:0,writeInsertReferencesMs:0,writeInsertImportsMs:0,writeInsertImportBindingsMs:0,writeInsertFileMs:0,writeFinalizeMs:0,writeInsertFtsMs:0,writeResidualMs:0}),G=Math.max(0,Math.min(Le,Ae)),Se=Math.max(G,Math.max(Le,Ae)),je=e=>new Promise(r=>setTimeout(r,e));function we(e){if(!e)return!1;let r=e.code,t=e.errcode;if(r==="ERR_SQLITE_BUSY"||r==="SQLITE_BUSY"||r==="ERR_SQLITE_ERROR"&&t===5)return!0;let n=e?.message??String(e);return typeof n=="string"&&n.toLowerCase().includes("database is locked")}function He(){if(Se<=G)return G;let e=Se-G;return G+Math.floor(Math.random()*(e+1))}async function se(e,r){let t=0,n=Date.now();for(;;)try{let i=e();return A&&t>0&&f(`[WriterWorker] ${r} recovered after retry`,{attempts:t,ms:Date.now()-n}),i}catch(i){if(!we(i)||t>=ge)throw f(`[WriterWorker] ${r} failed`,{attempts:t,ms:Date.now()-n,error:i?.message??String(i),locked:we(i)}),i;t+=1;let o=He();f(`[WriterWorker] ${r} retry ${t}/${ge} after locked database; waiting ${o}ms`),await je(o)}}var L=null,v=null,de=null,_e=null,Te=null,me=null,fe=null,C=null,K=null,w=null,h=null,V=null,q=null,H=new Map,M=new Map,Y=new Map,le=new Map,ae=Math.max(1e4,Number(process.env.PANDO_DICT_CACHE_MAX_ENTRIES||"200000")),Qe=Math.max(64,Number(process.env.PANDO_DICT_CACHE_MAX_KEY_LENGTH||"1024")),he=Math.floor(ae*.7),$=0,Q=null,O=null,z=null,J=null,Z=null,ee=null,ce,W=null,j={reference:1,call:2,new:4,type:8,import:16,export:32};function ue(){if(!L)throw new Error("writer not initialized");return L}function ve(e){v||(v=e.prepare("DELETE FROM nodes WHERE file_id = ?"),de=e.prepare("DELETE FROM exports WHERE file_id = ?"),_e=e.prepare("DELETE FROM files WHERE file_id = ?"),Te=e.prepare("DELETE FROM file_imports WHERE file_id = ?"),me=e.prepare("DELETE FROM file_import_bindings WHERE file_id = ?"),fe=e.prepare("DELETE FROM file_symbol_mentions WHERE file_id = ?"))}function te(e){C||(C=e.prepare("INSERT OR IGNORE INTO dict_kinds (text) VALUES (?)"),K=e.prepare("SELECT id FROM dict_kinds WHERE text = ?")),w||(w=e.prepare("INSERT OR IGNORE INTO dict_symbols (text) VALUES (?)"),h=e.prepare("SELECT id FROM dict_symbols WHERE text = ?")),V||(V=e.prepare("INSERT OR IGNORE INTO dict_files (path) VALUES (?)"),q=e.prepare("SELECT id FROM dict_files WHERE path = ?"))}function b(e,r,t,n,i){if(!i)return null;let o=i.length<=Qe,l=o?r.get(i):void 0;if(l!=null)return l;t.run(i);let c=n.get(i);if(!c||typeof c.id!="number")return null;if(o){if(r.size>=ae){let T=0;for(let p of r.keys())if(r.delete(p),T+=1,r.size<=he)break;$+=1,($<=10||$%25===0)&&f("[WriterWorker] dictionary cache trimmed",{trimCount:$,removed:T,maxEntries:ae,targetAfterTrim:he,cacheSizeAfter:r.size})}r.set(i,c.id)}return c.id}function Ve(e,r){te(e);let t=Y.get(r);if(t!=null)return t;V.run(r);let n=q.get(r);if(!n||typeof n.id!="number")throw new Error(`Failed to resolve file id for ${r}`);return Y.set(r,n.id),n.id}function qe(e,r){te(e);let t=Y.get(r);if(t!=null)return t;let n=q.get(r);return!n||typeof n.id!="number"?null:(Y.set(r,n.id),n.id)}function Je(e,r,t){te(e);let n=new Map;if(Array.isArray(r.symbolMentionRows)&&r.symbolMentionRows.length>0){for(let i of r.symbolMentionRows){let o=typeof i?.[0]=="string"?String(i[0]).trim():"";if(!o)continue;let l=b(e,M,w,h,o);if(l==null)continue;let c=typeof i?.[1]=="string"?String(i[1]).trim().toLowerCase():"",T=j[c]??j.reference,p=typeof i?.[2]=="string"?String(i[2]).trim():"",a=typeof i?.[3]=="string"?String(i[3]).trim():"",s=Number(i?.[4]),I=Number.isFinite(s)&&s>0?Math.floor(s):1,E=`${l}\0${p}\0${a}`,_=n.get(E);if(_){_.mentionKinds|=T,_.mentionCount+=I;continue}n.set(E,{symbolId:l,targetSymbolKey:p,containerQualifiedName:a,mentionKinds:T,mentionCount:I})}return Array.from(n.values()).map(i=>[t,r.lang,i.symbolId,i.targetSymbolKey,i.containerQualifiedName,i.mentionKinds,i.mentionCount])}for(let i of r.referenceRows||[]){let o=typeof i?.[3]=="string"?String(i[3]).trim():"";if(!o)continue;let l=b(e,M,w,h,o);if(l==null)continue;let c=typeof i?.[4]=="string"?String(i[4]).trim().toLowerCase():"",T=j[c]??j.reference,p=typeof i?.[13]=="string"?String(i[13]).trim():"",a=typeof i?.[12]=="string"?String(i[12]).trim():"",s=`${l}\0${p}\0${a}`,I=n.get(s);if(I){I.mentionKinds|=T,I.mentionCount+=1;continue}n.set(s,{symbolId:l,targetSymbolKey:p,containerQualifiedName:a,mentionKinds:T,mentionCount:1})}return Array.from(n.values()).map(i=>[t,r.lang,i.symbolId,i.targetSymbolKey,i.containerQualifiedName,i.mentionKinds,i.mentionCount])}function ke(e,r){let t=r?.journal_mode||"WAL";e.pragma(`journal_mode=${t}`),e.pragma("synchronous=OFF"),e.pragma("temp_store=MEMORY"),e.pragma("cache_size=-20000"),e.pragma("mmap_size=268435456"),e.pragma("journal_size_limit=134217728"),e.pragma("wal_autocheckpoint=1000"),e.pragma("busy_timeout=5000")}function oe(e){try{return Ee.statSync(e).size}catch{return null}}function P(e){if(!W)return;let r=`${W}-wal`,t=`${W}-shm`,n=oe(W),i=oe(r),o=oe(t);f("[WriterWorker] db sizes",{reason:e,dbPath:W,dbSize:n,walSize:i,shmSize:o})}function Ze(e){let r=B.dirname(e),t=B.basename(e),n=t.replace(".pando-index-chunk-",".pando-fts-chunk-");return B.join(r,n===t?`${t}.fts`:n)}function ye(){if(!Q)throw new Error("FTS database path not configured");if(!O){try{Ee.mkdirSync(B.dirname(Q),{recursive:!0})}catch{}O=new ie(Q),ke(O,ce)}return O}function et(e){z||(e.exec("CREATE VIRTUAL TABLE IF NOT EXISTS blob_content_fts USING fts5(blob_oid UNINDEXED, content)"),e.exec("CREATE TABLE IF NOT EXISTS blob_fts_presence (blob_oid TEXT PRIMARY KEY)"),z=e.prepare("SELECT 1 FROM blob_fts_presence WHERE blob_oid = ?"),J=e.prepare("INSERT INTO blob_content_fts (blob_oid, content) VALUES (?, ?)"),Z=e.prepare("INSERT OR REPLACE INTO blob_fts_presence (blob_oid) VALUES (?)"),ee=e.prepare("DELETE FROM blob_content_fts WHERE blob_oid = ?"))}function tt(e,r){if(!e||typeof e.blobOid!="string"||e.blobOid.length===0)return;let t=ye();et(t);let n=Date.now();r?.inTransaction||t.exec("BEGIN");try{z.get(e.blobOid)&&ee.run(e.blobOid),J.run(e.blobOid,e.content??""),Z.run(e.blobOid),r?.inTransaction||t.exec("COMMIT")}catch(o){if(!r?.inTransaction)try{t.exec("ROLLBACK")}catch(l){R("[WriterWorker] rollback failed:",l?.message??l)}throw o}let i=Date.now()-n;i>2e3&&f("[WriterWorker] slow fts insert",{blobOid:e.blobOid,ms:i,contentBytes:e.content?e.content.length:0})}function nt(e,r,t,n){let i=`${r}|${t}|${n}`,o=le.get(i);if(!o){let l=Array.from({length:n},()=>`(${new Array(t).fill("?").join(",")})`).join(","),c=`${r} VALUES ${l}`;o=e.prepare(c),le.set(i,o)}return o}function F(e,r,t,n){if(!n.length||t<=0)return;let i=Date.now(),o=Math.max(1,Math.floor(999/t));for(let c=0;c<n.length;c+=o){let T=n.slice(c,c+o);if(!T.length)continue;let p=nt(e,r,t,T.length),a=[];for(let E of T)a.push(...E);let s=Date.now();p.run(...a);let I=Date.now()-s;I>500&&f("[WriterWorker] slow insert chunk",{sqlPrefix:r,columnCount:t,rows:T.length,ms:I})}let l=Date.now()-i;l>2e3&&f("[WriterWorker] slow insertRows",{sqlPrefix:r,columnCount:t,rows:n.length,ms:l})}function De(e,r){ve(e);let t=qe(e,r);t!=null&&(v.run(t),de.run(t),_e.run(t),Te.run(t),me.run(t),fe.run(t))}function rt(e){if(!e.length)return x();let r=ue(),t=x(),n=Date.now();r.exec("BEGIN");try{for(let i of e)De(r,i);r.exec("COMMIT")}catch(i){try{r.exec("ROLLBACK")}catch(o){R("[WriterWorker] rollback failed:",o?.message??o)}throw i}return t.writePreDeleteMs=Date.now()-n,t.writeTrackedMs=t.writePreDeleteMs,t.writeMs=t.writePreDeleteMs,t}function xe(e,r){let t=ue();te(t);let n=x(),i=Date.now(),o=Ve(t,e.fileRel),l={exports:e.exportRows.length,nodes:e.nodeRows.length,refs:e.referenceRows.length,imports:e.importRows.length,importBindings:e.importBindingRows.length,fileRow:e.fileRow?1:0,fts:e.fts?1:0},c=l.exports+l.nodes+l.refs+l.imports+l.importBindings;r?.inTransaction||t.exec("BEGIN");try{if(t.exec("SAVEPOINT idx_file"),!e.preDeleted){let a=Date.now();De(t,e.fileRel),n.writePreDeleteMs+=Date.now()-a}let T=(a,s,I,E)=>{let _=Date.now();A&&f("[WriterWorker] section begin",{file:e.fileRel,label:s,count:I});let k=Date.now();E();let d=Date.now()-k;n[a]+=d,A&&f("[WriterWorker] section end",{file:e.fileRel,label:s,count:I,ms:d,elapsedSinceWriteStartMs:Date.now()-_}),d>2e3&&f("[WriterWorker] section slow",{file:e.fileRel,label:s,count:I,ms:d})};T("writeInsertExportsMs","exports",e.exportRows.length,()=>{let a=e.exportRows.map(E=>[o,e.lang,b(t,M,w,h,E[1]),U(E[2]),E[3],E[4]??null,b(t,M,w,h,E[5]),E[6]??null,E[7]??null]),s=[],I=new Map;for(let E of a){let _=E[2];_!=null&&(I.has(_)||(I.set(_,E),s.push(E)))}s.length!==a.length&&R("[WriterWorker] export rows deduped",{file:e.fileRel,lang:e.lang,before:a.length,after:s.length});try{F(t,"INSERT OR REPLACE INTO exports (file_id, lang, export_name_id, node_id, is_reexport, reexport_from, reexport_name_id, export_kind, target_symbol_key)",9,s)}catch(E){try{let _=new Map;for(let d of a){let u=d[2];u!=null&&_.set(u,(_.get(u)??0)+1)}let k=Array.from(_.entries()).filter(([,d])=>d>1);if(k.length){let d=t.prepare("SELECT text FROM dict_symbols WHERE id = ?"),u=k.map(([m,ne])=>{let Fe=d.get(m)?.text??null,We=a.filter(y=>y[2]===m).map(y=>({node_id:y[3],is_reexport:y[4],reexport_from:y[5],reexport_name_id:y[6],export_kind:y[7],target_symbol_key:y[8]}));return{id:m,count:ne,name:Fe,rows:We}});R("[WriterWorker] export duplicates detected",{file:e.fileRel,lang:e.lang,totalExports:a.length,duplicates:u});let N=a.map(m=>{let ne=m[2]!=null?d.get(m[2]):void 0,Ie=m[6]?d.get(m[6]):void 0;return{name_id:m[2],name:ne?.text??null,node_id:m[3],is_reexport:m[4],reexport_from:m[5],reexport_name_id:m[6],reexport_name:Ie?.text??null,export_kind:m[7],target_symbol_key:m[8]}});R("[WriterWorker] export rows dump",{file:e.fileRel,lang:e.lang,rows:N})}}catch(_){R("[WriterWorker] failed to compute export duplicates",_?.message??_)}throw R("[WriterWorker] export insert failed",{file:e.fileRel,lang:e.lang,exportCount:s.length,error:E?.message??E}),E}}),T("writeInsertNodesMs","nodes",e.nodeRows.length,()=>{for(let s of e.nodeRows){let I=s[2],E=s[3],_=s[4];if(!I||!String(I).trim())throw new Error(`[WriterWorker] Missing normalized kind for node in ${e.fileRel}`);if(!E||!String(E).trim())throw new Error(`[WriterWorker] Missing raw kind for node in ${e.fileRel}`);if(!_||!String(_).trim())throw new Error(`[WriterWorker] Missing raw kind source for node in ${e.fileRel}`)}let a=e.nodeRows.map(s=>[U(s[0]),o,e.lang,b(t,M,w,h,s[1]),b(t,H,C,K,s[2]),s[3],s[4],b(t,H,C,K,s[5]),s[6],s[7],s[8],b(t,H,C,K,s[9]),s[10],s[11],s[12],s[13],s[14],s[15],s[16]]);try{F(t,"INSERT OR REPLACE INTO nodes (id, file_id, lang, name_id, kind_id, raw_kind, raw_kind_source, semantic_kind_id, start_pos, end_pos, is_exported, container_kind_id, container_raw_kind, container_raw_kind_source, param_count, qualified_name, scope_chain, symbol_key, metadata)",19,a)}catch(s){if((s?.message??String(s)).includes("UNIQUE constraint failed: nodes.id")){try{let E=new Map;for(let d of e.nodeRows){let u=U(d[0]);if(u==null)continue;let N=u.toString(),m=E.get(N);m?(m.count+=1,m.rawSample.length<3&&m.rawSample.push(d[0])):E.set(N,{count:1,rawSample:[d[0]]})}let _=Array.from(E.entries()).filter(([,d])=>d.count>1).slice(0,5).map(([d,u])=>({id:d,count:u.count,rawSample:u.rawSample})),k=_.map(d=>{let u=e.nodeRows.filter(N=>{let m=U(N[0]);return m!=null&&m.toString()===d.id}).slice(0,3);return{id:d.id,count:d.count,rows:u.map(N=>({rawId:N[0],name:N[1],kind:N[2],rawKind:N[3],semanticKind:N[5],start:N[6],end:N[7],containerKind:N[9],paramCount:N[12]}))}});f("[WriterWorker] UNIQUE nodes.id collision",{file:e.fileRel,lang:e.lang,nodeCount:a.length,duplicateCount:_.length,duplicates:_,duplicateDetails:k})}catch{}try{let E=t.prepare("SELECT id, file_id, lang, start_pos, end_pos FROM nodes WHERE id = ?"),_=t.prepare("SELECT path FROM dict_files WHERE id = ?");for(let k of a){let d=k[0];if(d==null)continue;let u=E.get(d);if(u&&typeof u.file_id=="number"){let N=_.get(u.file_id);f("[WriterWorker] nodes.id collision existing row",{file:e.fileRel,lang:e.lang,nodeId:d?.toString?.()??String(d),existingFileId:u.file_id,existingPath:N?.path,existingLang:u.lang,existingRange:{start:u.start_pos,end:u.end_pos}});break}}}catch{}}throw s}}),T("writeInsertReferencesMs","references",e.referenceRows.length,()=>{let a=Je(t,e,o);A&&e.lang==="clojure"&&a.length>0&&ze({stage:"writer-symbol-mentions",file:e.fileRel,refs:e.referenceRows.length,mentionRows:a.length,sample:a.slice(0,5).map(s=>({symbolId:s[2],mentionKinds:s[3],mentionCount:s[4]}))}),F(t,"INSERT OR REPLACE INTO file_symbol_mentions (file_id, lang, symbol_id, target_symbol_key, container_qualified_name, mention_kinds, mention_count)",7,a)}),T("writeInsertImportsMs","imports",e.importRows.length,()=>{let a=e.importRows.map(s=>[o,e.lang,s[1]??null,s[2]]);F(t,"INSERT INTO file_imports (file_id, lang, module_spec, is_type_only)",4,a)}),T("writeInsertImportBindingsMs","import_bindings",e.importBindingRows.length,()=>{let a=e.importBindingRows.map(s=>[o,e.lang,s[1]??null,b(t,M,w,h,s[2]),b(t,M,w,h,s[3]),b(t,M,w,h,s[4]),s[5]]);F(t,"INSERT INTO file_import_bindings (file_id, lang, module_spec, binding_kind_id, local_name_id, imported_name_id, is_type_only)",7,a)}),T("writeInsertFileMs","files",e.fileRow?1:0,()=>{let a=e.fileRow,s=[o,e.lang,a[1],a[2],a[3],a[4]];F(t,"INSERT OR REPLACE INTO files (file_id, lang, last_modified, file_size, status, indexed_at)",6,[s])}),T("writeInsertFtsMs","fts",e.fts?1:0,()=>tt(e.fts,{inTransaction:r?.inTransaction}));let p=Date.now();t.exec("RELEASE SAVEPOINT idx_file"),r?.inTransaction||t.exec("COMMIT"),n.writeFinalizeMs+=Date.now()-p}catch(T){try{t.exec("ROLLBACK TO SAVEPOINT idx_file")}catch(p){R("[WriterWorker] rollback to savepoint failed:",p?.message??p)}if(!r?.inTransaction)try{t.exec("ROLLBACK")}catch(p){R("[WriterWorker] rollback failed:",p?.message??p)}throw T}return n.writeMs=Date.now()-i,n.writeTrackedMs=n.writePreDeleteMs+n.writeInsertExportsMs+n.writeInsertNodesMs+n.writeInsertImportsMs+n.writeInsertImportBindingsMs+n.writeInsertFileMs+n.writeInsertFtsMs+n.writeFinalizeMs,n.writeResidualMs=Math.max(0,n.writeMs-n.writeTrackedMs),n}function it(e){if(!e.length)return x();let r=Date.now(),t=x(),n=ue(),i=e.some(l=>l.fts&&typeof l.fts.blobOid=="string"&&l.fts.blobOid.length>0),o=null;n.exec("BEGIN");try{i&&(o=ye(),o.exec("BEGIN"));for(let l of e){let c=xe(l,{inTransaction:!0});t.writePreDeleteMs+=c.writePreDeleteMs,t.writeInsertExportsMs+=c.writeInsertExportsMs,t.writeInsertNodesMs+=c.writeInsertNodesMs,t.writeInsertReferencesMs+=c.writeInsertReferencesMs,t.writeInsertImportsMs+=c.writeInsertImportsMs,t.writeInsertImportBindingsMs+=c.writeInsertImportBindingsMs,t.writeInsertFileMs+=c.writeInsertFileMs,t.writeFinalizeMs+=c.writeFinalizeMs,t.writeInsertFtsMs+=c.writeInsertFtsMs}o&&o.exec("COMMIT"),n.exec("COMMIT")}catch(l){if(f("[WriterWorker] handleWriteBatch error",{error:l?.message??l,stack:l?.stack?.split(`
234
+ `).slice(0,3).join(" | ")}),o)try{o.exec("ROLLBACK")}catch(c){R("[WriterWorker] fts batch rollback failed:",c?.message??c)}try{n.exec("ROLLBACK")}catch(c){R("[WriterWorker] batch rollback failed:",c?.message??c)}throw l}return t.writeTrackedMs=t.writePreDeleteMs+t.writeInsertExportsMs+t.writeInsertNodesMs+t.writeInsertReferencesMs+t.writeInsertImportsMs+t.writeInsertImportBindingsMs+t.writeInsertFileMs+t.writeInsertFtsMs+t.writeFinalizeMs,t.writeMs=Date.now()-r,t.writeResidualMs=Math.max(0,t.writeMs-t.writeTrackedMs),t}function Xe(){return x()}function Oe(){try{Xe()}catch(e){R("[WriterWorker] backfill on shutdown failed:",e?.message??e)}if(L){try{L.close()}catch(e){R("[WriterWorker] failed to close database:",e?.message??e)}L=null}if(O){try{O.close()}catch(e){R("[WriterWorker] failed to close FTS database:",e?.message??e)}O=null}v=null,de=null,_e=null,Te=null,me=null,fe=null,z=null,J=null,Z=null,ee=null,C=null,K=null,w=null,h=null,V=null,q=null,le.clear(),H.clear(),M.clear(),Y.clear()}S.on("message",async e=>{let r=(t,n)=>{let i=n instanceof Error?n:new Error(String(n));S.postMessage({type:"error",id:t,message:i.message,stack:i.stack})};if(e.cmd==="init"){try{let t=Date.now();X("init"),L&&Oe();let n=e.dbPath;W=n,ce=e.pragmas;try{Ee.mkdirSync(B.dirname(n),{recursive:!0})}catch{}if(L=new ie(n),ke(L,ce),Re(L),Q=Ze(n),O)try{O.close()}catch(i){R("[WriterWorker] failed to close FTS database:",i?.message??i)}O=null,z=null,J=null,Z=null,ee=null,S.postMessage({type:"ready"}),f("[WriterWorker] init complete",{dbPath:n,ms:Date.now()-t}),P("init"),g()}catch(t){g(),r(void 0,t)}return}if(e.cmd==="write"){try{let t=Date.now(),n=e.payload,i=Array.isArray(n?.fileRow)&&typeof n.fileRow[0]=="string"?n.fileRow[0]:void 0;X("write",e.id,i);let o=await se(()=>xe(n),"write");S.postMessage({type:"response",id:e.id,metrics:o});let l=Date.now()-t;l>2e3&&(f("[WriterWorker] slow write",{id:e.id,ms:l}),P("slow write")),g()}catch(t){g(),r(e.id,t)}return}if(e.cmd==="batchPreDelete"){try{let t=Date.now();X("batchPreDelete",e.id);let n=await se(()=>rt(e.files),"batchPreDelete");S.postMessage({type:"response",id:e.id,metrics:n});let i=Date.now()-t;i>2e3&&(f("[WriterWorker] slow batchPreDelete",{id:e.id,ms:i,count:Array.isArray(e.files)?e.files.length:0}),P("slow batchPreDelete")),g()}catch(t){g(),r(e.id,t)}return}if(e.cmd==="writeBatch"){try{let t=Date.now(),n=Array.isArray(e.payloads)?e.payloads:[],i=n.length?n[0].fileRel:void 0;X("writeBatch",e.id,i),Ye(`writeBatch received id=${e.id} count=${n.length} sample=${n[0]?.fileRel??""}`),A&&f("[WriterWorker] writeBatch begin",{id:e.id,count:n.length,sample:n.slice(0,5).map(c=>c.fileRel)});let o=await se(()=>it(n),"writeBatch");S.postMessage({type:"response",id:e.id,metrics:o});let l=Date.now()-t;A&&f("[WriterWorker] writeBatch end",{id:e.id,ms:l,count:n.length,metrics:o}),l>2e3&&(f("[WriterWorker] slow write batch",{id:e.id,ms:l,count:n.length}),P("slow write batch")),g()}catch(t){g(),r(e.id,t)}return}if(e.cmd==="flush"){try{let t=Date.now();X("flush",e.id);let n=Xe();S.postMessage({type:"response",id:e.id,metrics:n});let i=Date.now()-t;i>2e3&&(f("[WriterWorker] slow flush",{id:e.id,ms:i}),P("slow flush")),g()}catch(t){g(),r(e.id,t)}return}if(e.cmd==="shutdown"){try{X("shutdown",e.id),Oe(),S.postMessage({type:"response",id:e.id,metrics:x()}),g()}catch(t){g(),r(e.id,t)}return}});process.on("uncaughtException",e=>{try{S.postMessage({type:"error",message:e?.message||String(e),stack:e?.stack})}catch(r){R("[WriterWorker] failed to notify parent about uncaughtException:",r?.message??r)}});process.on("unhandledRejection",e=>{try{S.postMessage({type:"error",message:String(e)})}catch(r){R("[WriterWorker] failed to notify parent about unhandledRejection:",r?.message??r)}});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pando-ai",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Standalone pando MCP CLI",
5
5
  "bin": {
6
6
  "pando-ai": "bin/pando-ai.js"
@@ -8,15 +8,16 @@
8
8
  "files": [
9
9
  "bin/",
10
10
  "dist/",
11
- "resources/tools/pando-tools.json",
11
+ "resources/tools/generated_pando-tools.json",
12
+ "resources/tools/generated_tools.md",
12
13
  "tools/clojure-indexer/bin/",
13
14
  "tools/clojure-indexer/lib/*.jar",
14
15
  "tools/clojure-editor/bin/",
15
16
  "tools/clojure-editor/lib/*.jar",
16
17
  "tools/csharp-indexer/CSharpIndexer.csproj",
18
+ "tools/csharp-indexer/src/",
17
19
  "tools/csharp-indexer/bin/pando-csharp-indexer",
18
- "tools/csharp-indexer/bin/pando-csharp-indexer.cmd",
19
- "tools/csharp-indexer/bin/Release/**/*"
20
+ "tools/csharp-indexer/bin/pando-csharp-indexer.cmd"
20
21
  ],
21
22
  "engines": {
22
23
  "node": ">=22.5.0"
@@ -29,9 +30,9 @@
29
30
  "access": "public"
30
31
  },
31
32
  "dependencies": {
33
+ "@parcel/watcher": "^2.5.6",
32
34
  "ajv": "^8.20.0",
33
35
  "ajv-formats": "^3.0.1",
34
- "chokidar": "^4.0.3",
35
36
  "datascript": "^1.7.5",
36
37
  "glob": "^13.0.6",
37
38
  "ignore": "^5.3.2",
@@ -2,9 +2,9 @@
2
2
  "_generated": {
3
3
  "note": "Generated file. JSON does not support comments, so regeneration instructions live here.",
4
4
  "doNotEdit": true,
5
- "docs": "../../docs/tools.md",
5
+ "docs": "generated_tools.md",
6
6
  "sourceOfTruth": "../pando-backend/src/lib/tooling/tools.d/",
7
- "backendAssembledFile": "../pando-backend/src/lib/tooling/tools.json",
7
+ "backendAssembledFile": "../pando-backend/src/lib/tooling/generated_tools.json",
8
8
  "regenerate": {
9
9
  "extension": "npm run tools:schema:pando",
10
10
  "backendValidate": "cd ../pando-backend && node scripts/validate-tools.mjs",
@@ -14,7 +14,7 @@
14
14
  "workflow": [
15
15
  "Edit backend tool schema in ../pando-backend/src/lib/tooling/tools.d/.",
16
16
  "If adding a tool, update ../pando-backend/src/lib/tooling/tools.d/index.json.",
17
- "Validate and assemble backend tools.json.",
17
+ "Validate and assemble backend generated_tools.json.",
18
18
  "Run npm run tools:schema:pando in this repo to refresh this file."
19
19
  ]
20
20
  },
@@ -63,7 +63,7 @@
63
63
  "name": "read-this-first",
64
64
  "category": "pando",
65
65
  "signature": "read-this-first()",
66
- "description": "pandō tools are the required code surface for supported-language source operations in pandō benchmark runs. Use pandō for supported source-code read, search, navigation, refactor, edit, delete, insert, replace, rename, references, callers, exports, SQL index queries, and filter-map-reduce operations. Supported source languages include TypeScript, JavaScript, Python, C, C++, C#, Dart, Java, Clojure, and ClojureScript files (.cljs via the Clojure language id). Use non-pandō text/shell tools only for non-code files, unsupported languages, shell setup, builds, and tests. Current find-nodes is Datalog-only and accepts { op, lang?, snapshot?, scope, datalog, prefilter?, include?, page? }; legacy fields such as q, qMode, name, symbolKinds, scopeNode, limit, offset, and top-level cursor are rejected. Example find-nodes declaration lookup: { op:'find-nodes', lang:['ts','js'], scope:{workspace:true}, datalog:{query:'[:find ?n :where [?n :node/name \"myFunction\"]]', bindings:['?n'], result:{nodeVar:'?n'}}, include:{self:true, topN:1}, page:{limit:5} }. Then pass the returned path and hash without @ to modifying tools such as rename, replace, replace-body, insert, or delete. pandō modifying tools automatically create snapshots before and after execution; do not manually snapshot before pandō operations. If a pandō operation fails because of a stale path or hash mismatch, call find-nodes again to refresh the current path/hash and retry with pandō.",
66
+ "description": "Pando is an AST-aware code navigation and editing layer for large repos. It keeps a light index of supported source files, uses that index to narrow candidate files, then parses exact AST details at query or edit time.\n\nUse Pando for source-code search, navigation, references, callers, exports, renames, inserts, replacements, and deletes. Use shell/text tools for builds, tests, generated files, non-code files, and unsupported languages.\n\nRead next:\n- workspace-overview: quick inventory of indexed files and symbols.\n- find-nodes: search by language, scope, and Datalog; request include.self/topN when you need paths and hashes for edits.\n- get-content: read files or node paths returned by search tools.\n- list-exports, find-references, and find-callers: follow symbols before changing them.\n- Writers: rename, replace, replace-body, insert, and delete. Re-run find-nodes first if a path or hash is stale.\n\nUnnamed nodes can and should still be edited with Pando. Statements, returns, calls, arguments, branches, literals, and other unnamed syntax are normal AST nodes; find them by starting from a named entity or file, then narrowing by kind, text, role, parent, or child index.\n\nExamples:\n- In one find-nodes call, search for a function by name within the workspace and request include.self/topN to get the exact node path and hash.\n- To edit a statement inside a named function, find the function with include.self, then call find-nodes again with scope.node set to { path, expectedHash } for that function. Use predicates such as :node/kind \"ReturnStatement\" or :node/text \"oldValue\", then pass the returned statement path and hash without @ to replace or insert; delete uses expectedHashes.\n- For scripts or top-level code, scope find-nodes to the file path instead of a named node, find the statement by kind/text/role/index, then edit that returned node with a writer.\n- Insert code is literal: include the newline and indentation you want when inserting before or after a statement anchor.",
67
67
  "parameters": {
68
68
  "type": "object",
69
69
  "properties": {},
@@ -146,7 +146,7 @@
146
146
  "name": "find-nodes",
147
147
  "category": "pando",
148
148
  "signature": "find-nodes(lang, snapshot, scope, datalog, prefilter, include, page)",
149
- "description": "Search code nodes with per-file lazy Datalog execution. Candidate files are processed in deterministic order, one file at a time, and execution stops as soon as page.limit items have been emitted. Pagination is cursor-only via page.cursor. page.limit defaults to 5 when omitted and caps at 20. Optional prefilter.fts narrows candidate files before Datalog execution. This operation is per-file structural search only; cross-file Datalog joins are not supported here. For arbitrary unnamed AST nodes, first find a stable enclosing node such as a function/class, then re-run find-nodes with scope.node and use :node/kind, :node/parent, :node/role, :node/index-in-parent, include.self, and include.parents to disambiguate the exact child node before editing.",
149
+ "description": "Search code nodes with per-file lazy Datalog execution. Candidate files are processed in deterministic order, one file at a time, and execution stops as soon as page.limit items have been emitted. Pagination is cursor-only via page.cursor. page.limit defaults to 5 when omitted and caps at 20. Optional prefilter.fts narrows candidate files before Datalog execution. This operation is per-file structural search only; cross-file Datalog joins are not supported here.",
150
150
  "parameters": {
151
151
  "type": "object",
152
152
  "properties": {
@@ -286,7 +286,7 @@
286
286
  "properties": {
287
287
  "fts": {
288
288
  "type": "string",
289
- "description": "SQLite FTS5 MATCH query passed through unchanged after trimming; used only to narrow candidate files."
289
+ "description": "SQLite FTS-style query used only to narrow candidate files."
290
290
  }
291
291
  },
292
292
  "additionalProperties": false
@@ -408,45 +408,6 @@
408
408
  "limit": 5,
409
409
  "cursor": null
410
410
  }
411
- },
412
- {
413
- "lang": [
414
- "ts",
415
- "js"
416
- ],
417
- "scope": {
418
- "node": {
419
- "path": "src/service.ts#120-520:FunctionDeclaration",
420
- "expectedHash": "p123:c456"
421
- }
422
- },
423
- "datalog": {
424
- "query": "[:find ?n ?parent ?role ?idx :where [?n :node/kind \"IfStatement\"] [?n :node/parent ?parent] [?n :node/role ?role] [?n :node/index-in-parent ?idx]]",
425
- "bindings": [
426
- "?n",
427
- "?parent",
428
- "?role",
429
- "?idx"
430
- ],
431
- "result": {
432
- "nodeVar": "?n",
433
- "columns": {
434
- "parent": "?parent",
435
- "role": "?role",
436
- "index": "?idx"
437
- }
438
- }
439
- },
440
- "include": {
441
- "self": true,
442
- "parents": true,
443
- "topN": 5,
444
- "maxChars": 4000
445
- },
446
- "page": {
447
- "limit": 10,
448
- "cursor": null
449
- }
450
411
  }
451
412
  ]
452
413
  },
@@ -738,7 +699,7 @@
738
699
  "name": "query-db",
739
700
  "category": "pando",
740
701
  "signature": "query-db(sql, maxRows)",
741
- "description": "Execute passthrough SQL against all index chunks (readonly), then globally merge and apply ORDER BY/LIMIT/OFFSET semantics in code. Chunk identity is intentionally hidden from results. Use get-db-schema first when exploring. For relationship mining, inspect node_references plus dict_kinds; non-TS find-references/find-callers often resolve at query time via target_symbol_key or target_node_id rather than a generic relationships table. Grouped ORDER BY queries must include an explicit LIMIT. Example: { sql:'SELECT * FROM nodes LIMIT 20' }",
702
+ "description": "Execute readonly SQL against each index chunk separately, then concatenate rows and reapply global ORDER BY/LIMIT/OFFSET semantics in code. It does not compute global aggregates across chunks: COUNT/SUM/MIN/MAX/AVG and GROUP BY results remain per-chunk unless you combine them yourself. Use get-db-schema first when exploring. For relationship mining, inspect node_references plus dict_kinds; non-TS find-references/find-callers often resolve at query time via target_symbol_key or target_node_id rather than a generic relationships table. Grouped ORDER BY queries must include an explicit LIMIT. Example: { sql:'SELECT * FROM nodes LIMIT 20' }",
742
703
  "parameters": {
743
704
  "type": "object",
744
705
  "properties": {
@@ -0,0 +1,93 @@
1
+ # Tool Schema Pipeline
2
+
3
+ `resources/tools/generated_pando-tools.json` in this repo is generated. Do not edit it directly.
4
+
5
+ ## Source of Truth
6
+
7
+ The canonical tool definitions live in the backend repo:
8
+
9
+ - Backend per-tool files: [`../pando-backend/src/lib/tooling/tools.d/`](/Users/george/Documents/GitHub/pando-backend/src/lib/tooling/tools.d)
10
+ - Backend assembled file: [`../pando-backend/src/lib/tooling/generated_tools.json`](/Users/george/Documents/GitHub/pando-backend/src/lib/tooling/generated_tools.json)
11
+ - Extension bundled subset: [`resources/tools/generated_pando-tools.json`](/Users/george/Documents/GitHub/pando-extension/resources/tools/generated_pando-tools.json)
12
+ - CLI package bundled subset: [`packages/pando-cli/resources/tools/generated_pando-tools.json`](/Users/george/Documents/GitHub/pando-extension/packages/pando-cli/resources/tools/generated_pando-tools.json)
13
+
14
+ Each tool has its own JSON file in `tools.d`. `tools.d/index.json` controls ordering and the assembled signature list.
15
+
16
+ ## Backend Workflow
17
+
18
+ When changing tool schemas:
19
+
20
+ 1. Edit or add the relevant `tools.d/*.json` file in `../pando-backend/src/lib/tooling/tools.d/`.
21
+ 2. If it is a new tool, update `tools.d/index.json`:
22
+ - add its signature to `signatures`
23
+ - add its name to `order`
24
+ 3. Keep the generated signatures aligned with the live MCP surface. If a parameter is removed from a tool implementation, remove it from the backend `tools.d/*.json` schema first, then regenerate the assembled and bundled JSON files.
25
+ 4. Validate schemas:
26
+
27
+ ```bash
28
+ cd ../pando-backend
29
+ node scripts/validate-tools.mjs
30
+ ```
31
+
32
+ 5. Re-assemble `generated_tools.json`:
33
+
34
+ ```bash
35
+ cd ../pando-backend
36
+ node scripts/assemble-tools.mjs
37
+ ```
38
+
39
+ If you ever need to rebuild `tools.d/` from an edited backend `generated_tools.json`, use:
40
+
41
+ ```bash
42
+ cd ../pando-backend
43
+ node scripts/split-tools.mjs
44
+ ```
45
+
46
+ ## Extension Workflow
47
+
48
+ The extension bundles only the Pando-prefixed subset of the backend tool catalog.
49
+
50
+ Generate the bundled file with:
51
+
52
+ ```bash
53
+ cd /Users/george/Documents/GitHub/pando-extension
54
+ npm run tools:schema:pando
55
+ ```
56
+
57
+ This runs [`scripts/generate-pando-tools.mjs`](/Users/george/Documents/GitHub/pando-extension/scripts/generate-pando-tools.mjs), which:
58
+
59
+ - reads `../pando-backend/src/lib/tooling/generated_tools.json` by default
60
+ - keeps only `pando_*` / `pando-*` tools
61
+ - normalizes names like `pando_find_nodes` to `find-nodes`
62
+ - writes [`resources/tools/generated_pando-tools.json`](/Users/george/Documents/GitHub/pando-extension/resources/tools/generated_pando-tools.json)
63
+ - writes the same bundled schema to [`packages/pando-cli/resources/tools/generated_pando-tools.json`](/Users/george/Documents/GitHub/pando-extension/packages/pando-cli/resources/tools/generated_pando-tools.json)
64
+ - fails if the backend assembled `generated_tools.json` cannot be found, so builds do not silently reuse a stale bundled schema
65
+
66
+ To point the extension generator at a different backend file temporarily:
67
+
68
+ ```bash
69
+ PANDO_BACKEND_TOOLS_JSON=/abs/path/to/generated_tools.json npm run tools:schema:pando
70
+ ```
71
+
72
+ ## Build Integration
73
+
74
+ These extension scripts already regenerate the bundled schema:
75
+
76
+ - `npm run compile`
77
+ - `npm run vscode:prepublish`
78
+
79
+ Both flow through `npm run tools:schema:pando`.
80
+
81
+ ## Runtime Loading
82
+
83
+ The extension reads the bundled schema from:
84
+
85
+ - [`resources/tools/generated_pando-tools.json`](/Users/george/Documents/GitHub/pando-extension/resources/tools/generated_pando-tools.json)
86
+
87
+ Relevant code paths:
88
+
89
+ - webview loading: [`src/extension/webview/ChatViewProvider.ts`](/Users/george/Documents/GitHub/pando-extension/src/extension/webview/ChatViewProvider.ts)
90
+ - MCP server loading: [`src/extension/mcp/PandoMcpServer.ts`](/Users/george/Documents/GitHub/pando-extension/src/extension/mcp/PandoMcpServer.ts)
91
+ - refresh helper: [`src/extension/utils/toolsSchemaCache.ts`](/Users/george/Documents/GitHub/pando-extension/src/extension/utils/toolsSchemaCache.ts)
92
+
93
+ `toolsSchemaCache.ts` is currently a no-op refresh path, so the bundled file is the normal source at runtime.
@@ -1,7 +1,7 @@
1
1
  <Project Sdk="Microsoft.NET.Sdk">
2
2
  <PropertyGroup>
3
3
  <OutputType>Exe</OutputType>
4
- <TargetFrameworks>net8.0;net10.0</TargetFrameworks>
4
+ <TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
5
5
  <Nullable>enable</Nullable>
6
6
  <LangVersion>latest</LangVersion>
7
7
  </PropertyGroup>