@vpxa/kb 0.1.20 → 0.1.22

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 (86) hide show
  1. package/package.json +1 -1
  2. package/packages/analyzers/dist/structure-analyzer.d.ts +5 -0
  3. package/packages/analyzers/dist/structure-analyzer.js +4 -2
  4. package/packages/analyzers/dist/types.d.ts +2 -0
  5. package/packages/cli/dist/commands/init/config.js +1 -1
  6. package/packages/cli/dist/commands/init/constants.d.ts +0 -1
  7. package/packages/cli/dist/commands/init/constants.js +1 -1
  8. package/packages/cli/dist/kb-init.js +1 -1
  9. package/packages/core/dist/constants.d.ts +2 -1
  10. package/packages/core/dist/constants.js +1 -1
  11. package/packages/core/dist/index.d.ts +2 -2
  12. package/packages/core/dist/index.js +1 -1
  13. package/packages/core/dist/logger.d.ts +12 -1
  14. package/packages/core/dist/logger.js +1 -1
  15. package/packages/server/dist/config.d.ts +9 -1
  16. package/packages/server/dist/config.js +1 -1
  17. package/packages/server/dist/curated-manager.d.ts +4 -0
  18. package/packages/server/dist/curated-manager.js +2 -2
  19. package/packages/server/dist/index.js +1 -1
  20. package/packages/server/dist/mcp-logging.d.ts +11 -0
  21. package/packages/server/dist/mcp-logging.js +1 -0
  22. package/packages/server/dist/output-schemas.d.ts +120 -0
  23. package/packages/server/dist/output-schemas.js +1 -0
  24. package/packages/server/dist/prompts.d.ts +6 -0
  25. package/packages/server/dist/prompts.js +6 -0
  26. package/packages/server/dist/resource-links.d.ts +34 -0
  27. package/packages/server/dist/resource-links.js +1 -0
  28. package/packages/server/dist/resources/curated-resources.d.ts +13 -0
  29. package/packages/server/dist/resources/curated-resources.js +2 -0
  30. package/packages/server/dist/resources/resources.d.ts +2 -1
  31. package/packages/server/dist/resources/resources.js +2 -2
  32. package/packages/server/dist/server.d.ts +3 -2
  33. package/packages/server/dist/server.js +1 -1
  34. package/packages/server/dist/tool-metadata.d.ts +38 -0
  35. package/packages/server/dist/tool-metadata.js +1 -0
  36. package/packages/server/dist/tools/analyze.tools.js +8 -2
  37. package/packages/server/dist/tools/audit.tool.js +1 -1
  38. package/packages/server/dist/tools/bridge.tools.js +7 -7
  39. package/packages/server/dist/tools/context.tools.d.ts +15 -0
  40. package/packages/server/dist/tools/context.tools.js +9 -0
  41. package/packages/server/dist/tools/evolution.tools.js +5 -5
  42. package/packages/server/dist/tools/execution.tools.d.ts +13 -0
  43. package/packages/server/dist/tools/execution.tools.js +3 -0
  44. package/packages/server/dist/tools/forge.tools.js +10 -10
  45. package/packages/server/dist/tools/forget.tool.js +1 -1
  46. package/packages/server/dist/tools/graph.tool.js +5 -4
  47. package/packages/server/dist/tools/infra.tools.d.ts +10 -0
  48. package/packages/server/dist/tools/infra.tools.js +3 -0
  49. package/packages/server/dist/tools/list.tool.js +2 -2
  50. package/packages/server/dist/tools/lookup.tool.js +2 -2
  51. package/packages/server/dist/tools/manipulation.tools.d.ts +10 -0
  52. package/packages/server/dist/tools/manipulation.tools.js +4 -0
  53. package/packages/server/dist/tools/onboard.tool.js +2 -2
  54. package/packages/server/dist/tools/persistence.tools.d.ts +10 -0
  55. package/packages/server/dist/tools/persistence.tools.js +5 -0
  56. package/packages/server/dist/tools/policy.tools.js +2 -2
  57. package/packages/server/dist/tools/produce.tool.js +2 -2
  58. package/packages/server/dist/tools/read.tool.js +2 -2
  59. package/packages/server/dist/tools/reindex.tool.js +2 -2
  60. package/packages/server/dist/tools/remember.tool.js +3 -3
  61. package/packages/server/dist/tools/replay.tool.js +2 -2
  62. package/packages/server/dist/tools/restore.tool.d.ts +6 -0
  63. package/packages/server/dist/tools/restore.tool.js +3 -0
  64. package/packages/server/dist/tools/search.tool.js +4 -4
  65. package/packages/server/dist/tools/status.tool.js +2 -2
  66. package/packages/server/dist/tools/toolkit.tools.js +18 -18
  67. package/packages/server/dist/tools/update.tool.js +1 -1
  68. package/packages/server/dist/tools/utility.tools.js +10 -10
  69. package/packages/store/dist/graph-store.interface.d.ts +13 -1
  70. package/packages/store/dist/index.d.ts +2 -2
  71. package/packages/store/dist/sqlite-graph-store.d.ts +2 -1
  72. package/packages/store/dist/sqlite-graph-store.js +13 -1
  73. package/packages/tools/dist/codemod.js +2 -2
  74. package/packages/tools/dist/graph-query.d.ts +3 -2
  75. package/packages/tools/dist/graph-query.js +1 -1
  76. package/packages/tools/dist/index.d.ts +2 -1
  77. package/packages/tools/dist/index.js +1 -1
  78. package/packages/tools/dist/rename.js +2 -2
  79. package/packages/tools/dist/restore-points.d.ts +22 -0
  80. package/packages/tools/dist/restore-points.js +1 -0
  81. package/packages/tui/dist/{App-CYLNJLr6.js → App-DE_tdOhs.js} +1 -1
  82. package/packages/tui/dist/App.js +1 -1
  83. package/packages/tui/dist/LogPanel-Ce3jMQbH.js +3 -0
  84. package/packages/tui/dist/index.js +1 -1
  85. package/packages/tui/dist/panels/LogPanel.js +1 -1
  86. package/packages/tui/dist/LogPanel-DtMnoyXT.js +0 -3
@@ -0,0 +1,4 @@
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{createLogger as n,serializeError as r}from"../../../core/dist/index.js";import{codemod as i,dataTransform as a,diffParse as o,gitContext as s,rename as c}from"../../../tools/dist/index.js";const l=n(`tools:manipulation`);function u(n){let i=e(`git_context`);n.registerTool(`git_context`,{title:i.title,description:`Summarize the current Git branch, working tree state, recent commits, and optional diff statistics for the repository.`,inputSchema:{cwd:t.string().optional().describe(`Repository root or working directory`),commit_count:t.number().min(1).max(50).default(5).optional().describe(`How many recent commits to include`),include_diff:t.boolean().default(!1).optional().describe(`Include diff stat for working tree changes`)},annotations:i.annotations},async({cwd:e,commit_count:t,include_diff:n})=>{try{return{content:[{type:`text`,text:h(await s({cwd:e,commitCount:t,includeDiff:n}))}]}}catch(e){return l.error(`Git context failed`,r(e)),{content:[{type:`text`,text:`Git context failed. Check server logs for details.`}],isError:!0}}})}function d(n){let i=e(`diff_parse`);n.registerTool(`diff_parse`,{title:i.title,description:`Parse raw unified diff text into file-level and hunk-level structural changes.`,inputSchema:{diff:t.string().max(1e6).describe(`Raw unified diff text`)},annotations:i.annotations},async({diff:e})=>{try{return{content:[{type:`text`,text:g(o({diff:e.replace(/\\n/g,`
2
+ `).replace(/\\t/g,` `)}))}]}}catch(e){return l.error(`Diff parse failed`,r(e)),{content:[{type:`text`,text:`Diff parse failed. Check server logs for details.`}],isError:!0}}})}function f(n){let i=e(`rename`);n.registerTool(`rename`,{title:i.title,description:`Rename a symbol across files using whole-word regex matching for exports, imports, and general usage references.`,inputSchema:{old_name:t.string().describe(`Existing symbol name to replace`),new_name:t.string().describe(`New symbol name to use`),root_path:t.string().describe(`Root directory to search within`),extensions:t.array(t.string()).optional().describe(`Optional file extensions to include, such as .ts,.tsx,.js,.jsx`),dry_run:t.boolean().default(!0).describe(`Preview changes without writing files`)},annotations:i.annotations},async({old_name:e,new_name:t,root_path:n,extensions:i,dry_run:a})=>{try{let r=await c({oldName:e,newName:t,rootPath:n,extensions:i,dryRun:a});return{content:[{type:`text`,text:JSON.stringify(r,null,2)}]}}catch(e){return l.error(`Rename failed`,r(e)),{content:[{type:`text`,text:`Rename failed. Check server logs for details.`}],isError:!0}}})}function p(n){let a=e(`codemod`);n.registerTool(`codemod`,{title:a.title,description:`Apply regex-based codemod rules across files and return structured before/after changes for each affected line.`,inputSchema:{root_path:t.string().describe(`Root directory to transform within`),rules:t.array(t.object({description:t.string().describe(`What the codemod rule does`),pattern:t.string().describe(`Regex pattern in string form`),replacement:t.string().describe(`Replacement string with optional capture groups`)})).min(1).describe(`Codemod rules to apply`),dry_run:t.boolean().default(!0).describe(`Preview changes without writing files`)},annotations:a.annotations},async({root_path:e,rules:t,dry_run:n})=>{try{let r=await i({rootPath:e,rules:t,dryRun:n});return{content:[{type:`text`,text:JSON.stringify(r,null,2)}]}}catch(e){return l.error(`Codemod failed`,r(e)),{content:[{type:`text`,text:`Codemod failed. Check server logs for details.`}],isError:!0}}})}function m(n){let i=e(`data_transform`);n.registerTool(`data_transform`,{title:i.title,description:`Apply small jq-like transforms to JSON input for filtering, projection, grouping, and path extraction.`,inputSchema:{input:t.string().max(5e5).describe(`Input JSON string`),expression:t.string().max(1e4).describe(`Transform expression to apply`)},annotations:i.annotations},async({input:e,expression:t})=>{try{return{content:[{type:`text`,text:a({input:e,expression:t}).outputString}]}}catch(e){return l.error(`Data transform failed`,r(e)),{content:[{type:`text`,text:`Data transform failed. Check server logs for details.`}],isError:!0}}})}function h(e){let t=[`Branch: ${e.branch}`,`Staged: ${e.status.staged.length}`,...e.status.staged.map(e=>` - ${e}`),`Modified: ${e.status.modified.length}`,...e.status.modified.map(e=>` - ${e}`),`Untracked: ${e.status.untracked.length}`,...e.status.untracked.map(e=>` - ${e}`),``,`Recent commits:`];if(e.recentCommits.length===0)t.push(` none`);else for(let n of e.recentCommits)t.push(` - ${n.hash} ${n.message}`),t.push(` ${n.author} @ ${n.date}`);return e.diff&&t.push(``,`Diff stat:`,e.diff),t.join(`
3
+ `)}function g(e){if(e.length===0)return`No diff files found.`;let t=[];for(let n of e){let e=n.oldPath?` (from ${n.oldPath})`:``;t.push(`${n.path}${e} [${n.status}] +${n.additions} -${n.deletions} (${n.hunks.length} hunks)`);for(let e of n.hunks){let n=e.header?` ${e.header}`:``;t.push(` @@ -${e.oldStart},${e.oldLines} +${e.newStart},${e.newLines} @@${n}`)}}return t.join(`
4
+ `)}export{p as registerCodemodTool,m as registerDataTransformTool,d as registerDiffParseTool,u as registerGitContextTool,f as registerRenameTool};
@@ -1,2 +1,2 @@
1
- import{createHash as e}from"node:crypto";import{createLogger as t,serializeError as n}from"../../../core/dist/index.js";import{onboard as r}from"../../../tools/dist/index.js";import{z as i}from"zod";const a=t(`tools`);async function o(t,r,i){for(let o of i.steps)if(!(o.status!==`success`||!o.output))try{let n=e(`sha256`).update(i.path).digest(`hex`).slice(0,12),a=`produced/onboard/${o.name}/${n}.md`,s=e(`sha256`).update(o.output).digest(`hex`).slice(0,16),c=new Date().toISOString(),l=o.output.length>2e3?o.output.split(/(?=^## )/m).filter(e=>e.trim().length>0):[o.output],u=l.map((t,n)=>({id:e(`sha256`).update(`${a}::${n}`).digest(`hex`).slice(0,16),content:t.trim(),sourcePath:a,contentType:`produced-knowledge`,chunkIndex:n,totalChunks:l.length,startLine:0,endLine:0,fileHash:s,indexedAt:c,origin:`produced`,tags:[`onboard`,o.name],category:`analysis`,version:1})),d=await r.embedBatch(u.map(e=>e.content));await t.upsert(u,d)}catch(e){a.warn(`Auto-persist onboard step failed`,{stepName:o.name,...n(e)})}}function s(e,t,s){e.registerTool(`onboard`,{description:`First-time codebase onboarding: runs all analysis tools (structure, dependencies, entry-points, symbols, patterns, diagram) in one command. Results are auto-persisted to KB. Use mode=generate to also write structured output to .ai/kb/ directory.`,inputSchema:{path:i.string().describe(`Root path of the codebase to onboard`),mode:i.enum([`memory`,`generate`]).default(`memory`).describe(`Output mode: memory = KB vector store only; generate = also write to .ai/kb/ directory`),out_dir:i.string().optional().describe(`Custom output directory for generate mode (default: <path>/.ai/kb)`)}},async({path:e,mode:i,out_dir:c})=>{try{a.info(`Starting onboard`,{path:e,mode:i});let n=await r({path:e,mode:i,outDir:c});o(t,s,n);let l=[`## Onboard Complete`,``,`**Path:** \`${n.path}\``,`**Mode:** ${n.mode}`,`**Duration:** ${n.totalDurationMs}ms`,``];n.outDir&&(l.push(`**Output directory:** \`${n.outDir}\``),l.push(``)),l.push(`### Analysis Results`,``);let u=[],d=[];for(let e of n.steps)e.status===`success`?u.push(`- ✓ **${e.name}** (${e.durationMs}ms) — ${e.output.length} chars`):d.push(`- ✗ **${e.name}** — ${e.error}`);l.push(...u),d.length>0&&l.push(``,`### Failed`,``,...d),l.push(``,`---`,``);for(let e of n.steps)e.status===`success`&&l.push(`### ${e.name}`,``,e.output,``,`---`,``);return l.push(`_All results auto-saved to KB.`,n.mode===`generate`?` Files written to \`${n.outDir}\`.`:``," Next: Use `search` to query the knowledge, or `remember` to add custom insights._"),{content:[{type:`text`,text:l.join(`
2
- `)}]}}catch(e){return a.error(`Onboard failed`,n(e)),{content:[{type:`text`,text:`Onboard failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{s as registerOnboardTool};
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{createHash as t}from"node:crypto";import{z as n}from"zod";import{createLogger as r,serializeError as i}from"../../../core/dist/index.js";import{onboard as a}from"../../../tools/dist/index.js";const o=r(`tools`);async function s(e,n,r){for(let a of r.steps)if(!(a.status!==`success`||!a.output))try{let i=t(`sha256`).update(r.path).digest(`hex`).slice(0,12),o=`produced/onboard/${a.name}/${i}.md`,s=t(`sha256`).update(a.output).digest(`hex`).slice(0,16),c=new Date().toISOString(),l=a.output.length>2e3?a.output.split(/(?=^## )/m).filter(e=>e.trim().length>0):[a.output],u=l.map((e,n)=>({id:t(`sha256`).update(`${o}::${n}`).digest(`hex`).slice(0,16),content:e.trim(),sourcePath:o,contentType:`produced-knowledge`,chunkIndex:n,totalChunks:l.length,startLine:0,endLine:0,fileHash:s,indexedAt:c,origin:`produced`,tags:[`onboard`,a.name],category:`analysis`,version:1})),d=await n.embedBatch(u.map(e=>e.content));await e.upsert(u,d)}catch(e){o.warn(`Auto-persist onboard step failed`,{stepName:a.name,...i(e)})}}function c(t,r,c){let l=e(`onboard`);t.registerTool(`onboard`,{title:l.title,description:`First-time codebase onboarding: runs all analysis tools (structure, dependencies, entry-points, symbols, patterns, diagram) in one command. Results are auto-persisted to KB. Use mode=generate to also write structured output to .ai/kb/ directory.`,inputSchema:{path:n.string().describe(`Root path of the codebase to onboard`),mode:n.enum([`memory`,`generate`]).default(`memory`).describe(`Output mode: memory = KB vector store only; generate = also write to .ai/kb/ directory`),out_dir:n.string().optional().describe(`Custom output directory for generate mode (default: <path>/.ai/kb)`)},annotations:l.annotations},async({path:e,mode:t,out_dir:n})=>{try{o.info(`Starting onboard`,{path:e,mode:t});let i=await a({path:e,mode:t,outDir:n});s(r,c,i);let l=[`## Onboard Complete`,``,`**Path:** \`${i.path}\``,`**Mode:** ${i.mode}`,`**Duration:** ${i.totalDurationMs}ms`,``];i.outDir&&(l.push(`**Output directory:** \`${i.outDir}\``),l.push(``)),l.push(`### Analysis Results`,``);let u=[],d=[];for(let e of i.steps)e.status===`success`?u.push(`- ✓ **${e.name}** (${e.durationMs}ms) — ${e.output.length} chars`):d.push(`- ✗ **${e.name}** — ${e.error}`);l.push(...u),d.length>0&&l.push(``,`### Failed`,``,...d),l.push(``,`---`,``);for(let e of i.steps)e.status===`success`&&l.push(`### ${e.name}`,``,e.output,``,`---`,``);return l.push(`_All results auto-saved to KB.`,i.mode===`generate`?` Files written to \`${i.outDir}\`.`:``," Next: Use `search` to query the knowledge, or `remember` to add custom insights._"),{content:[{type:`text`,text:l.join(`
2
+ `)}]}}catch(e){return o.error(`Onboard failed`,i(e)),{content:[{type:`text`,text:`Onboard failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{c as registerOnboardTool};
@@ -0,0 +1,10 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+
3
+ //#region packages/server/src/tools/persistence.tools.d.ts
4
+ declare function registerWorksetTool(server: McpServer): void;
5
+ declare function registerStashTool(server: McpServer): void;
6
+ declare function registerCheckpointTool(server: McpServer): void;
7
+ declare function registerLaneTool(server: McpServer): void;
8
+ declare function registerQueueTool(server: McpServer): void;
9
+ //#endregion
10
+ export { registerCheckpointTool, registerLaneTool, registerQueueTool, registerStashTool, registerWorksetTool };
@@ -0,0 +1,5 @@
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{createLogger as n,serializeError as r}from"../../../core/dist/index.js";import{addToWorkset as i,checkpointLatest as a,checkpointList as o,checkpointLoad as s,checkpointSave as c,deleteWorkset as l,getWorkset as u,laneCreate as d,laneDiff as f,laneDiscard as p,laneList as m,laneMerge as h,laneStatus as g,listWorksets as _,queueClear as v,queueCreate as y,queueDelete as b,queueDone as x,queueFail as S,queueGet as C,queueList as w,queueNext as T,queuePush as E,removeFromWorkset as D,saveWorkset as O,stashClear as k,stashDelete as A,stashGet as j,stashList as M,stashSet as N}from"../../../tools/dist/index.js";const P=n(`tools:persistence`);function F(n){let a=e(`workset`);n.registerTool(`workset`,{title:a.title,description:`Manage named file sets (worksets). Save, load, list, add/remove files. Worksets persist across sessions in .kb-state/worksets.json.`,inputSchema:{action:t.enum([`save`,`get`,`list`,`delete`,`add`,`remove`]).describe(`Operation to perform`),name:t.string().optional().describe(`Workset name (required for all except list)`),files:t.array(t.string()).optional().describe(`File paths (required for save, add, remove)`),description:t.string().optional().describe(`Description (for save)`)},annotations:a.annotations},async({action:e,name:t,files:n,description:a})=>{try{switch(e){case`save`:{if(!t||!n)throw Error(`name and files required for save`);let e=O(t,n,{description:a});return{content:[{type:`text`,text:`Saved workset "${e.name}" with ${e.files.length} files.`}]}}case`get`:{if(!t)throw Error(`name required for get`);let e=u(t);return e?{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}:{content:[{type:`text`,text:`Workset "${t}" not found.`}]}}case`list`:{let e=_();return e.length===0?{content:[{type:`text`,text:`No worksets.`}]}:{content:[{type:`text`,text:e.map(e=>`- **${e.name}** (${e.files.length} files) — ${e.description??`no description`}`).join(`
2
+ `)}]}}case`delete`:if(!t)throw Error(`name required for delete`);return{content:[{type:`text`,text:l(t)?`Deleted workset "${t}".`:`Workset "${t}" not found.`}]};case`add`:{if(!t||!n)throw Error(`name and files required for add`);let e=i(t,n);return{content:[{type:`text`,text:`Added to workset "${e.name}": now ${e.files.length} files.`}]}}case`remove`:{if(!t||!n)throw Error(`name and files required for remove`);let e=D(t,n);return e?{content:[{type:`text`,text:`Removed from workset "${e.name}": now ${e.files.length} files.`}]}:{content:[{type:`text`,text:`Workset "${t}" not found.`}]}}}}catch(e){return P.error(`Workset operation failed`,r(e)),{content:[{type:`text`,text:`Workset operation failed. Check server logs for details.`}],isError:!0}}})}function I(n){let i=e(`stash`);n.registerTool(`stash`,{title:i.title,description:`Persist and retrieve named values in .kb-state/stash.json for intermediate results between tool calls.`,inputSchema:{action:t.enum([`set`,`get`,`list`,`delete`,`clear`]).describe(`Operation to perform on the stash`),key:t.string().optional().describe(`Entry key for set/get/delete operations`),value:t.string().optional().describe(`String or JSON value for set operations`)},annotations:i.annotations},async({action:e,key:t,value:n})=>{try{switch(e){case`set`:{if(!t)throw Error(`key required for set`);let e=N(t,V(n??``));return{content:[{type:`text`,text:`Stored stash entry "${e.key}" (${e.type}) at ${e.storedAt}.`}]}}case`get`:{if(!t)throw Error(`key required for get`);let e=j(t);return{content:[{type:`text`,text:e?JSON.stringify(e,null,2):`Stash entry "${t}" not found.`}]}}case`list`:{let e=M();return{content:[{type:`text`,text:e.length===0?`Stash is empty.`:e.map(e=>`- ${e.key} (${e.type}) — ${e.storedAt}`).join(`
3
+ `)}]}}case`delete`:if(!t)throw Error(`key required for delete`);return{content:[{type:`text`,text:A(t)?`Deleted stash entry "${t}".`:`Stash entry "${t}" not found.`}]};case`clear`:{let e=k();return{content:[{type:`text`,text:`Cleared ${e} stash entr${e===1?`y`:`ies`}.`}]}}}}catch(e){return P.error(`Stash operation failed`,r(e)),{content:[{type:`text`,text:`Stash operation failed. Check server logs for details.`}],isError:!0}}})}function L(n){let i=e(`checkpoint`);n.registerTool(`checkpoint`,{title:i.title,description:`Save and restore lightweight session checkpoints in .kb-state/checkpoints for cross-session continuity.`,inputSchema:{action:t.enum([`save`,`load`,`list`,`latest`]).describe(`Checkpoint action to perform`),label:t.string().optional().describe(`Checkpoint label for save, or checkpoint id for load`),data:t.string().max(5e5).optional().describe(`JSON object string for save actions`),notes:t.string().max(1e4).optional().describe(`Optional notes for save actions`)},annotations:i.annotations},async({action:e,label:t,data:n,notes:i})=>{try{switch(e){case`save`:if(!t)throw Error(`label required for save`);return{content:[{type:`text`,text:B(c(t,H(n),{notes:i}))}]};case`load`:{if(!t)throw Error(`label required for load`);let e=s(t);return{content:[{type:`text`,text:e?B(e):`Checkpoint "${t}" not found.`}]}}case`list`:{let e=o();return{content:[{type:`text`,text:e.length===0?`No checkpoints saved.`:e.map(e=>`- ${e.id} — ${e.label} (${e.createdAt})`).join(`
4
+ `)}]}}case`latest`:{let e=a();return{content:[{type:`text`,text:e?B(e):`No checkpoints saved.`}]}}}}catch(e){return P.error(`Checkpoint failed`,r(e)),{content:[{type:`text`,text:`Checkpoint failed. Check server logs for details.`}],isError:!0}}})}function R(n){let i=e(`lane`);n.registerTool(`lane`,{title:i.title,description:`Manage verified lanes — isolated file copies for parallel exploration. Create a lane, make changes, diff, merge back, or discard.`,inputSchema:{action:t.enum([`create`,`list`,`status`,`diff`,`merge`,`discard`]).describe(`Lane action to perform`),name:t.string().optional().describe(`Lane name (required for create/status/diff/merge/discard)`),files:t.array(t.string()).optional().describe(`File paths to copy into the lane (required for create)`)},annotations:i.annotations},async({action:e,name:t,files:n})=>{try{switch(e){case`create`:{if(!t)throw Error(`name is required for create`);if(!n||n.length===0)throw Error(`files are required for create`);let e=d(t,n);return{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}}case`list`:return{content:[{type:`text`,text:JSON.stringify(m(),null,2)}]};case`status`:if(!t)throw Error(`name is required for status`);return{content:[{type:`text`,text:JSON.stringify(g(t),null,2)}]};case`diff`:if(!t)throw Error(`name is required for diff`);return{content:[{type:`text`,text:JSON.stringify(f(t),null,2)}]};case`merge`:if(!t)throw Error(`name is required for merge`);return{content:[{type:`text`,text:JSON.stringify(h(t),null,2)}]};case`discard`:if(!t)throw Error(`name is required for discard`);return{content:[{type:`text`,text:JSON.stringify({discarded:p(t)},null,2)}]}}}catch(e){return P.error(`Lane action failed`,r(e)),{content:[{type:`text`,text:`Lane action failed. Check server logs for details.`}],isError:!0}}})}function z(n){let i=e(`queue`);n.registerTool(`queue`,{title:i.title,description:`Manage task queues for sequential agent operations. Push items, take next, mark done/failed, list queues.`,inputSchema:{action:t.enum([`create`,`push`,`next`,`done`,`fail`,`get`,`list`,`clear`,`delete`]).describe(`Queue action`),name:t.string().optional().describe(`Queue name (required for most actions)`),title:t.string().optional().describe(`Item title (required for push)`),id:t.string().optional().describe(`Item ID (required for done/fail)`),data:t.unknown().optional().describe(`Arbitrary data to attach to a queue item`),error:t.string().optional().describe(`Error message (required for fail)`)},annotations:i.annotations},async({action:e,name:t,title:n,id:i,data:a,error:o})=>{try{switch(e){case`create`:if(!t)throw Error(`name is required for create`);return{content:[{type:`text`,text:JSON.stringify(y(t),null,2)}]};case`push`:if(!t)throw Error(`name is required for push`);if(!n)throw Error(`title is required for push`);return{content:[{type:`text`,text:JSON.stringify(E(t,n,a),null,2)}]};case`next`:{if(!t)throw Error(`name is required for next`);let e=T(t);return{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}}case`done`:if(!t)throw Error(`name is required for done`);if(!i)throw Error(`id is required for done`);return{content:[{type:`text`,text:JSON.stringify(x(t,i),null,2)}]};case`fail`:if(!t)throw Error(`name is required for fail`);if(!i)throw Error(`id is required for fail`);if(!o)throw Error(`error is required for fail`);return{content:[{type:`text`,text:JSON.stringify(S(t,i,o),null,2)}]};case`get`:if(!t)throw Error(`name is required for get`);return{content:[{type:`text`,text:JSON.stringify(C(t),null,2)}]};case`list`:return{content:[{type:`text`,text:JSON.stringify(w(),null,2)}]};case`clear`:if(!t)throw Error(`name is required for clear`);return{content:[{type:`text`,text:JSON.stringify({cleared:v(t)},null,2)}]};case`delete`:if(!t)throw Error(`name is required for delete`);return{content:[{type:`text`,text:JSON.stringify({deleted:b(t)},null,2)}]}}}catch(e){return P.error(`Queue action failed`,r(e)),{content:[{type:`text`,text:`Queue action failed. Check server logs for details.`}],isError:!0}}})}function B(e){let t=[e.id,`Label: ${e.label}`,`Created: ${e.createdAt}`];if(e.notes&&t.push(`Notes: ${e.notes}`),e.files?.length){t.push(`Files: ${e.files.length}`);for(let n of e.files)t.push(` - ${n}`)}return t.push(``,`Data:`,JSON.stringify(e.data,null,2)),t.join(`
5
+ `)}function V(e){let t=e.trim();if(!t)return``;try{return JSON.parse(t)}catch{return e}}function H(e){let t=e?.trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch{throw Error(`data must be a valid JSON object string`)}if(!n||typeof n!=`object`||Array.isArray(n))throw Error(`data must be a JSON object string`);return n}export{L as registerCheckpointTool,R as registerLaneTool,z as registerQueueTool,I as registerStashTool,F as registerWorksetTool};
@@ -1,2 +1,2 @@
1
- import{createLogger as e,serializeError as t}from"../../../core/dist/index.js";import{z as n}from"zod";const r=e(`tools`);function i(e,i){e.registerTool(`er_update_policy`,{description:`Manage ER push classification rules. Supports listing, updating, creating, and deleting rules that determine when knowledge should be pushed to Enterprise RAG.`,inputSchema:{action:n.enum([`list`,`get`,`update`,`create`,`delete`]).describe(`Action to perform on classification rules`),rule_id:n.string().optional().describe(`Rule ID (required for get, update, delete)`),changes:n.object({patterns:n.array(n.string()).optional(),category:n.string().optional(),pushWeight:n.number().min(0).max(1).optional(),description:n.string().optional(),examples:n.array(n.string()).optional(),enabled:n.boolean().optional()}).optional().describe(`Changes to apply (for update action)`),new_rule:n.object({id:n.string().regex(/^[a-z][a-z0-9-]*$/),patterns:n.array(n.string()).min(1),category:n.string(),pushWeight:n.number().min(0).max(1),description:n.string(),examples:n.array(n.string()).default([]),enabled:n.boolean().default(!0)}).optional().describe(`New rule definition (for create action)`)}},async({action:e,rule_id:n,changes:a,new_rule:o})=>{try{if(e===`list`){let e=i.getRules();return{content:[{type:`text`,text:`## Classification Rules\n\n${e.map(e=>`- **${e.id}** (${e.enabled?`enabled`:`disabled`}) — ${e.description}\n Category: ${e.category} | Weight: ${e.pushWeight} | Patterns: ${e.patterns.join(`, `)}`).join(`
2
- `)}\n\n---\n_${e.length} rules total. Use \`action: "update"\` to modify a rule._`}]}}if(e===`get`){if(!n)return{content:[{type:`text`,text:'`rule_id` is required for "get" action.'}],isError:!0};let e=i.getRule(n);return e?{content:[{type:`text`,text:`## Rule: ${e.id}\n\n${JSON.stringify(e,null,2)}`}]}:{content:[{type:`text`,text:`Rule "${n}" not found.`}],isError:!0}}if(e===`update`){if(!n||!a)return{content:[{type:`text`,text:'`rule_id` and `changes` are required for "update" action.'}],isError:!0};let e=i.updateRule(n,a);return e?{content:[{type:`text`,text:`Updated rule **${n}**.\n\n${JSON.stringify(e,null,2)}\n\n---\n_Next: Use \`action: "list"\` to verify all rules._`}]}:{content:[{type:`text`,text:`Rule "${n}" not found.`}],isError:!0}}if(e===`create`){if(!o)return{content:[{type:`text`,text:'`new_rule` is required for "create" action.'}],isError:!0};let e=i.addRule(o);return{content:[{type:`text`,text:`Created rule **${e.id}**.\n\n${JSON.stringify(e,null,2)}\n\n---\n_Next: Test classification with \`remember\` and check signals._`}]}}return e===`delete`?n?i.deleteRule(n)?{content:[{type:`text`,text:`Deleted rule **${n}**.\n\n---\n_Next: Use \`action: "list"\` to verify._`}]}:{content:[{type:`text`,text:`Rule "${n}" not found.`}],isError:!0}:{content:[{type:`text`,text:'`rule_id` is required for "delete" action.'}],isError:!0}:{content:[{type:`text`,text:`Unknown action: ${e}`}],isError:!0}}catch(e){return r.error(`Policy update failed`,t(e)),{content:[{type:`text`,text:`Policy update failed. Check server logs for details.`}],isError:!0}}})}export{i as registerErUpdatePolicyTool};
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{createLogger as n,serializeError as r}from"../../../core/dist/index.js";const i=n(`tools`);function a(n,a){let o=e(`er_update_policy`);n.registerTool(`er_update_policy`,{title:o.title,description:`Manage ER push classification rules. Supports listing, updating, creating, and deleting rules that determine when knowledge should be pushed to Enterprise RAG.`,inputSchema:{action:t.enum([`list`,`get`,`update`,`create`,`delete`]).describe(`Action to perform on classification rules`),rule_id:t.string().optional().describe(`Rule ID (required for get, update, delete)`),changes:t.object({patterns:t.array(t.string()).optional(),category:t.string().optional(),pushWeight:t.number().min(0).max(1).optional(),description:t.string().optional(),examples:t.array(t.string()).optional(),enabled:t.boolean().optional()}).optional().describe(`Changes to apply (for update action)`),new_rule:t.object({id:t.string().regex(/^[a-z][a-z0-9-]*$/),patterns:t.array(t.string()).min(1),category:t.string(),pushWeight:t.number().min(0).max(1),description:t.string(),examples:t.array(t.string()).default([]),enabled:t.boolean().default(!0)}).optional().describe(`New rule definition (for create action)`)},annotations:o.annotations},async({action:e,rule_id:t,changes:n,new_rule:o})=>{try{if(e===`list`){let e=a.getRules();return{content:[{type:`text`,text:`## Classification Rules\n\n${e.map(e=>`- **${e.id}** (${e.enabled?`enabled`:`disabled`}) — ${e.description}\n Category: ${e.category} | Weight: ${e.pushWeight} | Patterns: ${e.patterns.join(`, `)}`).join(`
2
+ `)}\n\n---\n_${e.length} rules total. Use \`action: "update"\` to modify a rule._`}]}}if(e===`get`){if(!t)return{content:[{type:`text`,text:'`rule_id` is required for "get" action.'}],isError:!0};let e=a.getRule(t);return e?{content:[{type:`text`,text:`## Rule: ${e.id}\n\n${JSON.stringify(e,null,2)}`}]}:{content:[{type:`text`,text:`Rule "${t}" not found.`}],isError:!0}}if(e===`update`){if(!t||!n)return{content:[{type:`text`,text:'`rule_id` and `changes` are required for "update" action.'}],isError:!0};let e=a.updateRule(t,n);return e?{content:[{type:`text`,text:`Updated rule **${t}**.\n\n${JSON.stringify(e,null,2)}\n\n---\n_Next: Use \`action: "list"\` to verify all rules._`}]}:{content:[{type:`text`,text:`Rule "${t}" not found.`}],isError:!0}}if(e===`create`){if(!o)return{content:[{type:`text`,text:'`new_rule` is required for "create" action.'}],isError:!0};let e=a.addRule(o);return{content:[{type:`text`,text:`Created rule **${e.id}**.\n\n${JSON.stringify(e,null,2)}\n\n---\n_Next: Test classification with \`remember\` and check signals._`}]}}return e===`delete`?t?a.deleteRule(t)?{content:[{type:`text`,text:`Deleted rule **${t}**.\n\n---\n_Next: Use \`action: "list"\` to verify._`}]}:{content:[{type:`text`,text:`Rule "${t}" not found.`}],isError:!0}:{content:[{type:`text`,text:'`rule_id` is required for "delete" action.'}],isError:!0}:{content:[{type:`text`,text:`Unknown action: ${e}`}],isError:!0}}catch(e){return i.error(`Policy update failed`,r(e)),{content:[{type:`text`,text:`Policy update failed. Check server logs for details.`}],isError:!0}}})}export{a as registerErUpdatePolicyTool};
@@ -1,4 +1,4 @@
1
- import{DependencyAnalyzer as e,DiagramGenerator as t,EntryPointAnalyzer as n,KnowledgeProducer as r,PatternAnalyzer as i,StructureAnalyzer as a,SymbolAnalyzer as o}from"../../../analyzers/dist/index.js";import{createLogger as s,serializeError as c}from"../../../core/dist/index.js";import{z as l}from"zod";const u=s(`tools`);function d(s){let d=new r({structure:new a,dependencies:new e,symbols:new o,patterns:new i,entryPoints:new n,diagrams:new t});s.registerTool(`produce_knowledge`,{description:`Run automated codebase analysis and produce synthesis instructions. Executes Tier 1 deterministic analyzers, then returns structured baselines and instructions for you to synthesize knowledge using remember.`,inputSchema:{scope:l.string().optional().describe(`Root path to analyze (defaults to workspace root)`),aspects:l.array(l.enum([`all`,`structure`,`dependencies`,`symbols`,`patterns`,`entry-points`,`diagrams`])).default([`all`]).describe(`Which analysis aspects to run`)}},async({scope:e,aspects:t})=>{try{let n=e??`.`;u.info(`Running knowledge production`,{rootPath:n,aspects:t});let r=await d.runExtraction(n,t);return{content:[{type:`text`,text:d.buildSynthesisInstructions(r,t)+`
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{DependencyAnalyzer as n,DiagramGenerator as r,EntryPointAnalyzer as i,KnowledgeProducer as a,PatternAnalyzer as o,StructureAnalyzer as s,SymbolAnalyzer as c}from"../../../analyzers/dist/index.js";import{createLogger as l,serializeError as u}from"../../../core/dist/index.js";const d=l(`tools`);function f(l){let f=new a({structure:new s,dependencies:new n,symbols:new c,patterns:new o,entryPoints:new i,diagrams:new r}),p=e(`produce_knowledge`);l.registerTool(`produce_knowledge`,{title:p.title,description:`Run automated codebase analysis and produce synthesis instructions. Executes Tier 1 deterministic analyzers, then returns structured baselines and instructions for you to synthesize knowledge using remember.`,inputSchema:{scope:t.string().optional().describe(`Root path to analyze (defaults to workspace root)`),aspects:t.array(t.enum([`all`,`structure`,`dependencies`,`symbols`,`patterns`,`entry-points`,`diagrams`])).default([`all`]).describe(`Which analysis aspects to run`)},annotations:p.annotations},async({scope:e,aspects:t})=>{try{let n=e??`.`;d.info(`Running knowledge production`,{rootPath:n,aspects:t});let r=await f.runExtraction(n,t);return{content:[{type:`text`,text:f.buildSynthesisInstructions(r,t)+`
2
2
 
3
3
  ---
4
- _Next: Review the baselines above and use \`remember\` to store synthesized knowledge entries._`}]}}catch(e){return u.error(`Knowledge production failed`,c(e)),{content:[{type:`text`,text:`Knowledge production failed. Check server logs for details.`}],isError:!0}}})}export{d as registerProduceKnowledgeTool};
4
+ _Next: Review the baselines above and use \`remember\` to store synthesized knowledge entries._`}]}}catch(e){return d.error(`Knowledge production failed`,u(e)),{content:[{type:`text`,text:`Knowledge production failed. Check server logs for details.`}],isError:!0}}})}export{f as registerProduceKnowledgeTool};
@@ -1,2 +1,2 @@
1
- import{createLogger as e,serializeError as t}from"../../../core/dist/index.js";import{z as n}from"zod";const r=e(`tools`);function i(e,i){e.registerTool(`read`,{description:`Read the full content of a specific curated knowledge entry by its path. Use list first to discover available entries.`,inputSchema:{path:n.string().describe(`Relative path within .ai/curated/ (e.g., "decisions/use-lancedb.md")`)}},async({path:e})=>{try{let t=await i.read(e);return{content:[{type:`text`,text:`${[`## ${t.title}`,`- **Path**: .ai/curated/${e}`,`- **Category**: ${t.category}`,t.tags.length?`- **Tags**: ${t.tags.join(`, `)}`:null,`- **Version**: ${t.version}`,`- **Created**: ${t.created}`,t.updated===t.created?null:`- **Updated**: ${t.updated}`,``].filter(e=>e!==null).join(`
2
- `)}\n${t.content}\n\n---\n_Next: Use \`update\` to modify this entry, or \`search\` to find related entries._`}]}}catch(e){return r.error(`Read failed`,t(e)),{content:[{type:`text`,text:`Read failed. Check server logs for details.`}],isError:!0}}})}export{i as registerReadTool};
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{curatedResourceLink as t}from"../resource-links.js";import{z as n}from"zod";import{createLogger as r,serializeError as i}from"../../../core/dist/index.js";const a=r(`tools`);function o(r,o){let s=e(`read`);r.registerTool(`read`,{title:s.title,description:`Read the full content of a specific curated knowledge entry by its path. Use list first to discover available entries.`,inputSchema:{path:n.string().describe(`Relative path within .ai/curated/ (e.g., "decisions/use-lancedb.md")`)},annotations:s.annotations},async({path:e})=>{try{let n=await o.read(e),r=[`## ${n.title}`,`- **Path**: .ai/curated/${e}`,`- **Category**: ${n.category}`,n.tags.length?`- **Tags**: ${n.tags.join(`, `)}`:null,`- **Version**: ${n.version}`,`- **Created**: ${n.created}`,n.updated===n.created?null:`- **Updated**: ${n.updated}`,``].filter(e=>e!==null).join(`
2
+ `),i=t(e,n.title,`[${n.category}]`);return{content:[{type:`text`,text:`${r}\n${n.content}\n\n---\n_Next: Use \`update\` to modify this entry, or \`search\` to find related entries._`},...i?[i]:[]]}}catch(e){return a.error(`Read failed`,i(e)),{content:[{type:`text`,text:`Read failed. Check server logs for details.`}],isError:!0}}})}export{o as registerReadTool};
@@ -1,3 +1,3 @@
1
- import{createLogger as e,serializeError as t}from"../../../core/dist/index.js";import{z as n}from"zod";const r=e(`tools`);function i(e,i,a,o,s){e.registerTool(`reindex`,{description:`Trigger re-indexing of the knowledge base. Can do incremental (only changed files) or full re-index.`,inputSchema:{full:n.boolean().default(!1).describe(`If true, force full re-index ignoring file hashes`)}},async({full:e})=>{try{if(i.isIndexing)return{content:[{type:`text`,text:`## Reindex Already in Progress
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{createLogger as n,serializeError as r}from"../../../core/dist/index.js";const i=n(`tools`);function a(n,a,o,s,c){let l=e(`reindex`);n.registerTool(`reindex`,{title:l.title,description:`Trigger re-indexing of the knowledge base. Can do incremental (only changed files) or full re-index.`,inputSchema:{full:t.boolean().default(!1).describe(`If true, force full re-index ignoring file hashes`)},annotations:l.annotations},async({full:e})=>{try{if(a.isIndexing)return{content:[{type:`text`,text:`## Reindex Already in Progress
2
2
 
3
- A reindex operation is currently running. Search and other tools continue to work with existing data. Use \`status({})\` to check when it completes.`}]};r.info(`Starting background re-index`,{mode:e?`full`:`incremental`});let n=e=>t=>{t.phase===`chunking`&&t.currentFile&&r.debug(`Re-index progress`,{prefix:e,current:t.filesProcessed+1,total:t.filesTotal,file:t.currentFile})};return(e?i.reindexAll(a,n(`Reindex`)):i.index(a,n(`Index`))).then(async e=>{if(r.info(`Background re-index complete`,{filesProcessed:e.filesProcessed,chunksCreated:e.chunksCreated,durationMs:e.durationMs}),s)try{await s.createFtsIndex(),r.info(`FTS index rebuilt after reindex`)}catch(e){r.warn(`FTS index rebuild failed`,t(e))}try{let e=await o.reindexAll();r.info(`Curated re-index complete`,{indexed:e.indexed})}catch(e){r.warn(`Curated re-index failed`,t(e))}}).catch(e=>{r.error(`Background reindex failed`,t(e))}),{content:[{type:`text`,text:`## Reindex Started (Background)\n\n- **Mode**: ${e?`Full`:`Incremental`}\n- Search and other tools continue to work with existing data during reindex.\n- Completion will be logged. Use \`status({})\` to check index stats afterward.\n\n---\n_Next: Continue working — the reindex runs in the background._`}]}}catch(e){return r.error(`Reindex failed`,t(e)),{content:[{type:`text`,text:`Reindex failed. Check server logs for details.`}],isError:!0}}})}export{i as registerReindexTool};
3
+ A reindex operation is currently running. Search and other tools continue to work with existing data. Use \`status({})\` to check when it completes.`}]};i.info(`Starting background re-index`,{mode:e?`full`:`incremental`});let t=e=>t=>{t.phase===`chunking`&&t.currentFile&&i.debug(`Re-index progress`,{prefix:e,current:t.filesProcessed+1,total:t.filesTotal,file:t.currentFile})};return(e?a.reindexAll(o,t(`Reindex`)):a.index(o,t(`Index`))).then(async e=>{if(i.info(`Background re-index complete`,{filesProcessed:e.filesProcessed,chunksCreated:e.chunksCreated,durationMs:e.durationMs}),c)try{await c.createFtsIndex(),i.info(`FTS index rebuilt after reindex`)}catch(e){i.warn(`FTS index rebuild failed`,r(e))}try{let e=await s.reindexAll();i.info(`Curated re-index complete`,{indexed:e.indexed})}catch(e){i.warn(`Curated re-index failed`,r(e))}}).catch(e=>{i.error(`Background reindex failed`,r(e))}),{content:[{type:`text`,text:`## Reindex Started (Background)\n\n- **Mode**: ${e?`Full`:`Incremental`}\n- Search and other tools continue to work with existing data during reindex.\n- Completion will be logged. Use \`status({})\` to check index stats afterward.\n\n---\n_Next: Continue working — the reindex runs in the background._`}]}}catch(e){return i.error(`Reindex failed`,r(e)),{content:[{type:`text`,text:`Reindex failed. Check server logs for details.`}],isError:!0}}})}export{a as registerReindexTool};
@@ -1,4 +1,4 @@
1
- import{createLogger as e,serializeError as t}from"../../../core/dist/index.js";import{z as n}from"zod";const r=e(`tools`);function i(e,i,a,o){e.registerTool(`remember`,{description:`Store a new piece of curated knowledge. Use this to persist decisions, patterns, conventions, or any insight worth remembering across sessions.`,inputSchema:{title:n.string().min(3).max(120).describe(`Short descriptive title for the knowledge entry`),content:n.string().min(10).max(1e5).describe(`The markdown content to store`),category:n.string().regex(/^[a-z][a-z0-9-]*$/).describe(`Category slug (e.g., "decisions", "patterns", "conventions", "api-contracts")`),tags:n.array(n.string()).default([]).describe(`Optional tags for filtering`)}},async({title:e,content:n,category:s,tags:c})=>{try{let t=await i.remember(e,n,s,c),r=``;if(a){let t=a.classify(e,n,c);o&&o.recordClassification(e,t.matchingRules.map(e=>e.ruleId),t.pushRecommended),t.matchingRules.length>0&&(r=`\n\n### Classification Signals\n${t.matchingRules.map(e=>` - **${e.ruleId}** (${e.category}, weight: ${e.pushWeight}) — matched: ${e.matchedPatterns.join(`, `)}`).join(`
2
- `)}\n- **Push recommended**: ${t.pushRecommended?`yes`:`no`} (max weight: ${t.maxPushWeight})`,t.pushRecommended&&(r+=`
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{curatedResourceLink as t}from"../resource-links.js";import{z as n}from"zod";import{createLogger as r,serializeError as i}from"../../../core/dist/index.js";const a=r(`tools`);function o(r,o,s,c){let l=e(`remember`);r.registerTool(`remember`,{title:l.title,description:`Store a new piece of curated knowledge. Use this to persist decisions, patterns, conventions, or any insight worth remembering across sessions.`,inputSchema:{title:n.string().min(3).max(120).describe(`Short descriptive title for the knowledge entry`),content:n.string().min(10).max(1e5).describe(`The markdown content to store`),category:n.string().regex(/^[a-z][a-z0-9-]*$/).describe(`Category slug (e.g., "decisions", "patterns", "conventions", "api-contracts")`),tags:n.array(n.string()).default([]).describe(`Optional tags for filtering`)},annotations:l.annotations},async({title:e,content:n,category:l,tags:u})=>{try{let i=await o.remember(e,n,l,u),a=``;if(s){let t=s.classify(e,n,u);c&&c.recordClassification(e,t.matchingRules.map(e=>e.ruleId),t.pushRecommended),t.matchingRules.length>0&&(a=`\n\n### Classification Signals\n${t.matchingRules.map(e=>` - **${e.ruleId}** (${e.category}, weight: ${e.pushWeight}) — matched: ${e.matchedPatterns.join(`, `)}`).join(`
2
+ `)}\n- **Push recommended**: ${t.pushRecommended?`yes`:`no`} (max weight: ${t.maxPushWeight})`,t.pushRecommended&&(a+=`
3
3
 
4
- > 💡 This entry matches push rules. Consider \`er_push\` to share with Enterprise RAG.`))}return{content:[{type:`text`,text:`Remembered: **${e}**\n\nStored at \`.ai/curated/${t.path}\` and indexed for semantic search.${r}\n\n---\n_Next: Use \`search\` to verify the entry is findable, or \`list\` to see all curated entries._`}]}}catch(e){return r.error(`Remember failed`,t(e)),{content:[{type:`text`,text:`Remember failed. Check server logs for details.`}],isError:!0}}})}export{i as registerRememberTool};
4
+ > 💡 This entry matches push rules. Consider \`er_push\` to share with Enterprise RAG.`))}r.sendResourceListChanged();let d=t(i.path,e,`[${l}]`);return{content:[{type:`text`,text:`Remembered: **${e}**\n\nStored at \`.ai/curated/${i.path}\` and indexed for semantic search.${a}\n\n---\n_Next: Use \`search\` to verify the entry is findable, or \`list\` to see all curated entries._`},...d?[d]:[]]}}catch(e){return a.error(`Remember failed`,i(e)),{content:[{type:`text`,text:`Remember failed. Check server logs for details.`}],isError:!0}}})}export{o as registerRememberTool};
@@ -1,3 +1,3 @@
1
- import{createLogger as e,serializeError as t}from"../../../core/dist/index.js";import{replayClear as n,replayList as r,replayTrim as i}from"../../../tools/dist/index.js";import{z as a}from"zod";const o=e(`tools`);function s(e){e.registerTool(`replay`,{description:`View or clear the audit trail of recent MCP tool and CLI invocations. Shows tool name, duration, status, and input/output summaries.`,inputSchema:{action:a.enum([`list`,`clear`]).default(`list`).describe(`Action: "list" (default) to view entries, "clear" to wipe the log`),last:a.number().optional().describe(`Number of entries to return (default: 20, list only)`),tool:a.string().optional().describe(`Filter by tool name (list only)`),source:a.enum([`mcp`,`cli`]).optional().describe(`Filter by source: "mcp" or "cli" (list only)`),since:a.string().optional().describe(`ISO timestamp — only show entries after this time (list only)`)}},async({action:e,last:a,tool:s,source:c,since:l})=>{try{if(e===`clear`)return n(),{content:[{type:`text`,text:`Replay log cleared.`}]};let t=r({last:a,tool:s,source:c,since:l});if(t.length===0)return{content:[{type:`text`,text:`No replay entries found. Activity is logged when tools are invoked via MCP or CLI.`}]};let o=t.map(e=>`${e.ts.split(`T`)[1]?.split(`.`)[0]??e.ts} ${e.status===`ok`?`✓`:`✗`} ${e.tool} (${e.durationMs}ms) [${e.source}]\n in: ${e.input}\n out: ${e.output}`);return i(),{content:[{type:`text`,text:`**Replay Log** (${t.length} entries)\n\n${o.join(`
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{createLogger as n,serializeError as r}from"../../../core/dist/index.js";import{replayClear as i,replayList as a,replayTrim as o}from"../../../tools/dist/index.js";const s=n(`tools`);function c(n){let c=e(`replay`);n.registerTool(`replay`,{title:c.title,description:`View or clear the audit trail of recent MCP tool and CLI invocations. Shows tool name, duration, status, and input/output summaries.`,inputSchema:{action:t.enum([`list`,`clear`]).default(`list`).describe(`Action: "list" (default) to view entries, "clear" to wipe the log`),last:t.number().optional().describe(`Number of entries to return (default: 20, list only)`),tool:t.string().optional().describe(`Filter by tool name (list only)`),source:t.enum([`mcp`,`cli`]).optional().describe(`Filter by source: "mcp" or "cli" (list only)`),since:t.string().optional().describe(`ISO timestamp — only show entries after this time (list only)`)},annotations:c.annotations},async({action:e,last:t,tool:n,source:c,since:l})=>{try{if(e===`clear`)return i(),{content:[{type:`text`,text:`Replay log cleared.`}]};let r=a({last:t,tool:n,source:c,since:l});if(r.length===0)return{content:[{type:`text`,text:`No replay entries found. Activity is logged when tools are invoked via MCP or CLI.`}]};let s=r.map(e=>`${e.ts.split(`T`)[1]?.split(`.`)[0]??e.ts} ${e.status===`ok`?`✓`:`✗`} ${e.tool} (${e.durationMs}ms) [${e.source}]\n in: ${e.input}\n out: ${e.output}`);return o(),{content:[{type:`text`,text:`**Replay Log** (${r.length} entries)\n\n${s.join(`
2
2
 
3
- `)}`}]}}catch(e){return o.error(`Replay failed`,t(e)),{content:[{type:`text`,text:`Replay failed. Check server logs for details.`}],isError:!0}}})}export{s as registerReplayTool};
3
+ `)}`}]}}catch(e){return s.error(`Replay failed`,r(e)),{content:[{type:`text`,text:`Replay failed. Check server logs for details.`}],isError:!0}}})}export{c as registerReplayTool};
@@ -0,0 +1,6 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+
3
+ //#region packages/server/src/tools/restore.tool.d.ts
4
+ declare function registerRestoreTool(server: McpServer): void;
5
+ //#endregion
6
+ export { registerRestoreTool };
@@ -0,0 +1,3 @@
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{createLogger as n,serializeError as r}from"../../../core/dist/index.js";import{listRestorePoints as i,restoreFromPoint as a}from"../../../tools/dist/index.js";const o=n(`tools`);function s(n){let s=e(`restore`);n.registerTool(`restore`,{title:s.title,description:`List and restore file snapshots taken before destructive operations (codemod, rename, forget). Use action=list to see available restore points, action=restore with an id to undo.`,inputSchema:{action:t.enum([`list`,`restore`]).describe(`list: show restore points, restore: apply a restore point`),id:t.string().optional().describe(`Restore point ID (required for action=restore)`),limit:t.number().min(1).max(50).default(10).describe(`Max restore points to list`)},annotations:s.annotations},async({action:e,id:t,limit:n})=>{try{if(e===`list`){let e=i().slice(0,n);return e.length===0?{content:[{type:`text`,text:`No restore points found.`}]}:{content:[{type:`text`,text:`## Restore Points\n\n${e.map(e=>`- **${e.id}** (${e.timestamp}) — ${e.operation}: ${e.description} (${e.files.length} files)`).join(`
2
+ `)}`}]}}if(!t)throw Error(`id is required for restore action`);let r=await a(t);return{content:[{type:`text`,text:`Restored ${r.length} files:\n${r.map(e=>`- \`${e}\``).join(`
3
+ `)}`}]}}catch(e){return o.error(`Restore failed`,r(e)),{content:[{type:`text`,text:`Restore failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{s as registerRestoreTool};
@@ -1,9 +1,9 @@
1
- import{fanOutFtsSearch as e,fanOutSearch as t,openWorkspaceStores as n,resolveWorkspaces as r}from"../cross-workspace.js";import{stat as i}from"node:fs/promises";import{CONTENT_TYPES as a,KNOWLEDGE_ORIGINS as o,SOURCE_TYPES as s,computePartitionKey as c,createLogger as l,serializeError as u}from"../../../core/dist/index.js";import{graphAugmentSearch as d,truncateToTokenBudget as f}from"../../../tools/dist/index.js";import{z as p}from"zod";import{mergeResults as m}from"../../../enterprise-bridge/dist/index.js";const h=l(`tools`);async function g(e,t,n,r,i){if(!e||t>=e.config.fallbackThreshold&&n.length>0)return{results:n,triggered:!1,cacheHit:!1};let a=!1;try{let t=e.cache.get(r);return t?a=!0:(t=await e.client.search(r,i),t.length>0&&e.cache.set(r,t)),t.length>0?{results:m(n,t,i).map(e=>({record:{id:`er:${e.sourcePath}`,content:e.content,sourcePath:e.source===`er`?`[ER] ${e.sourcePath}`:e.sourcePath,startLine:e.startLine??0,endLine:e.endLine??0,contentType:e.contentType??`documentation`,headingPath:e.headingPath,origin:e.source===`er`?`curated`:e.origin??`indexed`,category:e.category,tags:e.tags??[],chunkIndex:0,totalChunks:1,fileHash:``,indexedAt:new Date().toISOString(),version:1},score:e.score})),triggered:!0,cacheHit:a}:{results:n,triggered:!0,cacheHit:a}}catch(e){return h.warn(`ER fallback failed`,u(e)),{results:n,triggered:!0,cacheHit:a}}}function _(e,t,n=60){let r=new Map;for(let t=0;t<e.length;t++){let i=e[t];r.set(i.record.id,{record:i.record,score:1/(n+t+1)})}for(let e=0;e<t.length;e++){let i=t[e],a=r.get(i.record.id);a?a.score+=1/(n+e+1):r.set(i.record.id,{record:i.record,score:1/(n+e+1)})}return[...r.values()].sort((e,t)=>t.score-e.score).map(({record:e,score:t})=>({record:e,score:t}))}function v(e,t){let n=t.toLowerCase().split(/\s+/).filter(e=>e.length>=2);return n.length<2?e:e.map(e=>{let t=e.record.content.toLowerCase(),r=n.map(e=>{let n=[],r=t.indexOf(e);for(;r!==-1;)n.push(r),r=t.indexOf(e,r+1);return n});if(r.some(e=>e.length===0))return e;let i=t.length;for(let e of r[0]){let t=e,a=e+n[0].length;for(let i=1;i<r.length;i++){let o=r[i][0],s=Math.abs(o-e);for(let t=1;t<r[i].length;t++){let n=Math.abs(r[i][t]-e);n<s&&(s=n,o=r[i][t])}t=Math.min(t,o),a=Math.max(a,o+n[i].length)}i=Math.min(i,a-t)}let a=1+.25/(1+i/200);return{record:e.record,score:e.score*a}}).sort((e,t)=>t.score-e.score)}function y(e,t,n=8){let r=new Set(t.toLowerCase().split(/\s+/).filter(e=>e.length>=2)),i=new Map,a=e.length;for(let t of e){let e=new Set(t.record.content.split(/[^a-zA-Z0-9_]+/).filter(e=>e.length>=3&&!b.has(e.toLowerCase())));for(let t of e){let e=t.toLowerCase();/[_A-Z]/.test(t)&&i.set(`__id__${e}`,1)}let n=new Set(t.record.content.toLowerCase().split(/[^a-zA-Z0-9_]+/).filter(e=>e.length>=3&&!b.has(e)));for(let e of n)i.set(e,(i.get(e)??0)+1)}let o=[];for(let[e,t]of i){if(e.startsWith(`__id__`)||r.has(e)||t>a*.8)continue;let n=Math.log(a/t),s=i.has(`__id__${e}`)?1:0,c=e.length>8?.5:0;o.push({term:e,score:n+s+c})}return o.sort((e,t)=>t.score-e.score).slice(0,n).map(e=>e.term)}const b=new Set(`the.and.for.are.but.not.you.all.can.had.her.was.one.our.out.has.have.from.this.that.with.they.been.said.each.which.their.will.other.about.many.then.them.these.some.would.make.like.into.could.time.very.when.come.just.know.take.people.also.back.after.only.more.than.over.such.import.export.const.function.return.true.false.null.undefined.string.number.boolean.void.type.interface`.split(`.`));async function x(e,t){try{let n=await e.getStats();if(!n.lastIndexedAt)return;let r=new Date(n.lastIndexedAt).getTime(),a=Date.now(),o=[...new Set(t.map(e=>e.record.sourcePath))].filter(e=>!e.startsWith(`[ER]`)).slice(0,5);if(o.length===0)return;let s=0;for(let e of o)try{(await i(e)).mtimeMs>r&&s++}catch{s++}if(s>0){let e=a-r,t=Math.floor(e/6e4),n=t<1?`<1 min`:`${t} min`;return`> ⚠️ **Index may be stale** — ${s} file(s) modified since last index (${n} ago). Use \`reindex\` to refresh.`}}catch{}}function S(i,l,m,b,S,C){i.registerTool(`search`,{description:`Search the knowledge base with hybrid vector + keyword matching (BM25 + RRF fusion). Best for finding code, docs, and prior decisions. Supports semantic, keyword, and hybrid modes.`,inputSchema:{query:p.string().max(5e3).describe(`Natural language search query`),limit:p.number().min(1).max(20).default(5).describe(`Maximum results to return`),search_mode:p.enum([`hybrid`,`semantic`,`keyword`]).default(`hybrid`).describe(`Search strategy: hybrid (vector + FTS + RRF fusion, default), semantic (vector only), keyword (FTS only)`),content_type:p.enum(a).optional().describe(`Filter by content type`),source_type:p.enum(s).optional().describe(`Coarse filter: "source" (code only), "documentation" (md, curated), "test", "config". Overrides content_type if both set.`),origin:p.enum(o).optional().describe(`Filter by knowledge origin`),category:p.string().optional().describe(`Filter by category (e.g., decisions, patterns, conventions)`),tags:p.array(p.string()).optional().describe(`Filter by tags (returns results matching ANY of the specified tags)`),min_score:p.number().min(0).max(1).default(.25).describe(`Minimum similarity score`),graph_hops:p.number().min(0).max(3).default(1).describe(`Number of graph hops to augment results with connected entities (0 = disabled, 1 = direct connections, 2-3 = deeper traversal). Default 1 provides module/symbol context automatically.`),max_tokens:p.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`),dedup:p.enum([`file`,`chunk`]).default(`chunk`).describe(`Deduplication mode: "chunk" (default, show all matching chunks) or "file" (collapse chunks from same file into single result with merged line ranges)`),workspaces:p.array(p.string()).optional().describe(`Cross-workspace search: partition names or folder basenames to include. Use ["*"] for all registered workspaces. Only works in user-level install mode.`)}},async({query:i,limit:a,search_mode:o,content_type:s,source_type:p,origin:w,category:T,tags:E,min_score:D,graph_hops:O,max_tokens:k,dedup:A,workspaces:j})=>{try{let M={limit:a,minScore:D,contentType:s,sourceType:p,origin:w,category:T,tags:E},N,P=!1,F=!1;if(o===`keyword`)N=await m.ftsSearch(i,M),N=N.slice(0,a);else if(o===`semantic`){let e=await l.embedQuery(i);N=await m.search(e,M);let t=await g(S,N[0]?.score??0,N,i,a);N=t.results,P=t.triggered,F=t.cacheHit}else{let e=await l.embedQuery(i),[t,n]=await Promise.all([m.search(e,{...M,limit:a*2}),m.ftsSearch(i,{...M,limit:a*2}).catch(()=>[])]);N=_(t,n).slice(0,a);let r=await g(S,t[0]?.score??0,N,i,a);N=r.results,P=r.triggered,F=r.cacheHit}C&&C.recordSearch(i,P,F),N.length>1&&(N=v(N,i));let I=``;if(j&&j.length>0){let s=r(j,c(process.cwd()));if(s.length>0){let{stores:r,closeAll:c}=await n(s);try{let n;n=o===`keyword`?await e(r,i,{...M,limit:a}):await t(r,await l.embedQuery(i),{...M,limit:a});for(let e of n)N.push({record:{...e.record,sourcePath:`[${e.workspace}] ${e.record.sourcePath}`},score:e.score});N=N.sort((e,t)=>t.score-e.score).slice(0,a),I=` + ${s.length} workspace(s)`}finally{await c()}}}if(A===`file`&&N.length>1){let e=new Map;for(let t of N){let n=t.record.sourcePath,r=e.get(n);r?(t.score>r.best.score&&(r.best=t),r.ranges.push({start:t.record.startLine,end:t.record.endLine})):e.set(n,{best:t,ranges:[{start:t.record.startLine,end:t.record.endLine}]})}N=[...e.values()].sort((e,t)=>t.best.score-e.best.score).map(({best:e,ranges:t})=>({record:{...e.record,content:t.length>1?`${e.record.content}\n\n_Matched ${t.length} sections: ${t.sort((e,t)=>e.start-t.start).map(e=>`L${e.start}-${e.end}`).join(`, `)}_`:e.record.content},score:e.score}))}if(N.length===0)return{content:[{type:`text`,text:`No results found for the given query.`}]};let L,R;if(O>0&&!b&&(R="> **Note:** `graph_hops` was set but no graph store is available. Graph augmentation skipped."),O>0&&b)try{let e=await d(b,N.map(e=>({recordId:e.record.id,score:e.score,sourcePath:e.record.sourcePath})),{hops:O,maxPerHit:5});L=new Map;for(let t of e)if(t.graphContext.nodes.length>0){let e=t.graphContext.nodes.slice(0,5).map(e=>` - **${e.name}** (${e.type})`).join(`
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{fanOutFtsSearch as t,fanOutSearch as n,openWorkspaceStores as r,resolveWorkspaces as i}from"../cross-workspace.js";import{curatedResourceLink as a,extractCuratedPath as o}from"../resource-links.js";import{stat as s}from"node:fs/promises";import{z as c}from"zod";import{CONTENT_TYPES as l,KNOWLEDGE_ORIGINS as u,SOURCE_TYPES as d,computePartitionKey as f,createLogger as p,serializeError as m}from"../../../core/dist/index.js";import{graphAugmentSearch as h,truncateToTokenBudget as g}from"../../../tools/dist/index.js";import{mergeResults as _}from"../../../enterprise-bridge/dist/index.js";const v=p(`tools`);async function y(e,t,n,r,i){if(!e||t>=e.config.fallbackThreshold&&n.length>0)return{results:n,triggered:!1,cacheHit:!1};let a=!1;try{let t=e.cache.get(r);return t?a=!0:(t=await e.client.search(r,i),t.length>0&&e.cache.set(r,t)),t.length>0?{results:_(n,t,i).map(e=>({record:{id:`er:${e.sourcePath}`,content:e.content,sourcePath:e.source===`er`?`[ER] ${e.sourcePath}`:e.sourcePath,startLine:e.startLine??0,endLine:e.endLine??0,contentType:e.contentType??`documentation`,headingPath:e.headingPath,origin:e.source===`er`?`curated`:e.origin??`indexed`,category:e.category,tags:e.tags??[],chunkIndex:0,totalChunks:1,fileHash:``,indexedAt:new Date().toISOString(),version:1},score:e.score})),triggered:!0,cacheHit:a}:{results:n,triggered:!0,cacheHit:a}}catch(e){return v.warn(`ER fallback failed`,m(e)),{results:n,triggered:!0,cacheHit:a}}}function b(e,t,n=60){let r=new Map;for(let t=0;t<e.length;t++){let i=e[t];r.set(i.record.id,{record:i.record,score:1/(n+t+1)})}for(let e=0;e<t.length;e++){let i=t[e],a=r.get(i.record.id);a?a.score+=1/(n+e+1):r.set(i.record.id,{record:i.record,score:1/(n+e+1)})}return[...r.values()].sort((e,t)=>t.score-e.score).map(({record:e,score:t})=>({record:e,score:t}))}function x(e,t){let n=t.toLowerCase().split(/\s+/).filter(e=>e.length>=2);return n.length<2?e:e.map(e=>{let t=e.record.content.toLowerCase(),r=n.map(e=>{let n=[],r=t.indexOf(e);for(;r!==-1;)n.push(r),r=t.indexOf(e,r+1);return n});if(r.some(e=>e.length===0))return e;let i=t.length;for(let e of r[0]){let t=e,a=e+n[0].length;for(let i=1;i<r.length;i++){let o=r[i][0],s=Math.abs(o-e);for(let t=1;t<r[i].length;t++){let n=Math.abs(r[i][t]-e);n<s&&(s=n,o=r[i][t])}t=Math.min(t,o),a=Math.max(a,o+n[i].length)}i=Math.min(i,a-t)}let a=1+.25/(1+i/200);return{record:e.record,score:e.score*a}}).sort((e,t)=>t.score-e.score)}function S(e,t,n=8){let r=new Set(t.toLowerCase().split(/\s+/).filter(e=>e.length>=2)),i=new Map,a=e.length;for(let t of e){let e=new Set(t.record.content.split(/[^a-zA-Z0-9_]+/).filter(e=>e.length>=3&&!C.has(e.toLowerCase())));for(let t of e){let e=t.toLowerCase();/[_A-Z]/.test(t)&&i.set(`__id__${e}`,1)}let n=new Set(t.record.content.toLowerCase().split(/[^a-zA-Z0-9_]+/).filter(e=>e.length>=3&&!C.has(e)));for(let e of n)i.set(e,(i.get(e)??0)+1)}let o=[];for(let[e,t]of i){if(e.startsWith(`__id__`)||r.has(e)||t>a*.8)continue;let n=Math.log(a/t),s=i.has(`__id__${e}`)?1:0,c=e.length>8?.5:0;o.push({term:e,score:n+s+c})}return o.sort((e,t)=>t.score-e.score).slice(0,n).map(e=>e.term)}const C=new Set(`the.and.for.are.but.not.you.all.can.had.her.was.one.our.out.has.have.from.this.that.with.they.been.said.each.which.their.will.other.about.many.then.them.these.some.would.make.like.into.could.time.very.when.come.just.know.take.people.also.back.after.only.more.than.over.such.import.export.const.function.return.true.false.null.undefined.string.number.boolean.void.type.interface`.split(`.`));async function w(e,t){try{let n=await e.getStats();if(!n.lastIndexedAt)return;let r=new Date(n.lastIndexedAt).getTime(),i=Date.now(),a=[...new Set(t.map(e=>e.record.sourcePath))].filter(e=>!e.startsWith(`[ER]`)).slice(0,5);if(a.length===0)return;let o=0;for(let e of a)try{(await s(e)).mtimeMs>r&&o++}catch{o++}if(o>0){let e=i-r,t=Math.floor(e/6e4),n=t<1?`<1 min`:`${t} min`;return`> ⚠️ **Index may be stale** — ${o} file(s) modified since last index (${n} ago). Use \`reindex\` to refresh.`}}catch{}}function T(s,p,_,C,T,E){let D=e(`search`);s.registerTool(`search`,{title:D.title,description:`Search the knowledge base with hybrid vector + keyword matching (BM25 + RRF fusion). Best for finding code, docs, and prior decisions. Supports semantic, keyword, and hybrid modes.`,inputSchema:{query:c.string().max(5e3).describe(`Natural language search query`),limit:c.number().min(1).max(20).default(5).describe(`Maximum results to return`),search_mode:c.enum([`hybrid`,`semantic`,`keyword`]).default(`hybrid`).describe(`Search strategy: hybrid (vector + FTS + RRF fusion, default), semantic (vector only), keyword (FTS only)`),content_type:c.enum(l).optional().describe(`Filter by content type`),source_type:c.enum(d).optional().describe(`Coarse filter: "source" (code only), "documentation" (md, curated), "test", "config". Overrides content_type if both set.`),origin:c.enum(u).optional().describe(`Filter by knowledge origin`),category:c.string().optional().describe(`Filter by category (e.g., decisions, patterns, conventions)`),tags:c.array(c.string()).optional().describe(`Filter by tags (returns results matching ANY of the specified tags)`),min_score:c.number().min(0).max(1).default(.25).describe(`Minimum similarity score`),graph_hops:c.number().min(0).max(3).default(1).describe(`Number of graph hops to augment results with connected entities (0 = disabled, 1 = direct connections, 2-3 = deeper traversal). Default 1 provides module/symbol context automatically.`),max_tokens:c.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`),dedup:c.enum([`file`,`chunk`]).default(`chunk`).describe(`Deduplication mode: "chunk" (default, show all matching chunks) or "file" (collapse chunks from same file into single result with merged line ranges)`),workspaces:c.array(c.string()).optional().describe(`Cross-workspace search: partition names or folder basenames to include. Use ["*"] for all registered workspaces. Only works in user-level install mode.`)},annotations:D.annotations},async({query:e,limit:s,search_mode:c,content_type:l,source_type:u,origin:d,category:D,tags:O,min_score:k,graph_hops:A,max_tokens:j,dedup:M,workspaces:N})=>{try{let P={limit:s,minScore:k,contentType:l,sourceType:u,origin:d,category:D,tags:O},F,I=!1,L=!1;if(c===`keyword`)F=await _.ftsSearch(e,P),F=F.slice(0,s);else if(c===`semantic`){let t=await p.embedQuery(e);F=await _.search(t,P);let n=await y(T,F[0]?.score??0,F,e,s);F=n.results,I=n.triggered,L=n.cacheHit}else{let t=await p.embedQuery(e),[n,r]=await Promise.all([_.search(t,{...P,limit:s*2}),_.ftsSearch(e,{...P,limit:s*2}).catch(()=>[])]);F=b(n,r).slice(0,s);let i=await y(T,n[0]?.score??0,F,e,s);F=i.results,I=i.triggered,L=i.cacheHit}E&&E.recordSearch(e,I,L),F.length>1&&(F=x(F,e));let R=``;if(N&&N.length>0){let a=i(N,f(process.cwd()));if(a.length>0){let{stores:i,closeAll:o}=await r(a);try{let r;r=c===`keyword`?await t(i,e,{...P,limit:s}):await n(i,await p.embedQuery(e),{...P,limit:s});for(let e of r)F.push({record:{...e.record,sourcePath:`[${e.workspace}] ${e.record.sourcePath}`},score:e.score});F=F.sort((e,t)=>t.score-e.score).slice(0,s),R=` + ${a.length} workspace(s)`}finally{await o()}}}if(M===`file`&&F.length>1){let e=new Map;for(let t of F){let n=t.record.sourcePath,r=e.get(n);r?(t.score>r.best.score&&(r.best=t),r.ranges.push({start:t.record.startLine,end:t.record.endLine})):e.set(n,{best:t,ranges:[{start:t.record.startLine,end:t.record.endLine}]})}F=[...e.values()].sort((e,t)=>t.best.score-e.best.score).map(({best:e,ranges:t})=>({record:{...e.record,content:t.length>1?`${e.record.content}\n\n_Matched ${t.length} sections: ${t.sort((e,t)=>e.start-t.start).map(e=>`L${e.start}-${e.end}`).join(`, `)}_`:e.record.content},score:e.score}))}if(F.length===0)return{content:[{type:`text`,text:`No results found for the given query.`}]};let z,B;if(A>0&&!C&&(B="> **Note:** `graph_hops` was set but no graph store is available. Graph augmentation skipped."),A>0&&C)try{let e=await h(C,F.map(e=>({recordId:e.record.id,score:e.score,sourcePath:e.record.sourcePath})),{hops:A,maxPerHit:5});z=new Map;for(let t of e)if(t.graphContext.nodes.length>0){let e=t.graphContext.nodes.slice(0,5).map(e=>` - **${e.name}** (${e.type})`).join(`
2
2
  `),n=t.graphContext.edges.slice(0,5).map(e=>` - ${e.fromId} —[${e.type}]→ ${e.toId}`).join(`
3
- `),r=[`- **Graph Context** (${O} hop${O>1?`s`:``}):`];e&&r.push(` Entities:\n${e}`),n&&r.push(` Relationships:\n${n}`),L.set(t.recordId,r.join(`
4
- `))}}catch(e){h.warn(`Graph augmentation failed`,u(e)),R=`> **Note:** Graph augmentation failed. Results shown without graph context.`}let z=N.map((e,t)=>{let n=e.record;return`${`### Result ${t+1} (score: ${e.score.toFixed(3)})`}\n${[`- **Source**: ${n.sourcePath}`,n.headingPath?`- **Section**: ${n.headingPath}`:null,`- **Type**: ${n.contentType}`,n.startLine?`- **Lines**: ${n.startLine}-${n.endLine}`:null,n.origin===`indexed`?null:`- **Origin**: ${n.origin}`,n.category?`- **Category**: ${n.category}`:null,n.tags?.length?`- **Tags**: ${n.tags.join(`, `)}`:null,L?.get(n.id)??null].filter(Boolean).join(`
3
+ `),r=[`- **Graph Context** (${A} hop${A>1?`s`:``}):`];e&&r.push(` Entities:\n${e}`),n&&r.push(` Relationships:\n${n}`),z.set(t.recordId,r.join(`
4
+ `))}}catch(e){v.warn(`Graph augmentation failed`,m(e)),B=`> **Note:** Graph augmentation failed. Results shown without graph context.`}let V=F.map((e,t)=>{let n=e.record;return`${`### Result ${t+1} (score: ${e.score.toFixed(3)})`}\n${[`- **Source**: ${n.sourcePath}`,n.headingPath?`- **Section**: ${n.headingPath}`:null,`- **Type**: ${n.contentType}`,n.startLine?`- **Lines**: ${n.startLine}-${n.endLine}`:null,n.origin===`indexed`?null:`- **Origin**: ${n.origin}`,n.category?`- **Category**: ${n.category}`:null,n.tags?.length?`- **Tags**: ${n.tags.join(`, `)}`:null,z?.get(n.id)??null].filter(Boolean).join(`
5
5
  `)}\n\n${n.content}`}).join(`
6
6
 
7
7
  ---
8
8
 
9
- `),B=(o===`hybrid`?`hybrid (vector + keyword RRF)`:o===`keyword`?`keyword (FTS)`:`semantic (vector)`)+I,V=y(N,i),H=V.length>0?`\n_Distinctive terms: ${V.map(e=>`\`${e}\``).join(`, `)}_`:``,U=await x(m,N),W=[];if(N.length===0)W.push("`reindex` — no results found, index may be stale"),W.push("`find` — try federated search with glob/regex");else{let e=N[0]?.record.sourcePath;e&&W.push(`\`lookup\` — see all chunks from \`${e}\``),W.push("`symbol` — resolve a specific symbol from the results"),W.push("`compact` — compress a result file for focused reading")}let G=[R?`${R}\n\n`:``,U?`${U}\n\n`:``,z,`\n\n---\n_Search mode: ${B} | ${N.length} results_${H}`,`\n_Next: ${W.join(` | `)}_`].join(``);return k&&(G=f(G,k)),{content:[{type:`text`,text:G}]}}catch(e){return h.error(`Search failed`,u(e)),{content:[{type:`text`,text:`Search failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{S as registerSearchTool};
9
+ `),H=(c===`hybrid`?`hybrid (vector + keyword RRF)`:c===`keyword`?`keyword (FTS)`:`semantic (vector)`)+R,U=S(F,e),W=U.length>0?`\n_Distinctive terms: ${U.map(e=>`\`${e}\``).join(`, `)}_`:``,G=await w(_,F),K=[];if(F.length===0)K.push("`reindex` — no results found, index may be stale"),K.push("`find` — try federated search with glob/regex");else{let e=F[0]?.record.sourcePath;e&&K.push(`\`lookup\` — see all chunks from \`${e}\``),K.push("`symbol` — resolve a specific symbol from the results"),K.push("`compact` — compress a result file for focused reading")}let q=[B?`${B}\n\n`:``,G?`${G}\n\n`:``,V,`\n\n---\n_Search mode: ${H} | ${F.length} results_${W}`,`\n_Next: ${K.join(` | `)}_`].join(``);j&&(q=g(q,j));let J=new Set,Y=[];for(let e of F){if(e.record.origin!==`curated`||e.record.sourcePath.startsWith(`[`))continue;let t=o(e.record.sourcePath);if(!t)continue;let n=a(t,e.record.headingPath??t);n&&!J.has(n.uri)&&(J.add(n.uri),Y.push(n))}return{content:[{type:`text`,text:q},...Y]}}catch(e){return v.error(`Search failed`,m(e)),{content:[{type:`text`,text:`Search failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{T as registerSearchTool};
@@ -1,2 +1,2 @@
1
- import{existsSync as e}from"node:fs";import{resolve as t}from"node:path";import{WasmRuntime as n}from"../../../chunker/dist/index.js";import{KB_PATHS as r,createLogger as i,serializeError as a}from"../../../core/dist/index.js";const o=i(`tools`);function s(i,s,c,l,u){i.registerTool(`status`,{description:`Get the current status and statistics of the knowledge base index.`},async()=>{try{let i=await s.getStats(),a=await s.listSourcePaths(),o=[`## Knowledge Base Status`,``,`- **Total Records**: ${i.totalRecords}`,`- **Total Files**: ${i.totalFiles}`,`- **Last Indexed**: ${i.lastIndexedAt??`Never`}`,``,`### Content Types`,...Object.entries(i.contentTypeBreakdown).map(([e,t])=>`- ${e}: ${t}`),``,`### Indexed Files`,...a.slice(0,50).map(e=>`- ${e}`),a.length>50?`\n... and ${a.length-50} more files`:``];if(c)try{let e=await c.getStats();o.push(``,`### Knowledge Graph`,`- **Nodes**: ${e.nodeCount}`,`- **Edges**: ${e.edgeCount}`,...Object.entries(e.nodeTypes).map(([e,t])=>` - ${e}: ${t}`))}catch{o.push(``,`### Knowledge Graph`,`- Graph store unavailable`)}let d=e(t(process.cwd(),r.aiKb)),f=u?.onboardComplete??d;if(o.push(``,`### Onboard Status`,f?`- ✅ Complete${u?.onboardTimestamp?` (last: ${u.onboardTimestamp})`:``}`:'- ❌ Not run — call `onboard({ path: "." })` to analyze the codebase'),l)try{let e=await l.list();o.push(``,`### Curated Knowledge`,e.length>0?`- ${e.length} entries`:"- Empty — use `remember()` to persist decisions")}catch{o.push(``,`### Curated Knowledge`,`- Unable to read curated entries`)}if(i.lastIndexedAt){let e=new Date(i.lastIndexedAt),t=(Date.now()-e.getTime())/(1e3*60*60);o.push(``,`### Index Freshness`,t>24?`- ⚠ Last indexed ${Math.floor(t)}h ago — may be stale. Run \`reindex({})\``:`- ✅ Last indexed ${t<1?`less than 1h`:`${Math.floor(t)}h`} ago`)}return o.push(``,`### Runtime`,`- **Tree-sitter (WASM)**: ${n.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`),{content:[{type:`text`,text:o.join(`
2
- `)+"\n\n---\n_Next: Use `search` to query indexed content, `graph(stats)` to explore the knowledge graph, or `reindex` to refresh the index._"}]}}catch(e){return o.error(`Status failed`,a(e)),{content:[{type:`text`,text:`Status check failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{s as registerStatusTool};
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{StatusOutputSchema as t}from"../output-schemas.js";import{existsSync as n}from"node:fs";import{resolve as r}from"node:path";import{WasmRuntime as i}from"../../../chunker/dist/index.js";import{KB_PATHS as a,createLogger as o,serializeError as s}from"../../../core/dist/index.js";const c=o(`tools`);function l(o,l,u,d,f){let p=e(`status`);o.registerTool(`status`,{title:p.title,description:`Get the current status and statistics of the knowledge base index.`,outputSchema:t,annotations:p.annotations},async()=>{try{let e=await l.getStats(),t=await l.listSourcePaths(),o=null,s=0,c=[`## Knowledge Base Status`,``,`- **Total Records**: ${e.totalRecords}`,`- **Total Files**: ${e.totalFiles}`,`- **Last Indexed**: ${e.lastIndexedAt??`Never`}`,``,`### Content Types`,...Object.entries(e.contentTypeBreakdown).map(([e,t])=>`- ${e}: ${t}`),``,`### Indexed Files`,...t.slice(0,50).map(e=>`- ${e}`),t.length>50?`\n... and ${t.length-50} more files`:``];if(u)try{let e=await u.getStats();o={nodes:e.nodeCount,edges:e.edgeCount},c.push(``,`### Knowledge Graph`,`- **Nodes**: ${e.nodeCount}`,`- **Edges**: ${e.edgeCount}`,...Object.entries(e.nodeTypes).map(([e,t])=>` - ${e}: ${t}`));try{let e=await u.validate();e.valid||c.push(`- **⚠ Integrity Issues**: ${e.danglingEdges.length} dangling edges`),e.orphanNodes.length>0&&c.push(`- **Orphan nodes**: ${e.orphanNodes.length}`)}catch{}}catch{c.push(``,`### Knowledge Graph`,`- Graph store unavailable`)}let p=n(r(process.cwd(),a.aiKb)),m=f?.onboardComplete??p;if(c.push(``,`### Onboard Status`,m?`- ✅ Complete${f?.onboardTimestamp?` (last: ${f.onboardTimestamp})`:``}`:'- ❌ Not run — call `onboard({ path: "." })` to analyze the codebase'),d)try{let e=await d.list();s=e.length,c.push(``,`### Curated Knowledge`,e.length>0?`- ${e.length} entries`:"- Empty — use `remember()` to persist decisions")}catch{c.push(``,`### Curated Knowledge`,`- Unable to read curated entries`)}if(e.lastIndexedAt){let t=new Date(e.lastIndexedAt),n=(Date.now()-t.getTime())/(1e3*60*60);c.push(``,`### Index Freshness`,n>24?`- ⚠ Last indexed ${Math.floor(n)}h ago — may be stale. Run \`reindex({})\``:`- ✅ Last indexed ${n<1?`less than 1h`:`${Math.floor(n)}h`} ago`)}c.push(``,`### Runtime`,`- **Tree-sitter (WASM)**: ${i.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`);let h=c.join(`
2
+ `),g={totalRecords:e.totalRecords,totalFiles:e.totalFiles,lastIndexedAt:e.lastIndexedAt??null,onboarded:m,contentTypes:e.contentTypeBreakdown,wasmAvailable:!!i.get(),graphStats:o,curatedCount:s};return{content:[{type:`text`,text:h+"\n\n---\n_Next: Use `search` to query indexed content, `graph(stats)` to explore the knowledge graph, or `reindex` to refresh the index._"}],structuredContent:g}}catch(e){return c.error(`Status failed`,s(e)),{content:[{type:`text`,text:`Status check failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{l as registerStatusTool};
@@ -1,20 +1,20 @@
1
- import{fanOutSearch as e,openWorkspaceStores as t,resolveWorkspaces as n}from"../cross-workspace.js";import{CONTENT_TYPES as r,computePartitionKey as i,createLogger as a,serializeError as o}from"../../../core/dist/index.js";import{addToWorkset as s,batch as c,check as l,checkpointLatest as u,checkpointList as d,checkpointLoad as f,checkpointSave as p,codemod as m,compact as h,dataTransform as g,delegate as ee,delegateListModels as te,deleteWorkset as ne,diffParse as re,evaluate as ie,fileSummary as ae,find as _,findDeadSymbols as oe,findExamples as se,getWorkset as v,gitContext as y,guide as b,health as x,laneCreate as S,laneDiff as C,laneDiscard as w,laneList as T,laneMerge as E,laneStatus as D,listWorksets as O,parseOutput as k,processList as A,processLogs as j,processStart as M,processStatus as N,processStop as P,queueClear as F,queueCreate as I,queueDelete as L,queueDone as R,queueFail as z,queueGet as B,queueList as V,queueNext as H,queuePush as U,removeFromWorkset as W,rename as G,saveWorkset as K,scopeMap as ce,stashClear as le,stashDelete as ue,stashGet as de,stashList as fe,stashSet as pe,summarizeCheckResult as me,symbol as q,testRun as he,trace as ge,truncateToTokenBudget as J,watchList as _e,watchStart as ve,watchStop as ye,webFetch as be}from"../../../tools/dist/index.js";import{z as Y}from"zod";const X=a(`tools`);function xe(e,t,n){e.registerTool(`compact`,{description:"Compress text to relevant sections using embedding similarity (no LLM). Provide either `text` or `path` (server reads the file — saves a round-trip). Segments by paragraph/sentence/line.",inputSchema:{text:Y.string().optional().describe(`The text to compress (provide this OR path, not both)`),path:Y.string().optional().describe(`File path to read server-side — avoids read_file round-trip + token doubling (provide this OR text)`),query:Y.string().describe(`Focus query — what are you trying to understand?`),max_chars:Y.number().min(100).max(5e4).default(3e3).describe(`Target output size in characters`),segmentation:Y.enum([`paragraph`,`sentence`,`line`]).default(`paragraph`).describe(`How to split the text for scoring`)}},async({text:e,path:r,query:i,max_chars:a,segmentation:s})=>{try{if(!e&&!r)return{content:[{type:`text`,text:`Error: Either "text" or "path" must be provided.`}],isError:!0};let o=await h(t,{text:e,path:r,query:i,maxChars:a,segmentation:s,cache:n});return{content:[{type:`text`,text:[`Compressed ${o.originalChars} → ${o.compressedChars} chars (${(o.ratio*100).toFixed(0)}%)`,`Kept ${o.segmentsKept}/${o.segmentsTotal} segments`,``,o.text].join(`
2
- `)}]}}catch(e){return X.error(`Compact failed`,o(e)),{content:[{type:`text`,text:`Compact failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function Se(e,t,n){e.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:Y.string().describe(`Description of the task to scope`),max_files:Y.number().min(1).max(50).default(15).describe(`Maximum files to include`),content_type:Y.enum(r).optional().describe(`Filter by content type`),max_tokens:Y.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`)}},async({task:e,max_files:r,content_type:i,max_tokens:a})=>{try{let o=await ce(t,n,{task:e,maxFiles:r,contentType:i}),s=[`## Scope Map: ${e}`,`Total estimated tokens: ~${o.totalEstimatedTokens}`,``,`### Files (by relevance)`,...o.files.map((e,t)=>`${t+1}. **${e.path}** (~${e.estimatedTokens} tokens, ${(e.relevance*100).toFixed(0)}% relevant)\n ${e.reason}\n Focus: ${e.focusRanges.map(e=>`L${e.start}-${e.end}`).join(`, `)}`),``,`### Suggested Reading Order`,...o.readingOrder.map((e,t)=>`${t+1}. ${e}`),``,`### Suggested Compact Calls`,`_Estimated compressed total: ~${Math.ceil(o.totalEstimatedTokens/5)} tokens_`,...o.compactCommands.map((e,t)=>`${t+1}. ${e}`)].join(`
3
- `)+"\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?J(s,a):s}]}}catch(e){return X.error(`Scope map failed`,o(e)),{content:[{type:`text`,text:`Scope map failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function Ce(a,s,c){a.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:Y.string().optional().describe(`Semantic/keyword search query (required for mode "examples")`),glob:Y.string().optional().describe(`File glob pattern (search mode only)`),pattern:Y.string().optional().describe(`Regex pattern to match in content (search mode only)`),limit:Y.number().min(1).max(50).default(10).describe(`Max results`),content_type:Y.enum(r).optional().describe(`Filter by content type`),mode:Y.enum([`search`,`examples`]).default(`search`).describe(`Mode: "search" (default) for federated search, "examples" to find usage examples of a symbol/pattern`),max_tokens:Y.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`),workspaces:Y.array(Y.string()).optional().describe(`Cross-workspace search: partition names or folder basenames to include. Use ["*"] for all. User-level mode only.`)}},async({query:r,glob:a,pattern:l,limit:u,content_type:d,mode:f,max_tokens:p,workspaces:m})=>{try{if(f===`examples`){if(!r)return{content:[{type:`text`,text:`Error: "query" is required for mode "examples".`}],isError:!0};let e=await se(s,c,{query:r,limit:u,contentType:d}),t=JSON.stringify(e,null,2);return{content:[{type:`text`,text:p?J(t,p):t}]}}let o=await _(s,c,{query:r,glob:a,pattern:l,limit:u,contentType:d}),h=``;if(m&&m.length>0&&r){let a=n(m,i(process.cwd()));if(a.length>0){let{stores:n,closeAll:i}=await t(a);try{let t=await e(n,await s.embedQuery(r),{limit:u,contentType:d});for(let e of t)o.results.push({path:`[${e.workspace}] ${e.record.sourcePath}`,score:e.score,source:`cross-workspace`,lineRange:e.record.startLine?{start:e.record.startLine,end:e.record.endLine}:void 0,preview:e.record.content.slice(0,200)});o.results.sort((e,t)=>t.score-e.score),o.results=o.results.slice(0,u),o.totalFound=o.results.length,h=` + ${a.length} workspace(s)`}finally{await i()}}}if(o.results.length===0)return{content:[{type:`text`,text:`No results found.`}]};let g=[`Found ${o.totalFound} results via ${o.strategies.join(` + `)}${h}`,``,...o.results.map(e=>{let t=e.lineRange?`:${e.lineRange.start}-${e.lineRange.end}`:``,n=e.preview?`\n ${e.preview.slice(0,100)}...`:``;return`- [${e.source}] ${e.path}${t} (${(e.score*100).toFixed(0)}%)${n}`})];return{content:[{type:`text`,text:p?J(g.join(`
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{fanOutSearch as t,openWorkspaceStores as n,resolveWorkspaces as r}from"../cross-workspace.js";import{HealthOutputSchema as i}from"../output-schemas.js";import{z as a}from"zod";import{CONTENT_TYPES as o,computePartitionKey as s,createLogger as c,serializeError as l}from"../../../core/dist/index.js";import{addToWorkset as u,batch as d,check as f,checkpointLatest as p,checkpointList as m,checkpointLoad as h,checkpointSave as g,codemod as _,compact as ee,dataTransform as te,delegate as ne,delegateListModels as re,deleteWorkset as ie,diffParse as ae,evaluate as oe,fileSummary as v,find as y,findDeadSymbols as b,findExamples as x,getWorkset as S,gitContext as C,guide as w,health as T,laneCreate as E,laneDiff as D,laneDiscard as O,laneList as k,laneMerge as A,laneStatus as j,listWorksets as M,parseOutput as N,processList as P,processLogs as F,processStart as I,processStatus as L,processStop as R,queueClear as z,queueCreate as B,queueDelete as V,queueDone as H,queueFail as U,queueGet as W,queueList as G,queueNext as K,queuePush as q,removeFromWorkset as se,rename as ce,saveWorkset as le,scopeMap as ue,stashClear as de,stashDelete as fe,stashGet as pe,stashList as me,stashSet as he,summarizeCheckResult as ge,symbol as J,testRun as _e,trace as ve,truncateToTokenBudget as Y,watchList as ye,watchStart as be,watchStop as xe,webFetch as Se}from"../../../tools/dist/index.js";const X=c(`tools`);function Ce(t,n,r){let i=e(`compact`);t.registerTool(`compact`,{title:i.title,description:"Compress text to relevant sections using embedding similarity (no LLM). Provide either `text` or `path` (server reads the file — saves a round-trip). Segments by paragraph/sentence/line.",inputSchema:{text:a.string().optional().describe(`The text to compress (provide this OR path, not both)`),path:a.string().optional().describe(`File path to read server-side — avoids read_file round-trip + token doubling (provide this OR text)`),query:a.string().describe(`Focus query — what are you trying to understand?`),max_chars:a.number().min(100).max(5e4).default(3e3).describe(`Target output size in characters`),segmentation:a.enum([`paragraph`,`sentence`,`line`]).default(`paragraph`).describe(`How to split the text for scoring`)},annotations:i.annotations},async({text:e,path:t,query:i,max_chars:a,segmentation:o})=>{try{if(!e&&!t)return{content:[{type:`text`,text:`Error: Either "text" or "path" must be provided.`}],isError:!0};let s=await ee(n,{text:e,path:t,query:i,maxChars:a,segmentation:o,cache:r});return{content:[{type:`text`,text:[`Compressed ${s.originalChars} → ${s.compressedChars} chars (${(s.ratio*100).toFixed(0)}%)`,`Kept ${s.segmentsKept}/${s.segmentsTotal} segments`,``,s.text].join(`
2
+ `)}]}}catch(e){return X.error(`Compact failed`,l(e)),{content:[{type:`text`,text:`Compact failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function we(t,n,r){let i=e(`scope_map`);t.registerTool(`scope_map`,{title:i.title,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:a.string().describe(`Description of the task to scope`),max_files:a.number().min(1).max(50).default(15).describe(`Maximum files to include`),content_type:a.enum(o).optional().describe(`Filter by content type`),max_tokens:a.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`)},annotations:i.annotations},async({task:e,max_files:t,content_type:i,max_tokens:a})=>{try{let o=await ue(n,r,{task:e,maxFiles:t,contentType:i}),s=[`## Scope Map: ${e}`,`Total estimated tokens: ~${o.totalEstimatedTokens}`,``,`### Files (by relevance)`,...o.files.map((e,t)=>`${t+1}. **${e.path}** (~${e.estimatedTokens} tokens, ${(e.relevance*100).toFixed(0)}% relevant)\n ${e.reason}\n Focus: ${e.focusRanges.map(e=>`L${e.start}-${e.end}`).join(`, `)}`),``,`### Suggested Reading Order`,...o.readingOrder.map((e,t)=>`${t+1}. ${e}`),``,`### Suggested Compact Calls`,`_Estimated compressed total: ~${Math.ceil(o.totalEstimatedTokens/5)} tokens_`,...o.compactCommands.map((e,t)=>`${t+1}. ${e}`)].join(`
3
+ `)+"\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?Y(s,a):s}]}}catch(e){return X.error(`Scope map failed`,l(e)),{content:[{type:`text`,text:`Scope map failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function Te(i,c,u){let d=e(`find`);i.registerTool(`find`,{title:d.title,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:a.string().optional().describe(`Semantic/keyword search query (required for mode "examples")`),glob:a.string().optional().describe(`File glob pattern (search mode only)`),pattern:a.string().optional().describe(`Regex pattern to match in content (search mode only)`),limit:a.number().min(1).max(50).default(10).describe(`Max results`),content_type:a.enum(o).optional().describe(`Filter by content type`),mode:a.enum([`search`,`examples`]).default(`search`).describe(`Mode: "search" (default) for federated search, "examples" to find usage examples of a symbol/pattern`),max_tokens:a.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`),workspaces:a.array(a.string()).optional().describe(`Cross-workspace search: partition names or folder basenames to include. Use ["*"] for all. User-level mode only.`)},annotations:d.annotations},async({query:e,glob:i,pattern:a,limit:o,content_type:d,mode:f,max_tokens:p,workspaces:m})=>{try{if(f===`examples`){if(!e)return{content:[{type:`text`,text:`Error: "query" is required for mode "examples".`}],isError:!0};let t=await x(c,u,{query:e,limit:o,contentType:d}),n=JSON.stringify(t,null,2);return{content:[{type:`text`,text:p?Y(n,p):n}]}}let l=await y(c,u,{query:e,glob:i,pattern:a,limit:o,contentType:d}),h=``;if(m&&m.length>0&&e){let i=r(m,s(process.cwd()));if(i.length>0){let{stores:r,closeAll:a}=await n(i);try{let n=await t(r,await c.embedQuery(e),{limit:o,contentType:d});for(let e of n)l.results.push({path:`[${e.workspace}] ${e.record.sourcePath}`,score:e.score,source:`cross-workspace`,lineRange:e.record.startLine?{start:e.record.startLine,end:e.record.endLine}:void 0,preview:e.record.content.slice(0,200)});l.results.sort((e,t)=>t.score-e.score),l.results=l.results.slice(0,o),l.totalFound=l.results.length,h=` + ${i.length} workspace(s)`}finally{await a()}}}if(l.results.length===0)return{content:[{type:`text`,text:`No results found.`}]};let g=[`Found ${l.totalFound} results via ${l.strategies.join(` + `)}${h}`,``,...l.results.map(e=>{let t=e.lineRange?`:${e.lineRange.start}-${e.lineRange.end}`:``,n=e.preview?`\n ${e.preview.slice(0,100)}...`:``;return`- [${e.source}] ${e.path}${t} (${(e.score*100).toFixed(0)}%)${n}`})];return{content:[{type:`text`,text:p?Y(g.join(`
4
4
  `),p):g.join(`
5
- `)}]}}catch(e){return X.error(`Find failed`,o(e)),{content:[{type:`text`,text:`Find failed. Check server logs for details.`}],isError:!0}}})}function we(e){e.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:Y.string().max(5e5).describe(`Raw output text from a build tool`),tool:Y.enum([`tsc`,`vitest`,`biome`,`git-status`]).optional().describe(`Tool to parse as (auto-detects if omitted)`)}},async({output:e,tool:t})=>{try{let n=k(e.replace(/\\n/g,`
6
- `).replace(/\\t/g,` `),t);return{content:[{type:`text`,text:JSON.stringify(n,null,2)}]}}catch(e){return X.error(`Parse failed`,o(e)),{content:[{type:`text`,text:`Parse failed. Check server logs for details.`}],isError:!0}}})}function Te(e){e.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:Y.enum([`save`,`get`,`list`,`delete`,`add`,`remove`]).describe(`Operation to perform`),name:Y.string().optional().describe(`Workset name (required for all except list)`),files:Y.array(Y.string()).optional().describe(`File paths (required for save, add, remove)`),description:Y.string().optional().describe(`Description (for save)`)}},async({action:e,name:t,files:n,description:r})=>{try{switch(e){case`save`:{if(!t||!n)throw Error(`name and files required for save`);let e=K(t,n,{description:r});return{content:[{type:`text`,text:`Saved workset "${e.name}" with ${e.files.length} files.`}]}}case`get`:{if(!t)throw Error(`name required for get`);let e=v(t);return e?{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}:{content:[{type:`text`,text:`Workset "${t}" not found.`}]}}case`list`:{let e=O();return e.length===0?{content:[{type:`text`,text:`No worksets.`}]}:{content:[{type:`text`,text:e.map(e=>`- **${e.name}** (${e.files.length} files) — ${e.description??`no description`}`).join(`
7
- `)}]}}case`delete`:if(!t)throw Error(`name required for delete`);return{content:[{type:`text`,text:ne(t)?`Deleted workset "${t}".`:`Workset "${t}" not found.`}]};case`add`:{if(!t||!n)throw Error(`name and files required for add`);let e=s(t,n);return{content:[{type:`text`,text:`Added to workset "${e.name}": now ${e.files.length} files.`}]}}case`remove`:{if(!t||!n)throw Error(`name and files required for remove`);let e=W(t,n);return e?{content:[{type:`text`,text:`Removed from workset "${e.name}": now ${e.files.length} files.`}]}:{content:[{type:`text`,text:`Workset "${t}" not found.`}]}}}}catch(e){return X.error(`Workset operation failed`,o(e)),{content:[{type:`text`,text:`Workset operation failed. Check server logs for details.`}],isError:!0}}})}function Ee(e){e.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:Y.array(Y.string()).optional().describe(`Specific files to check (if omitted, checks all)`),cwd:Y.string().optional().describe(`Working directory`),skip_types:Y.boolean().default(!1).describe(`Skip TypeScript typecheck`),skip_lint:Y.boolean().default(!1).describe(`Skip Biome lint`),detail:Y.enum([`summary`,`errors`,`full`]).default(`summary`).describe(`Output detail level: summary (default, ~300 tokens — pass/fail + counts + top errors), errors (parsed error objects), full (includes raw terminal output)`)}},async({files:e,cwd:t,skip_types:n,skip_lint:r,detail:i})=>{try{let a=await l({files:e,cwd:t,skipTypes:n,skipLint:r,detail:i===`summary`?`errors`:i});if(i===`summary`){let e=me(a),t=[];if(a.passed)t.push({tool:`test_run`,reason:`Types and lint clean — run tests next`});else{let e=a.tsc.errors[0]?.file??a.biome.errors[0]?.file;e&&t.push({tool:`symbol`,reason:`Resolve failing symbol in ${e}`,suggested_args:{name:e}}),t.push({tool:`check`,reason:`Re-check after fixing errors`,suggested_args:{detail:`errors`}})}return{content:[{type:`text`,text:JSON.stringify({...e,_next:t},null,2)}]}}return{content:[{type:`text`,text:JSON.stringify(a,null,2)}]}}catch(e){return X.error(`Check failed`,o(e)),{content:[{type:`text`,text:`Check failed. Check server logs for details.`}],isError:!0}}})}function De(e,t,n){e.registerTool(`batch`,{description:`Execute multiple built-in operations in parallel with concurrency control. Supported operation types: search, find, and check.`,inputSchema:{operations:Y.array(Y.object({id:Y.string().describe(`Unique ID for this operation`),type:Y.enum([`search`,`find`,`check`]).describe(`Built-in operation type`),args:Y.record(Y.string(),Y.unknown()).describe(`Arguments for the operation`)})).min(1).max(100).describe(`Operations to execute`),concurrency:Y.number().min(1).max(20).default(4).describe(`Max concurrent operations`)}},async({operations:e,concurrency:r})=>{try{let i=await c(e,async e=>Xe(e,t,n),{concurrency:r});return{content:[{type:`text`,text:JSON.stringify(i,null,2)}]}}catch(e){return X.error(`Batch failed`,o(e)),{content:[{type:`text`,text:`Batch failed. Check server logs for details.`}],isError:!0}}})}function Oe(e,r,a,s){e.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:Y.string().describe(`Symbol name to look up (function, class, type, etc.)`),limit:Y.number().min(1).max(50).default(20).describe(`Max results per category`),workspaces:Y.array(Y.string()).optional().describe(`Cross-workspace search: partition names or folder basenames to include. Use ["*"] for all. User-level mode only.`)}},async({name:e,limit:c,workspaces:l})=>{try{let o=await q(r,a,{name:e,limit:c,graphStore:s});if(l&&l.length>0){let a=n(l,i(process.cwd()));if(a.length>0){let{stores:n,closeAll:i}=await t(a);try{for(let[t,i]of n){let n=await q(r,i,{name:e,limit:c});n.definedIn&&!o.definedIn&&(o.definedIn={...n.definedIn,path:`[${t}] ${n.definedIn.path}`});for(let e of n.referencedIn)o.referencedIn.push({...e,path:`[${t}] ${e.path}`});if(n.importedBy){o.importedBy=o.importedBy??[];for(let e of n.importedBy)o.importedBy.push({...e,path:`[${t}] ${e.path}`})}}}finally{await i()}}}return{content:[{type:`text`,text:Qe(o)}]}}catch(e){return X.error(`Symbol lookup failed`,o(e)),{content:[{type:`text`,text:`Symbol lookup failed. Check server logs for details.`}],isError:!0}}})}function ke(e){e.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:Y.string().max(1e5).describe(`Code snippet to execute`),lang:Y.enum([`js`,`ts`]).default(`js`).optional().describe(`Language mode: js executes directly, ts strips common type syntax first`),timeout:Y.number().min(1).max(6e4).default(5e3).optional().describe(`Execution timeout in milliseconds`)}},async({code:e,lang:t,timeout:n})=>{try{let r=ie({code:e,lang:t,timeout:n});return r.success?{content:[{type:`text`,text:`Eval succeeded in ${r.durationMs}ms\n\n${r.output}`}]}:{content:[{type:`text`,text:`Eval failed in ${r.durationMs}ms: ${r.error??`Unknown error`}`}],isError:!0}}catch(e){return X.error(`Eval failed`,o(e)),{content:[{type:`text`,text:`Eval failed. Check server logs for details.`}],isError:!0}}})}function Ae(e){e.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:Y.array(Y.string()).optional().describe(`Specific test files or patterns to run`),grep:Y.string().optional().describe(`Only run tests whose names match this pattern`),cwd:Y.string().optional().describe(`Working directory for the test run`)}},async({files:e,grep:t,cwd:n})=>{try{let r=await he({files:e,grep:t,cwd:n});return{content:[{type:`text`,text:$e(r)}],isError:!r.passed}}catch(e){return X.error(`Test run failed`,o(e)),{content:[{type:`text`,text:`Test run failed. Check server logs for details.`}],isError:!0}}})}function je(e){e.registerTool(`stash`,{description:`Persist and retrieve named values in .kb-state/stash.json for intermediate results between tool calls.`,inputSchema:{action:Y.enum([`set`,`get`,`list`,`delete`,`clear`]).describe(`Operation to perform on the stash`),key:Y.string().optional().describe(`Entry key for set/get/delete operations`),value:Y.string().optional().describe(`String or JSON value for set operations`)}},async({action:e,key:t,value:n})=>{try{switch(e){case`set`:{if(!t)throw Error(`key required for set`);let e=pe(t,rt(n??``));return{content:[{type:`text`,text:`Stored stash entry "${e.key}" (${e.type}) at ${e.storedAt}.`}]}}case`get`:{if(!t)throw Error(`key required for get`);let e=de(t);return{content:[{type:`text`,text:e?JSON.stringify(e,null,2):`Stash entry "${t}" not found.`}]}}case`list`:{let e=fe();return{content:[{type:`text`,text:e.length===0?`Stash is empty.`:e.map(e=>`- ${e.key} (${e.type}) — ${e.storedAt}`).join(`
8
- `)}]}}case`delete`:if(!t)throw Error(`key required for delete`);return{content:[{type:`text`,text:ue(t)?`Deleted stash entry "${t}".`:`Stash entry "${t}" not found.`}]};case`clear`:{let e=le();return{content:[{type:`text`,text:`Cleared ${e} stash entr${e===1?`y`:`ies`}.`}]}}}}catch(e){return X.error(`Stash operation failed`,o(e)),{content:[{type:`text`,text:`Stash operation failed. Check server logs for details.`}],isError:!0}}})}function Me(e){e.registerTool(`git_context`,{description:`Summarize the current Git branch, working tree state, recent commits, and optional diff statistics for the repository.`,inputSchema:{cwd:Y.string().optional().describe(`Repository root or working directory`),commit_count:Y.number().min(1).max(50).default(5).optional().describe(`How many recent commits to include`),include_diff:Y.boolean().default(!1).optional().describe(`Include diff stat for working tree changes`)}},async({cwd:e,commit_count:t,include_diff:n})=>{try{return{content:[{type:`text`,text:et(await y({cwd:e,commitCount:t,includeDiff:n}))}]}}catch(e){return X.error(`Git context failed`,o(e)),{content:[{type:`text`,text:`Git context failed. Check server logs for details.`}],isError:!0}}})}function Ne(e){e.registerTool(`diff_parse`,{description:`Parse raw unified diff text into file-level and hunk-level structural changes.`,inputSchema:{diff:Y.string().max(1e6).describe(`Raw unified diff text`)}},async({diff:e})=>{try{return{content:[{type:`text`,text:tt(re({diff:e.replace(/\\n/g,`
9
- `).replace(/\\t/g,` `)}))}]}}catch(e){return X.error(`Diff parse failed`,o(e)),{content:[{type:`text`,text:`Diff parse failed. Check server logs for details.`}],isError:!0}}})}function Pe(e){e.registerTool(`rename`,{description:`Rename a symbol across files using whole-word regex matching for exports, imports, and general usage references.`,inputSchema:{old_name:Y.string().describe(`Existing symbol name to replace`),new_name:Y.string().describe(`New symbol name to use`),root_path:Y.string().describe(`Root directory to search within`),extensions:Y.array(Y.string()).optional().describe(`Optional file extensions to include, such as .ts,.tsx,.js,.jsx`),dry_run:Y.boolean().default(!0).describe(`Preview changes without writing files`)}},async({old_name:e,new_name:t,root_path:n,extensions:r,dry_run:i})=>{try{let a=await G({oldName:e,newName:t,rootPath:n,extensions:r,dryRun:i});return{content:[{type:`text`,text:JSON.stringify(a,null,2)}]}}catch(e){return X.error(`Rename failed`,o(e)),{content:[{type:`text`,text:`Rename failed. Check server logs for details.`}],isError:!0}}})}function Fe(e){e.registerTool(`codemod`,{description:`Apply regex-based codemod rules across files and return structured before/after changes for each affected line.`,inputSchema:{root_path:Y.string().describe(`Root directory to transform within`),rules:Y.array(Y.object({description:Y.string().describe(`What the codemod rule does`),pattern:Y.string().describe(`Regex pattern in string form`),replacement:Y.string().describe(`Replacement string with optional capture groups`)})).min(1).describe(`Codemod rules to apply`),dry_run:Y.boolean().default(!0).describe(`Preview changes without writing files`)}},async({root_path:e,rules:t,dry_run:n})=>{try{let r=await m({rootPath:e,rules:t,dryRun:n});return{content:[{type:`text`,text:JSON.stringify(r,null,2)}]}}catch(e){return X.error(`Codemod failed`,o(e)),{content:[{type:`text`,text:`Codemod failed. Check server logs for details.`}],isError:!0}}})}function Ie(e,t){e.registerTool(`file_summary`,{description:`Create a concise structural summary of a source file: imports, exports, functions, classes, interfaces, and types.`,inputSchema:{path:Y.string().describe(`Absolute path to the file to summarize`)}},async({path:e})=>{try{return{content:[{type:`text`,text:nt(await ae({path:e,content:(await t.get(e)).content}))}]}}catch(e){return X.error(`File summary failed`,o(e)),{content:[{type:`text`,text:`File summary failed. Check server logs for details.`}],isError:!0}}})}function Le(e){e.registerTool(`checkpoint`,{description:`Save and restore lightweight session checkpoints in .kb-state/checkpoints for cross-session continuity.`,inputSchema:{action:Y.enum([`save`,`load`,`list`,`latest`]).describe(`Checkpoint action to perform`),label:Y.string().optional().describe(`Checkpoint label for save, or checkpoint id for load`),data:Y.string().max(5e5).optional().describe(`JSON object string for save actions`),notes:Y.string().max(1e4).optional().describe(`Optional notes for save actions`)}},async({action:e,label:t,data:n,notes:r})=>{try{switch(e){case`save`:if(!t)throw Error(`label required for save`);return{content:[{type:`text`,text:Q(p(t,it(n),{notes:r}))}]};case`load`:{if(!t)throw Error(`label required for load`);let e=f(t);return{content:[{type:`text`,text:e?Q(e):`Checkpoint "${t}" not found.`}]}}case`list`:{let e=d();return{content:[{type:`text`,text:e.length===0?`No checkpoints saved.`:e.map(e=>`- ${e.id} — ${e.label} (${e.createdAt})`).join(`
10
- `)}]}}case`latest`:{let e=u();return{content:[{type:`text`,text:e?Q(e):`No checkpoints saved.`}]}}}}catch(e){return X.error(`Checkpoint failed`,o(e)),{content:[{type:`text`,text:`Checkpoint failed. Check server logs for details.`}],isError:!0}}})}function Re(e){e.registerTool(`data_transform`,{description:`Apply small jq-like transforms to JSON input for filtering, projection, grouping, and path extraction.`,inputSchema:{input:Y.string().max(5e5).describe(`Input JSON string`),expression:Y.string().max(1e4).describe(`Transform expression to apply`)}},async({input:e,expression:t})=>{try{return{content:[{type:`text`,text:g({input:e,expression:t}).outputString}]}}catch(e){return X.error(`Data transform failed`,o(e)),{content:[{type:`text`,text:`Data transform failed. Check server logs for details.`}],isError:!0}}})}function ze(e,t,n){e.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:Y.string().describe(`Starting point — symbol name or file:line reference`),direction:Y.enum([`forward`,`backward`,`both`]).describe(`Which direction to trace relationships`),max_depth:Y.number().min(1).max(10).default(3).optional().describe(`Maximum trace depth`)}},async({start:e,direction:r,max_depth:i})=>{try{let a=await ge(t,n,{start:e,direction:r,maxDepth:i}),o=[`## Trace: ${a.start}`,`Direction: ${a.direction} | Depth: ${a.depth}`,``];if(a.nodes.length===0)o.push(`No connections found.`);else{let e=a.nodes.filter(e=>e.relationship===`calls`),t=a.nodes.filter(e=>e.relationship===`called-by`),n=a.nodes.filter(e=>e.relationship===`imports`),r=a.nodes.filter(e=>e.relationship===`imported-by`),i=a.nodes.filter(e=>e.relationship===`references`);if(e.length>0){o.push(`### Calls (${e.length})`);for(let t of e){let e=t.scope?` (from ${t.scope}())`:``;o.push(`- ${t.symbol}() — ${t.path}:${t.line}${e}`)}o.push(``)}if(t.length>0){o.push(`### Called by (${t.length})`);for(let e of t){let t=e.scope?` in ${e.scope}()`:``;o.push(`- ${e.symbol}()${t} — ${e.path}:${e.line}`)}o.push(``)}if(n.length>0){o.push(`### Imports (${n.length})`);for(let e of n)o.push(`- ${e.symbol} — ${e.path}:${e.line}`);o.push(``)}if(r.length>0){o.push(`### Imported by (${r.length})`);for(let e of r)o.push(`- ${e.path}:${e.line}`);o.push(``)}if(i.length>0){o.push(`### References (${i.length})`);for(let e of i)o.push(`- ${e.path}:${e.line}`);o.push(``)}}return o.push(`---`,"_Next: `symbol` for definition details | `compact` to read a referenced file | `blast_radius` for impact analysis_"),{content:[{type:`text`,text:o.join(`
11
- `)}]}}catch(e){return X.error(`Trace failed`,o(e)),{content:[{type:`text`,text:`Trace failed. Check server logs for details.`}],isError:!0}}})}function Be(e){e.registerTool(`process`,{description:`Start, stop, inspect, list, and tail logs for in-memory managed child processes.`,inputSchema:{action:Y.enum([`start`,`stop`,`status`,`list`,`logs`]).describe(`Process action to perform`),id:Y.string().optional().describe(`Managed process ID`),command:Y.string().optional().describe(`Executable to start`),args:Y.array(Y.string()).optional().describe(`Arguments for start actions`),tail:Y.number().min(1).max(500).optional().describe(`Log lines to return for logs actions`)}},async({action:e,id:t,command:n,args:r,tail:i})=>{try{switch(e){case`start`:if(!t||!n)throw Error(`id and command are required for start`);return{content:[{type:`text`,text:JSON.stringify(M(t,n,r??[]),null,2)}]};case`stop`:if(!t)throw Error(`id is required for stop`);return{content:[{type:`text`,text:JSON.stringify(P(t)??null,null,2)}]};case`status`:if(!t)throw Error(`id is required for status`);return{content:[{type:`text`,text:JSON.stringify(N(t)??null,null,2)}]};case`list`:return{content:[{type:`text`,text:JSON.stringify(A(),null,2)}]};case`logs`:if(!t)throw Error(`id is required for logs`);return{content:[{type:`text`,text:JSON.stringify(j(t,i),null,2)}]}}}catch(e){return X.error(`Process action failed`,o(e)),{content:[{type:`text`,text:`Process action failed. Check server logs for details.`}],isError:!0}}})}function Ve(e){e.registerTool(`watch`,{description:`Start, stop, and list in-memory filesystem watchers for a directory.`,inputSchema:{action:Y.enum([`start`,`stop`,`list`]).describe(`Watch action to perform`),path:Y.string().optional().describe(`Directory path to watch for start actions`),id:Y.string().optional().describe(`Watcher ID for stop actions`)}},async({action:e,path:t,id:n})=>{try{switch(e){case`start`:if(!t)throw Error(`path is required for start`);return{content:[{type:`text`,text:JSON.stringify(ve({path:t}),null,2)}]};case`stop`:if(!n)throw Error(`id is required for stop`);return{content:[{type:`text`,text:JSON.stringify({stopped:ye(n)},null,2)}]};case`list`:return{content:[{type:`text`,text:JSON.stringify(_e(),null,2)}]}}}catch(e){return X.error(`Watch action failed`,o(e)),{content:[{type:`text`,text:`Watch action failed. Check server logs for details.`}],isError:!0}}})}function He(e,t,n){e.registerTool(`dead_symbols`,{description:`Find exported symbols that appear to be unused because they are never imported or re-exported.`,inputSchema:{path:Y.string().optional().describe(`Root path to scope the search (default: cwd)`),limit:Y.number().min(1).max(500).default(100).optional().describe(`Maximum exported symbols to scan`)}},async({path:e,limit:r})=>{try{let i=await oe(t,n,{rootPath:e,limit:r}),a=[`## Dead Symbol Analysis`,``,`**Exports scanned:** ${i.totalExports}`,`**Dead in source:** ${i.totalDeadSource} (actionable)`,`**Dead in docs:** ${i.totalDeadDocs} (informational — code samples in .md files)`,``];if(i.deadInSource.length>0){a.push(`### Dead in Source (actionable)`);for(let e of i.deadInSource)a.push(`- \`${e.name}\` (${e.kind}) — ${e.path}:${e.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 — not actionable dead code._`);for(let e of i.deadInDocs.slice(0,5))a.push(`- \`${e.name}\` — ${e.path}:${e.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` — no dead symbols found, validate types and lint_"),{content:[{type:`text`,text:a.join(`
12
- `)}]}}catch(e){return X.error(`Dead symbol scan failed`,o(e)),{content:[{type:`text`,text:`Dead symbol scan failed. Check server logs for details.`}],isError:!0}}})}function Ue(e){e.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:Y.string().max(2e5).describe(`The task or question to send to the local model`),model:Y.string().optional().describe(`Ollama model name (default: first available model)`),system:Y.string().optional().describe(`System prompt for the model`),context:Y.string().max(5e5).optional().describe(`Context text to include before the prompt (e.g. file contents)`),temperature:Y.number().min(0).max(2).default(.3).optional().describe(`Sampling temperature (0=deterministic, default 0.3)`),timeout:Y.number().min(1e3).max(6e5).default(12e4).optional().describe(`Timeout in milliseconds (default 120000)`),action:Y.enum([`generate`,`list_models`]).default(`generate`).optional().describe(`Action: generate a response or list available models`)}},async({prompt:e,model:t,system:n,context:r,temperature:i,timeout:a,action:s})=>{try{if(s===`list_models`){let e=await te();return{content:[{type:`text`,text:JSON.stringify({models:e,count:e.length,_Next:`Use delegate with a model name`},null,2)}]}}let o=await ee({prompt:e,model:t,system:n,context:r,temperature:i,timeout:a});return o.error?{content:[{type:`text`,text:JSON.stringify({error:o.error,model:o.model,durationMs:o.durationMs},null,2)}],isError:!0}:{content:[{type:`text`,text:JSON.stringify({model:o.model,response:o.response,durationMs:o.durationMs,tokenCount:o.tokenCount,_Next:`Use the response in your workflow. stash to save it.`},null,2)}]}}catch(e){return X.error(`Delegate failed`,o(e)),{content:[{type:`text`,text:`Delegate failed. Check server logs for details.`}],isError:!0}}})}function We(e){e.registerTool(`lane`,{description:`Manage verified lanes — isolated file copies for parallel exploration. Create a lane, make changes, diff, merge back, or discard.`,inputSchema:{action:Y.enum([`create`,`list`,`status`,`diff`,`merge`,`discard`]).describe(`Lane action to perform`),name:Y.string().optional().describe(`Lane name (required for create/status/diff/merge/discard)`),files:Y.array(Y.string()).optional().describe(`File paths to copy into the lane (required for create)`)}},async({action:e,name:t,files:n})=>{try{switch(e){case`create`:{if(!t)throw Error(`name is required for create`);if(!n||n.length===0)throw Error(`files are required for create`);let e=S(t,n);return{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}}case`list`:return{content:[{type:`text`,text:JSON.stringify(T(),null,2)}]};case`status`:if(!t)throw Error(`name is required for status`);return{content:[{type:`text`,text:JSON.stringify(D(t),null,2)}]};case`diff`:if(!t)throw Error(`name is required for diff`);return{content:[{type:`text`,text:JSON.stringify(C(t),null,2)}]};case`merge`:if(!t)throw Error(`name is required for merge`);return{content:[{type:`text`,text:JSON.stringify(E(t),null,2)}]};case`discard`:if(!t)throw Error(`name is required for discard`);return{content:[{type:`text`,text:JSON.stringify({discarded:w(t)},null,2)}]}}}catch(e){return X.error(`Lane action failed`,o(e)),{content:[{type:`text`,text:`Lane action failed. Check server logs for details.`}],isError:!0}}})}function Ge(e){e.registerTool(`health`,{description:`Run project health checks — verifies package.json, tsconfig, scripts, lockfile, README, LICENSE, .gitignore.`,inputSchema:{path:Y.string().optional().describe(`Root directory to check (defaults to cwd)`)}},async({path:e})=>{try{let t=x(e);return{content:[{type:`text`,text:JSON.stringify(t,null,2)}]}}catch(e){return X.error(`Health check failed`,o(e)),{content:[{type:`text`,text:`Health check failed. Check server logs for details.`}],isError:!0}}})}function Ke(e){e.registerTool(`queue`,{description:`Manage task queues for sequential agent operations. Push items, take next, mark done/failed, list queues.`,inputSchema:{action:Y.enum([`create`,`push`,`next`,`done`,`fail`,`get`,`list`,`clear`,`delete`]).describe(`Queue action`),name:Y.string().optional().describe(`Queue name (required for most actions)`),title:Y.string().optional().describe(`Item title (required for push)`),id:Y.string().optional().describe(`Item ID (required for done/fail)`),data:Y.unknown().optional().describe(`Arbitrary data to attach to a queue item`),error:Y.string().optional().describe(`Error message (required for fail)`)}},async({action:e,name:t,title:n,id:r,data:i,error:a})=>{try{switch(e){case`create`:if(!t)throw Error(`name is required for create`);return{content:[{type:`text`,text:JSON.stringify(I(t),null,2)}]};case`push`:if(!t)throw Error(`name is required for push`);if(!n)throw Error(`title is required for push`);return{content:[{type:`text`,text:JSON.stringify(U(t,n,i),null,2)}]};case`next`:{if(!t)throw Error(`name is required for next`);let e=H(t);return{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}}case`done`:if(!t)throw Error(`name is required for done`);if(!r)throw Error(`id is required for done`);return{content:[{type:`text`,text:JSON.stringify(R(t,r),null,2)}]};case`fail`:if(!t)throw Error(`name is required for fail`);if(!r)throw Error(`id is required for fail`);if(!a)throw Error(`error is required for fail`);return{content:[{type:`text`,text:JSON.stringify(z(t,r,a),null,2)}]};case`get`:if(!t)throw Error(`name is required for get`);return{content:[{type:`text`,text:JSON.stringify(B(t),null,2)}]};case`list`:return{content:[{type:`text`,text:JSON.stringify(V(),null,2)}]};case`clear`:if(!t)throw Error(`name is required for clear`);return{content:[{type:`text`,text:JSON.stringify({cleared:F(t)},null,2)}]};case`delete`:if(!t)throw Error(`name is required for delete`);return{content:[{type:`text`,text:JSON.stringify({deleted:L(t)},null,2)}]}}}catch(e){return X.error(`Queue action failed`,o(e)),{content:[{type:`text`,text:`Queue action failed. Check server logs for details.`}],isError:!0}}})}const qe=Y.object({query:Y.string(),limit:Y.number().min(1).max(20).default(5).optional(),search_mode:Y.enum([`hybrid`,`semantic`,`keyword`]).default(`hybrid`).optional(),content_type:Y.enum(r).optional(),origin:Y.enum([`indexed`,`curated`,`produced`]).optional(),category:Y.string().optional(),tags:Y.array(Y.string()).optional(),min_score:Y.number().min(0).max(1).default(.25).optional()}),Je=Y.object({query:Y.string().optional(),glob:Y.string().optional(),pattern:Y.string().optional(),limit:Y.number().min(1).max(50).default(10).optional(),content_type:Y.enum(r).optional(),cwd:Y.string().optional()}),Ye=Y.object({files:Y.array(Y.string()).optional(),cwd:Y.string().optional(),skip_types:Y.boolean().optional(),skip_lint:Y.boolean().optional()});async function Xe(e,t,n){switch(e.type){case`search`:return Z(t,n,qe.parse(e.args));case`find`:{let r=Je.parse(e.args);if(!r.query&&!r.glob&&!r.pattern)throw Error(`find operation requires query, glob, or pattern`);return _(t,n,{query:r.query,glob:r.glob,pattern:r.pattern,limit:r.limit,contentType:r.content_type,cwd:r.cwd})}case`check`:{let t=Ye.parse(e.args);return l({files:t.files,cwd:t.cwd,skipTypes:t.skip_types,skipLint:t.skip_lint})}default:throw Error(`Unsupported batch operation type: ${e.type}`)}}async function Z(e,t,n){let r=n.limit??5,i={limit:r,minScore:n.min_score??.25,contentType:n.content_type,origin:n.origin,category:n.category,tags:n.tags},a=e.embedQuery?.bind(e)??e.embed.bind(e);if(n.search_mode===`keyword`)return(await t.ftsSearch(n.query,i)).slice(0,r);let o=await a(n.query);if(n.search_mode===`semantic`)return t.search(o,i);let[s,c]=await Promise.all([t.search(o,{...i,limit:r*2}),t.ftsSearch(n.query,{...i,limit:r*2})]);return Ze(s,c).slice(0,r)}function Ze(e,t,n=60){let r=new Map;for(let t=0;t<e.length;t++){let i=e[t];r.set(i.record.id,{record:i.record,score:1/(n+t+1)})}for(let e=0;e<t.length;e++){let i=t[e],a=r.get(i.record.id);if(a){a.score+=1/(n+e+1);continue}r.set(i.record.id,{record:i.record,score:1/(n+e+1)})}return[...r.values()].sort((e,t)=>t.score-e.score)}function Qe(e){let t=[`Symbol: ${e.name}`];if(e.definedIn){let n=`Defined in: ${e.definedIn.path}:${e.definedIn.line} (${e.definedIn.kind})`;e.definedIn.signature&&(n+=`\nSignature: ${e.definedIn.signature}`),t.push(n)}else t.push(`Defined in: not found`);if(t.push(``,`Imported by:`),e.importedBy.length===0)t.push(` none`);else for(let n of e.importedBy)t.push(` - ${n.path}:${n.line} ${n.importStatement}`);if(t.push(``,`Referenced in:`),e.referencedIn.length===0)t.push(` none`);else for(let n of e.referencedIn){let e=`scope`in n&&n.scope?` in ${n.scope}()`:``;t.push(` - ${n.path}:${n.line}${e} ${n.context}`)}if(e.graphContext){let n=e.graphContext;t.push(``,`Graph context:`),n.definingModule&&t.push(` Module: ${n.definingModule}`),n.importedByModules.length>0&&t.push(` Imported by modules: ${n.importedByModules.join(`, `)}`),n.siblingSymbols.length>0&&t.push(` Sibling symbols: ${n.siblingSymbols.join(`, `)}`)}return t.join(`
13
- `)}function $e(e){let t=[`Vitest run: ${e.passed?`passed`:`failed`}`,`Duration: ${e.durationMs}ms`,`Passed: ${e.summary.passed}`,`Failed: ${e.summary.failed}`,`Skipped: ${e.summary.skipped}`];e.summary.suites!==void 0&&t.push(`Suites: ${e.summary.suites}`);let n=e.summary.tests.filter(e=>e.status===`fail`);if(n.length>0){t.push(``,`Failed tests:`);for(let e of n)t.push(`- ${e.name}${e.file?` (${e.file})`:``}`),e.error&&t.push(` ${e.error}`)}return t.join(`
14
- `)}function et(e){let t=[`Branch: ${e.branch}`,`Staged: ${e.status.staged.length}`,...e.status.staged.map(e=>` - ${e}`),`Modified: ${e.status.modified.length}`,...e.status.modified.map(e=>` - ${e}`),`Untracked: ${e.status.untracked.length}`,...e.status.untracked.map(e=>` - ${e}`),``,`Recent commits:`];if(e.recentCommits.length===0)t.push(` none`);else for(let n of e.recentCommits)t.push(` - ${n.hash} ${n.message}`),t.push(` ${n.author} @ ${n.date}`);return e.diff&&t.push(``,`Diff stat:`,e.diff),t.join(`
15
- `)}function tt(e){if(e.length===0)return`No diff files found.`;let t=[];for(let n of e){let e=n.oldPath?` (from ${n.oldPath})`:``;t.push(`${n.path}${e} [${n.status}] +${n.additions} -${n.deletions} (${n.hunks.length} hunks)`);for(let e of n.hunks){let n=e.header?` ${e.header}`:``;t.push(` @@ -${e.oldStart},${e.oldLines} +${e.newStart},${e.newLines} @@${n}`)}}return t.join(`
16
- `)}function nt(e){let t=[e.path,`Language: ${e.language}`,`Lines: ${e.lines}`,`Estimated tokens: ~${e.estimatedTokens}`,``,`Imports (${e.imports.length}):`,...$(e.imports),``,`Exports (${e.exports.length}):`,...$(e.exports),``,`Functions (${e.functions.length}):`,...$(e.functions.map(e=>`${e.name} @ line ${e.line}${e.exported?` [exported]`:``}${`signature`in e&&e.signature?` — ${e.signature}`:``}`)),``,`Classes (${e.classes.length}):`,...$(e.classes.map(e=>`${e.name} @ line ${e.line}${e.exported?` [exported]`:``}${e.signature?` — ${e.signature}`:``}`)),``,`Interfaces (${e.interfaces.length}):`,...$(e.interfaces.map(e=>`${e.name} @ line ${e.line}${`exported`in e&&e.exported?` [exported]`:``}`)),``,`Types (${e.types.length}):`,...$(e.types.map(e=>`${e.name} @ line ${e.line}${`exported`in e&&e.exported?` [exported]`:``}`))];if(`importDetails`in e&&e.importDetails&&e.importDetails.length>0){let n=e.importDetails.filter(e=>e.isExternal).length,r=e.importDetails.length-n;t.push(``,`Import breakdown: ${n} external, ${r} internal`)}if(`callEdges`in e&&e.callEdges&&e.callEdges.length>0){t.push(``,`Call edges (${e.callEdges.length} intra-file):`);for(let n of e.callEdges.slice(0,30))t.push(` - ${n.caller}() → ${n.callee}() @ line ${n.line}`);e.callEdges.length>30&&t.push(` - ... ${e.callEdges.length-30} more`)}return t.join(`
5
+ `)}]}}catch(e){return X.error(`Find failed`,l(e)),{content:[{type:`text`,text:`Find failed. Check server logs for details.`}],isError:!0}}})}function Ee(t){let n=e(`parse_output`);t.registerTool(`parse_output`,{title:n.title,description:`Parse structured data from build tool output. Supports tsc, vitest, biome, and git status. Auto-detects the tool or specify explicitly.`,inputSchema:{output:a.string().max(5e5).describe(`Raw output text from a build tool`),tool:a.enum([`tsc`,`vitest`,`biome`,`git-status`]).optional().describe(`Tool to parse as (auto-detects if omitted)`)},annotations:n.annotations},async({output:e,tool:t})=>{try{let n=N(e.replace(/\\n/g,`
6
+ `).replace(/\\t/g,` `),t);return{content:[{type:`text`,text:JSON.stringify(n,null,2)}]}}catch(e){return X.error(`Parse failed`,l(e)),{content:[{type:`text`,text:`Parse failed. Check server logs for details.`}],isError:!0}}})}function De(t){let n=e(`workset`);t.registerTool(`workset`,{title:n.title,description:`Manage named file sets (worksets). Save, load, list, add/remove files. Worksets persist across sessions in .kb-state/worksets.json.`,inputSchema:{action:a.enum([`save`,`get`,`list`,`delete`,`add`,`remove`]).describe(`Operation to perform`),name:a.string().optional().describe(`Workset name (required for all except list)`),files:a.array(a.string()).optional().describe(`File paths (required for save, add, remove)`),description:a.string().optional().describe(`Description (for save)`)},annotations:n.annotations},async({action:e,name:t,files:n,description:r})=>{try{switch(e){case`save`:{if(!t||!n)throw Error(`name and files required for save`);let e=le(t,n,{description:r});return{content:[{type:`text`,text:`Saved workset "${e.name}" with ${e.files.length} files.`}]}}case`get`:{if(!t)throw Error(`name required for get`);let e=S(t);return e?{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}:{content:[{type:`text`,text:`Workset "${t}" not found.`}]}}case`list`:{let e=M();return e.length===0?{content:[{type:`text`,text:`No worksets.`}]}:{content:[{type:`text`,text:e.map(e=>`- **${e.name}** (${e.files.length} files) — ${e.description??`no description`}`).join(`
7
+ `)}]}}case`delete`:if(!t)throw Error(`name required for delete`);return{content:[{type:`text`,text:ie(t)?`Deleted workset "${t}".`:`Workset "${t}" not found.`}]};case`add`:{if(!t||!n)throw Error(`name and files required for add`);let e=u(t,n);return{content:[{type:`text`,text:`Added to workset "${e.name}": now ${e.files.length} files.`}]}}case`remove`:{if(!t||!n)throw Error(`name and files required for remove`);let e=se(t,n);return e?{content:[{type:`text`,text:`Removed from workset "${e.name}": now ${e.files.length} files.`}]}:{content:[{type:`text`,text:`Workset "${t}" not found.`}]}}}}catch(e){return X.error(`Workset operation failed`,l(e)),{content:[{type:`text`,text:`Workset operation failed. Check server logs for details.`}],isError:!0}}})}function Oe(t){let n=e(`check`);t.registerTool(`check`,{title:n.title,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:a.array(a.string()).optional().describe(`Specific files to check (if omitted, checks all)`),cwd:a.string().optional().describe(`Working directory`),skip_types:a.boolean().default(!1).describe(`Skip TypeScript typecheck`),skip_lint:a.boolean().default(!1).describe(`Skip Biome lint`),detail:a.enum([`summary`,`errors`,`full`]).default(`summary`).describe(`Output detail level: summary (default, ~300 tokens — pass/fail + counts + top errors), errors (parsed error objects), full (includes raw terminal output)`)},annotations:n.annotations},async({files:e,cwd:t,skip_types:n,skip_lint:r,detail:i})=>{try{let a=await f({files:e,cwd:t,skipTypes:n,skipLint:r,detail:i===`summary`?`errors`:i});if(i===`summary`){let e=ge(a),t=[];if(a.passed)t.push({tool:`test_run`,reason:`Types and lint clean — run tests next`});else{let e=a.tsc.errors[0]?.file??a.biome.errors[0]?.file;e&&t.push({tool:`symbol`,reason:`Resolve failing symbol in ${e}`,suggested_args:{name:e}}),t.push({tool:`check`,reason:`Re-check after fixing errors`,suggested_args:{detail:`errors`}})}return{content:[{type:`text`,text:JSON.stringify({...e,_next:t},null,2)}]}}return{content:[{type:`text`,text:JSON.stringify(a,null,2)}]}}catch(e){return X.error(`Check failed`,l(e)),{content:[{type:`text`,text:`Check failed. Check server logs for details.`}],isError:!0}}})}function ke(t,n,r){let i=e(`batch`);t.registerTool(`batch`,{title:i.title,description:`Execute multiple built-in operations in parallel with concurrency control. Supported operation types: search, find, and check.`,inputSchema:{operations:a.array(a.object({id:a.string().describe(`Unique ID for this operation`),type:a.enum([`search`,`find`,`check`]).describe(`Built-in operation type`),args:a.record(a.string(),a.unknown()).describe(`Arguments for the operation`)})).min(1).max(100).describe(`Operations to execute`),concurrency:a.number().min(1).max(20).default(4).describe(`Max concurrent operations`)},annotations:i.annotations},async({operations:e,concurrency:t})=>{try{let i=await d(e,async e=>Ze(e,n,r),{concurrency:t});return{content:[{type:`text`,text:JSON.stringify(i,null,2)}]}}catch(e){return X.error(`Batch failed`,l(e)),{content:[{type:`text`,text:`Batch failed. Check server logs for details.`}],isError:!0}}})}function Ae(t,i,o,c){let u=e(`symbol`);t.registerTool(`symbol`,{title:u.title,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:a.string().describe(`Symbol name to look up (function, class, type, etc.)`),limit:a.number().min(1).max(50).default(20).describe(`Max results per category`),workspaces:a.array(a.string()).optional().describe(`Cross-workspace search: partition names or folder basenames to include. Use ["*"] for all. User-level mode only.`)},annotations:u.annotations},async({name:e,limit:t,workspaces:a})=>{try{let l=await J(i,o,{name:e,limit:t,graphStore:c});if(a&&a.length>0){let o=r(a,s(process.cwd()));if(o.length>0){let{stores:r,closeAll:a}=await n(o);try{for(let[n,a]of r){let r=await J(i,a,{name:e,limit:t});r.definedIn&&!l.definedIn&&(l.definedIn={...r.definedIn,path:`[${n}] ${r.definedIn.path}`});for(let e of r.referencedIn)l.referencedIn.push({...e,path:`[${n}] ${e.path}`});if(r.importedBy){l.importedBy=l.importedBy??[];for(let e of r.importedBy)l.importedBy.push({...e,path:`[${n}] ${e.path}`})}}}finally{await a()}}}return{content:[{type:`text`,text:et(l)}]}}catch(e){return X.error(`Symbol lookup failed`,l(e)),{content:[{type:`text`,text:`Symbol lookup failed. Check server logs for details.`}],isError:!0}}})}function je(t){let n=e(`eval`);t.registerTool(`eval`,{title:n.title,description:`Execute a JavaScript or TypeScript snippet in a constrained VM sandbox with a timeout. Captures console output and returned values.`,inputSchema:{code:a.string().max(1e5).describe(`Code snippet to execute`),lang:a.enum([`js`,`ts`]).default(`js`).optional().describe(`Language mode: js executes directly, ts strips common type syntax first`),timeout:a.number().min(1).max(6e4).default(5e3).optional().describe(`Execution timeout in milliseconds`)},annotations:n.annotations},async({code:e,lang:t,timeout:n})=>{try{let r=oe({code:e,lang:t,timeout:n});return r.success?{content:[{type:`text`,text:`Eval succeeded in ${r.durationMs}ms\n\n${r.output}`}]}:{content:[{type:`text`,text:`Eval failed in ${r.durationMs}ms: ${r.error??`Unknown error`}`}],isError:!0}}catch(e){return X.error(`Eval failed`,l(e)),{content:[{type:`text`,text:`Eval failed. Check server logs for details.`}],isError:!0}}})}function Me(t){let n=e(`test_run`);t.registerTool(`test_run`,{title:n.title,description:`Run Vitest for the current project or a subset of files, then return a structured summary of passing and failing tests.`,inputSchema:{files:a.array(a.string()).optional().describe(`Specific test files or patterns to run`),grep:a.string().optional().describe(`Only run tests whose names match this pattern`),cwd:a.string().optional().describe(`Working directory for the test run`)},annotations:n.annotations},async({files:e,grep:t,cwd:n})=>{try{let r=await _e({files:e,grep:t,cwd:n});return{content:[{type:`text`,text:tt(r)}],isError:!r.passed}}catch(e){return X.error(`Test run failed`,l(e)),{content:[{type:`text`,text:`Test run failed. Check server logs for details.`}],isError:!0}}})}function Ne(t){let n=e(`stash`);t.registerTool(`stash`,{title:n.title,description:`Persist and retrieve named values in .kb-state/stash.json for intermediate results between tool calls.`,inputSchema:{action:a.enum([`set`,`get`,`list`,`delete`,`clear`]).describe(`Operation to perform on the stash`),key:a.string().optional().describe(`Entry key for set/get/delete operations`),value:a.string().optional().describe(`String or JSON value for set operations`)},annotations:n.annotations},async({action:e,key:t,value:n})=>{try{switch(e){case`set`:{if(!t)throw Error(`key required for set`);let e=he(t,at(n??``));return{content:[{type:`text`,text:`Stored stash entry "${e.key}" (${e.type}) at ${e.storedAt}.`}]}}case`get`:{if(!t)throw Error(`key required for get`);let e=pe(t);return{content:[{type:`text`,text:e?JSON.stringify(e,null,2):`Stash entry "${t}" not found.`}]}}case`list`:{let e=me();return{content:[{type:`text`,text:e.length===0?`Stash is empty.`:e.map(e=>`- ${e.key} (${e.type}) — ${e.storedAt}`).join(`
8
+ `)}]}}case`delete`:if(!t)throw Error(`key required for delete`);return{content:[{type:`text`,text:fe(t)?`Deleted stash entry "${t}".`:`Stash entry "${t}" not found.`}]};case`clear`:{let e=de();return{content:[{type:`text`,text:`Cleared ${e} stash entr${e===1?`y`:`ies`}.`}]}}}}catch(e){return X.error(`Stash operation failed`,l(e)),{content:[{type:`text`,text:`Stash operation failed. Check server logs for details.`}],isError:!0}}})}function Pe(t){let n=e(`git_context`);t.registerTool(`git_context`,{title:n.title,description:`Summarize the current Git branch, working tree state, recent commits, and optional diff statistics for the repository.`,inputSchema:{cwd:a.string().optional().describe(`Repository root or working directory`),commit_count:a.number().min(1).max(50).default(5).optional().describe(`How many recent commits to include`),include_diff:a.boolean().default(!1).optional().describe(`Include diff stat for working tree changes`)},annotations:n.annotations},async({cwd:e,commit_count:t,include_diff:n})=>{try{return{content:[{type:`text`,text:nt(await C({cwd:e,commitCount:t,includeDiff:n}))}]}}catch(e){return X.error(`Git context failed`,l(e)),{content:[{type:`text`,text:`Git context failed. Check server logs for details.`}],isError:!0}}})}function Fe(t){let n=e(`diff_parse`);t.registerTool(`diff_parse`,{title:n.title,description:`Parse raw unified diff text into file-level and hunk-level structural changes.`,inputSchema:{diff:a.string().max(1e6).describe(`Raw unified diff text`)},annotations:n.annotations},async({diff:e})=>{try{return{content:[{type:`text`,text:rt(ae({diff:e.replace(/\\n/g,`
9
+ `).replace(/\\t/g,` `)}))}]}}catch(e){return X.error(`Diff parse failed`,l(e)),{content:[{type:`text`,text:`Diff parse failed. Check server logs for details.`}],isError:!0}}})}function Ie(t){let n=e(`rename`);t.registerTool(`rename`,{title:n.title,description:`Rename a symbol across files using whole-word regex matching for exports, imports, and general usage references.`,inputSchema:{old_name:a.string().describe(`Existing symbol name to replace`),new_name:a.string().describe(`New symbol name to use`),root_path:a.string().describe(`Root directory to search within`),extensions:a.array(a.string()).optional().describe(`Optional file extensions to include, such as .ts,.tsx,.js,.jsx`),dry_run:a.boolean().default(!0).describe(`Preview changes without writing files`)},annotations:n.annotations},async({old_name:e,new_name:t,root_path:n,extensions:r,dry_run:i})=>{try{let a=await ce({oldName:e,newName:t,rootPath:n,extensions:r,dryRun:i});return{content:[{type:`text`,text:JSON.stringify(a,null,2)}]}}catch(e){return X.error(`Rename failed`,l(e)),{content:[{type:`text`,text:`Rename failed. Check server logs for details.`}],isError:!0}}})}function Le(t){let n=e(`codemod`);t.registerTool(`codemod`,{title:n.title,description:`Apply regex-based codemod rules across files and return structured before/after changes for each affected line.`,inputSchema:{root_path:a.string().describe(`Root directory to transform within`),rules:a.array(a.object({description:a.string().describe(`What the codemod rule does`),pattern:a.string().describe(`Regex pattern in string form`),replacement:a.string().describe(`Replacement string with optional capture groups`)})).min(1).describe(`Codemod rules to apply`),dry_run:a.boolean().default(!0).describe(`Preview changes without writing files`)},annotations:n.annotations},async({root_path:e,rules:t,dry_run:n})=>{try{let r=await _({rootPath:e,rules:t,dryRun:n});return{content:[{type:`text`,text:JSON.stringify(r,null,2)}]}}catch(e){return X.error(`Codemod failed`,l(e)),{content:[{type:`text`,text:`Codemod failed. Check server logs for details.`}],isError:!0}}})}function Re(t,n){let r=e(`file_summary`);t.registerTool(`file_summary`,{title:r.title,description:`Create a concise structural summary of a source file: imports, exports, functions, classes, interfaces, and types.`,inputSchema:{path:a.string().describe(`Absolute path to the file to summarize`)},annotations:r.annotations},async({path:e})=>{try{return{content:[{type:`text`,text:it(await v({path:e,content:(await n.get(e)).content}))}]}}catch(e){return X.error(`File summary failed`,l(e)),{content:[{type:`text`,text:`File summary failed. Check server logs for details.`}],isError:!0}}})}function ze(t){let n=e(`checkpoint`);t.registerTool(`checkpoint`,{title:n.title,description:`Save and restore lightweight session checkpoints in .kb-state/checkpoints for cross-session continuity.`,inputSchema:{action:a.enum([`save`,`load`,`list`,`latest`]).describe(`Checkpoint action to perform`),label:a.string().optional().describe(`Checkpoint label for save, or checkpoint id for load`),data:a.string().max(5e5).optional().describe(`JSON object string for save actions`),notes:a.string().max(1e4).optional().describe(`Optional notes for save actions`)},annotations:n.annotations},async({action:e,label:t,data:n,notes:r})=>{try{switch(e){case`save`:if(!t)throw Error(`label required for save`);return{content:[{type:`text`,text:Q(g(t,ot(n),{notes:r}))}]};case`load`:{if(!t)throw Error(`label required for load`);let e=h(t);return{content:[{type:`text`,text:e?Q(e):`Checkpoint "${t}" not found.`}]}}case`list`:{let e=m();return{content:[{type:`text`,text:e.length===0?`No checkpoints saved.`:e.map(e=>`- ${e.id} — ${e.label} (${e.createdAt})`).join(`
10
+ `)}]}}case`latest`:{let e=p();return{content:[{type:`text`,text:e?Q(e):`No checkpoints saved.`}]}}}}catch(e){return X.error(`Checkpoint failed`,l(e)),{content:[{type:`text`,text:`Checkpoint failed. Check server logs for details.`}],isError:!0}}})}function Be(t){let n=e(`data_transform`);t.registerTool(`data_transform`,{title:n.title,description:`Apply small jq-like transforms to JSON input for filtering, projection, grouping, and path extraction.`,inputSchema:{input:a.string().max(5e5).describe(`Input JSON string`),expression:a.string().max(1e4).describe(`Transform expression to apply`)},annotations:n.annotations},async({input:e,expression:t})=>{try{return{content:[{type:`text`,text:te({input:e,expression:t}).outputString}]}}catch(e){return X.error(`Data transform failed`,l(e)),{content:[{type:`text`,text:`Data transform failed. Check server logs for details.`}],isError:!0}}})}function Ve(t,n,r){let i=e(`trace`);t.registerTool(`trace`,{title:i.title,description:`Trace data flow through a codebase by following imports, call sites, and references from a starting symbol or file location.`,inputSchema:{start:a.string().describe(`Starting point — symbol name or file:line reference`),direction:a.enum([`forward`,`backward`,`both`]).describe(`Which direction to trace relationships`),max_depth:a.number().min(1).max(10).default(3).optional().describe(`Maximum trace depth`)},annotations:i.annotations},async({start:e,direction:t,max_depth:i})=>{try{let a=await ve(n,r,{start:e,direction:t,maxDepth:i}),o=[`## Trace: ${a.start}`,`Direction: ${a.direction} | Depth: ${a.depth}`,``];if(a.nodes.length===0)o.push(`No connections found.`);else{let e=a.nodes.filter(e=>e.relationship===`calls`),t=a.nodes.filter(e=>e.relationship===`called-by`),n=a.nodes.filter(e=>e.relationship===`imports`),r=a.nodes.filter(e=>e.relationship===`imported-by`),i=a.nodes.filter(e=>e.relationship===`references`);if(e.length>0){o.push(`### Calls (${e.length})`);for(let t of e){let e=t.scope?` (from ${t.scope}())`:``;o.push(`- ${t.symbol}() — ${t.path}:${t.line}${e}`)}o.push(``)}if(t.length>0){o.push(`### Called by (${t.length})`);for(let e of t){let t=e.scope?` in ${e.scope}()`:``;o.push(`- ${e.symbol}()${t} — ${e.path}:${e.line}`)}o.push(``)}if(n.length>0){o.push(`### Imports (${n.length})`);for(let e of n)o.push(`- ${e.symbol} — ${e.path}:${e.line}`);o.push(``)}if(r.length>0){o.push(`### Imported by (${r.length})`);for(let e of r)o.push(`- ${e.path}:${e.line}`);o.push(``)}if(i.length>0){o.push(`### References (${i.length})`);for(let e of i)o.push(`- ${e.path}:${e.line}`);o.push(``)}}return o.push(`---`,"_Next: `symbol` for definition details | `compact` to read a referenced file | `blast_radius` for impact analysis_"),{content:[{type:`text`,text:o.join(`
11
+ `)}]}}catch(e){return X.error(`Trace failed`,l(e)),{content:[{type:`text`,text:`Trace failed. Check server logs for details.`}],isError:!0}}})}function He(t){let n=e(`process`);t.registerTool(`process`,{title:n.title,description:`Start, stop, inspect, list, and tail logs for in-memory managed child processes.`,inputSchema:{action:a.enum([`start`,`stop`,`status`,`list`,`logs`]).describe(`Process action to perform`),id:a.string().optional().describe(`Managed process ID`),command:a.string().optional().describe(`Executable to start`),args:a.array(a.string()).optional().describe(`Arguments for start actions`),tail:a.number().min(1).max(500).optional().describe(`Log lines to return for logs actions`)},annotations:n.annotations},async({action:e,id:t,command:n,args:r,tail:i})=>{try{switch(e){case`start`:if(!t||!n)throw Error(`id and command are required for start`);return{content:[{type:`text`,text:JSON.stringify(I(t,n,r??[]),null,2)}]};case`stop`:if(!t)throw Error(`id is required for stop`);return{content:[{type:`text`,text:JSON.stringify(R(t)??null,null,2)}]};case`status`:if(!t)throw Error(`id is required for status`);return{content:[{type:`text`,text:JSON.stringify(L(t)??null,null,2)}]};case`list`:return{content:[{type:`text`,text:JSON.stringify(P(),null,2)}]};case`logs`:if(!t)throw Error(`id is required for logs`);return{content:[{type:`text`,text:JSON.stringify(F(t,i),null,2)}]}}}catch(e){return X.error(`Process action failed`,l(e)),{content:[{type:`text`,text:`Process action failed. Check server logs for details.`}],isError:!0}}})}function Ue(t){let n=e(`watch`);t.registerTool(`watch`,{title:n.title,description:`Start, stop, and list in-memory filesystem watchers for a directory.`,inputSchema:{action:a.enum([`start`,`stop`,`list`]).describe(`Watch action to perform`),path:a.string().optional().describe(`Directory path to watch for start actions`),id:a.string().optional().describe(`Watcher ID for stop actions`)},annotations:n.annotations},async({action:e,path:t,id:n})=>{try{switch(e){case`start`:if(!t)throw Error(`path is required for start`);return{content:[{type:`text`,text:JSON.stringify(be({path:t}),null,2)}]};case`stop`:if(!n)throw Error(`id is required for stop`);return{content:[{type:`text`,text:JSON.stringify({stopped:xe(n)},null,2)}]};case`list`:return{content:[{type:`text`,text:JSON.stringify(ye(),null,2)}]}}}catch(e){return X.error(`Watch action failed`,l(e)),{content:[{type:`text`,text:`Watch action failed. Check server logs for details.`}],isError:!0}}})}function We(t,n,r){let i=e(`dead_symbols`);t.registerTool(`dead_symbols`,{title:i.title,description:`Find exported symbols that appear to be unused because they are never imported or re-exported.`,inputSchema:{path:a.string().optional().describe(`Root path to scope the search (default: cwd)`),limit:a.number().min(1).max(500).default(100).optional().describe(`Maximum exported symbols to scan`)},annotations:i.annotations},async({path:e,limit:t})=>{try{let i=await b(n,r,{rootPath:e,limit:t}),a=[`## Dead Symbol Analysis`,``,`**Exports scanned:** ${i.totalExports}`,`**Dead in source:** ${i.totalDeadSource} (actionable)`,`**Dead in docs:** ${i.totalDeadDocs} (informational — code samples in .md files)`,``];if(i.deadInSource.length>0){a.push(`### Dead in Source (actionable)`);for(let e of i.deadInSource)a.push(`- \`${e.name}\` (${e.kind}) — ${e.path}:${e.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 — not actionable dead code._`);for(let e of i.deadInDocs.slice(0,5))a.push(`- \`${e.name}\` — ${e.path}:${e.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` — no dead symbols found, validate types and lint_"),{content:[{type:`text`,text:a.join(`
12
+ `)}]}}catch(e){return X.error(`Dead symbol scan failed`,l(e)),{content:[{type:`text`,text:`Dead symbol scan failed. Check server logs for details.`}],isError:!0}}})}function Ge(t){let n=e(`delegate`);t.registerTool(`delegate`,{title:n.title,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:a.string().max(2e5).describe(`The task or question to send to the local model`),model:a.string().optional().describe(`Ollama model name (default: first available model)`),system:a.string().optional().describe(`System prompt for the model`),context:a.string().max(5e5).optional().describe(`Context text to include before the prompt (e.g. file contents)`),temperature:a.number().min(0).max(2).default(.3).optional().describe(`Sampling temperature (0=deterministic, default 0.3)`),timeout:a.number().min(1e3).max(6e5).default(12e4).optional().describe(`Timeout in milliseconds (default 120000)`),action:a.enum([`generate`,`list_models`]).default(`generate`).optional().describe(`Action: generate a response or list available models`)},annotations:n.annotations},async({prompt:e,model:t,system:n,context:r,temperature:i,timeout:a,action:o})=>{try{if(o===`list_models`){let e=await re();return{content:[{type:`text`,text:JSON.stringify({models:e,count:e.length,_Next:`Use delegate with a model name`},null,2)}]}}let s=await ne({prompt:e,model:t,system:n,context:r,temperature:i,timeout:a});return s.error?{content:[{type:`text`,text:JSON.stringify({error:s.error,model:s.model,durationMs:s.durationMs},null,2)}],isError:!0}:{content:[{type:`text`,text:JSON.stringify({model:s.model,response:s.response,durationMs:s.durationMs,tokenCount:s.tokenCount,_Next:`Use the response in your workflow. stash to save it.`},null,2)}]}}catch(e){return X.error(`Delegate failed`,l(e)),{content:[{type:`text`,text:`Delegate failed. Check server logs for details.`}],isError:!0}}})}function Ke(t){let n=e(`lane`);t.registerTool(`lane`,{title:n.title,description:`Manage verified lanes — isolated file copies for parallel exploration. Create a lane, make changes, diff, merge back, or discard.`,inputSchema:{action:a.enum([`create`,`list`,`status`,`diff`,`merge`,`discard`]).describe(`Lane action to perform`),name:a.string().optional().describe(`Lane name (required for create/status/diff/merge/discard)`),files:a.array(a.string()).optional().describe(`File paths to copy into the lane (required for create)`)},annotations:n.annotations},async({action:e,name:t,files:n})=>{try{switch(e){case`create`:{if(!t)throw Error(`name is required for create`);if(!n||n.length===0)throw Error(`files are required for create`);let e=E(t,n);return{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}}case`list`:return{content:[{type:`text`,text:JSON.stringify(k(),null,2)}]};case`status`:if(!t)throw Error(`name is required for status`);return{content:[{type:`text`,text:JSON.stringify(j(t),null,2)}]};case`diff`:if(!t)throw Error(`name is required for diff`);return{content:[{type:`text`,text:JSON.stringify(D(t),null,2)}]};case`merge`:if(!t)throw Error(`name is required for merge`);return{content:[{type:`text`,text:JSON.stringify(A(t),null,2)}]};case`discard`:if(!t)throw Error(`name is required for discard`);return{content:[{type:`text`,text:JSON.stringify({discarded:O(t)},null,2)}]}}}catch(e){return X.error(`Lane action failed`,l(e)),{content:[{type:`text`,text:`Lane action failed. Check server logs for details.`}],isError:!0}}})}function qe(t){let n=e(`health`);t.registerTool(`health`,{title:n.title,description:`Run project health checks — verifies package.json, tsconfig, scripts, lockfile, README, LICENSE, .gitignore.`,outputSchema:i,inputSchema:{path:a.string().optional().describe(`Root directory to check (defaults to cwd)`)},annotations:n.annotations},async({path:e})=>{try{let t=T(e),n={ok:t.checks.every(e=>e.status!==`fail`),checks:t.checks.map(e=>({name:e.name,ok:e.status===`pass`,message:e.message}))};return{content:[{type:`text`,text:JSON.stringify(t,null,2)}],structuredContent:n}}catch(e){return X.error(`Health check failed`,l(e)),{content:[{type:`text`,text:`Health check failed. Check server logs for details.`}],isError:!0}}})}function Je(t){let n=e(`queue`);t.registerTool(`queue`,{title:n.title,description:`Manage task queues for sequential agent operations. Push items, take next, mark done/failed, list queues.`,inputSchema:{action:a.enum([`create`,`push`,`next`,`done`,`fail`,`get`,`list`,`clear`,`delete`]).describe(`Queue action`),name:a.string().optional().describe(`Queue name (required for most actions)`),title:a.string().optional().describe(`Item title (required for push)`),id:a.string().optional().describe(`Item ID (required for done/fail)`),data:a.unknown().optional().describe(`Arbitrary data to attach to a queue item`),error:a.string().optional().describe(`Error message (required for fail)`)},annotations:n.annotations},async({action:e,name:t,title:n,id:r,data:i,error:a})=>{try{switch(e){case`create`:if(!t)throw Error(`name is required for create`);return{content:[{type:`text`,text:JSON.stringify(B(t),null,2)}]};case`push`:if(!t)throw Error(`name is required for push`);if(!n)throw Error(`title is required for push`);return{content:[{type:`text`,text:JSON.stringify(q(t,n,i),null,2)}]};case`next`:{if(!t)throw Error(`name is required for next`);let e=K(t);return{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}}case`done`:if(!t)throw Error(`name is required for done`);if(!r)throw Error(`id is required for done`);return{content:[{type:`text`,text:JSON.stringify(H(t,r),null,2)}]};case`fail`:if(!t)throw Error(`name is required for fail`);if(!r)throw Error(`id is required for fail`);if(!a)throw Error(`error is required for fail`);return{content:[{type:`text`,text:JSON.stringify(U(t,r,a),null,2)}]};case`get`:if(!t)throw Error(`name is required for get`);return{content:[{type:`text`,text:JSON.stringify(W(t),null,2)}]};case`list`:return{content:[{type:`text`,text:JSON.stringify(G(),null,2)}]};case`clear`:if(!t)throw Error(`name is required for clear`);return{content:[{type:`text`,text:JSON.stringify({cleared:z(t)},null,2)}]};case`delete`:if(!t)throw Error(`name is required for delete`);return{content:[{type:`text`,text:JSON.stringify({deleted:V(t)},null,2)}]}}}catch(e){return X.error(`Queue action failed`,l(e)),{content:[{type:`text`,text:`Queue action failed. Check server logs for details.`}],isError:!0}}})}const Ye=a.object({query:a.string(),limit:a.number().min(1).max(20).default(5).optional(),search_mode:a.enum([`hybrid`,`semantic`,`keyword`]).default(`hybrid`).optional(),content_type:a.enum(o).optional(),origin:a.enum([`indexed`,`curated`,`produced`]).optional(),category:a.string().optional(),tags:a.array(a.string()).optional(),min_score:a.number().min(0).max(1).default(.25).optional()}),Xe=a.object({query:a.string().optional(),glob:a.string().optional(),pattern:a.string().optional(),limit:a.number().min(1).max(50).default(10).optional(),content_type:a.enum(o).optional(),cwd:a.string().optional()}),Z=a.object({files:a.array(a.string()).optional(),cwd:a.string().optional(),skip_types:a.boolean().optional(),skip_lint:a.boolean().optional()});async function Ze(e,t,n){switch(e.type){case`search`:return Qe(t,n,Ye.parse(e.args));case`find`:{let r=Xe.parse(e.args);if(!r.query&&!r.glob&&!r.pattern)throw Error(`find operation requires query, glob, or pattern`);return y(t,n,{query:r.query,glob:r.glob,pattern:r.pattern,limit:r.limit,contentType:r.content_type,cwd:r.cwd})}case`check`:{let t=Z.parse(e.args);return f({files:t.files,cwd:t.cwd,skipTypes:t.skip_types,skipLint:t.skip_lint})}default:throw Error(`Unsupported batch operation type: ${e.type}`)}}async function Qe(e,t,n){let r=n.limit??5,i={limit:r,minScore:n.min_score??.25,contentType:n.content_type,origin:n.origin,category:n.category,tags:n.tags},a=e.embedQuery?.bind(e)??e.embed.bind(e);if(n.search_mode===`keyword`)return(await t.ftsSearch(n.query,i)).slice(0,r);let o=await a(n.query);if(n.search_mode===`semantic`)return t.search(o,i);let[s,c]=await Promise.all([t.search(o,{...i,limit:r*2}),t.ftsSearch(n.query,{...i,limit:r*2})]);return $e(s,c).slice(0,r)}function $e(e,t,n=60){let r=new Map;for(let t=0;t<e.length;t++){let i=e[t];r.set(i.record.id,{record:i.record,score:1/(n+t+1)})}for(let e=0;e<t.length;e++){let i=t[e],a=r.get(i.record.id);if(a){a.score+=1/(n+e+1);continue}r.set(i.record.id,{record:i.record,score:1/(n+e+1)})}return[...r.values()].sort((e,t)=>t.score-e.score)}function et(e){let t=[`Symbol: ${e.name}`];if(e.definedIn){let n=`Defined in: ${e.definedIn.path}:${e.definedIn.line} (${e.definedIn.kind})`;e.definedIn.signature&&(n+=`\nSignature: ${e.definedIn.signature}`),t.push(n)}else t.push(`Defined in: not found`);if(t.push(``,`Imported by:`),e.importedBy.length===0)t.push(` none`);else for(let n of e.importedBy)t.push(` - ${n.path}:${n.line} ${n.importStatement}`);if(t.push(``,`Referenced in:`),e.referencedIn.length===0)t.push(` none`);else for(let n of e.referencedIn){let e=`scope`in n&&n.scope?` in ${n.scope}()`:``;t.push(` - ${n.path}:${n.line}${e} ${n.context}`)}if(e.graphContext){let n=e.graphContext;t.push(``,`Graph context:`),n.definingModule&&t.push(` Module: ${n.definingModule}`),n.importedByModules.length>0&&t.push(` Imported by modules: ${n.importedByModules.join(`, `)}`),n.siblingSymbols.length>0&&t.push(` Sibling symbols: ${n.siblingSymbols.join(`, `)}`)}return t.join(`
13
+ `)}function tt(e){let t=[`Vitest run: ${e.passed?`passed`:`failed`}`,`Duration: ${e.durationMs}ms`,`Passed: ${e.summary.passed}`,`Failed: ${e.summary.failed}`,`Skipped: ${e.summary.skipped}`];e.summary.suites!==void 0&&t.push(`Suites: ${e.summary.suites}`);let n=e.summary.tests.filter(e=>e.status===`fail`);if(n.length>0){t.push(``,`Failed tests:`);for(let e of n)t.push(`- ${e.name}${e.file?` (${e.file})`:``}`),e.error&&t.push(` ${e.error}`)}return t.join(`
14
+ `)}function nt(e){let t=[`Branch: ${e.branch}`,`Staged: ${e.status.staged.length}`,...e.status.staged.map(e=>` - ${e}`),`Modified: ${e.status.modified.length}`,...e.status.modified.map(e=>` - ${e}`),`Untracked: ${e.status.untracked.length}`,...e.status.untracked.map(e=>` - ${e}`),``,`Recent commits:`];if(e.recentCommits.length===0)t.push(` none`);else for(let n of e.recentCommits)t.push(` - ${n.hash} ${n.message}`),t.push(` ${n.author} @ ${n.date}`);return e.diff&&t.push(``,`Diff stat:`,e.diff),t.join(`
15
+ `)}function rt(e){if(e.length===0)return`No diff files found.`;let t=[];for(let n of e){let e=n.oldPath?` (from ${n.oldPath})`:``;t.push(`${n.path}${e} [${n.status}] +${n.additions} -${n.deletions} (${n.hunks.length} hunks)`);for(let e of n.hunks){let n=e.header?` ${e.header}`:``;t.push(` @@ -${e.oldStart},${e.oldLines} +${e.newStart},${e.newLines} @@${n}`)}}return t.join(`
16
+ `)}function it(e){let t=[e.path,`Language: ${e.language}`,`Lines: ${e.lines}`,`Estimated tokens: ~${e.estimatedTokens}`,``,`Imports (${e.imports.length}):`,...$(e.imports),``,`Exports (${e.exports.length}):`,...$(e.exports),``,`Functions (${e.functions.length}):`,...$(e.functions.map(e=>`${e.name} @ line ${e.line}${e.exported?` [exported]`:``}${`signature`in e&&e.signature?` — ${e.signature}`:``}`)),``,`Classes (${e.classes.length}):`,...$(e.classes.map(e=>`${e.name} @ line ${e.line}${e.exported?` [exported]`:``}${e.signature?` — ${e.signature}`:``}`)),``,`Interfaces (${e.interfaces.length}):`,...$(e.interfaces.map(e=>`${e.name} @ line ${e.line}${`exported`in e&&e.exported?` [exported]`:``}`)),``,`Types (${e.types.length}):`,...$(e.types.map(e=>`${e.name} @ line ${e.line}${`exported`in e&&e.exported?` [exported]`:``}`))];if(`importDetails`in e&&e.importDetails&&e.importDetails.length>0){let n=e.importDetails.filter(e=>e.isExternal).length,r=e.importDetails.length-n;t.push(``,`Import breakdown: ${n} external, ${r} internal`)}if(`callEdges`in e&&e.callEdges&&e.callEdges.length>0){t.push(``,`Call edges (${e.callEdges.length} intra-file):`);for(let n of e.callEdges.slice(0,30))t.push(` - ${n.caller}() → ${n.callee}() @ line ${n.line}`);e.callEdges.length>30&&t.push(` - ... ${e.callEdges.length-30} more`)}return t.join(`
17
17
  `)}function Q(e){let t=[e.id,`Label: ${e.label}`,`Created: ${e.createdAt}`];if(e.notes&&t.push(`Notes: ${e.notes}`),e.files?.length){t.push(`Files: ${e.files.length}`);for(let n of e.files)t.push(` - ${n}`)}return t.push(``,`Data:`,JSON.stringify(e.data,null,2)),t.join(`
18
- `)}function $(e){return e.length===0?[` none`]:e.map(e=>` - ${e}`)}function rt(e){let t=e.trim();if(!t)return``;try{return JSON.parse(t)}catch{return e}}function it(e){let t=e?.trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch{throw Error(`data must be a valid JSON object string`)}if(!n||typeof n!=`object`||Array.isArray(n))throw Error(`data must be a JSON object string`);return n}function at(e){e.registerTool(`web_fetch`,{description:`PREFERRED web fetcher — 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:Y.string().url().describe(`URL to fetch (http/https only)`),mode:Y.enum([`markdown`,`raw`,`links`,`outline`]).default(`markdown`).describe(`Output mode: markdown (clean content), raw (HTML), links (extracted URLs), outline (heading hierarchy)`),selector:Y.string().optional().describe(`CSS selector to extract a specific element instead of auto-detecting main content`),max_length:Y.number().min(500).max(1e5).default(15e3).describe(`Max characters in output — truncates at paragraph boundaries`),include_metadata:Y.boolean().default(!0).describe(`Include page title, description, and URL as a header`),include_links:Y.boolean().default(!1).describe(`Append extracted links list at the end`),include_images:Y.boolean().default(!1).describe(`Include image alt texts inline`),timeout:Y.number().min(1e3).max(6e4).default(15e3).describe(`Request timeout in milliseconds`)}},async({url:e,mode:t,selector:n,max_length:r,include_metadata:i,include_links:a,include_images:s,timeout:c})=>{try{let o=await be({url:e,mode:t,selector:n,maxLength:r,includeMetadata:i,includeLinks:a,includeImages:s,timeout:c}),l=[`## ${o.title||`Web Page`}`,``,o.content];return o.truncated&&l.push(``,`_Original length: ${o.originalLength.toLocaleString()} chars_`),l.push(``,`---`,"_Next: Use `remember` to save key findings, or `web_fetch` with a `selector` to extract a specific section._"),{content:[{type:`text`,text:l.join(`
19
- `)}]}}catch(e){return X.error(`Web fetch failed`,o(e)),{content:[{type:`text`,text:`Web fetch failed. Check server logs for details.`}],isError:!0}}})}function ot(e){e.registerTool(`guide`,{description:`Tool discovery — 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:Y.string().describe(`What you want to accomplish (e.g., "audit this monorepo", "fix a failing test")`),max_recommendations:Y.number().min(1).max(10).default(5).describe(`Maximum number of tool recommendations`)}},async({goal:e,max_recommendations:t})=>{try{let n=b(e,t),r=[`## Recommended Workflow: **${n.workflow}**`,n.description,``,`### Tools`,...n.tools.map(e=>{let t=e.suggestedArgs?` — \`${JSON.stringify(e.suggestedArgs)}\``:``;return`${e.order}. **${e.tool}** — ${e.reason}${t}`})];return n.alternativeWorkflows.length>0&&r.push(``,`_Alternative workflows: ${n.alternativeWorkflows.join(`, `)}_`),r.push(``,`---`,"_Next: Run the first recommended tool, or use `guide` again with a more specific goal._"),{content:[{type:`text`,text:r.join(`
20
- `)}]}}catch(e){return X.error(`Guide failed`,o(e)),{content:[{type:`text`,text:`Guide failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{De as registerBatchTool,Ee as registerCheckTool,Le as registerCheckpointTool,Fe as registerCodemodTool,xe as registerCompactTool,Re as registerDataTransformTool,He as registerDeadSymbolsTool,Ue as registerDelegateTool,Ne as registerDiffParseTool,ke as registerEvalTool,Ie as registerFileSummaryTool,Ce as registerFindTool,Me as registerGitContextTool,ot as registerGuideTool,Ge as registerHealthTool,We as registerLaneTool,we as registerParseOutputTool,Be as registerProcessTool,Ke as registerQueueTool,Pe as registerRenameTool,Se as registerScopeMapTool,je as registerStashTool,Oe as registerSymbolTool,Ae as registerTestRunTool,ze as registerTraceTool,Ve as registerWatchTool,at as registerWebFetchTool,Te as registerWorksetTool};
18
+ `)}function $(e){return e.length===0?[` none`]:e.map(e=>` - ${e}`)}function at(e){let t=e.trim();if(!t)return``;try{return JSON.parse(t)}catch{return e}}function ot(e){let t=e?.trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch{throw Error(`data must be a valid JSON object string`)}if(!n||typeof n!=`object`||Array.isArray(n))throw Error(`data must be a JSON object string`);return n}function st(t){let n=e(`web_fetch`);t.registerTool(`web_fetch`,{title:n.title,description:`PREFERRED web fetcher — 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:a.string().url().describe(`URL to fetch (http/https only)`),mode:a.enum([`markdown`,`raw`,`links`,`outline`]).default(`markdown`).describe(`Output mode: markdown (clean content), raw (HTML), links (extracted URLs), outline (heading hierarchy)`),selector:a.string().optional().describe(`CSS selector to extract a specific element instead of auto-detecting main content`),max_length:a.number().min(500).max(1e5).default(15e3).describe(`Max characters in output — truncates at paragraph boundaries`),include_metadata:a.boolean().default(!0).describe(`Include page title, description, and URL as a header`),include_links:a.boolean().default(!1).describe(`Append extracted links list at the end`),include_images:a.boolean().default(!1).describe(`Include image alt texts inline`),timeout:a.number().min(1e3).max(6e4).default(15e3).describe(`Request timeout in milliseconds`)},annotations:n.annotations},async({url:e,mode:t,selector:n,max_length:r,include_metadata:i,include_links:a,include_images:o,timeout:s})=>{try{let c=await Se({url:e,mode:t,selector:n,maxLength:r,includeMetadata:i,includeLinks:a,includeImages:o,timeout:s}),l=[`## ${c.title||`Web Page`}`,``,c.content];return c.truncated&&l.push(``,`_Original length: ${c.originalLength.toLocaleString()} chars_`),l.push(``,`---`,"_Next: Use `remember` to save key findings, or `web_fetch` with a `selector` to extract a specific section._"),{content:[{type:`text`,text:l.join(`
19
+ `)}]}}catch(e){return X.error(`Web fetch failed`,l(e)),{content:[{type:`text`,text:`Web fetch failed. Check server logs for details.`}],isError:!0}}})}function ct(t){let n=e(`guide`);t.registerTool(`guide`,{title:n.title,description:`Tool discovery — 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:a.string().describe(`What you want to accomplish (e.g., "audit this monorepo", "fix a failing test")`),max_recommendations:a.number().min(1).max(10).default(5).describe(`Maximum number of tool recommendations`)},annotations:n.annotations},async({goal:e,max_recommendations:t})=>{try{let n=w(e,t),r=[`## Recommended Workflow: **${n.workflow}**`,n.description,``,`### Tools`,...n.tools.map(e=>{let t=e.suggestedArgs?` — \`${JSON.stringify(e.suggestedArgs)}\``:``;return`${e.order}. **${e.tool}** — ${e.reason}${t}`})];return n.alternativeWorkflows.length>0&&r.push(``,`_Alternative workflows: ${n.alternativeWorkflows.join(`, `)}_`),r.push(``,`---`,"_Next: Run the first recommended tool, or use `guide` again with a more specific goal._"),{content:[{type:`text`,text:r.join(`
20
+ `)}]}}catch(e){return X.error(`Guide failed`,l(e)),{content:[{type:`text`,text:`Guide failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{ke as registerBatchTool,Oe as registerCheckTool,ze as registerCheckpointTool,Le as registerCodemodTool,Ce as registerCompactTool,Be as registerDataTransformTool,We as registerDeadSymbolsTool,Ge as registerDelegateTool,Fe as registerDiffParseTool,je as registerEvalTool,Re as registerFileSummaryTool,Te as registerFindTool,Pe as registerGitContextTool,ct as registerGuideTool,qe as registerHealthTool,Ke as registerLaneTool,Ee as registerParseOutputTool,He as registerProcessTool,Je as registerQueueTool,Ie as registerRenameTool,we as registerScopeMapTool,Ne as registerStashTool,Ae as registerSymbolTool,Me as registerTestRunTool,Ve as registerTraceTool,Ue as registerWatchTool,st as registerWebFetchTool,De as registerWorksetTool};
@@ -1 +1 @@
1
- import{createLogger as e,serializeError as t}from"../../../core/dist/index.js";import{z as n}from"zod";const r=e(`tools`);function i(e,i){e.registerTool(`update`,{description:`Update an existing curated knowledge entry. Increments version and records the reason in the changelog.`,inputSchema:{path:n.string().describe(`Relative path within .ai/curated/ (e.g., "decisions/use-lancedb.md")`),content:n.string().min(10).max(1e5).describe(`New markdown content to replace existing content`),reason:n.string().min(3).max(1e3).describe(`Why this update is being made (recorded in changelog)`)}},async({path:e,content:n,reason:a})=>{try{let t=await i.update(e,n,a);return{content:[{type:`text`,text:`Updated: \`.ai/curated/${t.path}\` → version ${t.version}\n\nReason: ${a}\n\n---\n_Next: Use \`read\` to verify the updated content, or \`search\` to test searchability._`}]}}catch(e){return r.error(`Update failed`,t(e)),{content:[{type:`text`,text:`Update failed. Check server logs for details.`}],isError:!0}}})}export{i as registerUpdateTool};
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{createLogger as n,serializeError as r}from"../../../core/dist/index.js";const i=n(`tools`);function a(n,a){let o=e(`update`);n.registerTool(`update`,{title:o.title,description:`Update an existing curated knowledge entry. Increments version and records the reason in the changelog.`,inputSchema:{path:t.string().describe(`Relative path within .ai/curated/ (e.g., "decisions/use-lancedb.md")`),content:t.string().min(10).max(1e5).describe(`New markdown content to replace existing content`),reason:t.string().min(3).max(1e3).describe(`Why this update is being made (recorded in changelog)`)},annotations:o.annotations},async({path:e,content:t,reason:o})=>{try{let r=await a.update(e,t,o);return n.sendResourceListChanged(),{content:[{type:`text`,text:`Updated: \`.ai/curated/${r.path}\` → version ${r.version}\n\nReason: ${o}\n\n---\n_Next: Use \`read\` to verify the updated content, or \`search\` to test searchability._`}]}}catch(e){return i.error(`Update failed`,r(e)),{content:[{type:`text`,text:`Update failed. Check server logs for details.`}],isError:!0}}})}export{a as registerUpdateTool};