@vpxa/kb 0.1.11 → 0.1.13

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 (58) hide show
  1. package/README.md +48 -37
  2. package/package.json +1 -1
  3. package/packages/analyzers/dist/entry-point-analyzer.d.ts +18 -0
  4. package/packages/analyzers/dist/entry-point-analyzer.js +6 -5
  5. package/packages/analyzers/dist/pattern-analyzer.js +1 -1
  6. package/packages/analyzers/dist/types.d.ts +1 -1
  7. package/packages/cli/dist/commands/init.d.ts +2 -1
  8. package/packages/cli/dist/commands/init.js +242 -183
  9. package/packages/cli/dist/commands/knowledge.js +1 -1
  10. package/packages/cli/dist/commands/system.js +6 -3
  11. package/packages/cli/dist/helpers.js +5 -3
  12. package/packages/core/dist/content-detector.d.ts +5 -1
  13. package/packages/core/dist/content-detector.js +1 -1
  14. package/packages/core/dist/index.d.ts +1 -1
  15. package/packages/core/dist/index.js +1 -1
  16. package/packages/core/dist/types.d.ts +2 -0
  17. package/packages/server/dist/index.js +1 -1
  18. package/packages/server/dist/server.d.ts +0 -13
  19. package/packages/server/dist/server.js +1 -1
  20. package/packages/server/dist/tools/analyze.tools.js +3 -1
  21. package/packages/server/dist/tools/audit.tool.d.ts +5 -0
  22. package/packages/server/dist/tools/audit.tool.js +4 -0
  23. package/packages/server/dist/tools/replay.tool.js +4 -4
  24. package/packages/server/dist/tools/search.tool.js +18 -14
  25. package/packages/server/dist/tools/status.tool.js +3 -3
  26. package/packages/server/dist/tools/toolkit.tools.d.ts +1 -1
  27. package/packages/server/dist/tools/toolkit.tools.js +23 -20
  28. package/packages/server/dist/version-check.d.ts +10 -0
  29. package/packages/server/dist/version-check.js +1 -0
  30. package/packages/store/dist/lance-store.js +1 -1
  31. package/packages/store/dist/store.interface.d.ts +2 -0
  32. package/packages/tools/dist/audit.d.ts +66 -0
  33. package/packages/tools/dist/audit.js +7 -0
  34. package/packages/tools/dist/check.d.ts +19 -0
  35. package/packages/tools/dist/check.js +2 -2
  36. package/packages/tools/dist/compact.d.ts +4 -2
  37. package/packages/tools/dist/compact.js +2 -2
  38. package/packages/tools/dist/dead-symbols.d.ts +9 -1
  39. package/packages/tools/dist/dead-symbols.js +2 -2
  40. package/packages/tools/dist/forge-classify.js +1 -1
  41. package/packages/tools/dist/guide.d.ts +23 -0
  42. package/packages/tools/dist/guide.js +1 -0
  43. package/packages/tools/dist/health.js +2 -1
  44. package/packages/tools/dist/index.d.ts +6 -2
  45. package/packages/tools/dist/index.js +1 -1
  46. package/packages/tools/dist/path-resolver.d.ts +12 -0
  47. package/packages/tools/dist/path-resolver.js +1 -0
  48. package/packages/tools/dist/replay.d.ts +1 -1
  49. package/packages/tools/dist/response-envelope.d.ts +41 -0
  50. package/packages/tools/dist/response-envelope.js +1 -0
  51. package/packages/tools/dist/scope-map.d.ts +2 -0
  52. package/packages/tools/dist/scope-map.js +1 -1
  53. package/packages/tools/dist/truncation.d.ts +9 -0
  54. package/packages/tools/dist/truncation.js +8 -8
  55. package/packages/tui/dist/App.js +109 -109
  56. package/packages/tui/dist/index.js +116 -116
  57. package/packages/tui/dist/panels/LogPanel.js +100 -100
  58. package/skills/knowledge-base/SKILL.md +19 -19
@@ -1,21 +1,24 @@
1
- import{addToWorkset as x,batch as b,check as m,checkpointLatest as w,checkpointList as S,checkpointLoad as $,checkpointSave as k,codemod as E,compact as v,dataTransform as T,delegate as q,delegateListModels as O,deleteWorkset as M,diffParse as N,evaluate as _,fileSummary as R,find as g,findDeadSymbols as I,findExamples as J,getWorkset as C,gitContext as j,health as L,laneCreate as F,laneDiff as D,laneDiscard as A,laneList as P,laneMerge as W,laneStatus as K,listWorksets as U,parseOutput as B,processList as z,processLogs as G,processStart as Q,processStatus as H,processStop as V,queueClear as X,queueCreate as Y,queueDelete as Z,queueDone as ee,queueFail as te,queueGet as re,queueList as ne,queueNext as oe,queuePush as se,removeFromWorkset as ie,rename as ae,saveWorkset as ce,scopeMap as le,stashClear as de,stashDelete as ue,stashGet as pe,stashList as fe,stashSet as me,symbol as ge,testRun as he,trace as ye,watchList as xe,watchStart as be,watchStop as we,webFetch as Se}from"../../../tools/dist/index.js";import{z as r}from"zod";function Le(t,n){t.registerTool("compact",{description:"Compress text to relevant sections using embedding similarity (no LLM). Ideal for reducing file contents before context injection. Segments by paragraph/sentence/line.",inputSchema:{text:r.string().describe("The text to compress"),query:r.string().describe("Focus query \u2014 what are you trying to understand?"),max_chars:r.number().min(100).max(5e4).default(3e3).describe("Target output size in characters"),segmentation:r.enum(["paragraph","sentence","line"]).default("paragraph").describe("How to split the text for scoring")}},async({text:e,query:s,max_chars:o,segmentation:i})=>{try{const a=await v(n,{text:e,query:s,maxChars:o,segmentation:i});return{content:[{type:"text",text:[`Compressed ${a.originalChars} \u2192 ${a.compressedChars} chars (${(a.ratio*100).toFixed(0)}%)`,`Kept ${a.segmentsKept}/${a.segmentsTotal} segments`,"",a.text].join(`
2
- `)}]}}catch(a){return{content:[{type:"text",text:`Compact failed: ${a.message}`}],isError:!0}}})}function Fe(t,n,e){t.registerTool("scope_map",{description:"Generate a task-scoped reading plan. Given a task description, identifies which files and sections are relevant, with estimated token counts and suggested reading order.",inputSchema:{task:r.string().describe("Description of the task to scope"),max_files:r.number().min(1).max(50).default(15).describe("Maximum files to include"),content_type:r.string().optional().describe("Filter by content type")}},async({task:s,max_files:o,content_type:i})=>{try{const a=await le(n,e,{task:s,maxFiles:o,contentType:i});return{content:[{type:"text",text:[`## Scope Map: ${s}`,`Total estimated tokens: ~${a.totalEstimatedTokens}`,"","### Files (by relevance)",...a.files.map((c,u)=>`${u+1}. **${c.path}** (~${c.estimatedTokens} tokens, ${(c.relevance*100).toFixed(0)}% relevant)
3
- ${c.reason}
4
- Focus: ${c.focusRanges.map(d=>`L${d.start}-${d.end}`).join(", ")}`),"","### Suggested Reading Order",...a.readingOrder.map((c,u)=>`${u+1}. ${c}`)].join(`
5
- `)+"\n\n---\n_Next: Use `search` to dive into specific files, or `compact` to compress file contents for context._"}]}}catch(a){return{content:[{type:"text",text:`Scope map failed: ${a.message}`}],isError:!0}}})}function De(t,n,e){t.registerTool("find",{description:"Federated search across vector similarity, keyword (FTS), file glob, and regex pattern. Combines strategies, deduplicates, and returns unified results.",inputSchema:{query:r.string().optional().describe("Semantic/keyword search query"),glob:r.string().optional().describe("File glob pattern"),pattern:r.string().optional().describe("Regex pattern to match in content"),limit:r.number().min(1).max(50).default(10).describe("Max results"),content_type:r.string().optional().describe("Filter by content type")}},async({query:s,glob:o,pattern:i,limit:a,content_type:l})=>{try{const c=await g(n,e,{query:s,glob:o,pattern:i,limit:a,contentType:l});return c.results.length===0?{content:[{type:"text",text:"No results found."}]}:{content:[{type:"text",text:[`Found ${c.totalFound} results via ${c.strategies.join(" + ")}`,"",...c.results.map(d=>{const h=d.lineRange?`:${d.lineRange.start}-${d.lineRange.end}`:"",y=d.preview?`
6
- ${d.preview.slice(0,100)}...`:"";return`- [${d.source}] ${d.path}${h} (${(d.score*100).toFixed(0)}%)${y}`})].join(`
7
- `)}]}}catch(c){return{content:[{type:"text",text:`Find failed: ${c.message}`}],isError:!0}}})}function Ae(t){t.registerTool("parse_output",{description:"Parse structured data from build tool output. Supports tsc, vitest, biome, and git status. Auto-detects the tool or specify explicitly.",inputSchema:{output:r.string().describe("Raw output text from a build tool"),tool:r.enum(["tsc","vitest","biome","git-status"]).optional().describe("Tool to parse as (auto-detects if omitted)")}},async({output:n,tool:e})=>{try{const s=n.replace(/\\n/g,`
8
- `).replace(/\\t/g," "),o=B(s,e);return{content:[{type:"text",text:JSON.stringify(o,null,2)}]}}catch(s){return{content:[{type:"text",text:`Parse failed: ${s.message}`}],isError:!0}}})}function Pe(t){t.registerTool("workset",{description:"Manage named file sets (worksets). Save, load, list, add/remove files. Worksets persist across sessions in .kb-state/worksets.json.",inputSchema:{action:r.enum(["save","get","list","delete","add","remove"]).describe("Operation to perform"),name:r.string().optional().describe("Workset name (required for all except list)"),files:r.array(r.string()).optional().describe("File paths (required for save, add, remove)"),description:r.string().optional().describe("Description (for save)")}},async({action:n,name:e,files:s,description:o})=>{try{switch(n){case"save":{if(!e||!s)throw new Error("name and files required for save");const i=ce(e,s,{description:o});return{content:[{type:"text",text:`Saved workset "${i.name}" with ${i.files.length} files.`}]}}case"get":{if(!e)throw new Error("name required for get");const i=C(e);return i?{content:[{type:"text",text:JSON.stringify(i,null,2)}]}:{content:[{type:"text",text:`Workset "${e}" not found.`}]}}case"list":{const i=U();return i.length===0?{content:[{type:"text",text:"No worksets."}]}:{content:[{type:"text",text:i.map(l=>`- **${l.name}** (${l.files.length} files) \u2014 ${l.description??"no description"}`).join(`
9
- `)}]}}case"delete":{if(!e)throw new Error("name required for delete");return{content:[{type:"text",text:M(e)?`Deleted workset "${e}".`:`Workset "${e}" not found.`}]}}case"add":{if(!e||!s)throw new Error("name and files required for add");const i=x(e,s);return{content:[{type:"text",text:`Added to workset "${i.name}": now ${i.files.length} files.`}]}}case"remove":{if(!e||!s)throw new Error("name and files required for remove");const i=ie(e,s);return i?{content:[{type:"text",text:`Removed from workset "${i.name}": now ${i.files.length} files.`}]}:{content:[{type:"text",text:`Workset "${e}" not found.`}]}}}}catch(i){return{content:[{type:"text",text:`Workset operation failed: ${i.message}`}],isError:!0}}})}function We(t){t.registerTool("check",{description:"Run incremental typecheck (tsc) and lint (biome) on the project or specific files. Returns structured error and warning lists.",inputSchema:{files:r.array(r.string()).optional().describe("Specific files to check (if omitted, checks all)"),cwd:r.string().optional().describe("Working directory"),skip_types:r.boolean().default(!1).describe("Skip TypeScript typecheck"),skip_lint:r.boolean().default(!1).describe("Skip Biome lint")}},async({files:n,cwd:e,skip_types:s,skip_lint:o})=>{try{const i=await m({files:n,cwd:e,skipTypes:s,skipLint:o});return{content:[{type:"text",text:JSON.stringify(i,null,2)}]}}catch(i){return{content:[{type:"text",text:`Check failed: ${i.message}`}],isError:!0}}})}function Ke(t,n,e){t.registerTool("batch",{description:"Execute multiple built-in operations in parallel with concurrency control. Supported operation types: search, find, and check.",inputSchema:{operations:r.array(r.object({id:r.string().describe("Unique ID for this operation"),type:r.enum(["search","find","check"]).describe("Built-in operation type"),args:r.record(r.string(),r.unknown()).describe("Arguments for the operation")})).min(1).describe("Operations to execute"),concurrency:r.number().min(1).max(20).default(4).describe("Max concurrent operations")}},async({operations:s,concurrency:o})=>{try{const i=await b(s,async a=>ve(a,n,e),{concurrency:o});return{content:[{type:"text",text:JSON.stringify(i,null,2)}]}}catch(i){return{content:[{type:"text",text:`Batch failed: ${i.message}`}],isError:!0}}})}function Ue(t,n,e){t.registerTool("symbol",{description:"Resolve a symbol: find where it is defined, who imports it, and where it is referenced. Works on TypeScript and JavaScript codebases.",inputSchema:{name:r.string().describe("Symbol name to look up (function, class, type, etc.)"),limit:r.number().min(1).max(50).default(20).describe("Max results per category")}},async({name:s,limit:o})=>{try{const i=await ge(n,e,{name:s,limit:o});return{content:[{type:"text",text:Oe(i)}]}}catch(i){return{content:[{type:"text",text:`Symbol lookup failed: ${i.message}`}],isError:!0}}})}function Be(t){t.registerTool("eval",{description:"Execute a JavaScript or TypeScript snippet in a constrained VM sandbox with a timeout. Captures console output and returned values.",inputSchema:{code:r.string().describe("Code snippet to execute"),lang:r.enum(["js","ts"]).default("js").optional().describe("Language mode: js executes directly, ts strips common type syntax first"),timeout:r.number().min(1).max(6e4).default(5e3).optional().describe("Execution timeout in milliseconds")}},async({code:n,lang:e,timeout:s})=>{try{const o=_({code:n,lang:e,timeout:s});return o.success?{content:[{type:"text",text:`Eval succeeded in ${o.durationMs}ms
1
+ import{addToWorkset as S,batch as $,check as x,checkpointLatest as k,checkpointList as v,checkpointLoad as E,checkpointSave as T,codemod as q,compact as _,dataTransform as M,delegate as O,delegateListModels as R,deleteWorkset as N,diffParse as D,evaluate as I,fileSummary as C,find as b,findDeadSymbols as J,findExamples as j,getWorkset as L,gitContext as F,guide as A,health as W,laneCreate as P,laneDiff as U,laneDiscard as B,laneList as K,laneMerge as z,laneStatus as G,listWorksets as Q,parseOutput as H,processList as V,processLogs as X,processStart as Y,processStatus as Z,processStop as ee,queueClear as te,queueCreate as re,queueDelete as ne,queueDone as oe,queueFail as se,queueGet as ie,queueList as ae,queueNext as ce,queuePush as le,removeFromWorkset as de,rename as ue,saveWorkset as pe,scopeMap as fe,stashClear as me,stashDelete as ge,stashGet as he,stashList as ye,stashSet as xe,summarizeCheckResult as be,symbol as we,testRun as Se,trace as $e,truncateToTokenBudget as h,watchList as ke,watchStart as ve,watchStop as Ee,webFetch as Te}from"../../../tools/dist/index.js";import{z as r}from"zod";function Pe(t,o){t.registerTool("compact",{description:"Compress text to relevant sections using embedding similarity (no LLM). Provide either `text` or `path` (server reads the file \u2014 saves a round-trip). Segments by paragraph/sentence/line.",inputSchema:{text:r.string().optional().describe("The text to compress (provide this OR path, not both)"),path:r.string().optional().describe("File path to read server-side \u2014 avoids read_file round-trip + token doubling (provide this OR text)"),query:r.string().describe("Focus query \u2014 what are you trying to understand?"),max_chars:r.number().min(100).max(5e4).default(3e3).describe("Target output size in characters"),segmentation:r.enum(["paragraph","sentence","line"]).default("paragraph").describe("How to split the text for scoring")}},async({text:e,path:n,query:s,max_chars:i,segmentation:a})=>{try{if(!e&&!n)return{content:[{type:"text",text:'Error: Either "text" or "path" must be provided.'}],isError:!0};const c=await _(o,{text:e,path:n,query:s,maxChars:i,segmentation:a});return{content:[{type:"text",text:[`Compressed ${c.originalChars} \u2192 ${c.compressedChars} chars (${(c.ratio*100).toFixed(0)}%)`,`Kept ${c.segmentsKept}/${c.segmentsTotal} segments`,"",c.text].join(`
2
+ `)}]}}catch(c){return{content:[{type:"text",text:`Compact failed: ${c.message}`}],isError:!0}}})}function Ue(t,o,e){t.registerTool("scope_map",{description:"Generate a task-scoped reading plan. Given a task description, identifies which files and sections are relevant, with estimated token counts and suggested reading order.",inputSchema:{task:r.string().describe("Description of the task to scope"),max_files:r.number().min(1).max(50).default(15).describe("Maximum files to include"),content_type:r.string().optional().describe("Filter by content type"),max_tokens:r.number().min(100).max(5e4).optional().describe("Maximum token budget for the response. When set, output is truncated to fit.")}},async({task:n,max_files:s,content_type:i,max_tokens:a})=>{try{const c=await fe(o,e,{task:n,maxFiles:s,contentType:i}),d=[`## Scope Map: ${n}`,`Total estimated tokens: ~${c.totalEstimatedTokens}`,"","### Files (by relevance)",...c.files.map((u,f)=>`${f+1}. **${u.path}** (~${u.estimatedTokens} tokens, ${(u.relevance*100).toFixed(0)}% relevant)
3
+ ${u.reason}
4
+ Focus: ${u.focusRanges.map(p=>`L${p.start}-${p.end}`).join(", ")}`),"","### Suggested Reading Order",...c.readingOrder.map((u,f)=>`${f+1}. ${u}`),"","### Suggested Compact Calls",`_Estimated compressed total: ~${Math.ceil(c.totalEstimatedTokens/5)} tokens_`,...c.compactCommands.map((u,f)=>`${f+1}. ${u}`)].join(`
5
+ `)+"\n\n---\n_Next: Use `search` to dive into specific files, or `compact` to compress file contents for context._";return{content:[{type:"text",text:a?h(d,a):d}]}}catch(c){return{content:[{type:"text",text:`Scope map failed: ${c.message}`}],isError:!0}}})}function Be(t,o,e){t.registerTool("find",{description:'Federated search across vector similarity, keyword (FTS), file glob, and regex pattern. Combines strategies, deduplicates, and returns unified results. Use mode "examples" to find real usage examples of a symbol or pattern.',inputSchema:{query:r.string().optional().describe('Semantic/keyword search query (required for mode "examples")'),glob:r.string().optional().describe("File glob pattern (search mode only)"),pattern:r.string().optional().describe("Regex pattern to match in content (search mode only)"),limit:r.number().min(1).max(50).default(10).describe("Max results"),content_type:r.string().optional().describe("Filter by content type"),mode:r.enum(["search","examples"]).default("search").describe('Mode: "search" (default) for federated search, "examples" to find usage examples of a symbol/pattern'),max_tokens:r.number().min(100).max(5e4).optional().describe("Maximum token budget for the response. When set, output is truncated to fit.")}},async({query:n,glob:s,pattern:i,limit:a,content_type:c,mode:l,max_tokens:d})=>{try{if(l==="examples"){if(!n)return{content:[{type:"text",text:'Error: "query" is required for mode "examples".'}],isError:!0};const p=await j(o,e,{query:n,limit:a,contentType:c}),g=JSON.stringify(p,null,2);return{content:[{type:"text",text:d?h(g,d):g}]}}const u=await b(o,e,{query:n,glob:s,pattern:i,limit:a,contentType:c});if(u.results.length===0)return{content:[{type:"text",text:"No results found."}]};const f=[`Found ${u.totalFound} results via ${u.strategies.join(" + ")}`,"",...u.results.map(p=>{const g=p.lineRange?`:${p.lineRange.start}-${p.lineRange.end}`:"",w=p.preview?`
6
+ ${p.preview.slice(0,100)}...`:"";return`- [${p.source}] ${p.path}${g} (${(p.score*100).toFixed(0)}%)${w}`})];return{content:[{type:"text",text:d?h(f.join(`
7
+ `),d):f.join(`
8
+ `)}]}}catch(u){return{content:[{type:"text",text:`Find failed: ${u.message}`}],isError:!0}}})}function Ke(t){t.registerTool("parse_output",{description:"Parse structured data from build tool output. Supports tsc, vitest, biome, and git status. Auto-detects the tool or specify explicitly.",inputSchema:{output:r.string().describe("Raw output text from a build tool"),tool:r.enum(["tsc","vitest","biome","git-status"]).optional().describe("Tool to parse as (auto-detects if omitted)")}},async({output:o,tool:e})=>{try{const n=o.replace(/\\n/g,`
9
+ `).replace(/\\t/g," "),s=H(n,e);return{content:[{type:"text",text:JSON.stringify(s,null,2)}]}}catch(n){return{content:[{type:"text",text:`Parse failed: ${n.message}`}],isError:!0}}})}function ze(t){t.registerTool("workset",{description:"Manage named file sets (worksets). Save, load, list, add/remove files. Worksets persist across sessions in .kb-state/worksets.json.",inputSchema:{action:r.enum(["save","get","list","delete","add","remove"]).describe("Operation to perform"),name:r.string().optional().describe("Workset name (required for all except list)"),files:r.array(r.string()).optional().describe("File paths (required for save, add, remove)"),description:r.string().optional().describe("Description (for save)")}},async({action:o,name:e,files:n,description:s})=>{try{switch(o){case"save":{if(!e||!n)throw new Error("name and files required for save");const i=pe(e,n,{description:s});return{content:[{type:"text",text:`Saved workset "${i.name}" with ${i.files.length} files.`}]}}case"get":{if(!e)throw new Error("name required for get");const i=L(e);return i?{content:[{type:"text",text:JSON.stringify(i,null,2)}]}:{content:[{type:"text",text:`Workset "${e}" not found.`}]}}case"list":{const i=Q();return i.length===0?{content:[{type:"text",text:"No worksets."}]}:{content:[{type:"text",text:i.map(c=>`- **${c.name}** (${c.files.length} files) \u2014 ${c.description??"no description"}`).join(`
10
+ `)}]}}case"delete":{if(!e)throw new Error("name required for delete");return{content:[{type:"text",text:N(e)?`Deleted workset "${e}".`:`Workset "${e}" not found.`}]}}case"add":{if(!e||!n)throw new Error("name and files required for add");const i=S(e,n);return{content:[{type:"text",text:`Added to workset "${i.name}": now ${i.files.length} files.`}]}}case"remove":{if(!e||!n)throw new Error("name and files required for remove");const i=de(e,n);return i?{content:[{type:"text",text:`Removed from workset "${i.name}": now ${i.files.length} files.`}]}:{content:[{type:"text",text:`Workset "${e}" not found.`}]}}}}catch(i){return{content:[{type:"text",text:`Workset operation failed: ${i.message}`}],isError:!0}}})}function Ge(t){t.registerTool("check",{description:'Run incremental typecheck (tsc) and lint (biome) on the project or specific files. Returns structured error and warning lists. Default detail level is "summary" (~300 tokens).',inputSchema:{files:r.array(r.string()).optional().describe("Specific files to check (if omitted, checks all)"),cwd:r.string().optional().describe("Working directory"),skip_types:r.boolean().default(!1).describe("Skip TypeScript typecheck"),skip_lint:r.boolean().default(!1).describe("Skip Biome lint"),detail:r.enum(["summary","errors","full"]).default("summary").describe("Output detail level: summary (default, ~300 tokens \u2014 pass/fail + counts + top errors), errors (parsed error objects), full (includes raw terminal output)")}},async({files:o,cwd:e,skip_types:n,skip_lint:s,detail:i})=>{try{const a=await x({files:o,cwd:e,skipTypes:n,skipLint:s,detail:i==="summary"?"errors":i});if(i==="summary"){const c=be(a),l=[];if(a.passed)l.push({tool:"test_run",reason:"Types and lint clean \u2014 run tests next"});else{const d=a.tsc.errors[0]?.file??a.biome.errors[0]?.file;d&&l.push({tool:"symbol",reason:`Resolve failing symbol in ${d}`,suggested_args:{name:d}}),l.push({tool:"check",reason:"Re-check after fixing errors",suggested_args:{detail:"errors"}})}return{content:[{type:"text",text:JSON.stringify({...c,_next:l},null,2)}]}}return{content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(a){return{content:[{type:"text",text:`Check failed: ${a.message}`}],isError:!0}}})}function Qe(t,o,e){t.registerTool("batch",{description:"Execute multiple built-in operations in parallel with concurrency control. Supported operation types: search, find, and check.",inputSchema:{operations:r.array(r.object({id:r.string().describe("Unique ID for this operation"),type:r.enum(["search","find","check"]).describe("Built-in operation type"),args:r.record(r.string(),r.unknown()).describe("Arguments for the operation")})).min(1).describe("Operations to execute"),concurrency:r.number().min(1).max(20).default(4).describe("Max concurrent operations")}},async({operations:n,concurrency:s})=>{try{const i=await $(n,async a=>Oe(a,o,e),{concurrency:s});return{content:[{type:"text",text:JSON.stringify(i,null,2)}]}}catch(i){return{content:[{type:"text",text:`Batch failed: ${i.message}`}],isError:!0}}})}function He(t,o,e){t.registerTool("symbol",{description:"Resolve a symbol: find where it is defined, who imports it, and where it is referenced. Works on TypeScript and JavaScript codebases.",inputSchema:{name:r.string().describe("Symbol name to look up (function, class, type, etc.)"),limit:r.number().min(1).max(50).default(20).describe("Max results per category")}},async({name:n,limit:s})=>{try{const i=await we(o,e,{name:n,limit:s});return{content:[{type:"text",text:De(i)}]}}catch(i){return{content:[{type:"text",text:`Symbol lookup failed: ${i.message}`}],isError:!0}}})}function Ve(t){t.registerTool("eval",{description:"Execute a JavaScript or TypeScript snippet in a constrained VM sandbox with a timeout. Captures console output and returned values.",inputSchema:{code:r.string().describe("Code snippet to execute"),lang:r.enum(["js","ts"]).default("js").optional().describe("Language mode: js executes directly, ts strips common type syntax first"),timeout:r.number().min(1).max(6e4).default(5e3).optional().describe("Execution timeout in milliseconds")}},async({code:o,lang:e,timeout:n})=>{try{const s=I({code:o,lang:e,timeout:n});return s.success?{content:[{type:"text",text:`Eval succeeded in ${s.durationMs}ms
10
11
 
11
- ${o.output}`}]}:{content:[{type:"text",text:`Eval failed in ${o.durationMs}ms: ${o.error??"Unknown error"}`}],isError:!0}}catch(o){return console.error("[KB] Eval failed:",o),{content:[{type:"text",text:`Eval failed: ${o.message}`}],isError:!0}}})}function ze(t){t.registerTool("test_run",{description:"Run Vitest for the current project or a subset of files, then return a structured summary of passing and failing tests.",inputSchema:{files:r.array(r.string()).optional().describe("Specific test files or patterns to run"),grep:r.string().optional().describe("Only run tests whose names match this pattern"),cwd:r.string().optional().describe("Working directory for the test run")}},async({files:n,grep:e,cwd:s})=>{try{const o=await he({files:n,grep:e,cwd:s});return{content:[{type:"text",text:Me(o)}],isError:!o.passed}}catch(o){return{content:[{type:"text",text:`Test run failed: ${o.message}`}],isError:!0}}})}function Ge(t){t.registerTool("stash",{description:"Persist and retrieve named values in .kb-state/stash.json for intermediate results between tool calls.",inputSchema:{action:r.enum(["set","get","list","delete","clear"]).describe("Operation to perform on the stash"),key:r.string().optional().describe("Entry key for set/get/delete operations"),value:r.string().optional().describe("String or JSON value for set operations")}},async({action:n,key:e,value:s})=>{try{switch(n){case"set":{if(!e)throw new Error("key required for set");const o=me(e,Ie(s??""));return{content:[{type:"text",text:`Stored stash entry "${o.key}" (${o.type}) at ${o.storedAt}.`}]}}case"get":{if(!e)throw new Error("key required for get");const o=pe(e);return{content:[{type:"text",text:o?JSON.stringify(o,null,2):`Stash entry "${e}" not found.`}]}}case"list":{const o=fe();return{content:[{type:"text",text:o.length===0?"Stash is empty.":o.map(i=>`- ${i.key} (${i.type}) \u2014 ${i.storedAt}`).join(`
12
- `)}]}}case"delete":{if(!e)throw new Error("key required for delete");return{content:[{type:"text",text:ue(e)?`Deleted stash entry "${e}".`:`Stash entry "${e}" not found.`}]}}case"clear":{const o=de();return{content:[{type:"text",text:`Cleared ${o} stash entr${o===1?"y":"ies"}.`}]}}}}catch(o){return{content:[{type:"text",text:`Stash operation failed: ${o.message}`}],isError:!0}}})}function Qe(t){t.registerTool("git_context",{description:"Summarize the current Git branch, working tree state, recent commits, and optional diff statistics for the repository.",inputSchema:{cwd:r.string().optional().describe("Repository root or working directory"),commit_count:r.number().min(1).max(50).default(5).optional().describe("How many recent commits to include"),include_diff:r.boolean().default(!1).optional().describe("Include diff stat for working tree changes")}},async({cwd:n,commit_count:e,include_diff:s})=>{try{const o=await j({cwd:n,commitCount:e,includeDiff:s});return{content:[{type:"text",text:Ne(o)}]}}catch(o){return{content:[{type:"text",text:`Git context failed: ${o.message}`}],isError:!0}}})}function He(t){t.registerTool("diff_parse",{description:"Parse raw unified diff text into file-level and hunk-level structural changes.",inputSchema:{diff:r.string().describe("Raw unified diff text")}},async({diff:n})=>{try{const e=n.replace(/\\n/g,`
13
- `).replace(/\\t/g," "),s=N({diff:e});return{content:[{type:"text",text:_e(s)}]}}catch(e){return{content:[{type:"text",text:`Diff parse failed: ${e.message}`}],isError:!0}}})}function Ve(t){t.registerTool("rename",{description:"Rename a symbol across files using whole-word regex matching for exports, imports, and general usage references.",inputSchema:{old_name:r.string().describe("Existing symbol name to replace"),new_name:r.string().describe("New symbol name to use"),root_path:r.string().describe("Root directory to search within"),extensions:r.array(r.string()).optional().describe("Optional file extensions to include, such as .ts,.tsx,.js,.jsx"),dry_run:r.boolean().default(!0).describe("Preview changes without writing files")}},async({old_name:n,new_name:e,root_path:s,extensions:o,dry_run:i})=>{try{const a=await ae({oldName:n,newName:e,rootPath:s,extensions:o,dryRun:i});return{content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(a){return{content:[{type:"text",text:`Rename failed: ${a.message}`}],isError:!0}}})}function Xe(t){t.registerTool("codemod",{description:"Apply regex-based codemod rules across files and return structured before/after changes for each affected line.",inputSchema:{root_path:r.string().describe("Root directory to transform within"),rules:r.array(r.object({description:r.string().describe("What the codemod rule does"),pattern:r.string().describe("Regex pattern in string form"),replacement:r.string().describe("Replacement string with optional capture groups")})).min(1).describe("Codemod rules to apply"),dry_run:r.boolean().default(!0).describe("Preview changes without writing files")}},async({root_path:n,rules:e,dry_run:s})=>{try{const o=await E({rootPath:n,rules:e,dryRun:s});return{content:[{type:"text",text:JSON.stringify(o,null,2)}]}}catch(o){return{content:[{type:"text",text:`Codemod failed: ${o.message}`}],isError:!0}}})}function Ye(t){t.registerTool("file_summary",{description:"Create a concise structural summary of a source file: imports, exports, functions, classes, interfaces, and types.",inputSchema:{path:r.string().describe("Absolute path to the file to summarize")}},async({path:n})=>{try{const e=await R({path:n});return{content:[{type:"text",text:Re(e)}]}}catch(e){return{content:[{type:"text",text:`File summary failed: ${e.message}`}],isError:!0}}})}function Ze(t){t.registerTool("checkpoint",{description:"Save and restore lightweight session checkpoints in .kb-state/checkpoints for cross-session continuity.",inputSchema:{action:r.enum(["save","load","list","latest"]).describe("Checkpoint action to perform"),label:r.string().optional().describe("Checkpoint label for save, or checkpoint id for load"),data:r.string().optional().describe("JSON object string for save actions"),notes:r.string().optional().describe("Optional notes for save actions")}},async({action:n,label:e,data:s,notes:o})=>{try{switch(n){case"save":{if(!e)throw new Error("label required for save");const i=k(e,Je(s),{notes:o});return{content:[{type:"text",text:f(i)}]}}case"load":{if(!e)throw new Error("label required for load");const i=$(e);return{content:[{type:"text",text:i?f(i):`Checkpoint "${e}" not found.`}]}}case"list":{const i=S();return{content:[{type:"text",text:i.length===0?"No checkpoints saved.":i.map(a=>`- ${a.id} \u2014 ${a.label} (${a.createdAt})`).join(`
14
- `)}]}}case"latest":{const i=w();return{content:[{type:"text",text:i?f(i):"No checkpoints saved."}]}}}}catch(i){return{content:[{type:"text",text:`Checkpoint failed: ${i.message}`}],isError:!0}}})}function et(t){t.registerTool("data_transform",{description:"Apply small jq-like transforms to JSON input for filtering, projection, grouping, and path extraction.",inputSchema:{input:r.string().describe("Input JSON string"),expression:r.string().describe("Transform expression to apply")}},async({input:n,expression:e})=>{try{return{content:[{type:"text",text:T({input:n,expression:e}).outputString}]}}catch(s){return{content:[{type:"text",text:`Data transform failed: ${s.message}`}],isError:!0}}})}function tt(t,n,e){t.registerTool("trace",{description:"Trace data flow through a codebase by following imports, call sites, and references from a starting symbol or file location.",inputSchema:{start:r.string().describe("Starting point \u2014 symbol name or file:line reference"),direction:r.enum(["forward","backward","both"]).describe("Which direction to trace relationships"),max_depth:r.number().min(1).max(10).default(3).optional().describe("Maximum trace depth")}},async({start:s,direction:o,max_depth:i})=>{try{const a=await ye(n,e,{start:s,direction:o,maxDepth:i});return{content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(a){return{content:[{type:"text",text:`Trace failed: ${a.message}`}],isError:!0}}})}function rt(t,n,e){t.registerTool("find_examples",{description:"Find real usage examples of a function, class, or pattern in the indexed codebase.",inputSchema:{query:r.string().describe("Symbol or pattern to find examples of"),limit:r.number().min(1).max(20).default(5).optional().describe("Maximum examples to return"),content_type:r.string().optional().describe("Filter by content type")}},async({query:s,limit:o,content_type:i})=>{try{const a=await J(n,e,{query:s,limit:o,contentType:i});return{content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(a){return{content:[{type:"text",text:`Find examples failed: ${a.message}`}],isError:!0}}})}function nt(t){t.registerTool("process",{description:"Start, stop, inspect, list, and tail logs for in-memory managed child processes.",inputSchema:{action:r.enum(["start","stop","status","list","logs"]).describe("Process action to perform"),id:r.string().optional().describe("Managed process ID"),command:r.string().optional().describe("Executable to start"),args:r.array(r.string()).optional().describe("Arguments for start actions"),tail:r.number().min(1).max(500).optional().describe("Log lines to return for logs actions")}},async({action:n,id:e,command:s,args:o,tail:i})=>{try{switch(n){case"start":{if(!e||!s)throw new Error("id and command are required for start");return{content:[{type:"text",text:JSON.stringify(Q(e,s,o??[]),null,2)}]}}case"stop":{if(!e)throw new Error("id is required for stop");return{content:[{type:"text",text:JSON.stringify(V(e)??null,null,2)}]}}case"status":{if(!e)throw new Error("id is required for status");return{content:[{type:"text",text:JSON.stringify(H(e)??null,null,2)}]}}case"list":return{content:[{type:"text",text:JSON.stringify(z(),null,2)}]};case"logs":{if(!e)throw new Error("id is required for logs");return{content:[{type:"text",text:JSON.stringify(G(e,i),null,2)}]}}}}catch(a){return{content:[{type:"text",text:`Process action failed: ${a.message}`}],isError:!0}}})}function ot(t){t.registerTool("watch",{description:"Start, stop, and list in-memory filesystem watchers for a directory.",inputSchema:{action:r.enum(["start","stop","list"]).describe("Watch action to perform"),path:r.string().optional().describe("Directory path to watch for start actions"),id:r.string().optional().describe("Watcher ID for stop actions")}},async({action:n,path:e,id:s})=>{try{switch(n){case"start":{if(!e)throw new Error("path is required for start");return{content:[{type:"text",text:JSON.stringify(be({path:e}),null,2)}]}}case"stop":{if(!s)throw new Error("id is required for stop");return{content:[{type:"text",text:JSON.stringify({stopped:we(s)},null,2)}]}}case"list":return{content:[{type:"text",text:JSON.stringify(xe(),null,2)}]}}}catch(o){return{content:[{type:"text",text:`Watch action failed: ${o.message}`}],isError:!0}}})}function st(t,n,e){t.registerTool("dead_symbols",{description:"Find exported symbols that appear to be unused because they are never imported or re-exported.",inputSchema:{limit:r.number().min(1).max(500).default(100).optional().describe("Maximum exported symbols to scan")}},async({limit:s})=>{try{const o=await I(n,e,{limit:s});return{content:[{type:"text",text:JSON.stringify(o,null,2)}]}}catch(o){return{content:[{type:"text",text:`Dead symbol scan failed: ${o.message}`}],isError:!0}}})}function it(t){t.registerTool("delegate",{description:"Delegate a subtask to a local Ollama model. Use for summarization, classification, naming, or any task that can offload work from the host agent. Fails fast if Ollama is not running.",inputSchema:{prompt:r.string().describe("The task or question to send to the local model"),model:r.string().optional().describe("Ollama model name (default: first available model)"),system:r.string().optional().describe("System prompt for the model"),context:r.string().optional().describe("Context text to include before the prompt (e.g. file contents)"),temperature:r.number().min(0).max(2).default(.3).optional().describe("Sampling temperature (0=deterministic, default 0.3)"),timeout:r.number().min(1e3).max(6e5).default(12e4).optional().describe("Timeout in milliseconds (default 120000)"),action:r.enum(["generate","list_models"]).default("generate").optional().describe("Action: generate a response or list available models")}},async({prompt:n,model:e,system:s,context:o,temperature:i,timeout:a,action:l})=>{try{if(l==="list_models"){const u=await O();return{content:[{type:"text",text:JSON.stringify({models:u,count:u.length,_Next:"Use delegate with a model name"},null,2)}]}}const c=await q({prompt:n,model:e,system:s,context:o,temperature:i,timeout:a});return c.error?{content:[{type:"text",text:JSON.stringify({error:c.error,model:c.model,durationMs:c.durationMs},null,2)}],isError:!0}:{content:[{type:"text",text:JSON.stringify({model:c.model,response:c.response,durationMs:c.durationMs,tokenCount:c.tokenCount,_Next:"Use the response in your workflow. stash to save it."},null,2)}]}}catch(c){return{content:[{type:"text",text:`Delegate failed: ${c.message}`}],isError:!0}}})}function at(t){t.registerTool("lane",{description:"Manage verified lanes \u2014 isolated file copies for parallel exploration. Create a lane, make changes, diff, merge back, or discard.",inputSchema:{action:r.enum(["create","list","status","diff","merge","discard"]).describe("Lane action to perform"),name:r.string().optional().describe("Lane name (required for create/status/diff/merge/discard)"),files:r.array(r.string()).optional().describe("File paths to copy into the lane (required for create)")}},async({action:n,name:e,files:s})=>{try{switch(n){case"create":{if(!e)throw new Error("name is required for create");if(!s||s.length===0)throw new Error("files are required for create");const o=F(e,s);return{content:[{type:"text",text:JSON.stringify(o,null,2)}]}}case"list":return{content:[{type:"text",text:JSON.stringify(P(),null,2)}]};case"status":{if(!e)throw new Error("name is required for status");return{content:[{type:"text",text:JSON.stringify(K(e),null,2)}]}}case"diff":{if(!e)throw new Error("name is required for diff");return{content:[{type:"text",text:JSON.stringify(D(e),null,2)}]}}case"merge":{if(!e)throw new Error("name is required for merge");return{content:[{type:"text",text:JSON.stringify(W(e),null,2)}]}}case"discard":{if(!e)throw new Error("name is required for discard");return{content:[{type:"text",text:JSON.stringify({discarded:A(e)},null,2)}]}}}}catch(o){return{content:[{type:"text",text:`Lane action failed: ${o.message}`}],isError:!0}}})}function ct(t){t.registerTool("health",{description:"Run project health checks \u2014 verifies package.json, tsconfig, scripts, lockfile, README, LICENSE, .gitignore.",inputSchema:{path:r.string().optional().describe("Root directory to check (defaults to cwd)")}},async({path:n})=>{try{const e=L(n);return{content:[{type:"text",text:JSON.stringify(e,null,2)}]}}catch(e){return{content:[{type:"text",text:`Health check failed: ${e.message}`}],isError:!0}}})}function lt(t){t.registerTool("queue",{description:"Manage task queues for sequential agent operations. Push items, take next, mark done/failed, list queues.",inputSchema:{action:r.enum(["create","push","next","done","fail","get","list","clear","delete"]).describe("Queue action"),name:r.string().optional().describe("Queue name (required for most actions)"),title:r.string().optional().describe("Item title (required for push)"),id:r.string().optional().describe("Item ID (required for done/fail)"),data:r.unknown().optional().describe("Arbitrary data to attach to a queue item"),error:r.string().optional().describe("Error message (required for fail)")}},async({action:n,name:e,title:s,id:o,data:i,error:a})=>{try{switch(n){case"create":{if(!e)throw new Error("name is required for create");return{content:[{type:"text",text:JSON.stringify(Y(e),null,2)}]}}case"push":{if(!e)throw new Error("name is required for push");if(!s)throw new Error("title is required for push");return{content:[{type:"text",text:JSON.stringify(se(e,s,i),null,2)}]}}case"next":{if(!e)throw new Error("name is required for next");const l=oe(e);return{content:[{type:"text",text:JSON.stringify(l,null,2)}]}}case"done":{if(!e)throw new Error("name is required for done");if(!o)throw new Error("id is required for done");return{content:[{type:"text",text:JSON.stringify(ee(e,o),null,2)}]}}case"fail":{if(!e)throw new Error("name is required for fail");if(!o)throw new Error("id is required for fail");if(!a)throw new Error("error is required for fail");return{content:[{type:"text",text:JSON.stringify(te(e,o,a),null,2)}]}}case"get":{if(!e)throw new Error("name is required for get");return{content:[{type:"text",text:JSON.stringify(re(e),null,2)}]}}case"list":return{content:[{type:"text",text:JSON.stringify(ne(),null,2)}]};case"clear":{if(!e)throw new Error("name is required for clear");return{content:[{type:"text",text:JSON.stringify({cleared:X(e)},null,2)}]}}case"delete":{if(!e)throw new Error("name is required for delete");return{content:[{type:"text",text:JSON.stringify({deleted:Z(e)},null,2)}]}}}}catch(l){return{content:[{type:"text",text:`Queue action failed: ${l.message}`}],isError:!0}}})}const $e=r.object({query:r.string(),limit:r.number().min(1).max(20).default(5).optional(),search_mode:r.enum(["hybrid","semantic","keyword"]).default("hybrid").optional(),content_type:r.string().optional(),origin:r.enum(["indexed","curated","produced"]).optional(),category:r.string().optional(),tags:r.array(r.string()).optional(),min_score:r.number().min(0).max(1).default(.25).optional()}),ke=r.object({query:r.string().optional(),glob:r.string().optional(),pattern:r.string().optional(),limit:r.number().min(1).max(50).default(10).optional(),content_type:r.string().optional(),cwd:r.string().optional()}),Ee=r.object({files:r.array(r.string()).optional(),cwd:r.string().optional(),skip_types:r.boolean().optional(),skip_lint:r.boolean().optional()});async function ve(t,n,e){switch(t.type){case"search":{const s=$e.parse(t.args);return Te(n,e,s)}case"find":{const s=ke.parse(t.args);if(!s.query&&!s.glob&&!s.pattern)throw new Error("find operation requires query, glob, or pattern");return g(n,e,{query:s.query,glob:s.glob,pattern:s.pattern,limit:s.limit,contentType:s.content_type,cwd:s.cwd})}case"check":{const s=Ee.parse(t.args);return m({files:s.files,cwd:s.cwd,skipTypes:s.skip_types,skipLint:s.skip_lint})}default:throw new Error(`Unsupported batch operation type: ${t.type}`)}}async function Te(t,n,e){const s=e.limit??5,o={limit:s,minScore:e.min_score??.25,contentType:e.content_type,origin:e.origin,category:e.category,tags:e.tags},i=t.embedQuery?.bind(t)??t.embed.bind(t);if(e.search_mode==="keyword")return(await n.ftsSearch(e.query,o)).slice(0,s);const a=await i(e.query);if(e.search_mode==="semantic")return n.search(a,o);const[l,c]=await Promise.all([n.search(a,{...o,limit:s*2}),n.ftsSearch(e.query,{...o,limit:s*2})]);return qe(l,c).slice(0,s)}function qe(t,n,e=60){const s=new Map;for(let o=0;o<t.length;o++){const i=t[o];s.set(i.record.id,{record:i.record,score:1/(e+o+1)})}for(let o=0;o<n.length;o++){const i=n[o],a=s.get(i.record.id);if(a){a.score+=1/(e+o+1);continue}s.set(i.record.id,{record:i.record,score:1/(e+o+1)})}return[...s.values()].sort((o,i)=>i.score-o.score)}function Oe(t){const n=[`Symbol: ${t.name}`];if(t.definedIn?n.push(`Defined in: ${t.definedIn.path}:${t.definedIn.line} (${t.definedIn.kind})`):n.push("Defined in: not found"),n.push("","Imported by:"),t.importedBy.length===0)n.push(" none");else for(const e of t.importedBy)n.push(` - ${e.path}:${e.line} ${e.importStatement}`);if(n.push("","Referenced in:"),t.referencedIn.length===0)n.push(" none");else for(const e of t.referencedIn)n.push(` - ${e.path}:${e.line} ${e.context}`);return n.join(`
15
- `)}function Me(t){const n=[`Vitest run: ${t.passed?"passed":"failed"}`,`Duration: ${t.durationMs}ms`,`Passed: ${t.summary.passed}`,`Failed: ${t.summary.failed}`,`Skipped: ${t.summary.skipped}`];t.summary.suites!==void 0&&n.push(`Suites: ${t.summary.suites}`);const e=t.summary.tests.filter(s=>s.status==="fail");if(e.length>0){n.push("","Failed tests:");for(const s of e)n.push(`- ${s.name}${s.file?` (${s.file})`:""}`),s.error&&n.push(` ${s.error}`)}return n.join(`
16
- `)}function Ne(t){const n=[`Branch: ${t.branch}`,`Staged: ${t.status.staged.length}`,...t.status.staged.map(e=>` - ${e}`),`Modified: ${t.status.modified.length}`,...t.status.modified.map(e=>` - ${e}`),`Untracked: ${t.status.untracked.length}`,...t.status.untracked.map(e=>` - ${e}`),"","Recent commits:"];if(t.recentCommits.length===0)n.push(" none");else for(const e of t.recentCommits)n.push(` - ${e.hash} ${e.message}`),n.push(` ${e.author} @ ${e.date}`);return t.diff&&n.push("","Diff stat:",t.diff),n.join(`
17
- `)}function _e(t){if(t.length===0)return"No diff files found.";const n=[];for(const e of t){const s=e.oldPath?` (from ${e.oldPath})`:"";n.push(`${e.path}${s} [${e.status}] +${e.additions} -${e.deletions} (${e.hunks.length} hunks)`);for(const o of e.hunks){const i=o.header?` ${o.header}`:"";n.push(` @@ -${o.oldStart},${o.oldLines} +${o.newStart},${o.newLines} @@${i}`)}}return n.join(`
18
- `)}function Re(t){return[t.path,`Language: ${t.language}`,`Lines: ${t.lines}`,`Estimated tokens: ~${t.estimatedTokens}`,"",`Imports (${t.imports.length}):`,...p(t.imports),"",`Exports (${t.exports.length}):`,...p(t.exports),"",`Functions (${t.functions.length}):`,...p(t.functions.map(e=>`${e.name} @ line ${e.line}${e.exported?" [exported]":""}`)),"",`Classes (${t.classes.length}):`,...p(t.classes.map(e=>`${e.name} @ line ${e.line}${e.exported?" [exported]":""}`)),"",`Interfaces (${t.interfaces.length}):`,...p(t.interfaces.map(e=>`${e.name} @ line ${e.line}`)),"",`Types (${t.types.length}):`,...p(t.types.map(e=>`${e.name} @ line ${e.line}`))].join(`
19
- `)}function f(t){const n=[t.id,`Label: ${t.label}`,`Created: ${t.createdAt}`];if(t.notes&&n.push(`Notes: ${t.notes}`),t.files?.length){n.push(`Files: ${t.files.length}`);for(const e of t.files)n.push(` - ${e}`)}return n.push("","Data:",JSON.stringify(t.data,null,2)),n.join(`
20
- `)}function p(t){return t.length===0?[" none"]:t.map(n=>` - ${n}`)}function Ie(t){const n=t.trim();if(!n)return"";try{return JSON.parse(n)}catch{return t}}function Je(t){const n=t?.trim();if(!n)return{};const e=JSON.parse(n);if(!e||typeof e!="object"||Array.isArray(e))throw new Error("data must be a JSON object string");return e}function dt(t){t.registerTool("web_fetch",{description:"PREFERRED web fetcher \u2014 fetch any URL and convert to LLM-optimized markdown. Supports CSS selectors, 4 output modes (markdown/raw/links/outline), smart paragraph-boundary truncation. Strips scripts/styles/nav automatically.",inputSchema:{url:r.string().url().describe("URL to fetch (http/https only)"),mode:r.enum(["markdown","raw","links","outline"]).default("markdown").describe("Output mode: markdown (clean content), raw (HTML), links (extracted URLs), outline (heading hierarchy)"),selector:r.string().optional().describe("CSS selector to extract a specific element instead of auto-detecting main content"),max_length:r.number().min(500).max(1e5).default(15e3).describe("Max characters in output \u2014 truncates at paragraph boundaries"),include_metadata:r.boolean().default(!0).describe("Include page title, description, and URL as a header"),include_links:r.boolean().default(!1).describe("Append extracted links list at the end"),include_images:r.boolean().default(!1).describe("Include image alt texts inline"),timeout:r.number().min(1e3).max(6e4).default(15e3).describe("Request timeout in milliseconds")}},async({url:n,mode:e,selector:s,max_length:o,include_metadata:i,include_links:a,include_images:l,timeout:c})=>{try{const u=await Se({url:n,mode:e,selector:s,maxLength:o,includeMetadata:i,includeLinks:a,includeImages:l,timeout:c}),d=[`## ${u.title||"Web Page"}`,"",u.content];return u.truncated&&d.push("",`_Original length: ${u.originalLength.toLocaleString()} chars_`),d.push("","---","_Next: Use `remember` to save key findings, or `web_fetch` with a `selector` to extract a specific section._"),{content:[{type:"text",text:d.join(`
21
- `)}]}}catch(u){return{content:[{type:"text",text:`Web fetch failed: ${u.message}`}],isError:!0}}})}export{Ke as registerBatchTool,We as registerCheckTool,Ze as registerCheckpointTool,Xe as registerCodemodTool,Le as registerCompactTool,et as registerDataTransformTool,st as registerDeadSymbolsTool,it as registerDelegateTool,He as registerDiffParseTool,Be as registerEvalTool,Ye as registerFileSummaryTool,rt as registerFindExamplesTool,De as registerFindTool,Qe as registerGitContextTool,ct as registerHealthTool,at as registerLaneTool,Ae as registerParseOutputTool,nt as registerProcessTool,lt as registerQueueTool,Ve as registerRenameTool,Fe as registerScopeMapTool,Ge as registerStashTool,Ue as registerSymbolTool,ze as registerTestRunTool,tt as registerTraceTool,ot as registerWatchTool,dt as registerWebFetchTool,Pe as registerWorksetTool};
12
+ ${s.output}`}]}:{content:[{type:"text",text:`Eval failed in ${s.durationMs}ms: ${s.error??"Unknown error"}`}],isError:!0}}catch(s){return console.error("[KB] Eval failed:",s),{content:[{type:"text",text:`Eval failed: ${s.message}`}],isError:!0}}})}function Xe(t){t.registerTool("test_run",{description:"Run Vitest for the current project or a subset of files, then return a structured summary of passing and failing tests.",inputSchema:{files:r.array(r.string()).optional().describe("Specific test files or patterns to run"),grep:r.string().optional().describe("Only run tests whose names match this pattern"),cwd:r.string().optional().describe("Working directory for the test run")}},async({files:o,grep:e,cwd:n})=>{try{const s=await Se({files:o,grep:e,cwd:n});return{content:[{type:"text",text:Ie(s)}],isError:!s.passed}}catch(s){return{content:[{type:"text",text:`Test run failed: ${s.message}`}],isError:!0}}})}function Ye(t){t.registerTool("stash",{description:"Persist and retrieve named values in .kb-state/stash.json for intermediate results between tool calls.",inputSchema:{action:r.enum(["set","get","list","delete","clear"]).describe("Operation to perform on the stash"),key:r.string().optional().describe("Entry key for set/get/delete operations"),value:r.string().optional().describe("String or JSON value for set operations")}},async({action:o,key:e,value:n})=>{try{switch(o){case"set":{if(!e)throw new Error("key required for set");const s=xe(e,Le(n??""));return{content:[{type:"text",text:`Stored stash entry "${s.key}" (${s.type}) at ${s.storedAt}.`}]}}case"get":{if(!e)throw new Error("key required for get");const s=he(e);return{content:[{type:"text",text:s?JSON.stringify(s,null,2):`Stash entry "${e}" not found.`}]}}case"list":{const s=ye();return{content:[{type:"text",text:s.length===0?"Stash is empty.":s.map(i=>`- ${i.key} (${i.type}) \u2014 ${i.storedAt}`).join(`
13
+ `)}]}}case"delete":{if(!e)throw new Error("key required for delete");return{content:[{type:"text",text:ge(e)?`Deleted stash entry "${e}".`:`Stash entry "${e}" not found.`}]}}case"clear":{const s=me();return{content:[{type:"text",text:`Cleared ${s} stash entr${s===1?"y":"ies"}.`}]}}}}catch(s){return{content:[{type:"text",text:`Stash operation failed: ${s.message}`}],isError:!0}}})}function Ze(t){t.registerTool("git_context",{description:"Summarize the current Git branch, working tree state, recent commits, and optional diff statistics for the repository.",inputSchema:{cwd:r.string().optional().describe("Repository root or working directory"),commit_count:r.number().min(1).max(50).default(5).optional().describe("How many recent commits to include"),include_diff:r.boolean().default(!1).optional().describe("Include diff stat for working tree changes")}},async({cwd:o,commit_count:e,include_diff:n})=>{try{const s=await F({cwd:o,commitCount:e,includeDiff:n});return{content:[{type:"text",text:Ce(s)}]}}catch(s){return{content:[{type:"text",text:`Git context failed: ${s.message}`}],isError:!0}}})}function et(t){t.registerTool("diff_parse",{description:"Parse raw unified diff text into file-level and hunk-level structural changes.",inputSchema:{diff:r.string().describe("Raw unified diff text")}},async({diff:o})=>{try{const e=o.replace(/\\n/g,`
14
+ `).replace(/\\t/g," "),n=D({diff:e});return{content:[{type:"text",text:Je(n)}]}}catch(e){return{content:[{type:"text",text:`Diff parse failed: ${e.message}`}],isError:!0}}})}function tt(t){t.registerTool("rename",{description:"Rename a symbol across files using whole-word regex matching for exports, imports, and general usage references.",inputSchema:{old_name:r.string().describe("Existing symbol name to replace"),new_name:r.string().describe("New symbol name to use"),root_path:r.string().describe("Root directory to search within"),extensions:r.array(r.string()).optional().describe("Optional file extensions to include, such as .ts,.tsx,.js,.jsx"),dry_run:r.boolean().default(!0).describe("Preview changes without writing files")}},async({old_name:o,new_name:e,root_path:n,extensions:s,dry_run:i})=>{try{const a=await ue({oldName:o,newName:e,rootPath:n,extensions:s,dryRun:i});return{content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(a){return{content:[{type:"text",text:`Rename failed: ${a.message}`}],isError:!0}}})}function rt(t){t.registerTool("codemod",{description:"Apply regex-based codemod rules across files and return structured before/after changes for each affected line.",inputSchema:{root_path:r.string().describe("Root directory to transform within"),rules:r.array(r.object({description:r.string().describe("What the codemod rule does"),pattern:r.string().describe("Regex pattern in string form"),replacement:r.string().describe("Replacement string with optional capture groups")})).min(1).describe("Codemod rules to apply"),dry_run:r.boolean().default(!0).describe("Preview changes without writing files")}},async({root_path:o,rules:e,dry_run:n})=>{try{const s=await q({rootPath:o,rules:e,dryRun:n});return{content:[{type:"text",text:JSON.stringify(s,null,2)}]}}catch(s){return{content:[{type:"text",text:`Codemod failed: ${s.message}`}],isError:!0}}})}function nt(t){t.registerTool("file_summary",{description:"Create a concise structural summary of a source file: imports, exports, functions, classes, interfaces, and types.",inputSchema:{path:r.string().describe("Absolute path to the file to summarize")}},async({path:o})=>{try{const e=await C({path:o});return{content:[{type:"text",text:je(e)}]}}catch(e){return{content:[{type:"text",text:`File summary failed: ${e.message}`}],isError:!0}}})}function ot(t){t.registerTool("checkpoint",{description:"Save and restore lightweight session checkpoints in .kb-state/checkpoints for cross-session continuity.",inputSchema:{action:r.enum(["save","load","list","latest"]).describe("Checkpoint action to perform"),label:r.string().optional().describe("Checkpoint label for save, or checkpoint id for load"),data:r.string().optional().describe("JSON object string for save actions"),notes:r.string().optional().describe("Optional notes for save actions")}},async({action:o,label:e,data:n,notes:s})=>{try{switch(o){case"save":{if(!e)throw new Error("label required for save");const i=T(e,Fe(n),{notes:s});return{content:[{type:"text",text:y(i)}]}}case"load":{if(!e)throw new Error("label required for load");const i=E(e);return{content:[{type:"text",text:i?y(i):`Checkpoint "${e}" not found.`}]}}case"list":{const i=v();return{content:[{type:"text",text:i.length===0?"No checkpoints saved.":i.map(a=>`- ${a.id} \u2014 ${a.label} (${a.createdAt})`).join(`
15
+ `)}]}}case"latest":{const i=k();return{content:[{type:"text",text:i?y(i):"No checkpoints saved."}]}}}}catch(i){return{content:[{type:"text",text:`Checkpoint failed: ${i.message}`}],isError:!0}}})}function st(t){t.registerTool("data_transform",{description:"Apply small jq-like transforms to JSON input for filtering, projection, grouping, and path extraction.",inputSchema:{input:r.string().describe("Input JSON string"),expression:r.string().describe("Transform expression to apply")}},async({input:o,expression:e})=>{try{return{content:[{type:"text",text:M({input:o,expression:e}).outputString}]}}catch(n){return{content:[{type:"text",text:`Data transform failed: ${n.message}`}],isError:!0}}})}function it(t,o,e){t.registerTool("trace",{description:"Trace data flow through a codebase by following imports, call sites, and references from a starting symbol or file location.",inputSchema:{start:r.string().describe("Starting point \u2014 symbol name or file:line reference"),direction:r.enum(["forward","backward","both"]).describe("Which direction to trace relationships"),max_depth:r.number().min(1).max(10).default(3).optional().describe("Maximum trace depth")}},async({start:n,direction:s,max_depth:i})=>{try{const a=await $e(o,e,{start:n,direction:s,maxDepth:i});return{content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(a){return{content:[{type:"text",text:`Trace failed: ${a.message}`}],isError:!0}}})}function at(t){t.registerTool("process",{description:"Start, stop, inspect, list, and tail logs for in-memory managed child processes.",inputSchema:{action:r.enum(["start","stop","status","list","logs"]).describe("Process action to perform"),id:r.string().optional().describe("Managed process ID"),command:r.string().optional().describe("Executable to start"),args:r.array(r.string()).optional().describe("Arguments for start actions"),tail:r.number().min(1).max(500).optional().describe("Log lines to return for logs actions")}},async({action:o,id:e,command:n,args:s,tail:i})=>{try{switch(o){case"start":{if(!e||!n)throw new Error("id and command are required for start");return{content:[{type:"text",text:JSON.stringify(Y(e,n,s??[]),null,2)}]}}case"stop":{if(!e)throw new Error("id is required for stop");return{content:[{type:"text",text:JSON.stringify(ee(e)??null,null,2)}]}}case"status":{if(!e)throw new Error("id is required for status");return{content:[{type:"text",text:JSON.stringify(Z(e)??null,null,2)}]}}case"list":return{content:[{type:"text",text:JSON.stringify(V(),null,2)}]};case"logs":{if(!e)throw new Error("id is required for logs");return{content:[{type:"text",text:JSON.stringify(X(e,i),null,2)}]}}}}catch(a){return{content:[{type:"text",text:`Process action failed: ${a.message}`}],isError:!0}}})}function ct(t){t.registerTool("watch",{description:"Start, stop, and list in-memory filesystem watchers for a directory.",inputSchema:{action:r.enum(["start","stop","list"]).describe("Watch action to perform"),path:r.string().optional().describe("Directory path to watch for start actions"),id:r.string().optional().describe("Watcher ID for stop actions")}},async({action:o,path:e,id:n})=>{try{switch(o){case"start":{if(!e)throw new Error("path is required for start");return{content:[{type:"text",text:JSON.stringify(ve({path:e}),null,2)}]}}case"stop":{if(!n)throw new Error("id is required for stop");return{content:[{type:"text",text:JSON.stringify({stopped:Ee(n)},null,2)}]}}case"list":return{content:[{type:"text",text:JSON.stringify(ke(),null,2)}]}}}catch(s){return{content:[{type:"text",text:`Watch action failed: ${s.message}`}],isError:!0}}})}function lt(t,o,e){t.registerTool("dead_symbols",{description:"Find exported symbols that appear to be unused because they are never imported or re-exported.",inputSchema:{path:r.string().optional().describe("Root path to scope the search (default: cwd)"),limit:r.number().min(1).max(500).default(100).optional().describe("Maximum exported symbols to scan")}},async({path:n,limit:s})=>{try{const i=await J(o,e,{rootPath:n,limit:s}),a=["## Dead Symbol Analysis","",`**Exports scanned:** ${i.totalExports}`,`**Dead in source:** ${i.totalDeadSource} (actionable)`,`**Dead in docs:** ${i.totalDeadDocs} (informational \u2014 code samples in .md files)`,""];if(i.deadInSource.length>0){a.push("### Dead in Source (actionable)");for(const c of i.deadInSource)a.push(`- \`${c.name}\` (${c.kind}) \u2014 ${c.path}:${c.line}`);a.push("")}if(i.deadInDocs.length>0){a.push("### Dead in Docs (informational)"),a.push(`_${i.totalDeadDocs} symbol(s) found only in documentation code samples \u2014 not actionable dead code._`);for(const c of i.deadInDocs.slice(0,5))a.push(`- \`${c.name}\` \u2014 ${c.path}:${c.line}`);i.deadInDocs.length>5&&a.push(`- _... ${i.deadInDocs.length-5} more omitted_`)}return i.totalDeadSource>0?a.push("","---",`_Next: \`codemod\` to remove ${i.totalDeadSource} unused exports | \`symbol\` to verify usage before removing_`):a.push("","---","_Next: `check` \u2014 no dead symbols found, validate types and lint_"),{content:[{type:"text",text:a.join(`
16
+ `)}]}}catch(i){return{content:[{type:"text",text:`Dead symbol scan failed: ${i.message}`}],isError:!0}}})}function dt(t){t.registerTool("delegate",{description:"Delegate a subtask to a local Ollama model. Use for summarization, classification, naming, or any task that can offload work from the host agent. Fails fast if Ollama is not running.",inputSchema:{prompt:r.string().describe("The task or question to send to the local model"),model:r.string().optional().describe("Ollama model name (default: first available model)"),system:r.string().optional().describe("System prompt for the model"),context:r.string().optional().describe("Context text to include before the prompt (e.g. file contents)"),temperature:r.number().min(0).max(2).default(.3).optional().describe("Sampling temperature (0=deterministic, default 0.3)"),timeout:r.number().min(1e3).max(6e5).default(12e4).optional().describe("Timeout in milliseconds (default 120000)"),action:r.enum(["generate","list_models"]).default("generate").optional().describe("Action: generate a response or list available models")}},async({prompt:o,model:e,system:n,context:s,temperature:i,timeout:a,action:c})=>{try{if(c==="list_models"){const d=await R();return{content:[{type:"text",text:JSON.stringify({models:d,count:d.length,_Next:"Use delegate with a model name"},null,2)}]}}const l=await O({prompt:o,model:e,system:n,context:s,temperature:i,timeout:a});return l.error?{content:[{type:"text",text:JSON.stringify({error:l.error,model:l.model,durationMs:l.durationMs},null,2)}],isError:!0}:{content:[{type:"text",text:JSON.stringify({model:l.model,response:l.response,durationMs:l.durationMs,tokenCount:l.tokenCount,_Next:"Use the response in your workflow. stash to save it."},null,2)}]}}catch(l){return{content:[{type:"text",text:`Delegate failed: ${l.message}`}],isError:!0}}})}function ut(t){t.registerTool("lane",{description:"Manage verified lanes \u2014 isolated file copies for parallel exploration. Create a lane, make changes, diff, merge back, or discard.",inputSchema:{action:r.enum(["create","list","status","diff","merge","discard"]).describe("Lane action to perform"),name:r.string().optional().describe("Lane name (required for create/status/diff/merge/discard)"),files:r.array(r.string()).optional().describe("File paths to copy into the lane (required for create)")}},async({action:o,name:e,files:n})=>{try{switch(o){case"create":{if(!e)throw new Error("name is required for create");if(!n||n.length===0)throw new Error("files are required for create");const s=P(e,n);return{content:[{type:"text",text:JSON.stringify(s,null,2)}]}}case"list":return{content:[{type:"text",text:JSON.stringify(K(),null,2)}]};case"status":{if(!e)throw new Error("name is required for status");return{content:[{type:"text",text:JSON.stringify(G(e),null,2)}]}}case"diff":{if(!e)throw new Error("name is required for diff");return{content:[{type:"text",text:JSON.stringify(U(e),null,2)}]}}case"merge":{if(!e)throw new Error("name is required for merge");return{content:[{type:"text",text:JSON.stringify(z(e),null,2)}]}}case"discard":{if(!e)throw new Error("name is required for discard");return{content:[{type:"text",text:JSON.stringify({discarded:B(e)},null,2)}]}}}}catch(s){return{content:[{type:"text",text:`Lane action failed: ${s.message}`}],isError:!0}}})}function pt(t){t.registerTool("health",{description:"Run project health checks \u2014 verifies package.json, tsconfig, scripts, lockfile, README, LICENSE, .gitignore.",inputSchema:{path:r.string().optional().describe("Root directory to check (defaults to cwd)")}},async({path:o})=>{try{const e=W(o);return{content:[{type:"text",text:JSON.stringify(e,null,2)}]}}catch(e){return{content:[{type:"text",text:`Health check failed: ${e.message}`}],isError:!0}}})}function ft(t){t.registerTool("queue",{description:"Manage task queues for sequential agent operations. Push items, take next, mark done/failed, list queues.",inputSchema:{action:r.enum(["create","push","next","done","fail","get","list","clear","delete"]).describe("Queue action"),name:r.string().optional().describe("Queue name (required for most actions)"),title:r.string().optional().describe("Item title (required for push)"),id:r.string().optional().describe("Item ID (required for done/fail)"),data:r.unknown().optional().describe("Arbitrary data to attach to a queue item"),error:r.string().optional().describe("Error message (required for fail)")}},async({action:o,name:e,title:n,id:s,data:i,error:a})=>{try{switch(o){case"create":{if(!e)throw new Error("name is required for create");return{content:[{type:"text",text:JSON.stringify(re(e),null,2)}]}}case"push":{if(!e)throw new Error("name is required for push");if(!n)throw new Error("title is required for push");return{content:[{type:"text",text:JSON.stringify(le(e,n,i),null,2)}]}}case"next":{if(!e)throw new Error("name is required for next");const c=ce(e);return{content:[{type:"text",text:JSON.stringify(c,null,2)}]}}case"done":{if(!e)throw new Error("name is required for done");if(!s)throw new Error("id is required for done");return{content:[{type:"text",text:JSON.stringify(oe(e,s),null,2)}]}}case"fail":{if(!e)throw new Error("name is required for fail");if(!s)throw new Error("id is required for fail");if(!a)throw new Error("error is required for fail");return{content:[{type:"text",text:JSON.stringify(se(e,s,a),null,2)}]}}case"get":{if(!e)throw new Error("name is required for get");return{content:[{type:"text",text:JSON.stringify(ie(e),null,2)}]}}case"list":return{content:[{type:"text",text:JSON.stringify(ae(),null,2)}]};case"clear":{if(!e)throw new Error("name is required for clear");return{content:[{type:"text",text:JSON.stringify({cleared:te(e)},null,2)}]}}case"delete":{if(!e)throw new Error("name is required for delete");return{content:[{type:"text",text:JSON.stringify({deleted:ne(e)},null,2)}]}}}}catch(c){return{content:[{type:"text",text:`Queue action failed: ${c.message}`}],isError:!0}}})}const qe=r.object({query:r.string(),limit:r.number().min(1).max(20).default(5).optional(),search_mode:r.enum(["hybrid","semantic","keyword"]).default("hybrid").optional(),content_type:r.string().optional(),origin:r.enum(["indexed","curated","produced"]).optional(),category:r.string().optional(),tags:r.array(r.string()).optional(),min_score:r.number().min(0).max(1).default(.25).optional()}),_e=r.object({query:r.string().optional(),glob:r.string().optional(),pattern:r.string().optional(),limit:r.number().min(1).max(50).default(10).optional(),content_type:r.string().optional(),cwd:r.string().optional()}),Me=r.object({files:r.array(r.string()).optional(),cwd:r.string().optional(),skip_types:r.boolean().optional(),skip_lint:r.boolean().optional()});async function Oe(t,o,e){switch(t.type){case"search":{const n=qe.parse(t.args);return Re(o,e,n)}case"find":{const n=_e.parse(t.args);if(!n.query&&!n.glob&&!n.pattern)throw new Error("find operation requires query, glob, or pattern");return b(o,e,{query:n.query,glob:n.glob,pattern:n.pattern,limit:n.limit,contentType:n.content_type,cwd:n.cwd})}case"check":{const n=Me.parse(t.args);return x({files:n.files,cwd:n.cwd,skipTypes:n.skip_types,skipLint:n.skip_lint})}default:throw new Error(`Unsupported batch operation type: ${t.type}`)}}async function Re(t,o,e){const n=e.limit??5,s={limit:n,minScore:e.min_score??.25,contentType:e.content_type,origin:e.origin,category:e.category,tags:e.tags},i=t.embedQuery?.bind(t)??t.embed.bind(t);if(e.search_mode==="keyword")return(await o.ftsSearch(e.query,s)).slice(0,n);const a=await i(e.query);if(e.search_mode==="semantic")return o.search(a,s);const[c,l]=await Promise.all([o.search(a,{...s,limit:n*2}),o.ftsSearch(e.query,{...s,limit:n*2})]);return Ne(c,l).slice(0,n)}function Ne(t,o,e=60){const n=new Map;for(let s=0;s<t.length;s++){const i=t[s];n.set(i.record.id,{record:i.record,score:1/(e+s+1)})}for(let s=0;s<o.length;s++){const i=o[s],a=n.get(i.record.id);if(a){a.score+=1/(e+s+1);continue}n.set(i.record.id,{record:i.record,score:1/(e+s+1)})}return[...n.values()].sort((s,i)=>i.score-s.score)}function De(t){const o=[`Symbol: ${t.name}`];if(t.definedIn?o.push(`Defined in: ${t.definedIn.path}:${t.definedIn.line} (${t.definedIn.kind})`):o.push("Defined in: not found"),o.push("","Imported by:"),t.importedBy.length===0)o.push(" none");else for(const e of t.importedBy)o.push(` - ${e.path}:${e.line} ${e.importStatement}`);if(o.push("","Referenced in:"),t.referencedIn.length===0)o.push(" none");else for(const e of t.referencedIn)o.push(` - ${e.path}:${e.line} ${e.context}`);return o.join(`
17
+ `)}function Ie(t){const o=[`Vitest run: ${t.passed?"passed":"failed"}`,`Duration: ${t.durationMs}ms`,`Passed: ${t.summary.passed}`,`Failed: ${t.summary.failed}`,`Skipped: ${t.summary.skipped}`];t.summary.suites!==void 0&&o.push(`Suites: ${t.summary.suites}`);const e=t.summary.tests.filter(n=>n.status==="fail");if(e.length>0){o.push("","Failed tests:");for(const n of e)o.push(`- ${n.name}${n.file?` (${n.file})`:""}`),n.error&&o.push(` ${n.error}`)}return o.join(`
18
+ `)}function Ce(t){const o=[`Branch: ${t.branch}`,`Staged: ${t.status.staged.length}`,...t.status.staged.map(e=>` - ${e}`),`Modified: ${t.status.modified.length}`,...t.status.modified.map(e=>` - ${e}`),`Untracked: ${t.status.untracked.length}`,...t.status.untracked.map(e=>` - ${e}`),"","Recent commits:"];if(t.recentCommits.length===0)o.push(" none");else for(const e of t.recentCommits)o.push(` - ${e.hash} ${e.message}`),o.push(` ${e.author} @ ${e.date}`);return t.diff&&o.push("","Diff stat:",t.diff),o.join(`
19
+ `)}function Je(t){if(t.length===0)return"No diff files found.";const o=[];for(const e of t){const n=e.oldPath?` (from ${e.oldPath})`:"";o.push(`${e.path}${n} [${e.status}] +${e.additions} -${e.deletions} (${e.hunks.length} hunks)`);for(const s of e.hunks){const i=s.header?` ${s.header}`:"";o.push(` @@ -${s.oldStart},${s.oldLines} +${s.newStart},${s.newLines} @@${i}`)}}return o.join(`
20
+ `)}function je(t){return[t.path,`Language: ${t.language}`,`Lines: ${t.lines}`,`Estimated tokens: ~${t.estimatedTokens}`,"",`Imports (${t.imports.length}):`,...m(t.imports),"",`Exports (${t.exports.length}):`,...m(t.exports),"",`Functions (${t.functions.length}):`,...m(t.functions.map(e=>`${e.name} @ line ${e.line}${e.exported?" [exported]":""}`)),"",`Classes (${t.classes.length}):`,...m(t.classes.map(e=>`${e.name} @ line ${e.line}${e.exported?" [exported]":""}`)),"",`Interfaces (${t.interfaces.length}):`,...m(t.interfaces.map(e=>`${e.name} @ line ${e.line}`)),"",`Types (${t.types.length}):`,...m(t.types.map(e=>`${e.name} @ line ${e.line}`))].join(`
21
+ `)}function y(t){const o=[t.id,`Label: ${t.label}`,`Created: ${t.createdAt}`];if(t.notes&&o.push(`Notes: ${t.notes}`),t.files?.length){o.push(`Files: ${t.files.length}`);for(const e of t.files)o.push(` - ${e}`)}return o.push("","Data:",JSON.stringify(t.data,null,2)),o.join(`
22
+ `)}function m(t){return t.length===0?[" none"]:t.map(o=>` - ${o}`)}function Le(t){const o=t.trim();if(!o)return"";try{return JSON.parse(o)}catch{return t}}function Fe(t){const o=t?.trim();if(!o)return{};const e=JSON.parse(o);if(!e||typeof e!="object"||Array.isArray(e))throw new Error("data must be a JSON object string");return e}function mt(t){t.registerTool("web_fetch",{description:"PREFERRED web fetcher \u2014 fetch any URL and convert to LLM-optimized markdown. Supports CSS selectors, 4 output modes (markdown/raw/links/outline), smart paragraph-boundary truncation. Strips scripts/styles/nav automatically.",inputSchema:{url:r.string().url().describe("URL to fetch (http/https only)"),mode:r.enum(["markdown","raw","links","outline"]).default("markdown").describe("Output mode: markdown (clean content), raw (HTML), links (extracted URLs), outline (heading hierarchy)"),selector:r.string().optional().describe("CSS selector to extract a specific element instead of auto-detecting main content"),max_length:r.number().min(500).max(1e5).default(15e3).describe("Max characters in output \u2014 truncates at paragraph boundaries"),include_metadata:r.boolean().default(!0).describe("Include page title, description, and URL as a header"),include_links:r.boolean().default(!1).describe("Append extracted links list at the end"),include_images:r.boolean().default(!1).describe("Include image alt texts inline"),timeout:r.number().min(1e3).max(6e4).default(15e3).describe("Request timeout in milliseconds")}},async({url:o,mode:e,selector:n,max_length:s,include_metadata:i,include_links:a,include_images:c,timeout:l})=>{try{const d=await Te({url:o,mode:e,selector:n,maxLength:s,includeMetadata:i,includeLinks:a,includeImages:c,timeout:l}),u=[`## ${d.title||"Web Page"}`,"",d.content];return d.truncated&&u.push("",`_Original length: ${d.originalLength.toLocaleString()} chars_`),u.push("","---","_Next: Use `remember` to save key findings, or `web_fetch` with a `selector` to extract a specific section._"),{content:[{type:"text",text:u.join(`
23
+ `)}]}}catch(d){return{content:[{type:"text",text:`Web fetch failed: ${d.message}`}],isError:!0}}})}function gt(t){t.registerTool("guide",{description:"Tool discovery \u2014 given a goal description, recommends which KB tools to use and in what order. Matches against 10 predefined workflows: onboard, audit, bugfix, implement, refactor, search, context, memory, validate, analyze.",inputSchema:{goal:r.string().describe('What you want to accomplish (e.g., "audit this monorepo", "fix a failing test")'),max_recommendations:r.number().min(1).max(10).default(5).describe("Maximum number of tool recommendations")}},async({goal:o,max_recommendations:e})=>{try{const n=A(o,e),s=[`## Recommended Workflow: **${n.workflow}**`,n.description,"","### Tools",...n.tools.map(i=>{const a=i.suggestedArgs?` \u2014 \`${JSON.stringify(i.suggestedArgs)}\``:"";return`${i.order}. **${i.tool}** \u2014 ${i.reason}${a}`})];return n.alternativeWorkflows.length>0&&s.push("",`_Alternative workflows: ${n.alternativeWorkflows.join(", ")}_`),s.push("","---","_Next: Run the first recommended tool, or use `guide` again with a more specific goal._"),{content:[{type:"text",text:s.join(`
24
+ `)}]}}catch(n){return{content:[{type:"text",text:`Guide failed: ${n.message}`}],isError:!0}}})}export{Qe as registerBatchTool,Ge as registerCheckTool,ot as registerCheckpointTool,rt as registerCodemodTool,Pe as registerCompactTool,st as registerDataTransformTool,lt as registerDeadSymbolsTool,dt as registerDelegateTool,et as registerDiffParseTool,Ve as registerEvalTool,nt as registerFileSummaryTool,Be as registerFindTool,Ze as registerGitContextTool,gt as registerGuideTool,pt as registerHealthTool,ut as registerLaneTool,Ke as registerParseOutputTool,at as registerProcessTool,ft as registerQueueTool,tt as registerRenameTool,Ue as registerScopeMapTool,Ye as registerStashTool,He as registerSymbolTool,Xe as registerTestRunTool,it as registerTraceTool,ct as registerWatchTool,mt as registerWebFetchTool,ze as registerWorksetTool};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Non-blocking check for newer @vpxa/kb versions on npm.
3
+ * Logs a warning to stderr if the running version is outdated.
4
+ */
5
+ /**
6
+ * Check for a newer version on npm and log a warning if outdated.
7
+ * This is fire-and-forget — it never throws and never blocks startup.
8
+ */
9
+ export declare function checkForUpdates(): void;
10
+ //# sourceMappingURL=version-check.d.ts.map
@@ -0,0 +1 @@
1
+ import{readFileSync as s}from"node:fs";import{dirname as c,resolve as p}from"node:path";import{fileURLToPath as a}from"node:url";const u="@vpxa/kb",m=`https://registry.npmjs.org/${u}/latest`;function f(){const n=c(a(import.meta.url)),r=p(n,"..","..","..","package.json");try{return JSON.parse(s(r,"utf-8")).version??"0.0.0"}catch{return"0.0.0"}}function l(n,r){const t=n.split(".").map(Number),i=r.split(".").map(Number);for(let e=0;e<3;e++){const o=(t[e]??0)-(i[e]??0);if(o!==0)return o>0?1:-1}return 0}function h(){const n=f();fetch(m,{signal:AbortSignal.timeout(5e3)}).then(r=>{if(r.ok)return r.json()}).then(r=>{if(!r||typeof r!="object")return;const t=r.version;t&&l(n,t)<0&&console.error(`[KB] \u26A0 Update available: ${n} \u2192 ${t}. Run \`npx @vpxa/kb@${t} serve\` or update your mcp.json.`)}).catch(()=>{})}export{h as checkForUpdates};
@@ -1 +1 @@
1
- import{EMBEDDING_DEFAULTS as h,SEARCH_DEFAULTS as d,STORE_DEFAULTS as u}from"../../core/dist/index.js";import{connect as g,Index as m}from"@lancedb/lancedb";const b=/^[\w.\-/ ]+$/;function r(l,e){if(!b.test(l))throw new Error(`Invalid ${e} filter value: contains disallowed characters`);return l.replace(/'/g,"''")}class p{db=null;table=null;dbPath;tableName;constructor(e){this.dbPath=e?.path??u.path,this.tableName=e?.tableName??u.tableName}async initialize(){this.db=await g(this.dbPath),(await this.db.tableNames()).includes(this.tableName)&&(this.table=await this.db.openTable(this.tableName),await this.createFtsIndex())}async upsert(e,n){if(e.length===0)return;if(e.length!==n.length)throw new Error(`Record count (${e.length}) does not match vector count (${n.length})`);const a=e.map((t,i)=>({id:t.id,vector:Array.from(n[i]),content:t.content,sourcePath:t.sourcePath,contentType:t.contentType,headingPath:t.headingPath??"",chunkIndex:t.chunkIndex,totalChunks:t.totalChunks,startLine:t.startLine,endLine:t.endLine,fileHash:t.fileHash,indexedAt:t.indexedAt,origin:t.origin,tags:JSON.stringify(t.tags),category:t.category??"",version:t.version}));if(this.table){const t=[...new Set(e.map(i=>i.sourcePath))];for(const i of t)try{await this.table.delete(`sourcePath = '${r(i,"sourcePath")}'`)}catch{}await this.table.add(a)}else try{this.table=await this.db?.createTable(this.tableName,a)??null}catch(t){if(String(t).includes("already exists")&&this.db)this.table=await this.db.openTable(this.tableName),await this.table.add(a);else throw t}}async search(e,n){if(!this.table)return[];const a=n?.limit??d.maxResults,t=n?.minScore??d.minScore;let i=this.table.search(e).limit(a*2);const o=this.buildFilterString(n);return o&&(i=i.where(o)),(await i.toArray()).map(c=>({record:this.fromLanceRecord(c),score:1-(c._distance??1)})).filter(c=>c.score>=t).slice(0,a)}async createFtsIndex(){if(this.table)try{await this.table.createIndex("content",{config:m.fts()}),console.error("[KB] FTS index created on content column")}catch(e){String(e).includes("already exists")||console.error("[KB] FTS index creation failed (non-fatal):",e)}}async ftsSearch(e,n){if(!this.table)return[];const a=n?.limit??d.maxResults;try{let t=this.table.search(e).limit(a*2);const i=this.buildFilterString(n);return i&&(t=t.where(i)),(await t.toArray()).map(s=>({record:this.fromLanceRecord(s),score:s._score??s._relevance_score??0}))}catch(t){return console.error("[KB] FTS search failed (non-fatal):",t),[]}}async getById(e){if(!this.table)return null;const n=await this.table.query().where(`id = '${r(e,"id")}'`).limit(1).toArray();return n.length===0?null:this.fromLanceRecord(n[0])}async deleteBySourcePath(e){if(!this.table)return 0;const n=await this.getBySourcePath(e);return n.length===0?0:(await this.table.delete(`sourcePath = '${r(e,"sourcePath")}'`),n.length)}async deleteById(e){return!this.table||!await this.getById(e)?!1:(await this.table.delete(`id = '${r(e,"id")}'`),!0)}async getBySourcePath(e){return this.table?(await this.table.query().where(`sourcePath = '${r(e,"sourcePath")}'`).limit(1e3).toArray()).map(a=>this.fromLanceRecord(a)):[]}async getStats(){if(!this.table)return{totalRecords:0,totalFiles:0,contentTypeBreakdown:{},lastIndexedAt:null,storeBackend:"lancedb",embeddingModel:h.model};const e=await this.table.countRows(),n=await this.table.query().select(["sourcePath","contentType","indexedAt"]).limit(1e5).toArray(),a={},t=new Set;let i=null;for(const o of n){const s=o;a[s.contentType]=(a[s.contentType]??0)+1,t.add(s.sourcePath),(!i||s.indexedAt>i)&&(i=s.indexedAt)}return{totalRecords:e,totalFiles:t.size,contentTypeBreakdown:a,lastIndexedAt:i,storeBackend:"lancedb",embeddingModel:h.model}}async listSourcePaths(){if(!this.table)return[];const e=await this.table.query().select(["sourcePath"]).limit(1e5).toArray();return[...new Set(e.map(n=>n.sourcePath))]}async dropTable(){if(this.db&&(await this.db.tableNames()).includes(this.tableName))for(let a=1;a<=3;a++)try{await this.db.dropTable(this.tableName);break}catch(t){if(a===3)throw t;const i=a*500;console.error(`[KB] dropTable attempt ${a} failed, retrying in ${i}ms...`),await new Promise(o=>setTimeout(o,i))}this.table=null}async close(){try{this.db&&typeof this.db.close=="function"&&await this.db.close()}catch{}this.table=null,this.db=null}buildFilterString(e){const n=[];if(e?.contentType&&n.push(`contentType = '${r(e.contentType,"contentType")}'`),e?.origin&&n.push(`origin = '${r(e.origin,"origin")}'`),e?.category&&n.push(`category = '${r(e.category,"category")}'`),e?.tags&&e.tags.length>0){const a=e.tags.map(t=>`tags LIKE '%${r(t,"tag")}%'`);n.push(`(${a.join(" OR ")})`)}return n.length>0?n.join(" AND "):null}fromLanceRecord(e){return{id:e.id,content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath||void 0,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,indexedAt:e.indexedAt,origin:e.origin,tags:JSON.parse(e.tags||"[]"),category:e.category||void 0,version:e.version}}}export{p as LanceStore};
1
+ import{EMBEDDING_DEFAULTS as h,SEARCH_DEFAULTS as d,STORE_DEFAULTS as u,sourceTypeContentTypes as g}from"../../core/dist/index.js";import{connect as y,Index as m}from"@lancedb/lancedb";const b=/^[\w.\-/ ]+$/;function r(l,e){if(!b.test(l))throw new Error(`Invalid ${e} filter value: contains disallowed characters`);return l.replace(/'/g,"''")}class w{db=null;table=null;dbPath;tableName;constructor(e){this.dbPath=e?.path??u.path,this.tableName=e?.tableName??u.tableName}async initialize(){this.db=await y(this.dbPath),(await this.db.tableNames()).includes(this.tableName)&&(this.table=await this.db.openTable(this.tableName),await this.createFtsIndex())}async upsert(e,n){if(e.length===0)return;if(e.length!==n.length)throw new Error(`Record count (${e.length}) does not match vector count (${n.length})`);const a=e.map((t,i)=>({id:t.id,vector:Array.from(n[i]),content:t.content,sourcePath:t.sourcePath,contentType:t.contentType,headingPath:t.headingPath??"",chunkIndex:t.chunkIndex,totalChunks:t.totalChunks,startLine:t.startLine,endLine:t.endLine,fileHash:t.fileHash,indexedAt:t.indexedAt,origin:t.origin,tags:JSON.stringify(t.tags),category:t.category??"",version:t.version}));if(this.table){const t=[...new Set(e.map(i=>i.sourcePath))];for(const i of t)try{await this.table.delete(`sourcePath = '${r(i,"sourcePath")}'`)}catch{}await this.table.add(a)}else try{this.table=await this.db?.createTable(this.tableName,a)??null}catch(t){if(String(t).includes("already exists")&&this.db)this.table=await this.db.openTable(this.tableName),await this.table.add(a);else throw t}}async search(e,n){if(!this.table)return[];const a=n?.limit??d.maxResults,t=n?.minScore??d.minScore;let i=this.table.search(e).limit(a*2);const o=this.buildFilterString(n);return o&&(i=i.where(o)),(await i.toArray()).map(c=>({record:this.fromLanceRecord(c),score:1-(c._distance??1)})).filter(c=>c.score>=t).slice(0,a)}async createFtsIndex(){if(this.table)try{await this.table.createIndex("content",{config:m.fts()}),console.error("[KB] FTS index created on content column")}catch(e){String(e).includes("already exists")||console.error("[KB] FTS index creation failed (non-fatal):",e)}}async ftsSearch(e,n){if(!this.table)return[];const a=n?.limit??d.maxResults;try{let t=this.table.search(e).limit(a*2);const i=this.buildFilterString(n);return i&&(t=t.where(i)),(await t.toArray()).map(s=>({record:this.fromLanceRecord(s),score:s._score??s._relevance_score??0}))}catch(t){return console.error("[KB] FTS search failed (non-fatal):",t),[]}}async getById(e){if(!this.table)return null;const n=await this.table.query().where(`id = '${r(e,"id")}'`).limit(1).toArray();return n.length===0?null:this.fromLanceRecord(n[0])}async deleteBySourcePath(e){if(!this.table)return 0;const n=await this.getBySourcePath(e);return n.length===0?0:(await this.table.delete(`sourcePath = '${r(e,"sourcePath")}'`),n.length)}async deleteById(e){return!this.table||!await this.getById(e)?!1:(await this.table.delete(`id = '${r(e,"id")}'`),!0)}async getBySourcePath(e){return this.table?(await this.table.query().where(`sourcePath = '${r(e,"sourcePath")}'`).limit(1e3).toArray()).map(a=>this.fromLanceRecord(a)):[]}async getStats(){if(!this.table)return{totalRecords:0,totalFiles:0,contentTypeBreakdown:{},lastIndexedAt:null,storeBackend:"lancedb",embeddingModel:h.model};const e=await this.table.countRows(),n=await this.table.query().select(["sourcePath","contentType","indexedAt"]).limit(1e5).toArray(),a={},t=new Set;let i=null;for(const o of n){const s=o;a[s.contentType]=(a[s.contentType]??0)+1,t.add(s.sourcePath),(!i||s.indexedAt>i)&&(i=s.indexedAt)}return{totalRecords:e,totalFiles:t.size,contentTypeBreakdown:a,lastIndexedAt:i,storeBackend:"lancedb",embeddingModel:h.model}}async listSourcePaths(){if(!this.table)return[];const e=await this.table.query().select(["sourcePath"]).limit(1e5).toArray();return[...new Set(e.map(n=>n.sourcePath))]}async dropTable(){if(this.db&&(await this.db.tableNames()).includes(this.tableName))for(let a=1;a<=3;a++)try{await this.db.dropTable(this.tableName);break}catch(t){if(a===3)throw t;const i=a*500;console.error(`[KB] dropTable attempt ${a} failed, retrying in ${i}ms...`),await new Promise(o=>setTimeout(o,i))}this.table=null}async close(){try{this.db&&typeof this.db.close=="function"&&await this.db.close()}catch{}this.table=null,this.db=null}buildFilterString(e){const n=[];if(e?.contentType&&n.push(`contentType = '${r(e.contentType,"contentType")}'`),e?.sourceType){const a=g(e.sourceType);if(a.length>0){const t=a.map(i=>`'${r(i,"sourceType")}'`).join(", ");n.push(`contentType IN (${t})`)}}if(e?.origin&&n.push(`origin = '${r(e.origin,"origin")}'`),e?.category&&n.push(`category = '${r(e.category,"category")}'`),e?.tags&&e.tags.length>0){const a=e.tags.map(t=>`tags LIKE '%${r(t,"tag")}%'`);n.push(`(${a.join(" OR ")})`)}return n.length>0?n.join(" AND "):null}fromLanceRecord(e){return{id:e.id,content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath||void 0,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,indexedAt:e.indexedAt,origin:e.origin,tags:JSON.parse(e.tags||"[]"),category:e.category||void 0,version:e.version}}}export{w as LanceStore};
@@ -10,6 +10,8 @@ export interface SearchOptions {
10
10
  minScore?: number;
11
11
  /** Filter by content type */
12
12
  contentType?: string;
13
+ /** Filter by coarse source type (source, documentation, test, config, generated) */
14
+ sourceType?: string;
13
15
  /** Filter by origin */
14
16
  origin?: string;
15
17
  /** Filter by category */
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Unified audit tool (E-007) — runs structure, dependencies, patterns, health,
3
+ * dead_symbols, and check in one call, producing a synthesized report.
4
+ */
5
+ import type { IEmbedder } from '@kb/embeddings';
6
+ import type { IKnowledgeStore } from '@kb/store';
7
+ import { type KBResponse } from './response-envelope.js';
8
+ export type AuditCheck = 'structure' | 'dependencies' | 'patterns' | 'health' | 'dead_symbols' | 'check' | 'entry_points';
9
+ export interface AuditOptions {
10
+ /** Root path to audit (default: cwd) */
11
+ path?: string;
12
+ /** Which checks to run (default: all) */
13
+ checks?: AuditCheck[];
14
+ /** Detail level (default: 'summary') */
15
+ detail?: 'summary' | 'full';
16
+ }
17
+ export interface AuditRecommendation {
18
+ priority: 'high' | 'medium' | 'low';
19
+ area: string;
20
+ message: string;
21
+ }
22
+ export interface AuditData {
23
+ score: number;
24
+ structure?: {
25
+ files: number;
26
+ packages: number;
27
+ languages: Record<string, number>;
28
+ };
29
+ dependencies?: {
30
+ external: number;
31
+ internal: number;
32
+ };
33
+ patterns?: Array<{
34
+ name: string;
35
+ confidence: string;
36
+ count: number;
37
+ }>;
38
+ health?: {
39
+ score: number;
40
+ checks: number;
41
+ passed: number;
42
+ warned: number;
43
+ failed: number;
44
+ };
45
+ deadSymbols?: {
46
+ source: number;
47
+ docs: number;
48
+ };
49
+ entryPoints?: {
50
+ total: number;
51
+ types: Record<string, number>;
52
+ };
53
+ typecheck?: {
54
+ passed: boolean;
55
+ errorCount: number;
56
+ topErrors: string[];
57
+ };
58
+ lint?: {
59
+ passed: boolean;
60
+ errorCount: number;
61
+ topErrors: string[];
62
+ };
63
+ recommendations: AuditRecommendation[];
64
+ }
65
+ export declare function audit(store: IKnowledgeStore, embedder: IEmbedder, options?: AuditOptions): Promise<KBResponse<AuditData>>;
66
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1,7 @@
1
+ import{DependencyAnalyzer as $,EntryPointAnalyzer as A,PatternAnalyzer as w,StructureAnalyzer as S}from"../../analyzers/dist/index.js";import{check as x,summarizeCheckResult as C}from"./check.js";import{findDeadSymbols as D}from"./dead-symbols.js";import{health as R}from"./health.js";import{resolvePath as P}from"./path-resolver.js";import{errorResponse as z,okResponse as E}from"./response-envelope.js";const _=["structure","dependencies","patterns","health","dead_symbols","check","entry_points"];async function B(e,h,n={}){const o=Date.now(),i=P(n.path),l=n.checks??_,f=n.detail??"summary",d=[],t={score:100,recommendations:d};try{const c=[];l.includes("structure")&&c.push((async()=>{const s=await new S().analyze(i,{format:"json"}),a=s.data;t.structure={files:a.stats?.totalFiles??s.meta.fileCount,packages:Array.isArray(a.packages)?a.packages.length:0,languages:a.stats?.languages??{}}})()),l.includes("dependencies")&&c.push((async()=>{const a=(await new $().analyze(i)).data,u=a.imports??[];t.dependencies={external:a.external?.length??u.filter(p=>p.isExternal).length,internal:a.internal?.length??u.filter(p=>!p.isExternal).length}})()),l.includes("patterns")&&c.push((async()=>{const a=(await new w().analyze(i)).data;t.patterns=(a.patterns??[]).map(u=>({name:u.pattern,confidence:u.confidence,count:u.locations.length}))})()),l.includes("entry_points")&&c.push((async()=>{const a=(await new A().analyze(i)).data,u=a.entryPoints??[],p={};for(const b of u)p[b.type]=(p[b.type]??0)+1;t.entryPoints={total:a.total??u.length,types:p}})()),l.includes("health")&&c.push((async()=>{const r=R(i);t.health={score:r.score,checks:r.checks.length,passed:r.checks.filter(s=>s.status==="pass").length,warned:r.checks.filter(s=>s.status==="warn").length,failed:r.checks.filter(s=>s.status==="fail").length},r.score<70&&d.push({priority:"medium",area:"health",message:`Health score ${r.score}/100 \u2014 ${t.health.failed} failed checks`})})()),l.includes("dead_symbols")&&c.push((async()=>{const r=await D(h,e,{rootPath:i});t.deadSymbols={source:r.totalDeadSource,docs:r.totalDeadDocs},r.totalDeadSource>0&&d.push({priority:r.totalDeadSource>10?"high":"medium",area:"dead-code",message:`${r.totalDeadSource} unused exports in source files`})})()),l.includes("check")&&c.push((async()=>{const r=await x({cwd:i}),s=C(r);t.typecheck={passed:s.tsc.passed,errorCount:s.tsc.errorCount,topErrors:s.tsc.topErrors},t.lint={passed:s.biome.passed,errorCount:s.biome.errorCount,topErrors:s.biome.topErrors},s.tsc.passed||d.push({priority:"high",area:"type-safety",message:`Fix ${s.tsc.errorCount} tsc error(s)`}),s.biome.passed||d.push({priority:"medium",area:"lint",message:`Fix ${s.biome.errorCount} lint error(s)`})})()),await Promise.all(c);let m=0;t.typecheck&&!t.typecheck.passed&&(m+=15),t.lint&&!t.lint.passed&&(m+=5),t.health&&t.health.score<80&&(m+=10),t.deadSymbols&&t.deadSymbols.source>10&&(m+=5),t.entryPoints&&t.entryPoints.total===0&&(m+=5),t.score=Math.max(0,100-m);const g={high:0,medium:1,low:2};d.sort((r,s)=>g[r.priority]-g[s.priority]);const k=j(t,f),y=[];return t.typecheck&&!t.typecheck.passed&&y.push({tool:"check",reason:"Get full error details",suggested_args:{detail:"errors"}}),t.deadSymbols&&t.deadSymbols.source>0&&y.push({tool:"dead_symbols",reason:"See which exports are unused",suggested_args:{root_path:i}}),E("audit",k,t,{durationMs:Date.now()-o,detail:f},y)}catch(c){return z("audit",{code:"ANALYSIS_FAILED",category:"runtime",retryable:!1,message:`Audit failed: ${c.message}`},Date.now()-o)}}function j(e,h){const n=[];if(n.push(`## Audit Report \u2014 Score: ${e.score}/100
2
+ `),e.structure&&n.push(`**Structure:** ${e.structure.files} files, ${e.structure.packages} packages, ${Object.keys(e.structure.languages).length} languages`),e.entryPoints){const o=Object.entries(e.entryPoints.types).map(([i,l])=>`${l} ${i}`).join(", ");n.push(`**Entry Points:** ${e.entryPoints.total} (${o||"none"})`)}if(e.dependencies&&n.push(`**Dependencies:** ${e.dependencies.external} external, ${e.dependencies.internal} internal`),e.health&&n.push(`**Health:** ${e.health.score}/100 (${e.health.passed}\u2713 ${e.health.warned}\u26A0 ${e.health.failed}\u2717)`),e.deadSymbols&&n.push(`**Dead Symbols:** ${e.deadSymbols.source} in source (actionable), ${e.deadSymbols.docs} in docs`),e.typecheck){const o=e.typecheck.passed?"\u2713 passed":`\u2717 ${e.typecheck.errorCount} errors`;n.push(`**Typecheck:** ${o}`)}if(e.lint){const o=e.lint.passed?"\u2713 passed":`\u2717 ${e.lint.errorCount} errors`;n.push(`**Lint:** ${o}`)}if(e.recommendations.length>0){n.push(`
3
+ ### Recommendations
4
+ `);for(const o of e.recommendations){const i=o.priority==="high"?"\u{1F534}":o.priority==="medium"?"\u{1F7E1}":"\u{1F7E2}";n.push(`${i} **${o.area}:** ${o.message}`)}}if(h==="full"&&e.patterns&&e.patterns.length>0){n.push(`
5
+ ### Patterns Detected
6
+ `),n.push("| Pattern | Confidence | Count |"),n.push("|---------|-----------|-------|");for(const o of e.patterns)n.push(`| ${o.name} | ${o.confidence} | ${o.count} |`)}return n.join(`
7
+ `)}export{B as audit};
@@ -8,6 +8,23 @@ export interface CheckOptions {
8
8
  skipTypes?: boolean;
9
9
  /** Skip lint */
10
10
  skipLint?: boolean;
11
+ /** Detail level: summary (default, minimal), errors (parsed errors), full (includes raw) */
12
+ detail?: 'summary' | 'errors' | 'full';
13
+ }
14
+ export interface CheckSummaryResult {
15
+ passed: boolean;
16
+ tsc: {
17
+ passed: boolean;
18
+ errorCount: number;
19
+ warningCount: number;
20
+ topErrors: string[];
21
+ };
22
+ biome: {
23
+ passed: boolean;
24
+ errorCount: number;
25
+ warningCount: number;
26
+ topErrors: string[];
27
+ };
11
28
  }
12
29
  export interface CheckResult {
13
30
  tsc: {
@@ -23,4 +40,6 @@ export interface CheckResult {
23
40
  passed: boolean;
24
41
  }
25
42
  export declare function check(options?: CheckOptions): Promise<CheckResult>;
43
+ /** Produce a minimal summary for LLM consumption (~300 tokens) */
44
+ export declare function summarizeCheckResult(result: CheckResult): CheckSummaryResult;
26
45
  //# sourceMappingURL=check.d.ts.map
@@ -1,2 +1,2 @@
1
- import{execFile as p}from"node:child_process";import{readFile as l}from"node:fs/promises";import{join as d}from"node:path";import{promisify as f}from"node:util";import{parseBiome as u,parseTsc as g}from"./parse-output.js";const i=f(p);function n(r){const t=r,e=t.stdout?.toString()??"",s=t.stderr?.toString()??"";return[e,s].filter(Boolean).join(`
2
- `).trim()||t.message||"Command failed"}async function b(r={}){const t=r.cwd??process.cwd(),e={errors:[],passed:!0,raw:""},s={errors:[],passed:!0,raw:""};if(!r.skipTypes)try{const a=d(t,"package.json");let c=!1;try{c=!!JSON.parse(await l(a,"utf-8")).scripts?.typecheck}catch{}if(c&&!r.files?.length)await i("npx",["turbo","run","typecheck"],{cwd:t,shell:!0});else{const o=["--noEmit"];r.files?.length&&o.push(...r.files),await i("npx",["tsc",...o],{cwd:t,shell:!0})}}catch(a){e.raw=n(a),e.errors=g(e.raw),e.passed=e.errors.length===0}if(!r.skipLint)try{const a=["check"];r.files?.length&&a.push(...r.files),await i("npx",["biome",...a],{cwd:t,shell:!0})}catch(a){s.raw=n(a),s.errors=u(s.raw),s.passed=s.errors.length===0}return{tsc:e,biome:s,passed:e.passed&&s.passed}}export{b as check};
1
+ import{execFile as d}from"node:child_process";import{readFile as m}from"node:fs/promises";import{join as f}from"node:path";import{promisify as g}from"node:util";import{parseBiome as h,parseTsc as b}from"./parse-output.js";const c=g(d);function p(r){const o=r,t=o.stdout?.toString()??"",s=o.stderr?.toString()??"";return[t,s].filter(Boolean).join(`
2
+ `).trim()||o.message||"Command failed"}async function R(r={}){const o=r.cwd??process.cwd(),t={errors:[],passed:!0,raw:""},s={errors:[],passed:!0,raw:""};if(!r.skipTypes)try{const n=f(o,"package.json");let l=!1;try{l=!!JSON.parse(await m(n,"utf-8")).scripts?.typecheck}catch{}if(l&&!r.files?.length)await c("npx",["turbo","run","typecheck"],{cwd:o,shell:!0});else{const i=["--noEmit"];r.files?.length&&i.push(...r.files),await c("npx",["tsc",...i],{cwd:o,shell:!0})}}catch(n){t.raw=p(n),t.errors=b(t.raw),t.passed=t.errors.length===0}if(!r.skipLint)try{const n=["check"];r.files?.length&&n.push(...r.files),await c("npx",["biome",...n],{cwd:o,shell:!0})}catch(n){s.raw=p(n),s.errors=h(s.raw),s.passed=s.errors.length===0}const a=r.detail??"full",e={tsc:t,biome:s,passed:t.passed&&s.passed};return a==="full"?e:a==="errors"?{tsc:{errors:t.errors,passed:t.passed},biome:{errors:s.errors,passed:s.passed},passed:e.passed}:e}const u=3;function x(r){const o=r.tsc.errors.filter(e=>e.severity==="error"),t=r.tsc.errors.filter(e=>e.severity==="warning"),s=r.biome.errors.filter(e=>e.severity==="error"),a=r.biome.errors.filter(e=>e.severity==="warning");return{passed:r.passed,tsc:{passed:r.tsc.passed,errorCount:o.length,warningCount:t.length,topErrors:o.slice(0,u).map(e=>`${e.file}:${e.line} \u2014 ${e.message}`)},biome:{passed:r.biome.passed,errorCount:s.length,warningCount:a.length,topErrors:s.slice(0,u).map(e=>`${e.file}:${e.line} \u2014 ${e.message}`)}}}export{R as check,x as summarizeCheckResult};
@@ -10,8 +10,10 @@
10
10
  */
11
11
  import type { IEmbedder } from '@kb/embeddings';
12
12
  export interface CompactOptions {
13
- /** The text to compress */
14
- text: string;
13
+ /** The text to compress (at least one of text/path required) */
14
+ text?: string;
15
+ /** File path to read server-side — avoids read_file round-trip (at least one of text/path required) */
16
+ path?: string;
15
17
  /** The focus query — what are we trying to understand? */
16
18
  query: string;
17
19
  /** Target output size in characters (default: 3000) */
@@ -1,3 +1,3 @@
1
- import{cosineSimilarity as C,segment as b}from"./text-utils.js";async function S(m,g){const{text:t,query:l,maxChars:o=3e3,minScore:h=.3,segmentation:p="paragraph"}=g;if(t.length<=o)return{text:t,originalChars:t.length,compressedChars:t.length,ratio:1,segmentsKept:1,segmentsTotal:1};const n=b(t,p);if(n.length===0)return{text:"",originalChars:t.length,compressedChars:0,ratio:0,segmentsKept:0,segmentsTotal:0};const d=await m.embed(l),c=[];for(let e=0;e<n.length;e++){const s=await m.embed(n[e]),u=C(d,s);c.push({text:n[e],score:u,index:e})}const x=c.filter(e=>e.score>=h).sort((e,s)=>s.score-e.score),r=[];let i=0;for(const e of x){if(i+e.text.length>o){i===0&&(r.push({...e,text:e.text.slice(0,o)}),i=o);break}r.push(e),i+=e.text.length+2}r.sort((e,s)=>e.index-s.index);const a=r.map(e=>e.text).join(`
1
+ import{readFile as f}from"node:fs/promises";import{cosineSimilarity as b,segment as C}from"./text-utils.js";async function w(c,r){const{query:l,maxChars:a=3e3,minScore:h=.3,segmentation:p="paragraph"}=r;let t;if(r.text)t=r.text;else if(r.path)t=await f(r.path,"utf-8");else throw new Error('Either "text" or "path" must be provided');if(t.length<=a)return{text:t,originalChars:t.length,compressedChars:t.length,ratio:1,segmentsKept:1,segmentsTotal:1};const s=C(t,p);if(s.length===0)return{text:"",originalChars:t.length,compressedChars:0,ratio:0,segmentsKept:0,segmentsTotal:0};const d=await c.embed(l),g=[];for(let e=0;e<s.length;e++){const o=await c.embed(s[e]),u=b(d,o);g.push({text:s[e],score:u,index:e})}const x=g.filter(e=>e.score>=h).sort((e,o)=>o.score-e.score),n=[];let i=0;for(const e of x){if(i+e.text.length>a){i===0&&(n.push({...e,text:e.text.slice(0,a)}),i=a);break}n.push(e),i+=e.text.length+2}n.sort((e,o)=>e.index-o.index);const m=n.map(e=>e.text).join(`
2
2
 
3
- `);return{text:a,originalChars:t.length,compressedChars:a.length,ratio:a.length/t.length,segmentsKept:r.length,segmentsTotal:n.length}}export{S as compact};
3
+ `);return{text:m,originalChars:t.length,compressedChars:m.length,ratio:m.length/t.length,segmentsKept:n.length,segmentsTotal:s.length}}export{w as compact};
@@ -13,8 +13,16 @@ export interface DeadSymbol {
13
13
  kind: string;
14
14
  }
15
15
  export interface DeadSymbolResult {
16
- deadSymbols: DeadSymbol[];
16
+ /** Dead symbols in source files (.ts/.js/.tsx/.jsx) — actionable */
17
+ deadInSource: DeadSymbol[];
18
+ /** Dead symbols in documentation files (.md) — informational */
19
+ deadInDocs: DeadSymbol[];
17
20
  totalExports: number;
21
+ totalDeadSource: number;
22
+ totalDeadDocs: number;
23
+ /** @deprecated Use deadInSource instead */
24
+ deadSymbols: DeadSymbol[];
25
+ /** @deprecated Use totalDeadSource + totalDeadDocs instead */
18
26
  totalDead: number;
19
27
  }
20
28
  export declare function findDeadSymbols(embedder: IEmbedder, store: IKnowledgeStore, options?: DeadSymbolOptions): Promise<DeadSymbolResult>;
@@ -1,2 +1,2 @@
1
- async function w(o,r,n={}){const{rootPath:a,limit:b=100}=n,x=await o.embed("export function class const type interface enum"),y=await r.search(x,{limit:b*3}),u=/^export\s+(?:async\s+)?(?:function|class|const|let|interface|type|enum)\s+(\w+)/gm,h=[];for(const t of y){if(!D(t.record.sourcePath,a))continue;const e=t.record.content;u.lastIndex=0;for(const m of e.matchAll(u)){const p=m.index??0,d=e.slice(0,p).split(`
2
- `).length-1,l=e.slice(p).match(/export\s+(?:async\s+)?(\w+)/);h.push({name:m[1],path:t.record.sourcePath,line:t.record.startLine+d,kind:l?.[1]??"unknown"})}}const c=new Map;for(const t of h){const e=`${t.path}:${t.name}`;c.has(e)||c.set(e,t)}const i=[];for(const t of c.values()){const e=S(t.name),m=new RegExp(`import\\s+.*\\b${e}\\b.*from`,"m"),p=new RegExp(`export\\s+\\{[^}]*\\b${e}\\b`,"m"),d=await r.ftsSearch(`import ${t.name}`,{limit:10}),l=d.some(s=>s.record.sourcePath!==t.path&&m.test(s.record.content)),g=d.some(s=>s.record.sourcePath!==t.path&&p.test(s.record.content));!l&&!g&&i.push(t)}return i.sort((t,e)=>t.path===e.path?t.line-e.line:t.path.localeCompare(e.path)),{deadSymbols:i,totalExports:c.size,totalDead:i.length}}function S(o){return o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function D(o,r){if(!r)return!0;const n=f(r).replace(/\/+$/,"");if(/^[A-Za-z]:\//.test(n)||n.startsWith("/"))return!0;const a=f(o);return a===n||a.startsWith(`${n}/`)}function f(o){return o.replace(/\\/g,"/").replace(/^\.\//,"")}export{w as findDeadSymbols};
1
+ import{extname as I}from"node:path";const P=new Set([".md",".mdx"]);async function k(o,s,c={}){const{rootPath:i,limit:y=100}=c,D=await o.embed("export function class const type interface enum"),g=await s.search(D,{limit:y*3}),h=/^export\s+(?:async\s+)?(?:function|class|const|let|interface|type|enum)\s+(\w+)/gm,b=[];for(const e of g){if(!R(e.record.sourcePath,i))continue;const t=e.record.content;h.lastIndex=0;for(const d of t.matchAll(h)){const l=d.index??0,p=t.slice(0,l).split(`
2
+ `).length-1,u=t.slice(l).match(/export\s+(?:async\s+)?(\w+)/);b.push({name:d[1],path:e.record.sourcePath,line:e.record.startLine+p,kind:u?.[1]??"unknown"})}}const m=new Map;for(const e of b){const t=`${e.path}:${e.name}`;m.has(t)||m.set(t,e)}const S=[];for(const e of m.values()){const t=E(e.name),d=new RegExp(`import\\s+.*\\b${t}\\b.*from`,"m"),l=new RegExp(`export\\s+\\{[^}]*\\b${t}\\b`,"m"),p=await s.ftsSearch(`import ${e.name}`,{limit:10}),u=p.some(a=>a.record.sourcePath!==e.path&&d.test(a.record.content)),w=p.some(a=>a.record.sourcePath!==e.path&&l.test(a.record.content));!u&&!w&&S.push(e)}const f=(e,t)=>e.path===t.path?e.line-t.line:e.path.localeCompare(t.path),n=[],r=[];for(const e of S){const t=I(e.path).toLowerCase();P.has(t)?r.push(e):n.push(e)}return n.sort(f),r.sort(f),{deadInSource:n,deadInDocs:r,totalExports:m.size,totalDeadSource:n.length,totalDeadDocs:r.length,deadSymbols:[...n,...r],totalDead:n.length+r.length}}function E(o){return o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function R(o,s){if(!s)return!0;const c=x(s).replace(/\/+$/,""),i=x(o);return i===c||i.startsWith(`${c}/`)}function x(o){return o.replace(/\\/g,"/").replace(/^\.\//,"")}export{k as findDeadSymbols};
@@ -1,2 +1,2 @@
1
1
  import{existsSync as g,readdirSync as _,readFileSync as S,statSync as k}from"node:fs";import{dirname as m,extname as C,relative as p,resolve as a}from"node:path";import{fileSummary as w}from"./file-summary.js";const E=1e5,x=200,v=new Set([".ts",".tsx",".js",".jsx",".mts",".cts",".mjs",".cjs"]),A=new Set([".git",".kb-data",".kb-state",".turbo",".yarn","build","coverage","dist","node_modules"]),N=/auth|token|permission|acl|encrypt|secret|credential|jwt|oauth|password/i,R=/\b(hash|sign|verify|bcrypt|jwt|decrypt|secret|password)\b/i,P=/auth|security|permission|encrypt|secret|credential/i,F=/types\.ts$|schema\.ts$|contract\.ts$|\.proto$|openapi|swagger|\.graphql$/i,U=/(?:^|\/)(events|contracts|shared)(?:\/|$)/i,$=/export\s+interface\b|export\s+type\b|export\s+const\s+\w*Schema\w*\s*=\s*z\./i,j=/schema|contract|migration|breaking.change|api.change/i,I=/migration|data.?model|multi.?service|breaking|backward.?compat/i,D={floor:{ground:"Parasitic \u2014 read target file only",build:"Implement directly",break:"Skip",evidenceMap:"Not required",gate:"Self-certify"},standard:{ground:"Scope map + blast radius + constraint seed",build:"TDD \u2014 test first, then implement",break:"Error paths + edge cases",evidenceMap:"3-8 critical-path entries",gate:"YIELD/HOLD evaluation"},critical:{ground:"Full scope map + blast radius + trace + patterns + constraint pack",build:"TDD + contract verification + cross-service validation",break:"Error paths + edge cases + security dimensions + data-flow verification",evidenceMap:"Comprehensive \u2014 all critical-path claims with receipts",gate:"Strict YIELD/HOLD/HARD_BLOCK evaluation"}};async function W(t){const s=a(t.rootPath),r=t.task.trim(),e=t.files.map(c=>a(s,c)),n=[];let i=!1,o=!1;for(const c of e){const f=O(c,s),T=b(c);(N.test(f)||R.test(T)||P.test(r))&&(i=!0),(F.test(f)||U.test(f)||j.test(r)||$.test(T)||await M(c))&&(o=!0)}i&&l(n,{rule:"security-path",detail:"Security/auth path, task, or content matched security heuristics",source:"security_auth"}),o&&l(n,{rule:"schema-contract",detail:"Schema or contract path, task, or export shape matched contract heuristics",source:"schema_contract"});const d=H(e,s);d.affectedFiles>5&&l(n,{rule:"blast-radius-importers",detail:`${d.affectedFiles} affected files via direct import scanning`,source:"blast_radius"});const u=[...new Set(e.map(c=>B(c,s)).filter(c=>!!c))].sort();u.length>=2&&l(n,{rule:"cross-package-boundary",detail:`Files span ${u.length} packages: ${u.join(", ")}`,source:"cross_package"}),I.test(r)&&l(n,{rule:"task-hint-critical",detail:"Task description matched migration or compatibility criticality hints",source:"task_hint"});const y=n.length>0?"critical":e.length===1?"floor":"standard";return{tier:y,triggers:n,packagesCrossed:u,hasSchemaChange:o,hasSecurityPath:i,typedUnknownSeeds:q(n),ceremony:D[y]}}function l(t,s){t.some(r=>r.rule===s.rule&&r.source===s.source)||t.push(s)}function O(t,s){const r=a(s,t),e=p(s,r);return(e&&!e.startsWith("..")?e:r).replace(/\\/g,"/")}function h(t){if(!g(t))return!1;try{return k(t).size<=E}catch{return!1}}function b(t){if(!h(t))return"";try{return S(t,"utf-8").split(/\r?\n/).slice(0,x).join(`
2
- `)}catch{return""}}async function M(t){if(!h(t))return!1;try{const s=await w({path:t}),r=new Set(s.exports);return s.interfaces.some(e=>r.has(e.name))||s.types.some(e=>r.has(e.name))}catch{return!1}}function H(t,s){const r=new Set(t.filter(n=>g(n)));if(r.size===0)return{affectedFiles:t.length,importers:[]};const e=new Set;for(const n of L(s)){if(r.has(n)||!h(n))continue;const i=b(n);if(!i)continue;z(i).some(d=>Y(d,n,r))&&e.add(n)}return{affectedFiles:t.length+e.size,importers:[...e].map(n=>p(s,n).replace(/\\/g,"/"))}}function L(t){const s=[];function r(e){let n=[];try{n=_(e)}catch{return}for(const i of n){if(A.has(i))continue;const o=a(e,i);let d;try{d=k(o)}catch{continue}if(d.isDirectory()){r(o);continue}v.has(C(i).toLowerCase())&&s.push(o)}}return r(t),s}function z(t){const s=new Set,r=/(?:from\s+['"]([^'"]+)['"]|import\s+['"]([^'"]+)['"]|require\(\s*['"]([^'"]+)['"]\s*\))/g;for(const e of t.matchAll(r)){const n=e[1]??e[2]??e[3];n&&s.add(n)}return[...s]}function Y(t,s,r){if(!t.startsWith("."))return!1;const e=a(m(s),t);return[e,`${e}.ts`,`${e}.tsx`,`${e}.js`,`${e}.jsx`,`${e}.mts`,`${e}.cts`,`${e}.mjs`,`${e}.cjs`,a(e,"index.ts"),a(e,"index.tsx"),a(e,"index.js"),a(e,"index.jsx")].some(i=>r.has(i))}function q(t){return t.map(s=>{switch(s.source){case"security_auth":return{description:"Verify auth and security assumptions before yielding",type:"contract",suggestedTool:"kb_search"};case"schema_contract":return{description:"Confirm schema and contract compatibility",type:"contract",suggestedTool:"kb_schema_validate"};case"blast_radius":return{description:"Inspect affected importers before delivery",type:"impact",suggestedTool:"kb_blast_radius"};case"cross_package":return{description:"Assess downstream package impact across boundaries",type:"impact",suggestedTool:"kb_blast_radius"};case"task_hint":return{description:"Check established conventions for migrations or compatibility work",type:"convention",suggestedTool:"kb_find_examples"};default:return{description:"No explicit unknown routing required",type:"freshness",suggestedTool:"kb_lookup"}}})}function B(t,s){let r=m(a(s,t));const e=a(s);for(;r.length>=e.length;){const n=a(r,"package.json");if(g(n))try{return JSON.parse(S(n,"utf-8")).name??p(e,r).replace(/\\/g,"/")}catch{return p(e,r).replace(/\\/g,"/")}const i=m(r);if(i===r)break;r=i}}export{W as forgeClassify};
2
+ `)}catch{return""}}async function M(t){if(!h(t))return!1;try{const s=await w({path:t}),r=new Set(s.exports);return s.interfaces.some(e=>r.has(e.name))||s.types.some(e=>r.has(e.name))}catch{return!1}}function H(t,s){const r=new Set(t.filter(n=>g(n)));if(r.size===0)return{affectedFiles:t.length,importers:[]};const e=new Set;for(const n of L(s)){if(r.has(n)||!h(n))continue;const i=b(n);if(!i)continue;z(i).some(d=>Y(d,n,r))&&e.add(n)}return{affectedFiles:t.length+e.size,importers:[...e].map(n=>p(s,n).replace(/\\/g,"/"))}}function L(t){const s=[];function r(e){let n=[];try{n=_(e)}catch{return}for(const i of n){if(A.has(i))continue;const o=a(e,i);let d;try{d=k(o)}catch{continue}if(d.isDirectory()){r(o);continue}v.has(C(i).toLowerCase())&&s.push(o)}}return r(t),s}function z(t){const s=new Set,r=/(?:from\s+['"]([^'"]+)['"]|import\s+['"]([^'"]+)['"]|require\(\s*['"]([^'"]+)['"]\s*\))/g;for(const e of t.matchAll(r)){const n=e[1]??e[2]??e[3];n&&s.add(n)}return[...s]}function Y(t,s,r){if(!t.startsWith("."))return!1;const e=a(m(s),t);return[e,`${e}.ts`,`${e}.tsx`,`${e}.js`,`${e}.jsx`,`${e}.mts`,`${e}.cts`,`${e}.mjs`,`${e}.cjs`,a(e,"index.ts"),a(e,"index.tsx"),a(e,"index.js"),a(e,"index.jsx")].some(i=>r.has(i))}function q(t){return t.map(s=>{switch(s.source){case"security_auth":return{description:"Verify auth and security assumptions before yielding",type:"contract",suggestedTool:"kb_search"};case"schema_contract":return{description:"Confirm schema and contract compatibility",type:"contract",suggestedTool:"kb_schema_validate"};case"blast_radius":return{description:"Inspect affected importers before delivery",type:"impact",suggestedTool:"kb_blast_radius"};case"cross_package":return{description:"Assess downstream package impact across boundaries",type:"impact",suggestedTool:"kb_blast_radius"};case"task_hint":return{description:"Check established conventions for migrations or compatibility work",type:"convention",suggestedTool:"kb_find"};default:return{description:"No explicit unknown routing required",type:"freshness",suggestedTool:"kb_lookup"}}})}function B(t,s){let r=m(a(s,t));const e=a(s);for(;r.length>=e.length;){const n=a(r,"package.json");if(g(n))try{return JSON.parse(S(n,"utf-8")).name??p(e,r).replace(/\\/g,"/")}catch{return p(e,r).replace(/\\/g,"/")}const i=m(r);if(i===r)break;r=i}}export{W as forgeClassify};
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Tool discovery — recommends MCP tools and workflows for a given goal.
3
+ *
4
+ * Uses keyword matching against predefined workflow templates.
5
+ * No embeddings required — pure string matching for instant results.
6
+ */
7
+ export interface GuideRecommendation {
8
+ tool: string;
9
+ reason: string;
10
+ order: number;
11
+ suggestedArgs?: Record<string, unknown>;
12
+ }
13
+ export interface GuideResult {
14
+ workflow: string;
15
+ description: string;
16
+ tools: GuideRecommendation[];
17
+ alternativeWorkflows: string[];
18
+ }
19
+ /**
20
+ * Match a goal description to the best workflow and return tool recommendations.
21
+ */
22
+ export declare function guide(goal: string, maxRecommendations?: number): GuideResult;
23
+ //# sourceMappingURL=guide.d.ts.map
@@ -0,0 +1 @@
1
+ const t=[{name:"onboard",description:"First-time codebase exploration and understanding",keywords:["onboard","new project","understand","explore","first time","getting started","learn","overview"],tools:[{tool:"status",reason:"Check index health and record count",order:1},{tool:"onboard",reason:"Run all analysis tools in one command",order:2,suggestedArgs:{path:"."}},{tool:"search",reason:"Find specific topics of interest",order:3},{tool:"graph",reason:"Explore module relationships",order:4,suggestedArgs:{action:"stats"}}]},{name:"audit",description:"Assess project health, quality, and structure",keywords:["audit","health","quality","assess","review project","check quality","code quality","tech debt"],tools:[{tool:"status",reason:"Check index freshness",order:1},{tool:"audit",reason:"Unified audit report with score and recommendations",order:2,suggestedArgs:{detail:"summary"}},{tool:"check",reason:"Typecheck + lint validation",order:3},{tool:"health",reason:"Detailed health checks on package.json, tsconfig, etc.",order:4}]},{name:"bugfix",description:"Diagnose and fix a bug or failing test",keywords:["bug","fix","debug","error","failing","broken","crash","wrong","issue","problem","not working"],tools:[{tool:"parse_output",reason:"Parse error output from build tools (tsc, vitest, biome)",order:1},{tool:"symbol",reason:"Find definition and all references of the failing symbol",order:2},{tool:"trace",reason:"Trace call chain backward from the failure point",order:3,suggestedArgs:{direction:"backward"}},{tool:"search",reason:"Search for related patterns or similar fixes",order:4},{tool:"test_run",reason:"Re-run tests after fix",order:5}]},{name:"implement",description:"Add a new feature or implement a change",keywords:["implement","add feature","new feature","build","create","add","develop","write code"],tools:[{tool:"scope_map",reason:"Generate a reading plan for affected files",order:1},{tool:"search",reason:"Find related patterns and prior art",order:2},{tool:"find",reason:"Find usage examples of similar patterns",order:3,suggestedArgs:{mode:"examples"}},{tool:"check",reason:"Validate after implementation",order:4},{tool:"test_run",reason:"Run tests to verify",order:5},{tool:"blast_radius",reason:"Check impact of changes",order:6}]},{name:"refactor",description:"Restructure or clean up existing code",keywords:["refactor","restructure","clean up","reorganize","rename","move","extract","DRY","dead code"],tools:[{tool:"dead_symbols",reason:"Find unused exports to remove",order:1},{tool:"symbol",reason:"Find all references before renaming",order:2},{tool:"blast_radius",reason:"Assess impact before making changes",order:3},{tool:"rename",reason:"Safe cross-file rename",order:4},{tool:"check",reason:"Validate after refactoring",order:5},{tool:"test_run",reason:"Ensure no regressions",order:6}]},{name:"search",description:"Find specific code, patterns, or information",keywords:["find","search","where","locate","look for","grep","which file","how does"],tools:[{tool:"search",reason:"Hybrid semantic + keyword search",order:1},{tool:"find",reason:"Federated search with glob and regex",order:2},{tool:"symbol",reason:"Resolve a specific symbol definition and references",order:3},{tool:"graph",reason:"Explore entity relationships",order:4,suggestedArgs:{action:"neighbors"}}]},{name:"context",description:"Compress or manage context for efficient LLM interaction",keywords:["context","compress","summarize","too long","token","budget","reduce","compact"],tools:[{tool:"file_summary",reason:"Quick structural overview without reading full file",order:1},{tool:"compact",reason:"Compress file to relevant sections",order:2,suggestedArgs:{segmentation:"paragraph"}},{tool:"digest",reason:"Compress multiple sources into budgeted summary",order:3},{tool:"stratum_card",reason:"Generate reusable context cards",order:4}]},{name:"memory",description:"Manage persistent knowledge across sessions",keywords:["memory","remember","persist","save","recall","decision","convention","session","checkpoint"],tools:[{tool:"list",reason:"See all stored knowledge entries",order:1},{tool:"search",reason:"Search curated knowledge",order:2,suggestedArgs:{origin:"curated"}},{tool:"remember",reason:"Store a new decision or pattern",order:3},{tool:"checkpoint",reason:"Save/restore session progress",order:4},{tool:"stash",reason:"Temporary key-value storage within session",order:5}]},{name:"validate",description:"Run checks, tests, and validation",keywords:["validate","check","test","lint","typecheck","verify","CI","pass","run tests"],tools:[{tool:"check",reason:"Typecheck + lint in one call",order:1,suggestedArgs:{detail:"errors"}},{tool:"test_run",reason:"Run tests with structured output",order:2},{tool:"health",reason:"Project health assessment",order:3}]},{name:"analyze",description:"Deep analysis of codebase structure, dependencies, or patterns",keywords:["analyze","dependency","structure","pattern","architecture","diagram","entry point","import"],tools:[{tool:"analyze_structure",reason:"Project structure overview",order:1},{tool:"analyze_dependencies",reason:"Dependency graph and analysis",order:2},{tool:"analyze_patterns",reason:"Detect code patterns and conventions",order:3},{tool:"analyze_entry_points",reason:"Find handlers, exports, and entry points",order:4},{tool:"analyze_diagram",reason:"Generate Mermaid diagrams",order:5}]}];function u(n,i=5){const d=n.toLowerCase(),s=t.map(e=>{let r=0;for(const a of e.keywords)d.includes(a)&&(r+=a.includes(" ")?2:1);return{workflow:e,score:r}}).filter(e=>e.score>0).sort((e,r)=>r.score-e.score),l=t.find(e=>e.name==="search")??t[0],o=s[0]?.workflow??l,c=s.slice(1,4).map(e=>e.workflow.name).filter(e=>e!==o.name);return{workflow:o.name,description:o.description,tools:o.tools.slice(0,i),alternativeWorkflows:c}}export{u as guide};