@vpxa/kb 0.1.24 → 0.1.26
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.
- package/README.md +3 -3
- package/package.json +9 -2
- package/packages/analyzers/dist/symbol-analyzer.js +5 -5
- package/packages/cli/dist/commands/init/adapters.js +1 -1
- package/packages/cli/dist/commands/init/constants.d.ts +4 -1
- package/packages/cli/dist/commands/init/constants.js +1 -1
- package/packages/cli/dist/commands/init/frontmatter.d.ts +54 -0
- package/packages/cli/dist/commands/init/frontmatter.js +2 -0
- package/packages/cli/dist/commands/init/index.js +4 -4
- package/packages/cli/dist/commands/init/manifest.d.ts +71 -0
- package/packages/cli/dist/commands/init/manifest.js +1 -0
- package/packages/cli/dist/commands/init/scaffold.d.ts +28 -5
- package/packages/cli/dist/commands/init/scaffold.js +1 -1
- package/packages/cli/dist/commands/init/templates.js +38 -9
- package/packages/cli/dist/commands/init/user.d.ts +3 -3
- package/packages/cli/dist/commands/init/user.js +4 -4
- package/packages/cli/dist/commands/system.js +2 -2
- package/packages/cli/dist/kb-init.js +1 -1
- package/packages/core/dist/errors.d.ts +2 -2
- package/packages/core/dist/errors.js +1 -1
- package/packages/core/dist/logger.d.ts +2 -1
- package/packages/core/dist/logger.js +1 -1
- package/packages/core/dist/types.d.ts +6 -0
- package/packages/dashboard/dist/assets/index-9ysCkze9.js +21 -0
- package/packages/dashboard/dist/assets/index-9ysCkze9.js.map +1 -0
- package/packages/dashboard/dist/assets/index-CHpVij2M.css +1 -0
- package/packages/dashboard/dist/index.html +18 -0
- package/packages/elicitation/dist/__tests__/build.test.d.ts +1 -0
- package/packages/elicitation/dist/__tests__/build.test.js +35 -0
- package/packages/elicitation/dist/__tests__/fields.test.d.ts +1 -0
- package/packages/elicitation/dist/__tests__/fields.test.js +81 -0
- package/packages/elicitation/dist/__tests__/normalize.test.d.ts +1 -0
- package/packages/elicitation/dist/__tests__/normalize.test.js +60 -0
- package/packages/elicitation/dist/build.d.ts +13 -0
- package/packages/elicitation/dist/build.js +23 -0
- package/packages/elicitation/dist/fields.d.ts +41 -0
- package/packages/elicitation/dist/fields.js +62 -0
- package/packages/elicitation/dist/index.d.ts +10 -0
- package/packages/elicitation/dist/index.js +12 -0
- package/packages/elicitation/dist/normalize.d.ts +15 -0
- package/packages/elicitation/dist/normalize.js +31 -0
- package/packages/elicitation/dist/types.d.ts +85 -0
- package/packages/elicitation/dist/types.js +8 -0
- package/packages/kb-client/dist/direct-client.d.ts +37 -0
- package/packages/kb-client/dist/direct-client.js +1 -0
- package/packages/kb-client/dist/index.d.ts +5 -0
- package/packages/kb-client/dist/index.js +1 -0
- package/packages/kb-client/dist/mcp-client.d.ts +19 -0
- package/packages/kb-client/dist/mcp-client.js +4 -0
- package/packages/kb-client/dist/parsers.d.ts +35 -0
- package/packages/kb-client/dist/parsers.js +2 -0
- package/packages/kb-client/dist/types.d.ts +62 -0
- package/packages/kb-client/dist/types.js +1 -0
- package/packages/present/dist/index.html +384 -0
- package/packages/server/dist/completions.d.ts +14 -0
- package/packages/server/dist/completions.js +1 -0
- package/packages/server/dist/dashboard-static.d.ts +27 -0
- package/packages/server/dist/dashboard-static.js +1 -0
- package/packages/server/dist/elicitor.d.ts +18 -0
- package/packages/server/dist/elicitor.js +1 -0
- package/packages/server/dist/index.js +1 -1
- package/packages/server/dist/mcp-logging.js +1 -1
- package/packages/server/dist/output-schemas.d.ts +118 -1
- package/packages/server/dist/output-schemas.js +1 -1
- package/packages/server/dist/prompts.d.ts +9 -2
- package/packages/server/dist/prompts.js +13 -7
- package/packages/server/dist/resources/curated-resources.js +1 -1
- package/packages/server/dist/resources/resource-notifier.d.ts +45 -0
- package/packages/server/dist/resources/resource-notifier.js +1 -0
- package/packages/server/dist/sampling.d.ts +41 -0
- package/packages/server/dist/sampling.js +2 -0
- package/packages/server/dist/server.d.ts +5 -2
- package/packages/server/dist/server.js +2 -2
- package/packages/server/dist/task-manager.d.ts +40 -0
- package/packages/server/dist/task-manager.js +1 -0
- package/packages/server/dist/tool-metadata.js +1 -1
- package/packages/server/dist/tool-prefix.d.ts +12 -0
- package/packages/server/dist/tool-prefix.js +1 -0
- package/packages/server/dist/tools/analyze.tools.js +4 -4
- package/packages/server/dist/tools/audit.tool.js +1 -1
- package/packages/server/dist/tools/brainstorm.tool.d.ts +7 -0
- package/packages/server/dist/tools/brainstorm.tool.js +9 -0
- package/packages/server/dist/tools/context.tools.js +9 -9
- package/packages/server/dist/tools/execution.tools.d.ts +2 -1
- package/packages/server/dist/tools/execution.tools.js +4 -4
- package/packages/server/dist/tools/forge.tools.js +10 -10
- package/packages/server/dist/tools/forget.tool.d.ts +2 -1
- package/packages/server/dist/tools/forget.tool.js +1 -1
- package/packages/server/dist/tools/graph.tool.js +2 -2
- package/packages/server/dist/tools/manipulation.tools.js +4 -4
- package/packages/server/dist/tools/onboard.tool.js +2 -2
- package/packages/server/dist/tools/present-blocks.d.ts +46 -0
- package/packages/server/dist/tools/present-blocks.js +27 -0
- package/packages/server/dist/tools/present-charts.d.ts +31 -0
- package/packages/server/dist/tools/present-charts.js +34 -0
- package/packages/server/dist/tools/present-theme.d.ts +14 -0
- package/packages/server/dist/tools/present-theme.js +395 -0
- package/packages/server/dist/tools/present-utils.d.ts +11 -0
- package/packages/server/dist/tools/present-utils.js +1 -0
- package/packages/server/dist/tools/present.tool.d.ts +7 -0
- package/packages/server/dist/tools/present.tool.js +113 -0
- package/packages/server/dist/tools/produce.tool.js +2 -2
- package/packages/server/dist/tools/reindex.tool.d.ts +2 -1
- package/packages/server/dist/tools/reindex.tool.js +2 -2
- package/packages/server/dist/tools/remember.tool.d.ts +2 -1
- package/packages/server/dist/tools/remember.tool.js +2 -2
- package/packages/server/dist/tools/replay.tool.js +1 -1
- package/packages/server/dist/tools/search.tool.d.ts +2 -1
- package/packages/server/dist/tools/search.tool.js +5 -4
- package/packages/server/dist/tools/status.tool.js +2 -2
- package/packages/server/dist/tools/update.tool.d.ts +2 -1
- package/packages/server/dist/tools/update.tool.js +1 -1
- package/packages/server/dist/tools/utility.tools.js +1 -1
- package/packages/tools/dist/batch.js +1 -1
- package/packages/tools/dist/checkpoint.js +1 -1
- package/packages/tools/dist/config-extractor.d.ts +9 -0
- package/packages/tools/dist/config-extractor.js +7 -0
- package/packages/tools/dist/dead-symbols.js +2 -2
- package/packages/tools/dist/diagram-builder.d.ts +9 -0
- package/packages/tools/dist/diagram-builder.js +9 -0
- package/packages/tools/dist/evidence-map.d.ts +12 -1
- package/packages/tools/dist/evidence-map.js +2 -2
- package/packages/tools/dist/find-examples.js +2 -2
- package/packages/tools/dist/forge-classify.d.ts +4 -0
- package/packages/tools/dist/forge-classify.js +1 -1
- package/packages/tools/dist/git-context.d.ts +1 -0
- package/packages/tools/dist/git-context.js +3 -3
- package/packages/tools/dist/index.d.ts +3 -2
- package/packages/tools/dist/index.js +1 -1
- package/packages/tools/dist/onboard-utils.d.ts +12 -0
- package/packages/tools/dist/onboard-utils.js +1 -0
- package/packages/tools/dist/onboard.js +2 -21
- package/packages/tools/dist/regex-utils.d.ts +8 -0
- package/packages/tools/dist/regex-utils.js +1 -0
- package/packages/tools/dist/rename.js +2 -2
- package/packages/tools/dist/replay.d.ts +2 -1
- package/packages/tools/dist/replay.js +4 -4
- package/packages/tools/dist/symbol.js +3 -3
- package/packages/tools/dist/synthesis-engine.d.ts +13 -0
- package/packages/tools/dist/synthesis-engine.js +6 -0
- package/packages/tools/dist/trace.js +2 -2
- package/packages/tui/dist/App-DXY0-tlW.js +2 -0
- package/packages/tui/dist/App.d.ts +3 -3
- package/packages/tui/dist/App.js +1 -1
- package/packages/tui/dist/CuratedPanel-BIamXLNy.js +2 -0
- package/packages/tui/dist/LogPanel-D6u6o84n.js +3 -0
- package/packages/tui/dist/SearchPanel-CpJGczAc.js +2 -0
- package/packages/tui/dist/StatusPanel-BAbUxyqQ.js +2 -0
- package/packages/tui/dist/hooks/useKBClient.d.ts +9 -0
- package/packages/tui/dist/hooks/useKBClient.js +2 -0
- package/packages/tui/dist/hooks/usePolling.d.ts +8 -0
- package/packages/tui/dist/hooks/usePolling.js +2 -0
- package/packages/tui/dist/index.d.ts +6 -2
- package/packages/tui/dist/index.js +1 -1
- package/packages/tui/dist/jsx-runtime-y6Gdq5PZ.js +294 -0
- package/packages/tui/dist/panels/CuratedPanel.d.ts +1 -7
- package/packages/tui/dist/panels/CuratedPanel.js +1 -1
- package/packages/tui/dist/panels/LogPanel.js +1 -1
- package/packages/tui/dist/panels/SearchPanel.d.ts +1 -10
- package/packages/tui/dist/panels/SearchPanel.js +1 -1
- package/packages/tui/dist/panels/StatusPanel.d.ts +1 -7
- package/packages/tui/dist/panels/StatusPanel.js +1 -1
- package/packages/tui/dist/react-D__J1GQe.js +24 -0
- package/packages/tui/dist/types-VcTHNV6s.d.ts +64 -0
- package/packages/tui/dist/useKBClient-C35iA4uG.js +2 -0
- package/packages/tui/dist/usePolling-BbjnRWgx.js +2 -0
- package/scaffold/adapters/copilot.mjs +9 -81
- package/scaffold/definitions/agents.mjs +12 -0
- package/scaffold/definitions/bodies.mjs +39 -14
- package/scaffold/definitions/protocols.mjs +149 -0
- package/scaffold/definitions/tools.mjs +40 -5
- package/scaffold/general/agents/Architect-Reviewer-Alpha.agent.md +1 -1
- package/scaffold/general/agents/Architect-Reviewer-Beta.agent.md +1 -1
- package/scaffold/general/agents/Code-Reviewer-Alpha.agent.md +1 -1
- package/scaffold/general/agents/Code-Reviewer-Beta.agent.md +1 -1
- package/scaffold/general/agents/Debugger.agent.md +2 -2
- package/scaffold/general/agents/Documenter.agent.md +2 -2
- package/scaffold/general/agents/Explorer.agent.md +4 -3
- package/scaffold/general/agents/Frontend.agent.md +1 -1
- package/scaffold/general/agents/Implementer.agent.md +1 -1
- package/scaffold/general/agents/Orchestrator.agent.md +16 -1
- package/scaffold/general/agents/Planner.agent.md +11 -4
- package/scaffold/general/agents/Refactor.agent.md +1 -1
- package/scaffold/general/agents/Researcher-Alpha.agent.md +1 -1
- package/scaffold/general/agents/Researcher-Beta.agent.md +1 -1
- package/scaffold/general/agents/Researcher-Delta.agent.md +1 -1
- package/scaffold/general/agents/Researcher-Gamma.agent.md +1 -1
- package/scaffold/general/agents/Security.agent.md +10 -8
- package/scaffold/general/agents/_shared/architect-reviewer-base.md +1 -0
- package/scaffold/general/agents/_shared/code-agent-base.md +28 -0
- package/scaffold/general/agents/_shared/code-reviewer-base.md +1 -0
- package/scaffold/general/agents/_shared/forge-protocol.md +44 -0
- package/scaffold/general/agents/_shared/researcher-base.md +14 -0
- package/scaffold/general/agents/templates/adr-template.md +1 -0
- package/scaffold/general/agents/templates/execution-state.md +1 -0
- package/skills/knowledge-base/SKILL.md +19 -6
- package/skills/present/SKILL.md +153 -0
- package/packages/server/dist/tools/toolkit.tools.d.ts +0 -36
- package/packages/server/dist/tools/toolkit.tools.js +0 -20
- package/packages/tui/dist/App-DE_tdOhs.js +0 -2
- package/packages/tui/dist/CuratedPanel-sYdZAICX.js +0 -2
- package/packages/tui/dist/LogPanel-Ce3jMQbH.js +0 -3
- package/packages/tui/dist/SearchPanel-DREo6zgt.js +0 -2
- package/packages/tui/dist/StatusPanel-2ex8fLOO.js +0 -2
- package/packages/tui/dist/embedder.interface-IFCBpOlX.d.ts +0 -28
- package/packages/tui/dist/index-C8NmOF18.d.ts +0 -13
- package/packages/tui/dist/jsx-runtime-Cof-kwFn.js +0 -316
- package/packages/tui/dist/store.interface-CnY6SPOH.d.ts +0 -150
- /package/packages/tui/dist/{devtools-DUyj952l.js → devtools-DMOZMn70.js} +0 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import{getToolMeta as e}from"../tool-metadata.js";import{escHtml as t}from"./present-utils.js";import{renderChecklistHtml as n,renderComparisonHtml as r,renderProgressHtml as i,renderPromptHtml as a,renderStatusBoardHtml as o,renderTimelineHtml as s}from"./present-blocks.js";import{renderChartAsHtml as c}from"./present-charts.js";import{FONT_LINK as l,getDesignSystemCSS as u}from"./present-theme.js";import{readFileSync as d}from"node:fs";import{dirname as f,join as p}from"node:path";import{fileURLToPath as m}from"node:url";import{z as h}from"zod";import{exec as g}from"node:child_process";import{createServer as _}from"node:http";import{createUIResource as v}from"@mcp-ui/server";import{RESOURCE_MIME_TYPE as y,registerAppResource as b,registerAppTool as x}from"@modelcontextprotocol/ext-apps/server";import{marked as S}from"marked";S.setOptions({async:!1,gfm:!0,breaks:!0}),S.use({renderer:{html(e){return t(e.text)}}});const C=import.meta.dirname??f(m(import.meta.url)),w=`ui://kb/present.html`;function T(){return p(C,`..`,`..`,`..`,`present`,`dist`,`index.html`)}let E;function D(){if(!E)try{E=d(T(),`utf-8`)}catch{E=``}return E}const O=h.object({type:h.enum([`button`,`select`]).describe(`Action type`),id:h.string().describe(`Unique action identifier`),label:h.string().describe(`Display label`),variant:h.enum([`primary`,`danger`,`default`]).optional().describe(`Button style variant`),options:h.array(h.union([h.string(),h.object({label:h.string(),value:h.string()})])).optional().describe(`Select options (for type=select)`)}),k={format:h.enum([`html`,`browser`]).default(`html`).describe(`Output format.
|
|
2
|
+
- "html" (default): Rich markdown in chat + embedded UIResource for MCP-UI hosts. Actions shown as numbered choices.
|
|
3
|
+
- "browser": Rich markdown in chat + opens beautiful themed dashboard in the browser. When actions are provided, the browser shows interactive buttons and the tool blocks until the user clicks, returning their selection.`),title:h.string().optional().describe(`Optional heading`),content:h.any().describe(`Content to present. Accepts: markdown string, array of objects (→ table), { nodes, edges } (→ mermaid graph), typed blocks [{ type, value }], or any JSON (→ tree).`),actions:h.array(O).optional().describe(`Interactive actions (buttons/selects). In html mode, shown as numbered choices. In browser mode, rendered as clickable buttons and the tool blocks until user clicks.`)};let A=!1;function j(t,n){let r=e(`present`);A||=(b(t,`KB Present App`,w,{description:`Rich interactive content viewer for KB tools`},async()=>({contents:[{uri:w,mimeType:y,text:D()}]})),!0),x(t,`present`,{title:r.title,description:`Present content to the user in the best format. Two modes:
|
|
4
|
+
- "html" (default): Rich markdown in chat + embedded UIResource. Actions shown as numbered choices for display.
|
|
5
|
+
- "browser": Rich markdown in chat + serves a themed dashboard on a local URL that auto-opens in your system browser. If openBrowserPage is available, also call it with the returned URL. When actions are provided, browser shows interactive buttons and the tool blocks until user clicks.
|
|
6
|
+
Use "html" for in-chat display. Use "browser" for visual dashboards and when you need interactive user input back.
|
|
7
|
+
After calling present with format "browser", extract the URL from the response and call openBrowserPage({ url }) to open it in VS Code.`,annotations:r.annotations,inputSchema:k,_meta:{ui:{resourceUri:w}}},async({format:e,title:t,content:r,actions:i})=>(e??`html`)===`browser`?await N(t,r,i,n):J(t,r,i))}let M=null;process.on(`exit`,()=>{if(M){try{M.close()}catch{}M=null}});async function N(e,t,n,r){let i=P(e,t),a=q(e,t,n),o,s,c=Array.isArray(n)?n:[],l=``;try{M&&=(M.close(),null),c.length>0&&(o=new Promise(e=>{s=e})),l=await new Promise((e,t)=>{let n=_((e,t)=>{if(e.method===`POST`&&e.url===`/callback`){let n=``;e.on(`data`,e=>{n+=e.toString()}),e.on(`end`,()=>{t.writeHead(200,{"Content-Type":`application/json`,"Access-Control-Allow-Origin":`*`}),t.end(`{"ok":true}`);try{let e=JSON.parse(n);s?.(e)}catch{}});return}if(e.method===`OPTIONS`){t.writeHead(204,{"Access-Control-Allow-Origin":`*`,"Access-Control-Allow-Methods":`POST`,"Access-Control-Allow-Headers":`Content-Type`}),t.end();return}t.writeHead(200,{"Content-Type":`text/html; charset=utf-8`}),t.end(a)});n.listen(0,`127.0.0.1`,()=>{let r=n.address();typeof r==`object`&&r?(M=n,e(`http://127.0.0.1:${r.port}`)):t(Error(`Failed to start present server`))}),setTimeout(()=>{n.close(),M===n&&(M=null)},300*1e3).unref()});try{g(process.platform===`win32`?`start "" "${l}"`:process.platform===`darwin`?`open "${l}"`:`xdg-open "${l}"`)}catch{}}catch{}let u=v({uri:`ui://kb/present-static.html`,content:{type:`rawHtml`,htmlString:a},encoding:`text`,adapters:{mcpApps:{enabled:!0}}}),d=l?`${i}\n\n---\n🌐 **Dashboard opened in browser:** ${l}`:i;if(c.length>0&&r?.available&&o)try{let e=await Promise.race([o,new Promise((e,t)=>setTimeout(()=>t(Error(`timeout`)),300*1e3))]);return{content:[{type:`text`,text:`${d}\n\n✅ **Selected:** ${e.actionId} = \`${e.value}\``},u]}}catch{return{content:[{type:`text`,text:`${d}\n\n⚠️ *No selection received (timed out).*`},u]}}return{content:[{type:`text`,text:d},u]}}function P(e,t){let n=[];if(e&&n.push(`# ${e}\n`),typeof t==`string`)n.push(t);else if(Array.isArray(t))if(t.length===0)n.push(`*(empty)*`);else if(Z(t[0]))for(let e of t)n.push(F(e));else if(typeof t[0]==`object`&&t[0]!==null)n.push(I(t));else for(let e of t)n.push(`- ${String(e)}`);else if(typeof t==`object`&&t){let e=t;Array.isArray(e.nodes)&&Array.isArray(e.edges)?n.push(R(e)):Array.isArray(e.metrics)?n.push(L(e.metrics)):n.push(z(e))}else n.push(String(t));return n.join(`
|
|
8
|
+
`)}function F(e){let t=[];switch(e.title&&t.push(`## ${e.title}\n`),e.type){case`markdown`:t.push(String(e.value??``));break;case`code`:t.push(`\`\`\`${e.language??``}\n${String(e.value??``)}\n\`\`\``);break;case`mermaid`:t.push(`\`\`\`mermaid\n${String(e.value??``)}\n\`\`\``);break;case`table`:Array.isArray(e.value)&&t.push(I(e.value));break;case`metrics`:Array.isArray(e.value)&&t.push(L(e.value));break;case`graph`:e.value&&typeof e.value==`object`&&t.push(R(e.value));break;case`cards`:if(Array.isArray(e.value))for(let n of e.value)t.push(`### ${n.title??`Card`}`),(n.body||n.description)&&t.push(String(n.body??n.description)),(n.badge||n.status)&&t.push(`> **${n.badge??n.status}**`),t.push(``);break;case`tree`:e.value&&typeof e.value==`object`&&t.push(z(e.value));break;case`chart`:{let n=e.value;n?.data&&Array.isArray(n.data)&&t.push(`*${String(n.chartType??`chart`)} chart — ${n.data.length} data points*`);break}case`timeline`:{let n=e.value;if(n?.items)for(let e of n.items){let n=e.status===`done`?`✅`:e.status===`active`?`🔄`:e.status===`error`?`❌`:`⬜`;t.push(`${n} **${e.title}**${e.description?` — ${e.description}`:``}`)}break}case`checklist`:{let n=e.value;if(n?.items)for(let e of n.items)t.push(`- [${e.checked?`x`:` `}] ${e.label}${e.note?` — ${e.note}`:``}`);break}case`comparison`:{let n=e.value;if(n?.columns&&n.columns.length>0){let e=Math.max(...n.columns.map(e=>e.items?.length??0)),r=n.columns.map(e=>e.title);t.push(`| ${r.join(` | `)} |`),t.push(`| ${r.map(()=>`---`).join(` | `)} |`);for(let r=0;r<e;r++)t.push(`| ${n.columns.map(e=>e.items?.[r]??``).join(` | `)} |`)}break}case`status-board`:{let n=e.value;if(n?.items)for(let e of n.items){let n=e.status===`success`?`🟢`:e.status===`warning`?`🟡`:e.status===`error`?`🔴`:e.status===`info`?`🔵`:`⚪`;t.push(`${n} **${e.label}**${e.detail?` — ${e.detail}`:``}`)}break}case`prompt`:{let n=e.value;n?.question&&(t.push(`> **${n.question}**`),n.context&&t.push(`> ${n.context}`));break}case`progress`:{let n=e.value;if(n?.items)for(let e of n.items){let n=e.max??100,r=n>0?Math.round(e.value/n*100):0,i=`█`.repeat(Math.round(r/5))+`░`.repeat(20-Math.round(r/5));t.push(`${e.label}: ${i} ${r}%`)}break}default:t.push(JSON.stringify(e.value,null,2))}return t.push(``),t.join(`
|
|
9
|
+
`)}function I(e){if(e.length===0)return`*(empty table)*`;let t=Object.keys(e[0]),n=[];n.push(`| ${t.join(` | `)} |`),n.push(`| ${t.map(()=>`---`).join(` | `)} |`);for(let r of e)n.push(`| ${t.map(e=>String(r[e]??``)).join(` | `)} |`);return n.join(`
|
|
10
|
+
`)}function L(e){return e.map(e=>`- **${e.label}**: ${e.value}`).join(`
|
|
11
|
+
`)}function R(e){let t=["```mermaid",`graph LR`];for(let n of e.nodes){let e=X(String(n.id??n.name??``)),r=String(n.label??n.name??e);t.push(` ${e}["${r}"]`)}for(let n of e.edges){let e=X(String(n.source??n.from??``)),r=X(String(n.target??n.to??``)),i=n.label?`|${String(n.label)}|`:``;t.push(` ${e} -->${i} ${r}`)}return t.push("```"),t.join(`
|
|
12
|
+
`)}function z(e,t=0){let n=` `.repeat(t),r=[];for(let[i,a]of Object.entries(e))typeof a==`object`&&a&&!Array.isArray(a)?(r.push(`${n}- **${i}**:`),r.push(z(a,t+1))):r.push(`${n}- **${i}**: ${Y(a)}`);return r.join(`
|
|
13
|
+
`)}function B(e,n){let r=[];if(e&&r.push(`<h1>${t(e)}</h1>`),typeof n==`string`)r.push(`<div class="md-content">${S.parse(n)}</div>`);else if(Array.isArray(n))if(n.length===0)r.push(`<p><em>empty</em></p>`);else if(Z(n[0]))for(let e of n)r.push(V(e));else typeof n[0]==`object`&&n[0]!==null?r.push(H(n)):r.push(`<ul>${n.map(e=>`<li>${t(String(e))}</li>`).join(``)}</ul>`);else if(typeof n==`object`&&n){let e=n;Array.isArray(e.metrics)?r.push(U(e.metrics)):Array.isArray(e.nodes)&&Array.isArray(e.edges)?(r.push(`<pre class="mermaid">${t(K(e))}</pre>`),r.push(`<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"><\/script>`),r.push(`<script>mermaid.run();<\/script>`)):r.push(G(e))}else r.push(`<p>${t(String(n))}</p>`);return r.join(`
|
|
14
|
+
`)}function V(e){let l=[];switch(e.title&&l.push(`<h2>${t(e.title)}</h2>`),e.type){case`markdown`:l.push(`<div class="md-content">${S.parse(String(e.value??``))}</div>`);break;case`code`:l.push(`<pre><code>${t(String(e.value??``))}</code></pre>`);break;case`mermaid`:l.push(`<pre class="mermaid">${t(String(e.value??``))}</pre>`);break;case`table`:if(Array.isArray(e.value)){let t=e.value;if(t.length>0&&Array.isArray(t[0])){let e=t,n=e[0].map(String),r=e.slice(1).map(e=>Object.fromEntries(n.map((t,n)=>[t,e[n]])));l.push(H(r))}else l.push(H(t))}break;case`metrics`:{let t;Array.isArray(e.value)?t=e.value:e.value&&typeof e.value==`object`&&(t=Object.entries(e.value).map(([e,t])=>({label:e,value:String(t)}))),t&&l.push(U(t))}break;case`cards`:Array.isArray(e.value)&&l.push(W(e.value));break;case`tree`:e.value&&typeof e.value==`object`&&l.push(G(e.value));break;case`graph`:e.value&&typeof e.value==`object`&&l.push(`<pre class="mermaid">${t(K(e.value))}</pre>`);break;case`chart`:{let t=e.value;if(t&&!t.chartType&&t.type&&Array.isArray(t.labels)&&Array.isArray(t.datasets)){let n=t.labels,r=t.datasets,i=r.map((e,t)=>e.label??`series${t+1}`),a=n.map((e,t)=>{let n={_label:e};return r.forEach((e,r)=>{n[i[r]]=e.data[t]??0}),n}),o={type:`chart`,title:e.title,value:{chartType:String(t.type),data:a,xKey:`_label`,yKeys:i}};l.push(c(o))}else l.push(c(e));break}case`timeline`:{let t=e.value;Array.isArray(t)&&(t={items:t.map(e=>({title:String(e.event??e.title??``),phase:e.date==null?e.phase==null?void 0:String(e.phase):String(e.date),description:e.description==null?void 0:String(e.description),status:e.status??`done`}))}),t&&l.push(s(t));break}case`checklist`:e.value&&l.push(n(e.value));break;case`comparison`:e.value&&l.push(r(e.value));break;case`status-board`:e.value&&l.push(o(e.value));break;case`prompt`:e.value&&l.push(a(e.value));break;case`progress`:e.value&&l.push(i(e.value));break;default:l.push(`<pre>${t(JSON.stringify(e.value,null,2))}</pre>`)}return l.join(`
|
|
15
|
+
`)}function H(e){if(e.length===0)return`<p><em>empty table</em></p>`;let n=Object.keys(e[0]);return`<div class="table-wrap"><table><thead><tr>${n.map(e=>`<th>${t(e)}</th>`).join(``)}</tr></thead><tbody>${e.map(e=>`<tr>${n.map(n=>`<td>${t(String(e[n]??``))}</td>`).join(``)}</tr>`).join(`
|
|
16
|
+
`)}</tbody></table></div>`}function U(e){return`<div class="metric-grid">${e.map(e=>`<div class="metric"><div class="metric-value">${t(String(e.value))}</div><div class="metric-label">${t(e.label)}</div></div>`).join(``)}</div>`}function W(e){return`<div class="card-grid">${e.map(e=>{let n=[`<div class="card">`];return e.title&&n.push(`<div class="card-title">${t(String(e.title))}</div>`),(e.body||e.description)&&n.push(`<div class="card-body">${t(String(e.body??e.description))}</div>`),(e.badge||e.status)&&n.push(`<span class="badge">${t(String(e.badge??e.status))}</span>`),n.push(`</div>`),n.join(``)}).join(``)}</div>`}function G(e){let n=[];for(let[r,i]of Object.entries(e))typeof i==`object`&&i&&!Array.isArray(i)?n.push(`<div class="tree-node"><span class="tree-key">${t(r)}:</span><div class="tree-children">${G(i)}</div></div>`):n.push(`<div class="tree-node"><span class="tree-key">${t(r)}:</span> ${t(Y(i))}</div>`);return n.join(``)}function K(e){let t=[`graph LR`];for(let n of e.nodes){let e=X(String(n.id??n.name??``)),r=String(n.label??n.name??e);t.push(` ${e}["${r}"]`)}for(let n of e.edges){let e=X(String(n.source??n.from??``)),r=X(String(n.target??n.to??``)),i=n.label?`|${String(n.label)}|`:``;t.push(` ${e} -->${i} ${r}`)}return t.join(`
|
|
17
|
+
`)}function q(e,n,r){let i=B(e,n);return`<!DOCTYPE html>
|
|
18
|
+
<html lang="en">
|
|
19
|
+
<head>
|
|
20
|
+
<meta charset="UTF-8">
|
|
21
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
22
|
+
<title>${t(e??`KB Dashboard`)}</title>
|
|
23
|
+
${l}
|
|
24
|
+
<style>${u()}</style>
|
|
25
|
+
</head>
|
|
26
|
+
<body>
|
|
27
|
+
<div class="dashboard">
|
|
28
|
+
<div class="header">
|
|
29
|
+
<h1>${t(e??`KB Dashboard`)}</h1>
|
|
30
|
+
<div class="subtitle">Knowledge Base</div>
|
|
31
|
+
</div>
|
|
32
|
+
${i}
|
|
33
|
+
${(()=>{let e=Array.isArray(r)?r:[];return e.length===0?``:`
|
|
34
|
+
<div class="actions-bar">
|
|
35
|
+
<h2>Actions</h2>
|
|
36
|
+
<div class="actions-grid">${e.map(e=>{let n=String(e.id??``);if(e.type===`select`&&Array.isArray(e.options)){let r=e.options.map(e=>{let n=typeof e==`string`?e:e.label;return`<option value="${t(typeof e==`string`?e:e.value)}">${t(n)}</option>`}).join(``);return`<div class="action-group"><label>${t(String(e.label??``))}</label><select data-action-id="${t(n)}" onchange="sendCallback(${t(JSON.stringify(n))},this.value)">${r}</select></div>`}return`<button class="action-btn action-${String(e.variant??`default`)}" onclick="sendCallback(${t(JSON.stringify(n))},'clicked')">${t(String(e.label??``))}</button>`}).join(`
|
|
37
|
+
`)}</div>
|
|
38
|
+
<div id="action-feedback" class="action-feedback"></div>
|
|
39
|
+
</div>
|
|
40
|
+
<script>
|
|
41
|
+
let _cbSent=false;
|
|
42
|
+
function sendCallback(actionId,value){
|
|
43
|
+
if(_cbSent)return;
|
|
44
|
+
_cbSent=true;
|
|
45
|
+
document.querySelectorAll('.action-btn,.action-group select').forEach(el=>{el.disabled=true;el.style.opacity='0.5'});
|
|
46
|
+
const fb=document.getElementById('action-feedback');
|
|
47
|
+
fb.textContent='⏳ Sending selection: '+actionId+' = '+value;
|
|
48
|
+
fb.className='action-feedback sent';
|
|
49
|
+
fetch('/callback',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({actionId,value})})
|
|
50
|
+
.then(()=>{
|
|
51
|
+
fb.textContent='✓ Selection sent: '+actionId+' = '+value;
|
|
52
|
+
})
|
|
53
|
+
.catch(e=>{
|
|
54
|
+
fb.textContent='✗ Callback failed — '+e.message;
|
|
55
|
+
fb.style.color='var(--error)';
|
|
56
|
+
_cbSent=false;
|
|
57
|
+
document.querySelectorAll('.action-btn,.action-group select').forEach(el=>{el.disabled=false;el.style.opacity='1'});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
<\/script>`})()}
|
|
61
|
+
<div class="footer">KB MCP Server · Generated ${new Date().toLocaleString()}</div>
|
|
62
|
+
</div>
|
|
63
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"><\/script>
|
|
64
|
+
<script>
|
|
65
|
+
// Mermaid initialization
|
|
66
|
+
if(document.querySelector('.mermaid'))mermaid.initialize({theme:'dark',startOnLoad:true});
|
|
67
|
+
|
|
68
|
+
// Table sorting
|
|
69
|
+
document.querySelectorAll('table').forEach(table=>{
|
|
70
|
+
const headers=table.querySelectorAll('th');
|
|
71
|
+
headers.forEach((th,i)=>{
|
|
72
|
+
let asc=true;
|
|
73
|
+
th.addEventListener('click',()=>{
|
|
74
|
+
const tbody=table.querySelector('tbody')||table;
|
|
75
|
+
const rows=[...tbody.querySelectorAll('tr')].filter(r=>r.querySelector('td'));
|
|
76
|
+
rows.sort((a,b)=>{
|
|
77
|
+
const at=(a.cells[i]?.textContent||'').trim();
|
|
78
|
+
const bt=(b.cells[i]?.textContent||'').trim();
|
|
79
|
+
return asc?at.localeCompare(bt,undefined,{numeric:true}):bt.localeCompare(at,undefined,{numeric:true});
|
|
80
|
+
});
|
|
81
|
+
rows.forEach(r=>tbody.appendChild(r));
|
|
82
|
+
asc=!asc;
|
|
83
|
+
headers.forEach(h=>h.style.color='');
|
|
84
|
+
th.style.color='var(--primary)';
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Table search/filter
|
|
90
|
+
document.querySelectorAll('.table-wrap').forEach(wrap=>{
|
|
91
|
+
const table=wrap.querySelector('table');
|
|
92
|
+
if(!table||table.querySelectorAll('tr').length<5)return;
|
|
93
|
+
const bar=document.createElement('div');
|
|
94
|
+
bar.className='search-bar';
|
|
95
|
+
const input=document.createElement('input');
|
|
96
|
+
input.placeholder='Filter rows...';
|
|
97
|
+
const count=document.createElement('span');
|
|
98
|
+
count.className='count';
|
|
99
|
+
bar.appendChild(input);bar.appendChild(count);
|
|
100
|
+
wrap.parentNode.insertBefore(bar,wrap);
|
|
101
|
+
const rows=[...table.querySelectorAll('tbody tr, tr')].filter(r=>r.querySelector('td'));
|
|
102
|
+
const updateCount=()=>{const v=rows.filter(r=>r.style.display!=='none').length;count.textContent=v+'/'+rows.length};
|
|
103
|
+
updateCount();
|
|
104
|
+
input.addEventListener('input',()=>{
|
|
105
|
+
const q=input.value.toLowerCase();
|
|
106
|
+
rows.forEach(r=>{r.style.display=r.textContent.toLowerCase().includes(q)?'':'none'});
|
|
107
|
+
updateCount();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
<\/script>
|
|
111
|
+
</body>
|
|
112
|
+
</html>`}function J(e,t,n){let r=Array.isArray(n)?n:[],i=[];if(e&&i.push(`## ${e}\n`),Array.isArray(t)){for(let e of t)if(e&&typeof e==`object`&&typeof e.type==`string`)if(e.type===`metrics`&&e.value&&typeof e.value==`object`){let t=e.value;i.push(Object.entries(t).map(([e,t])=>`**${e}**: ${String(t)}`).join(` · `))}else e.type===`text`&&typeof e.value==`string`?i.push(e.value):i.push(`*${e.type}${e.title?`: ${String(e.title)}`:``}*`)}else typeof t==`string`&&i.push(t);if(r.length>0){i.push(``);for(let e=0;e<r.length;e++){let t=r[e],n=typeof t.label==`string`?t.label:`Action ${e+1}`;if(t.type===`select`&&Array.isArray(t.options)){let r=t.options.map(e=>typeof e==`string`?e:e.label).join(`, `);i.push(`${e+1}. **${n}** — choose: ${r}`)}else i.push(`${e+1}. **${n}**`)}}let a={title:e,content:t};return r.length>0&&(a.actions=r),{content:[{type:`text`,text:i.join(`
|
|
113
|
+
`)}],structuredContent:a}}function Y(e){return e==null?`null`:Array.isArray(e)?`[${e.map(Y).join(`, `)}]`:String(e)}function X(e){return e.replace(/[^a-zA-Z0-9_]/g,`_`)}function Z(e){return typeof e==`object`&&!!e&&`type`in e&&`value`in e}export{j as registerPresentTool};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{
|
|
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{DependencyAnalyzer as i,DiagramGenerator as a,EntryPointAnalyzer as o,KnowledgeProducer as s,PatternAnalyzer as c,StructureAnalyzer as l,SymbolAnalyzer as u}from"../../../analyzers/dist/index.js";const d=n(`tools`);function f(n){let f=new s({structure:new l,dependencies:new i,symbols:new u,patterns:new c,entryPoints:new o,diagrams:new a}),p=e(`produce_knowledge`);n.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 d.error(`Knowledge production failed`,
|
|
4
|
+
_Next: Review the baselines above and use \`remember\` to store synthesized knowledge entries._`}]}}catch(e){return d.error(`Knowledge production failed`,r(e)),{content:[{type:`text`,text:`Knowledge production failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{f as registerProduceKnowledgeTool};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { CuratedKnowledgeManager } from "../curated-manager.js";
|
|
2
|
+
import { ResourceNotifier } from "../resources/resource-notifier.js";
|
|
2
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
4
|
import { KBConfig } from "@kb/core";
|
|
4
5
|
import { IncrementalIndexer } from "@kb/indexer";
|
|
5
6
|
import { IKnowledgeStore } from "@kb/store";
|
|
6
7
|
|
|
7
8
|
//#region packages/server/src/tools/reindex.tool.d.ts
|
|
8
|
-
declare function registerReindexTool(server: McpServer, indexer: IncrementalIndexer, config: KBConfig, curated: CuratedKnowledgeManager, store?: IKnowledgeStore): void;
|
|
9
|
+
declare function registerReindexTool(server: McpServer, indexer: IncrementalIndexer, config: KBConfig, curated: CuratedKnowledgeManager, store?: IKnowledgeStore, resourceNotifier?: ResourceNotifier): void;
|
|
9
10
|
//#endregion
|
|
10
11
|
export { registerReindexTool };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{getToolMeta as e}from"../tool-metadata.js";import{
|
|
1
|
+
import{getToolMeta as e}from"../tool-metadata.js";import{createTaskRunner as t}from"../task-manager.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,l,u){let d=e(`reindex`);r.registerTool(`reindex`,{title:d.title,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`)},annotations:d.annotations},async({full:e},n)=>{try{if(o.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.`}]};
|
|
3
|
+
A reindex operation is currently running. Search and other tools continue to work with existing data. Use \`status({})\` to check when it completes.`}]};let r=t(n).createTask(`Reindex`,1);r.progress(0,`Starting ${e?`full`:`incremental`} reindex`),a.info(`Starting background re-index`,{mode:e?`full`:`incremental`});let d=e=>t=>{t.phase===`chunking`&&t.currentFile&&a.debug(`Re-index progress`,{prefix:e,current:t.filesProcessed+1,total:t.filesTotal,file:t.currentFile})};return(e?o.reindexAll(s,d(`Reindex`)):o.index(s,d(`Index`))).then(async e=>{if(a.info(`Background re-index complete`,{filesProcessed:e.filesProcessed,chunksCreated:e.chunksCreated,durationMs:e.durationMs}),r.complete(`Reindex complete: ${e.filesProcessed} files, ${e.chunksCreated} chunks in ${e.durationMs}ms`),l)try{await l.createFtsIndex(),a.info(`FTS index rebuilt after reindex`)}catch(e){a.warn(`FTS index rebuild failed`,i(e))}try{let e=await c.reindexAll();a.info(`Curated re-index complete`,{indexed:e.indexed})}catch(e){a.warn(`Curated re-index failed`,i(e))}if(u)try{await u.notifyAfterReindex()}catch(e){a.warn(`Post-reindex resource notification failed`,i(e))}}).catch(e=>{r.fail(`Reindex failed: ${e instanceof Error?e.message:String(e)}`),a.error(`Background reindex failed`,i(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 a.error(`Reindex failed`,i(e)),{content:[{type:`text`,text:`Reindex failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{o as registerReindexTool};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { CuratedKnowledgeManager } from "../curated-manager.js";
|
|
2
|
+
import { ResourceNotifier } from "../resources/resource-notifier.js";
|
|
2
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
4
|
import { EvolutionCollector, PolicyStore } from "@kb/enterprise-bridge";
|
|
4
5
|
|
|
5
6
|
//#region packages/server/src/tools/remember.tool.d.ts
|
|
6
|
-
declare function registerRememberTool(server: McpServer, curated: CuratedKnowledgeManager, policyStore?: PolicyStore, evolutionCollector?: EvolutionCollector): void;
|
|
7
|
+
declare function registerRememberTool(server: McpServer, curated: CuratedKnowledgeManager, policyStore?: PolicyStore, evolutionCollector?: EvolutionCollector, resourceNotifier?: ResourceNotifier): void;
|
|
7
8
|
//#endregion
|
|
8
9
|
export { registerRememberTool };
|
|
@@ -1,4 +1,4 @@
|
|
|
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
|
|
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,l){let u=e(`remember`);r.registerTool(`remember`,{title:u.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:u.annotations},async({title:e,content:n,category:r,tags:u})=>{try{let i=await o.remember(e,n,r,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
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.`))}
|
|
4
|
+
> 💡 This entry matches push rules. Consider \`er_push\` to share with Enterprise RAG.`))}l&&l.notifyAfterCuratedWrite(i.path).catch(()=>{});let d=t(i.path,e,`[${r}]`);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: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{o as registerRememberTool};
|
|
@@ -1,3 +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{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(`
|
|
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().catch(()=>{}),{content:[{type:`text`,text:`**Replay Log** (${r.length} entries)\n\n${s.join(`
|
|
2
2
|
|
|
3
3
|
`)}`}]}}catch(e){return s.error(`Replay failed`,r(e)),{content:[{type:`text`,text:`Replay failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{c as registerReplayTool};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ISamplingClient } from "../sampling.js";
|
|
1
2
|
import { BridgeComponents } from "./bridge.tools.js";
|
|
2
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
4
|
import { IEmbedder } from "@kb/embeddings";
|
|
@@ -5,6 +6,6 @@ import { EvolutionCollector } from "@kb/enterprise-bridge";
|
|
|
5
6
|
import { IGraphStore, IKnowledgeStore } from "@kb/store";
|
|
6
7
|
|
|
7
8
|
//#region packages/server/src/tools/search.tool.d.ts
|
|
8
|
-
declare function registerSearchTool(server: McpServer, embedder: IEmbedder, store: IKnowledgeStore, graphStore?: IGraphStore, bridge?: BridgeComponents, evolutionCollector?: EvolutionCollector): void;
|
|
9
|
+
declare function registerSearchTool(server: McpServer, embedder: IEmbedder, store: IKnowledgeStore, graphStore?: IGraphStore, bridge?: BridgeComponents, evolutionCollector?: EvolutionCollector, samplingClient?: ISamplingClient): void;
|
|
9
10
|
//#endregion
|
|
10
11
|
export { registerSearchTool };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import{getToolMeta as e}from"../tool-metadata.js";import{fanOutFtsSearch as
|
|
1
|
+
import{getToolMeta as e}from"../tool-metadata.js";import{SearchOutputSchema as t}from"../output-schemas.js";import{fanOutFtsSearch as n,fanOutSearch as r,openWorkspaceStores as i,resolveWorkspaces as a}from"../cross-workspace.js";import{curatedResourceLink as o,extractCuratedPath as s}from"../resource-links.js";import{stat as c}from"node:fs/promises";import{z as l}from"zod";import{CONTENT_TYPES as u,KNOWLEDGE_ORIGINS as d,SOURCE_TYPES as f,computePartitionKey as p,createLogger as m,serializeError as h}from"../../../core/dist/index.js";import{graphAugmentSearch as g,truncateToTokenBudget as _}from"../../../tools/dist/index.js";import{mergeResults as v}from"../../../enterprise-bridge/dist/index.js";const y=m(`tools`);async function b(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:v(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 y.warn(`ER fallback failed`,h(e)),{results:n,triggered:!0,cacheHit:a}}}function x(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 S(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 C(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&&!w.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&&!w.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 w=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 T(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 c(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 E(c,m,v,w,E,D,O){let k=e(`search`);c.registerTool(`search`,{title:k.title,description:`Search the knowledge base for code, docs, and prior decisions. Default choice for discovery. Modes: hybrid (default), semantic, keyword. For multi-strategy precision queries use find; for a known file path use lookup.`,outputSchema:t,inputSchema:{query:l.string().max(5e3).describe(`Natural language search query`),limit:l.number().min(1).max(20).default(5).describe(`Maximum results to return`),search_mode:l.enum([`hybrid`,`semantic`,`keyword`]).default(`hybrid`).describe(`Search strategy: hybrid (vector + FTS + RRF fusion, default), semantic (vector only), keyword (FTS only)`),content_type:l.enum(u).optional().describe(`Filter by content type`),source_type:l.enum(f).optional().describe(`Coarse filter: "source" (code only), "documentation" (md, curated), "test", "config". Overrides content_type if both set.`),origin:l.enum(d).optional().describe(`Filter by knowledge origin`),category:l.string().optional().describe(`Filter by category (e.g., decisions, patterns, conventions)`),tags:l.array(l.string()).optional().describe(`Filter by tags (returns results matching ANY of the specified tags)`),min_score:l.number().min(0).max(1).default(.25).describe(`Minimum similarity score`),graph_hops:l.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:l.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`),dedup:l.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:l.array(l.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:k.annotations},async({query:e,limit:t,search_mode:c,content_type:l,source_type:u,origin:d,category:f,tags:k,min_score:A,graph_hops:j,max_tokens:M,dedup:N,workspaces:P})=>{try{let F={limit:t,minScore:A,contentType:l,sourceType:u,origin:d,category:f,tags:k},I,L=!1,R=!1,z=``;if(c===`keyword`)I=await v.ftsSearch(e,F),I=I.slice(0,t);else if(c===`semantic`){let n=await m.embedQuery(e);I=await v.search(n,F);let r=await b(E,I[0]?.score??0,I,e,t);I=r.results,L=r.triggered,R=r.cacheHit}else{let n=await m.embedQuery(e),[r,i]=await Promise.all([v.search(n,{...F,limit:t*2}),v.ftsSearch(e,{...F,limit:t*2}).catch(()=>[])]);I=x(r,i).slice(0,t);let a=await b(E,r[0]?.score??0,I,e,t);I=a.results,L=a.triggered,R=a.cacheHit}D&&D.recordSearch(e,L,R),I.length>1&&(I=S(I,e));let B=``;if(P&&P.length>0){let o=a(P,p(process.cwd()));if(o.length>0){let{stores:a,closeAll:s}=await i(o);try{let i;i=c===`keyword`?await n(a,e,{...F,limit:t}):await r(a,await m.embedQuery(e),{...F,limit:t});for(let e of i)I.push({record:{...e.record,sourcePath:`[${e.workspace}] ${e.record.sourcePath}`},score:e.score});I=I.sort((e,t)=>t.score-e.score).slice(0,t),B=` + ${o.length} workspace(s)`}finally{await s()}}}if(N===`file`&&I.length>1){let e=new Map;for(let t of I){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}]})}I=[...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(I.length===0){if(O?.available)try{let t=(await O.createMessage({prompt:`The search query "${e}" returned 0 results in a code knowledge base. Suggest ONE alternative search query that might find relevant results. Reply with ONLY the alternative query, nothing else.`,systemPrompt:`You are a search query optimizer for a code knowledge base. Generate a single alternative query.`,maxTokens:100})).text.trim().split(`
|
|
2
|
+
`)[0].slice(0,500);if(t&&t!==e){let n=await m.embedQuery(t),r=await v.search(n,F);r.length>0&&(I=r,z=`> _Original query "${e}" returned 0 results. Auto-reformulated to "${t}"._\n\n`,y.info(`Smart search fallback succeeded`,{originalQuery:e,altQuery:t,resultCount:r.length}))}}catch(e){y.debug(`Smart search fallback failed`,{error:String(e)})}if(I.length===0)return{content:[{type:`text`,text:`No results found for the given query.`}],structuredContent:{results:[],totalResults:0,searchMode:c,query:e}}}let V,H;if(j>0&&!w&&(H="> **Note:** `graph_hops` was set but no graph store is available. Graph augmentation skipped."),j>0&&w)try{let e=await g(w,I.map(e=>({recordId:e.record.id,score:e.score,sourcePath:e.record.sourcePath})),{hops:j,maxPerHit:5});V=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
3
|
`),n=t.graphContext.edges.slice(0,5).map(e=>` - ${e.fromId} —[${e.type}]→ ${e.toId}`).join(`
|
|
3
|
-
`),r=[`- **Graph Context** (${
|
|
4
|
-
`))}}catch(e){
|
|
4
|
+
`),r=[`- **Graph Context** (${j} hop${j>1?`s`:``}):`];e&&r.push(` Entities:\n${e}`),n&&r.push(` Relationships:\n${n}`),V.set(t.recordId,r.join(`
|
|
5
|
+
`))}}catch(e){y.warn(`Graph augmentation failed`,h(e)),H=`> **Note:** Graph augmentation failed. Results shown without graph context.`}let U=I.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,V?.get(n.id)??null].filter(Boolean).join(`
|
|
5
6
|
`)}\n\n${n.content}`}).join(`
|
|
6
7
|
|
|
7
8
|
---
|
|
8
9
|
|
|
9
|
-
`),
|
|
10
|
+
`),W=(c===`hybrid`?`hybrid (vector + keyword RRF)`:c===`keyword`?`keyword (FTS)`:`semantic (vector)`)+B,G=C(I,e),K=G.length>0?`\n_Distinctive terms: ${G.map(e=>`\`${e}\``).join(`, `)}_`:``,q=await T(v,I),J=[];if(I.length===0)J.push("`reindex` — no results found, index may be stale"),J.push("`find` — try federated search with glob/regex");else{let e=I[0]?.record.sourcePath;e&&J.push(`\`lookup\` — see all chunks from \`${e}\``),J.push("`symbol` — resolve a specific symbol from the results"),J.push("`compact` — compress a result file for focused reading")}let Y=[H?`${H}\n\n`:``,q?`${q}\n\n`:``,U,`\n\n---\n_Search mode: ${W} | ${I.length} results_${K}`,`\n_Next: ${J.join(` | `)}_`],X=z+Y.join(``);M&&(X=_(X,M));let Z=new Set,Q=[];for(let e of I){if(e.record.origin!==`curated`||e.record.sourcePath.startsWith(`[`))continue;let t=s(e.record.sourcePath);if(!t)continue;let n=o(t,e.record.headingPath??t);n&&!Z.has(n.uri)&&(Z.add(n.uri),Q.push(n))}return{content:[{type:`text`,text:X},...Q],structuredContent:{results:I.map(e=>({sourcePath:e.record.sourcePath,contentType:e.record.contentType,score:e.score,...e.record.headingPath?{headingPath:e.record.headingPath}:{},...e.record.startLine?{startLine:e.record.startLine}:{},...e.record.endLine?{endLine:e.record.endLine}:{},...e.record.origin===`indexed`?{}:{origin:e.record.origin},...e.record.category?{category:e.record.category}:{},...e.record.tags?.length?{tags:e.record.tags}:{}})),totalResults:I.length,searchMode:c,query:e}}}catch(e){return y.error(`Search failed`,h(e)),{content:[{type:`text`,text:`Search failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{E as registerSearchTool};
|
|
@@ -1,2 +1,2 @@
|
|
|
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{
|
|
2
|
-
`),
|
|
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{KB_PATHS as i,createLogger as a,serializeError as o}from"../../../core/dist/index.js";import{WasmRuntime as s}from"../../../chunker/dist/index.js";const c=a(`tools`);function l(e,t,n,r=4e3){let i,a=new Promise(e=>{i=setTimeout(()=>{c.warn(`Status sub-operation "${n}" timed out after ${r}ms`),e({value:t,timedOut:!0})},r)});return Promise.race([e.then(e=>(clearTimeout(i),{value:e,timedOut:!1}),e=>(clearTimeout(i),c.warn(`Status sub-operation "${n}" failed: ${e instanceof Error?e.message:String(e)}`),{value:t,timedOut:!1})),a])}function u(a,u,d,f,p){let m=e(`status`);a.registerTool(`status`,{title:m.title,description:`Get the current status and statistics of the knowledge base index.`,outputSchema:t,annotations:m.annotations},async()=>{let e=[];try{let t=await l(u.getStats(),{totalRecords:0,totalFiles:0,lastIndexedAt:null,contentTypeBreakdown:{}},`store.getStats`),a=t.value;t.timedOut&&e.push(`⚠ Index stats timed out — values may be incomplete`);let o=await l(u.listSourcePaths(),[],`store.listSourcePaths`),c=o.value;o.timedOut&&e.push(`⚠ File listing timed out`);let m=null,h=0,g=[`## Knowledge Base Status`,``,`- **Total Records**: ${a.totalRecords}`,`- **Total Files**: ${a.totalFiles}`,`- **Last Indexed**: ${a.lastIndexedAt??`Never`}`,``,`### Content Types`,...Object.entries(a.contentTypeBreakdown).map(([e,t])=>`- ${e}: ${t}`),``,`### Indexed Files`,...c.slice(0,50).map(e=>`- ${e}`),c.length>50?`\n... and ${c.length-50} more files`:``];if(d)try{let t=await l(d.getStats(),{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}},`graphStore.getStats`);if(t.timedOut)e.push(`⚠ Graph stats timed out`),g.push(``,`### Knowledge Graph`,`- Graph stats timed out`);else{let e=t.value;m={nodes:e.nodeCount,edges:e.edgeCount},g.push(``,`### Knowledge Graph`,`- **Nodes**: ${e.nodeCount}`,`- **Edges**: ${e.edgeCount}`,...Object.entries(e.nodeTypes).map(([e,t])=>` - ${e}: ${t}`));try{let e=await l(d.validate(),{valid:!0,danglingEdges:[],orphanNodes:[],stats:{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}}},`graphStore.validate`);if(!e.timedOut){let t=e.value;t.valid||g.push(`- **⚠ Integrity Issues**: ${t.danglingEdges.length} dangling edges`),t.orphanNodes.length>0&&g.push(`- **Orphan nodes**: ${t.orphanNodes.length}`)}}catch{}}}catch{g.push(``,`### Knowledge Graph`,`- Graph store unavailable`)}let _=n(r(process.cwd(),i.aiKb)),v=p?.onboardComplete??_;if(g.push(``,`### Onboard Status`,v?`- ✅ Complete${p?.onboardTimestamp?` (last: ${p.onboardTimestamp})`:``}`:'- ❌ Not run — call `onboard({ path: "." })` to analyze the codebase'),f)try{let t=await l(f.list(),[],`curated.list`);if(t.timedOut)e.push(`⚠ Curated knowledge listing timed out`),g.push(``,`### Curated Knowledge`,`- Listing timed out`);else{let e=t.value;h=e.length,g.push(``,`### Curated Knowledge`,e.length>0?`- ${e.length} entries`:"- Empty — use `remember()` to persist decisions")}}catch{g.push(``,`### Curated Knowledge`,`- Unable to read curated entries`)}if(a.lastIndexedAt){let e=new Date(a.lastIndexedAt),t=(Date.now()-e.getTime())/(1e3*60*60);g.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`)}g.push(``,`### Runtime`,`- **Tree-sitter (WASM)**: ${s.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`),e.length>0&&g.push(``,`### ⚠ Warnings`,...e.map(e=>`- ${e}`));let y=g.join(`
|
|
2
|
+
`),b={totalRecords:a.totalRecords,totalFiles:a.totalFiles,lastIndexedAt:a.lastIndexedAt??null,onboarded:v,contentTypes:a.contentTypeBreakdown,wasmAvailable:!!s.get(),graphStats:m,curatedCount:h};return{content:[{type:`text`,text:y+"\n\n---\n_Next: Use `search` to query indexed content, `graph(stats)` to explore the knowledge graph, or `reindex` to refresh the index._"}],structuredContent:b}}catch(e){return c.error(`Status failed`,o(e)),{content:[{type:`text`,text:`Status check failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{u as registerStatusTool};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { CuratedKnowledgeManager } from "../curated-manager.js";
|
|
2
|
+
import { ResourceNotifier } from "../resources/resource-notifier.js";
|
|
2
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
4
|
|
|
4
5
|
//#region packages/server/src/tools/update.tool.d.ts
|
|
5
|
-
declare function registerUpdateTool(server: McpServer, curated: CuratedKnowledgeManager): void;
|
|
6
|
+
declare function registerUpdateTool(server: McpServer, curated: CuratedKnowledgeManager, resourceNotifier?: ResourceNotifier): void;
|
|
6
7
|
//#endregion
|
|
7
8
|
export { registerUpdateTool };
|
|
@@ -1 +1 @@
|
|
|
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
|
|
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){let s=e(`update`);n.registerTool(`update`,{title:s.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:s.annotations},async({path:e,content:t,reason:n})=>{try{let r=await a.update(e,t,n);return o&&o.notifyAfterCuratedWrite(e).catch(()=>{}),{content:[{type:`text`,text:`Updated: \`.ai/curated/${r.path}\` → version ${r.version}\n\nReason: ${n}\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: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{a as registerUpdateTool};
|
|
@@ -2,7 +2,7 @@ import{getToolMeta as e}from"../tool-metadata.js";import{EnvOutputSchema as t,Me
|
|
|
2
2
|
`)}]}}catch(e){return _.error(`Web search failed`,o(e)),{content:[{type:`text`,text:`Web search failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function y(t){let n=e(`http`);t.registerTool(`http`,{title:n.title,description:`Make HTTP requests (GET/POST/PUT/PATCH/DELETE/HEAD) for API testing. Returns status, headers, and formatted body with timing info.`,inputSchema:{url:i.string().url().describe(`Request URL (http/https only)`),method:i.enum([`GET`,`POST`,`PUT`,`PATCH`,`DELETE`,`HEAD`]).default(`GET`).describe(`HTTP method`),headers:i.record(i.string(),i.string()).optional().describe(`Request headers as key-value pairs`),body:i.string().optional().describe(`Request body (for POST/PUT/PATCH)`),timeout:i.number().min(1e3).max(6e4).default(15e3).describe(`Timeout in milliseconds`)},annotations:n.annotations},async({url:e,method:t,headers:n,body:r,timeout:i})=>{try{let a=await u({url:e,method:t,headers:n,body:r,timeout:i}),o=[`## ${t} ${e}`,``,`**Status:** ${a.status} ${a.statusText}`,`**Time:** ${a.durationMs}ms`,`**Size:** ${a.sizeBytes} bytes`,`**Content-Type:** ${a.contentType}`,``,`### Headers`,"```json",JSON.stringify(a.headers),"```",``,`### Body`,a.contentType.includes(`json`)?"```json":"```",a.body,"```"];return a.truncated&&o.push(``,`_Response truncated — total size: ${a.sizeBytes} bytes_`),{content:[{type:`text`,text:o.join(`
|
|
3
3
|
`)}]}}catch(e){return _.error(`HTTP request failed`,o(e)),{content:[{type:`text`,text:`HTTP request failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function b(t){let n=e(`regex_test`);t.registerTool(`regex_test`,{title:n.title,description:`Test a regex pattern against sample strings. Supports match, replace, and split modes.`,inputSchema:{pattern:i.string().max(500).describe(`Regex pattern (without delimiters)`),flags:i.string().max(10).regex(/^[gimsuy]*$/).default(``).describe(`Regex flags (g, i, m, s, etc.)`),test_strings:i.array(i.string().max(1e4)).max(50).describe(`Strings to test the pattern against`),mode:i.enum([`match`,`replace`,`split`]).default(`match`).describe(`Test mode`),replacement:i.string().optional().describe(`Replacement string (for replace mode)`)},annotations:n.annotations},async({pattern:e,flags:t,test_strings:n,mode:r,replacement:i})=>{let a=f({pattern:e,flags:t,testStrings:n,mode:r,replacement:i});if(!a.valid)return{content:[{type:`text`,text:`Invalid regex: ${a.error}`}],isError:!0};let o=[`## Regex: \`/${a.pattern}/${a.flags}\``,``,`Mode: ${r}`,``];for(let e of a.results){if(o.push(`**Input:** \`${e.input}\``),o.push(`**Matched:** ${e.matched}`),e.matches)for(let t of e.matches){let e=t.groups.length>0?` groups: [${t.groups.join(`, `)}]`:``;o.push(` - "${t.full}" at index ${t.index}${e}`)}e.replaced!==void 0&&o.push(`**Result:** \`${e.replaced}\``),e.split&&o.push(`**Split:** ${JSON.stringify(e.split)}`),o.push(``)}return{content:[{type:`text`,text:o.join(`
|
|
4
4
|
`)}]}})}function x(t){let n=e(`encode`);t.registerTool(`encode`,{title:n.title,description:`Encode, decode, or hash text. Supports base64, URL encoding, SHA-256, MD5, JWT decode, hex.`,inputSchema:{operation:i.enum([`base64_encode`,`base64_decode`,`url_encode`,`url_decode`,`sha256`,`md5`,`jwt_decode`,`hex_encode`,`hex_decode`]).describe(`Operation to perform`),input:i.string().max(1e6).describe(`Input text`)},annotations:n.annotations},async({operation:e,input:t})=>{try{let n=c({operation:e,input:t});return{content:[{type:`text`,text:`## ${e}\n\n**Input:** \`${t.length>100?`${t.slice(0,100)}...`:t}\`\n**Output:**\n\`\`\`\n${n.output}\n\`\`\``}]}}catch(e){return _.error(`Encode failed`,o(e)),{content:[{type:`text`,text:`Encode failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function S(t){let r=e(`measure`);t.registerTool(`measure`,{title:r.title,description:`Measure code complexity, line counts, and function counts for a file or directory. Returns per-file metrics sorted by complexity.`,outputSchema:n,inputSchema:{path:i.string().describe(`File or directory path to measure`),extensions:i.array(i.string()).optional().describe(`File extensions to include (default: .ts,.tsx,.js,.jsx)`)},annotations:r.annotations},async({path:e,extensions:t})=>{try{let n=await d({path:e,extensions:t}),r=[`## Code Metrics`,``,`**Files:** ${n.summary.totalFiles}`,`**Total lines:** ${n.summary.totalLines} (${n.summary.totalCodeLines} code)`,`**Functions:** ${n.summary.totalFunctions}`,`**Avg complexity:** ${n.summary.avgComplexity}`,`**Max complexity:** ${n.summary.maxComplexity.value} (${n.summary.maxComplexity.file})`,``,`### Top files by complexity`,``,`| File | Lines | Code | Complexity | Cognitive | Functions | Imports |`,`|------|-------|------|------------|-----------|-----------|---------|`];for(let e of n.files.slice(0,20)){let t=e.cognitiveComplexity===void 0?`—`:String(e.cognitiveComplexity);r.push(`| ${e.path} | ${e.lines.total} | ${e.lines.code} | ${e.complexity} | ${t} | ${e.functions} | ${e.imports} |`)}n.files.length>20&&r.push(``,`_...and ${n.files.length-20} more files_`);let i={summary:{totalFiles:n.summary.totalFiles,totalLines:n.summary.totalLines,totalCodeLines:n.summary.totalCodeLines,totalFunctions:n.summary.totalFunctions,avgComplexity:n.summary.avgComplexity,maxComplexity:{value:n.summary.maxComplexity.value,file:n.summary.maxComplexity.file}},files:n.files.map(e=>({path:e.path,lines:e.lines.total,code:e.lines.code,complexity:e.complexity,functions:e.functions}))};return{content:[{type:`text`,text:r.join(`
|
|
5
|
-
`)}],structuredContent:i}}catch(e){return _.error(`Measure failed`,o(e)),{content:[{type:`text`,text:`Measure failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function C(t){let n=e(`changelog`);t.registerTool(`changelog`,{title:n.title,description:`Generate a changelog from git history between two refs. Groups by conventional commit type.`,inputSchema:{from:i.string().max(200).describe(`Start ref (tag, SHA, HEAD~N)`),to:i.string().max(200).default(`HEAD`).describe(`End ref (default: HEAD)`),format:i.enum([`grouped`,`chronological`,`per-scope`]).default(`grouped`).describe(`Output format`),include_breaking:i.boolean().default(!0).describe(`Highlight breaking changes`)},annotations:n.annotations},async({from:e,to:t,format:n,include_breaking:r})=>{try{let
|
|
5
|
+
`)}],structuredContent:i}}catch(e){return _.error(`Measure failed`,o(e)),{content:[{type:`text`,text:`Measure failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function C(t){let n=e(`changelog`);t.registerTool(`changelog`,{title:n.title,description:`Generate a changelog from git history between two refs. Groups by conventional commit type.`,inputSchema:{from:i.string().max(200).describe(`Start ref (tag, SHA, HEAD~N)`),to:i.string().max(200).default(`HEAD`).describe(`End ref (default: HEAD)`),format:i.enum([`grouped`,`chronological`,`per-scope`]).default(`grouped`).describe(`Output format`),include_breaking:i.boolean().default(!0).describe(`Highlight breaking changes`),cwd:i.string().optional().describe(`Repository root or working directory`)},annotations:n.annotations},async({from:e,to:t,format:n,include_breaking:r,cwd:i})=>{try{let a=s({from:e,to:t,format:n,includeBreaking:r,cwd:i}),o=`${a.stats.total} commits (${Object.entries(a.stats.types).map(([e,t])=>`${t} ${e}`).join(`, `)})`;return{content:[{type:`text`,text:`${a.markdown}\n---\n_${o}_`}]}}catch(e){return _.error(`Changelog failed`,o(e)),{content:[{type:`text`,text:`Changelog failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function w(t){let n=e(`schema_validate`);t.registerTool(`schema_validate`,{title:n.title,description:`Validate JSON data against a JSON Schema. Supports type, required, properties, items, enum, pattern, min/max.`,inputSchema:{data:i.string().max(5e5).describe(`JSON data to validate (as string)`),schema:i.string().max(5e5).describe(`JSON Schema to validate against (as string)`)},annotations:n.annotations},async({data:e,schema:t})=>{try{let n=p({data:JSON.parse(e),schema:JSON.parse(t)});if(n.valid)return{content:[{type:`text`,text:`## Validation: PASSED
|
|
6
6
|
|
|
7
7
|
Data matches the schema.`}]};let r=[`## Validation: FAILED`,``,`**${n.errors.length} error(s):**`,``];for(let e of n.errors){let t=e.expected?` (expected: ${e.expected}, got: ${e.received})`:``;r.push(`- \`${e.path}\`: ${e.message}${t}`)}return{content:[{type:`text`,text:r.join(`
|
|
8
8
|
`)}]}}catch(e){return _.error(`Schema validation failed`,o(e)),{content:[{type:`text`,text:`Schema validation failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function T(t){let n=e(`snippet`);t.registerTool(`snippet`,{title:n.title,description:`Save, retrieve, search, and manage persistent code snippets/templates.`,inputSchema:{action:i.enum([`save`,`get`,`list`,`search`,`delete`]).describe(`Operation to perform`),name:i.string().optional().describe(`Snippet name (required for save/get/delete)`),language:i.string().optional().describe(`Language tag (for save)`),code:i.string().max(1e5).optional().describe(`Code content (for save)`),tags:i.array(i.string()).optional().describe(`Tags for categorization (for save)`),query:i.string().optional().describe(`Search query (for search)`)},annotations:n.annotations},async({action:e,name:t,language:n,code:r,tags:i,query:a})=>{try{let o=m({action:e,name:t,language:n,code:r,tags:i,query:a});if(`deleted`in o)return{content:[{type:`text`,text:o.deleted?`Snippet "${t}" deleted.`:`Snippet "${t}" not found.`}]};if(`snippets`in o){if(o.snippets.length===0)return{content:[{type:`text`,text:`No snippets found.`}]};let e=[`## Snippets`,``];for(let t of o.snippets){let n=t.tags.length>0?` [${t.tags.join(`, `)}]`:``;e.push(`- **${t.name}** (${t.language})${n}`)}return{content:[{type:`text`,text:e.join(`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
async function e(e,t,n={}){let r=Math.max(1,n.concurrency??4),i=[],a=[...e];async function o(e){let n=Date.now();try{let r=await t(e);return{id:e.id,status:`success`,result:r,durationMs:Date.now()-n}}catch(t){return{id:e.id,status:`error`,error:t instanceof Error?t.message:String(t),durationMs:Date.now()-n}}}for(;a.length>0;){let e=a.splice(0,r),t=await Promise.allSettled(e.map(e=>o(e)));for(let
|
|
1
|
+
async function e(e,t,n={}){let r=Math.max(1,n.concurrency??4),i=[],a=[...e];async function o(e){let n=Date.now();try{let r=await t(e);return{id:e.id,status:`success`,result:r,durationMs:Date.now()-n}}catch(t){return{id:e.id,status:`error`,error:t instanceof Error?t.message:String(t),durationMs:Date.now()-n}}}for(;a.length>0;){let e=a.splice(0,r),t=await Promise.allSettled(e.map(e=>o(e)));for(let n=0;n<t.length;n++){let r=t[n];if(r.status===`fulfilled`){i.push(r.value);continue}i.push({id:e[n]?.id??`unknown`,status:`error`,error:r.reason instanceof Error?r.reason.message:`Promise rejected`,durationMs:0})}}return i}export{e as batch};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{resolve as e}from"node:path";import{existsSync as t,mkdirSync as n,readFileSync as r,readdirSync as i,writeFileSync as a}from"node:fs";import{KB_PATHS as o}from"../../core/dist/index.js";const s=`${o.state}/checkpoints`;function c(r){let i=e(r??process.cwd(),s);return t(i)||n(i,{recursive:!0}),i}function l(t,n,r){let i=t.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-|-$/g,``)||`checkpoint`,o={id:`${Date.now()}-${i}`,label:t,createdAt:new Date().toISOString(),data:n,files:r?.files,notes:r?.notes};return a(e(c(r?.cwd),`${o.id}.json`),`${JSON.stringify(o,null,2)}\n`,`utf-8`),o}function u(n,i){let a=
|
|
1
|
+
import{resolve as e}from"node:path";import{existsSync as t,mkdirSync as n,readFileSync as r,readdirSync as i,writeFileSync as a}from"node:fs";import{KB_PATHS as o}from"../../core/dist/index.js";const s=`${o.state}/checkpoints`;function c(r){let i=e(r??process.cwd(),s);return t(i)||n(i,{recursive:!0}),i}function l(t,n,r){let i=t.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-|-$/g,``)||`checkpoint`,o={id:`${Date.now()}-${i}`,label:t,createdAt:new Date().toISOString(),data:n,files:r?.files,notes:r?.notes};return a(e(c(r?.cwd),`${o.id}.json`),`${JSON.stringify(o,null,2)}\n`,`utf-8`),o}function u(n,i){let a=c(i),o=e(a,`${n}.json`);if(o.startsWith(e(a))&&t(o))try{return JSON.parse(r(o,`utf-8`))}catch{return}}function d(t){let n=c(t);return i(n).filter(e=>e.endsWith(`.json`)).flatMap(t=>{try{return[JSON.parse(r(e(n,t),`utf-8`))]}catch{return[]}}).sort((e,t)=>t.createdAt.localeCompare(e.createdAt))}function f(e){return d(e)[0]}export{f as checkpointLatest,d as checkpointList,u as checkpointLoad,l as checkpointSave};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region packages/tools/src/config-extractor.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Configuration values extraction for onboard.
|
|
4
|
+
* Scans config files (.env, package.json, application.properties, etc.)
|
|
5
|
+
* and produces a Markdown summary with sensitive value masking.
|
|
6
|
+
*/
|
|
7
|
+
declare function extractConfigValues(rootPath: string, projectName: string): Promise<string>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { extractConfigValues };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{readFile as e,readdir as t}from"node:fs/promises";import{basename as n,join as r,relative as i}from"node:path";const a=new Set([`node_modules`,`.git`,`dist`,`build`,`coverage`,`.turbo`,`.cache`,`cdk.out`,`__pycache__`,`.venv`,`target`,`obj`,`.gradle`]),o=[{glob:/\.env(?:\.\w+)?$/,type:`env`},{glob:/\.env\.example$/,type:`env`},{glob:/package\.json$/,type:`package-json`},{glob:/^(?:app|config|settings|default)\.(?:json|ya?ml|toml)$/i,type:`config`},{glob:/docker-compose\.ya?ml$/,type:`docker`},{glob:/cdk\.json$/,type:`cdk`},{glob:/turbo\.json$/,type:`tooling`},{glob:/application\.(?:properties|ya?ml)$/i,type:`spring`},{glob:/settings\.py$/,type:`django`},{glob:/\.flaskenv$/,type:`env`},{glob:/appsettings\.(?:\w+\.)?json$/i,type:`dotnet`}];async function s(t,n){let r=[],a=await c(t),o=/kb\.config\.json$/;for(let n of a)try{let a=i(t,n).replace(/\\/g,`/`);if(o.test(a))continue;let s=await e(n,`utf-8`),c=l(n);if(a.split(`/`).length-1>1&&c===`tooling`)continue;let u=d(s,c);u.length>0&&r.push({file:a,type:c,values:u})}catch{}return p(r,n)}async function c(e){let n=[],i=async(e,s)=>{if(!(s>3))try{let c=await t(e,{withFileTypes:!0});for(let t of c){if(a.has(t.name))continue;let c=r(e,t.name);t.isDirectory()&&!t.name.startsWith(`.`)?await i(c,s+1):t.isFile()&&o.some(e=>e.glob.test(t.name))&&n.push(c)}}catch{}};return await i(e,0),n}function l(e){let t=n(e);for(let e of o)if(e.glob.test(t))return e.type;return`unknown`}const u=/(?:secret|password|token|key|api.?key|auth|credential|private)/i;function d(e,t){let n=[];if(t===`env`)for(let t of e.split(`
|
|
2
|
+
`)){let e=t.trim();if(!e||e.startsWith(`#`))continue;let r=e.indexOf(`=`);if(r===-1)continue;let i=e.slice(0,r).trim(),a=e.slice(r+1).trim(),o=u.test(i);n.push({key:i,value:o?`***`:a,sensitive:o})}else if(t===`package-json`)try{let t=JSON.parse(e);if(t.scripts)for(let[e,r]of Object.entries(t.scripts))n.push({key:`scripts.${e}`,value:String(r),sensitive:!1});if(t.engines)for(let[e,r]of Object.entries(t.engines))n.push({key:`engines.${e}`,value:String(r),sensitive:!1})}catch{}else if(t===`spring`)for(let t of e.split(`
|
|
3
|
+
`)){let e=t.trim();if(!e||e.startsWith(`#`)||e.startsWith(`---`))continue;let r=e.match(/^([\w.[\]-]+)\s*[=:]\s*(.*)$/);if(r){let e=r[1],t=r[2].trim(),i=u.test(e);n.push({key:e,value:i?`***`:t,sensitive:i})}}else if(t===`json`||t===`config`||t===`cdk`||t===`tooling`||t===`dotnet`)try{f(JSON.parse(e),``,n,0)}catch{}else if(t===`django`)for(let t of e.split(`
|
|
4
|
+
`)){let e=t.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.+)$/);if(e){let t=e[1],r=e[2].trim(),i=u.test(t);n.push({key:t,value:i?`***`:r.slice(0,100),sensitive:i})}}return n}function f(e,t,n,r){if(!(r>3)&&typeof e==`object`&&e&&!Array.isArray(e))for(let[i,a]of Object.entries(e)){let e=t?`${t}.${i}`:i;if(typeof a==`object`&&a&&!Array.isArray(a))f(a,e,n,r+1);else{let t=u.test(i),r=Array.isArray(a)?`[${a.length} items]`:String(a);n.push({key:e,value:t?`***`:r.slice(0,120),sensitive:t})}}}function p(e,t){let n=[];if(n.push(`## Configuration Values: ${t}\n`),e.length===0)return n.push(`No configuration files detected.`),n.join(`
|
|
5
|
+
`);n.push(`**${e.length} config files** found\n`);let r=new Map;for(let t of e)r.has(t.type)||r.set(t.type,[]),r.get(t.type)?.push(t);for(let[e,t]of r){if(e===`package-json`&&t.length>2){n.push(`### ${e}\n`);let r=t.find(e=>e.file===`package.json`);if(r){n.push(`#### ${r.file}\n`),n.push(`| Key | Value | Sensitive |`),n.push(`|-----|-------|-----------|`);for(let e of r.values.slice(0,50)){let t=e.value.replace(/\|/g,`\\|`);n.push(`| ${e.key} | ${t} | ${e.sensitive?`⚠️ yes`:`no`} |`)}n.push(``)}let i=t.filter(e=>e.file!==`package.json`);if(i.length>0){let e=new Map;for(let t of i)for(let n of t.values){let t=`${n.key}=${n.value}`;e.set(t,(e.get(t)??0)+1)}let t=Math.max(2,Math.floor(i.length*.5));n.push(`#### Sub-packages (${i.length} packages)\n`);let r=[...e.entries()].filter(([,e])=>e>=t).map(([e])=>{let[t,...n]=e.split(`=`);return{key:t,value:n.join(`=`)}});if(r.length>0){n.push(`**Common scripts** (shared by most sub-packages):
|
|
6
|
+
`),n.push(`| Key | Value |`),n.push(`|-----|-------|`);for(let e of r)n.push(`| ${e.key} | ${e.value.replace(/\|/g,`\\|`)} |`);n.push(``)}let a=new Map;for(let n of i){let r=n.values.filter(n=>{let r=`${n.key}=${n.value}`;return(e.get(r)??0)<t});if(r.length===0)continue;let i=r.map(e=>`${e.key}=${e.value}`).sort().join(`||`),o=a.get(i);o?o.files.push(n.file):a.set(i,{files:[n.file],entries:r.map(e=>({key:e.key,value:e.value}))})}for(let[,e]of a){e.files.length>1?n.push(`**${e.files.length} packages** (${e.files.map(e=>e.split(`/`).slice(-2,-1)[0]||e).join(`, `)}):`):n.push(`**${e.files[0]}**:`),n.push(`| Key | Value |`),n.push(`|-----|-------|`);for(let t of e.entries)n.push(`| ${t.key} | ${t.value.replace(/\|/g,`\\|`)} |`);n.push(``)}}continue}if(t.length>3){let r=t.map(e=>e.values.map(e=>`${e.key}=${e.value}`).sort().join(`||`)),i=r.sort((e,t)=>r.filter(e=>e===t).length-r.filter(t=>t===e).length)[0];if(r.filter(e=>e===i).length>2){n.push(`### ${e}\n`);let a=t[r.indexOf(i)],o=t.filter((e,t)=>r[t]===i).map(e=>e.file),s=t.filter((e,t)=>r[t]!==i);n.push(`**${o.length} identical files**: ${o.join(`, `)}\n`),n.push(`| Key | Value | Sensitive |`),n.push(`|-----|-------|-----------|`);for(let e of a.values.slice(0,30)){let t=e.value.replace(/\|/g,`\\|`);n.push(`| ${e.key} | ${t} | ${e.sensitive?`⚠️ yes`:`no`} |`)}n.push(``);for(let e of s){n.push(`#### ${e.file}\n`),n.push(`| Key | Value | Sensitive |`),n.push(`|-----|-------|-----------|`);for(let t of e.values.slice(0,30)){let e=t.value.replace(/\|/g,`\\|`);n.push(`| ${t.key} | ${e} | ${t.sensitive?`⚠️ yes`:`no`} |`)}n.push(``)}continue}}n.push(`### ${e}\n`);for(let e of t){n.push(`#### ${e.file}\n`),n.push(`| Key | Value | Sensitive |`),n.push(`|-----|-------|-----------|`);for(let t of e.values.slice(0,50)){let e=t.value.replace(/\|/g,`\\|`);n.push(`| ${t.key} | ${e} | ${t.sensitive?`⚠️ yes`:`no`} |`)}e.values.length>50&&n.push(`\n_...and ${e.values.length-50} more values._`),n.push(``)}}let i=e.reduce((e,t)=>e+t.values.filter(e=>e.sensitive).length,0);return i>0&&n.push(`\n**⚠️ ${i} sensitive values detected** (values masked).`),n.join(`
|
|
7
|
+
`)}export{s as extractConfigValues};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`).length-1,a=t.slice(r).match(/export\s+(?:async\s+)?(\w+)/);g.push({name:n[1],path:e.record.sourcePath,line:e.record.startLine+i,kind:a?.[1]??`unknown`})}}let y=new Map;for(let e of g){let t=`${e.path}:${e.name}`;y.has(t)||y.set(t,e)}let b=[];for(let
|
|
1
|
+
import{escapeRegExp as e}from"./regex-utils.js";import{readFile as t}from"node:fs/promises";import{extname as n}from"node:path";import{SUPPORTED_EXTENSIONS as r,WasmRuntime as i,extractSymbols as a}from"../../chunker/dist/index.js";const o=new Set([`.md`,`.mdx`]);async function s(s,l,u={}){let{rootPath:d,limit:f=100}=u,p=await s.embed(`export function class const type interface enum`),m=await l.search(p,{limit:f*3}),h=/^export\s+(?:async\s+)?(?:function|class|const|let|interface|type|enum)\s+(\w+)/gm,g=[],_=new Map;for(let e of m){if(!c(e.record.sourcePath,d))continue;let t=_.get(e.record.sourcePath)??[];t.push(e),_.set(e.record.sourcePath,t)}let v=new Set;if(i.get())for(let[e]of _){let i=n(e);if(r.has(i))try{let n=await a(await t(e,`utf-8`),i,e);for(let t of n)t.exported&&g.push({name:t.name,path:e,line:t.line,kind:t.kind});v.add(e)}catch{}}for(let[e,t]of _)if(!v.has(e))for(let e of t){let t=e.record.content;h.lastIndex=0;for(let n of t.matchAll(h)){let r=n.index??0,i=t.slice(0,r).split(`
|
|
2
|
+
`).length-1,a=t.slice(r).match(/export\s+(?:async\s+)?(\w+)/);g.push({name:n[1],path:e.record.sourcePath,line:e.record.startLine+i,kind:a?.[1]??`unknown`})}}let y=new Map;for(let e of g){let t=`${e.path}:${e.name}`;y.has(t)||y.set(t,e)}let b=[];for(let t of y.values()){let n=e(t.name),r=RegExp(`import\\s+.*\\b${n}\\b.*from`,`m`),i=RegExp(`export\\s+\\{[^}]*\\b${n}\\b`,`m`),a=await l.ftsSearch(`import ${t.name}`,{limit:10}),o=a.some(e=>e.record.sourcePath!==t.path&&r.test(e.record.content)),s=a.some(e=>e.record.sourcePath!==t.path&&i.test(e.record.content));!o&&!s&&b.push(t)}let x=(e,t)=>e.path===t.path?e.line-t.line:e.path.localeCompare(t.path),S=[],C=[];for(let e of b){let t=n(e.path).toLowerCase();o.has(t)?C.push(e):S.push(e)}return S.sort(x),C.sort(x),{deadInSource:S,deadInDocs:C,totalExports:y.size,totalDeadSource:S.length,totalDeadDocs:C.length}}function c(e,t){if(!t)return!0;let n=l(t).replace(/\/+$/,``),r=l(e);return r===n||r.startsWith(`${n}/`)}function l(e){return e.replace(/\\/g,`/`).replace(/^\.\//,``)}export{s as findDeadSymbols};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region packages/tools/src/diagram-builder.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Architecture diagram generation for onboard.
|
|
4
|
+
* Produces C4 Container + Architectural Flow Mermaid diagrams
|
|
5
|
+
* from AST call graph and analyzer data.
|
|
6
|
+
*/
|
|
7
|
+
declare function buildDiagrams(callGraph: Map<string, Map<string, string[]>>, dataMap: Map<string, Record<string, unknown>>, projectName: string): string;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { buildDiagrams };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{getPackageKey as e,isTestPath as t}from"./onboard-utils.js";function n(n,r,i){let a=r.get(`symbols`),o=r.get(`entry-points`),s=r.get(`dependencies`),c=new Map;for(let[r,i]of n)if(!t(r))for(let[n,a]of i){if(t(n))continue;let i=e(r),o=e(n);if(i===o)continue;let s=`${i}|${o}`;c.set(s,(c.get(s)??0)+a.length)}if(c.size===0)return`## Architecture Diagram
|
|
2
|
+
|
|
3
|
+
No cross-package dependencies detected.`;let l=new Set;for(let e of c.keys()){let[t,n]=e.split(`|`);l.add(t),l.add(n)}let u=new Map;if(a?.symbols)for(let n of a.symbols){if(!n.exported)continue;let r=n.filePath.replace(/\\/g,`/`);if(t(r))continue;let i=e(r);u.set(i,(u.get(i)??0)+1)}let d=new Map;if(o?.entryPoints)for(let t of o.entryPoints){let n=e(t.filePath.replace(/\\/g,`/`)),r=d.get(n);r?(r.count++,t.trigger&&r.triggers.add(t.trigger)):d.set(n,{count:1,triggers:new Set(t.trigger?[t.trigger]:[])})}let f=[];if(s?.external){let e=s.external,t={"client-dynamodb":{id:`dynamodb`,name:`DynamoDB`},"lib-dynamodb":{id:`dynamodb`,name:`DynamoDB`},"client-sqs":{id:`sqs`,name:`SQS`},"client-ses":{id:`ses`,name:`SES`},"client-sesv2":{id:`ses`,name:`SES`},"client-s3":{id:`s3`,name:`S3`},"client-eventbridge":{id:`eventbridge`,name:`EventBridge`},"client-sns":{id:`sns`,name:`SNS`},"client-secrets-manager":{id:`secrets`,name:`Secrets Manager`},"client-scheduler":{id:`scheduler`,name:`EventBridge Scheduler`},"client-apigatewaymanagementapi":{id:`apigw`,name:`API Gateway`},"client-cloudwatch":{id:`cloudwatch`,name:`CloudWatch`}},n=new Set;for(let r of Object.keys(e))for(let[e,i]of Object.entries(t))r.includes(e)&&!n.has(i.id)&&(n.add(i.id),f.push(i));f.sort((e,t)=>e.name.localeCompare(t.name))}let p=new Map;for(let e of[...l].sort()){let t=e.split(`/`)[0],n=p.get(t);n?n.push(e):p.set(t,[e])}let m=new Map;if(a?.symbols){let t=new Map;for(let n of a.symbols){let r=n.filePath.replace(/\\/g,`/`),i=e(r),a=r.match(/\.[^./]+$/)?.[0]||``;t.has(i)||t.set(i,new Map);let o=t.get(i);o.set(a,(o.get(a)??0)+1)}let n={".ts":`TypeScript`,".tsx":`TypeScript`,".js":`JavaScript`,".jsx":`JavaScript`,".java":`Java`,".kt":`Kotlin`,".scala":`Scala`,".py":`Python`,".go":`Go`,".rs":`Rust`,".cs":`C#`,".rb":`Ruby`,".php":`PHP`,".swift":`Swift`};for(let[e,r]of t){let t=``,i=0;for(let[e,n]of r)n>i&&(i=n,t=e);m.set(e,n[t]||`TypeScript`)}}let h=e=>e.replace(/[^a-zA-Z0-9]/g,`_`),g=[];g.push("```mermaid"),g.push(`C4Container`),g.push(` title C4 Container: ${i}`),g.push(``);let _=e=>{let t=[],n=d.get(e);n&&(t.push(`${n.count} handlers`),n.triggers.size>0&&t.push([...n.triggers].join(`, `)));let r=u.get(e);return r&&t.push(`${r} exports`),t.join(` · `)||``},v=e=>{let t=m.get(e)||`TypeScript`;if(e.startsWith(`infra`))return`CDK/${t}`;if(d.has(e)){let n=d.get(e);if(n?.triggers.has(`SQS`)||n?.triggers.has(`SNS`)||n?.triggers.has(`API Gateway`))return`Lambda/${t}`;if(n?.triggers.has(`HTTP Server`)||n?.triggers.has(`HTTP Endpoint`))return`Spring Boot/${t}`}return t};for(let[e,t]of[...p.entries()].sort()){let n=new Set([`com`,`org`,`net`,`io`,`dev`,`src`]).has(e)?i.charAt(0).toUpperCase()+i.slice(1):e.charAt(0).toUpperCase()+e.slice(1);if(t.length===1&&t[0]===e){let e=t[0];g.push(` Container(${h(e)}, "${e}", "${v(e)}", "${_(e)}")`)}else{g.push(` System_Boundary(${h(e)}_boundary, "${n}") {`);for(let e of t){let t=e.split(`/`).slice(1).join(`/`)||e;g.push(` Container(${h(e)}, "${t}", "${v(e)}", "${_(e)}")`)}g.push(` }`)}g.push(``)}if(f.length>0){for(let e of f)g.push(` System_Ext(ext_${e.id}, "${e.name}", "AWS")`);g.push(``)}let y=[...c.entries()].sort((e,t)=>t[1]-e[1]);for(let[e,t]of y.slice(0,30)){let[n,r]=e.split(`|`);g.push(` Rel(${h(n)}, ${h(r)}, "Uses", "${t} calls")`)}g.push("```");let b=`## C4 Container Diagram\n\n${g.join(`
|
|
4
|
+
`)}`,x=[];x.push("```mermaid"),x.push(`graph TB`);let S=new Set;for(let[,e]of d)for(let t of e.triggers)S.add(t);if(S.size>0){x.push(` subgraph Triggers["External Triggers"]`);for(let e of[...S].sort()){let t=`trigger_${e.replace(/[^a-zA-Z0-9]/g,`_`)}`;x.push(` ${t}(("${e}"))`)}x.push(` end`),x.push(``)}let C=[...l].filter(e=>d.has(e)).sort(),w=[...l].filter(e=>!d.has(e)).sort();if(C.length>0){x.push(` subgraph Services["Service Layer"]`);for(let e of C){let t=`flow_${h(e)}`,n=e.includes(`/`)?e.split(`/`).pop()??e:e,r=d.get(e);x.push(` ${t}["${n} (${r?.count??0} handlers)"]`)}x.push(` end`),x.push(``)}if(w.length>0){x.push(` subgraph Libraries["Shared Libraries"]`);for(let e of w){let t=`flow_${h(e)}`,n=e.includes(`/`)?e.split(`/`).pop()??e:e;x.push(` ${t}["${n}"]`)}x.push(` end`),x.push(``)}if(f.length>0){x.push(` subgraph External["AWS Services"]`);for(let e of f)x.push(` flow_ext_${e.id}[("${e.name}")]`);x.push(` end`),x.push(``)}for(let e of C){let t=d.get(e);if(!t)continue;let n=`flow_${h(e)}`;for(let e of t.triggers){let t=`trigger_${e.replace(/[^a-zA-Z0-9]/g,`_`)}`;x.push(` ${t} --> ${n}`)}}let T=y.filter(([e])=>{let[t,n]=e.split(`|`);return d.has(t)&&!d.has(n)});for(let[e,t]of T.slice(0,15)){let[n,r]=e.split(`|`);x.push(` flow_${h(n)} -->|${t}| flow_${h(r)}`)}let E=y.filter(([e])=>{let[t,n]=e.split(`|`);return!d.has(t)&&!d.has(n)});for(let[e,t]of E.slice(0,10)){let[n,r]=e.split(`|`);x.push(` flow_${h(n)} -->|${t}| flow_${h(r)}`)}x.push("```");let D=`## Architectural Flow\n\n${x.join(`
|
|
5
|
+
`)}`,O=[`# Architecture Diagrams: ${i}\n`];return O.push(b),O.push(D),O.join(`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
`)}export{n as buildDiagrams};
|
|
@@ -9,6 +9,7 @@ type EvidenceStatus = 'V' | 'A' | 'U';
|
|
|
9
9
|
type UnknownType = 'contract' | 'convention' | 'freshness' | 'runtime' | 'data-flow' | 'impact';
|
|
10
10
|
type GateDecision = 'YIELD' | 'HOLD' | 'HARD_BLOCK' | 'FORCED_DELIVERY';
|
|
11
11
|
type ForgeTier = 'floor' | 'standard' | 'critical';
|
|
12
|
+
type SafetyGate = 'provenance' | 'commitment' | 'coverage';
|
|
12
13
|
interface EvidenceEntry {
|
|
13
14
|
id: number;
|
|
14
15
|
claim: string;
|
|
@@ -16,6 +17,7 @@ interface EvidenceEntry {
|
|
|
16
17
|
receipt: string;
|
|
17
18
|
criticalPath: boolean;
|
|
18
19
|
unknownType?: UnknownType;
|
|
20
|
+
safetyGate?: SafetyGate;
|
|
19
21
|
}
|
|
20
22
|
interface EvidenceMapState {
|
|
21
23
|
taskId: string;
|
|
@@ -24,6 +26,12 @@ interface EvidenceMapState {
|
|
|
24
26
|
createdAt: string;
|
|
25
27
|
updatedAt: string;
|
|
26
28
|
}
|
|
29
|
+
interface SafetyGateResult {
|
|
30
|
+
provenance: 'pass' | 'fail';
|
|
31
|
+
commitment: 'pass' | 'fail';
|
|
32
|
+
coverage: 'pass' | 'fail';
|
|
33
|
+
failures: string[];
|
|
34
|
+
}
|
|
27
35
|
interface GateResult {
|
|
28
36
|
decision: GateDecision;
|
|
29
37
|
reason: string;
|
|
@@ -35,6 +43,7 @@ interface GateResult {
|
|
|
35
43
|
assumed: number;
|
|
36
44
|
unresolved: number;
|
|
37
45
|
};
|
|
46
|
+
safetyGates?: SafetyGateResult;
|
|
38
47
|
annotation?: string;
|
|
39
48
|
}
|
|
40
49
|
type EvidenceMapAction = {
|
|
@@ -49,6 +58,7 @@ type EvidenceMapAction = {
|
|
|
49
58
|
receipt: string;
|
|
50
59
|
criticalPath?: boolean;
|
|
51
60
|
unknownType?: UnknownType;
|
|
61
|
+
safetyGate?: SafetyGate;
|
|
52
62
|
} | {
|
|
53
63
|
action: 'update';
|
|
54
64
|
taskId: string;
|
|
@@ -77,5 +87,6 @@ interface EvidenceMapResult {
|
|
|
77
87
|
formattedMap?: string;
|
|
78
88
|
}
|
|
79
89
|
declare function evidenceMap(action: EvidenceMapAction, cwd?: string): EvidenceMapResult;
|
|
90
|
+
declare function autoClaimTestFailures(taskId: string, failures: string[], cwd?: string): EvidenceEntry[];
|
|
80
91
|
//#endregion
|
|
81
|
-
export { EvidenceEntry, EvidenceMapAction, EvidenceMapResult, EvidenceMapState, EvidenceStatus, ForgeTier, GateDecision, GateResult, UnknownType, evidenceMap };
|
|
92
|
+
export { EvidenceEntry, EvidenceMapAction, EvidenceMapResult, EvidenceMapState, EvidenceStatus, ForgeTier, GateDecision, GateResult, SafetyGate, SafetyGateResult, UnknownType, autoClaimTestFailures, evidenceMap };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{dirname as e,resolve as t}from"node:path";import{existsSync as n,mkdirSync as r,readFileSync as i,writeFileSync as a}from"node:fs";import{KB_PATHS as o}from"../../core/dist/index.js";const s=o.state;function c(e){return t(e??process.cwd(),s,`evidence-maps.json`)}function l(e){let t=c(e);if(!n(t))return{};try{let e=i(t,`utf-8`);return JSON.parse(e)}catch{return{}}}function u(t,i){let o=c(i),s=e(o);n(s)||r(s,{recursive:!0}),a(o,`${JSON.stringify(t,null,2)}\n`,`utf-8`)}function d(e,t){let n=l(t),r=n[e];if(!r)throw Error(`Evidence map not found: ${e}`);return{maps:n,state:r}}function f(e){return e.reduce((e,t)=>Math.max(e,t.id),0)+1}function p(e){let t=e.trim();if(!t)throw Error(`Claim is required`);if(/\r?\n/.test(t))throw Error(`Claim must be a single line`);return t}function m(e){return(e??``).replace(/\r?\n/g,` `).replace(/\|/g,`\\|`)}function h(e){let t=[`| # | Claim | Status | Receipt | Critical | Type
|
|
2
|
-
`)}function g(e){return{total:e.length,verified:e.filter(e=>e.status===`V`).length,assumed:e.filter(e=>e.status===`A`).length,unresolved:e.filter(e=>e.status===`U`).length}}function _(e){let t=[];for(let n of e.entries)n.status===`V`&&n.receipt.trim()===``&&t.push(`V entry without receipt`),n.status===`A`&&e.tier===`critical`&&n.unknownType===`contract`&&t.push(`Assumed contract at Critical tier — should be Verified`);return t}function v(e){return`FORCED DELIVERY annotation: unresolved entries remain -> ${e.filter(e=>e.status===`U`).map(e=>`#${e.id} ${e.claim}`).join(`; `)}`}function y(e,t=0){let n=e.entries.filter(e=>e.criticalPath&&e.status===`U`),r=_(e),i=g(e.entries);return n.find(e=>e.unknownType===`contract`)?{decision:`HARD_BLOCK`,reason:`Unresolved contract unknown on critical path`,unresolvedCritical:n,warnings:r,stats:i}:n.length>0&&t===0?{decision:`HOLD`,reason:`Unresolved critical-path unknown — retry available`,unresolvedCritical:n,warnings:r,stats:i}:n.length>0&&t>=1?{decision:`FORCED_DELIVERY`,reason:`Unresolved critical-path unknown after retry`,unresolvedCritical:n,warnings:r,stats:i,annotation:v(e.entries)}:{decision:`YIELD`,reason:`All critical-path claims satisfy gate rules`,unresolvedCritical:[],warnings:r,stats:i}}function
|
|
1
|
+
import{dirname as e,resolve as t}from"node:path";import{existsSync as n,mkdirSync as r,readFileSync as i,writeFileSync as a}from"node:fs";import{KB_PATHS as o}from"../../core/dist/index.js";const s=o.state;function c(e){return t(e??process.cwd(),s,`evidence-maps.json`)}function l(e){let t=c(e);if(!n(t))return{};try{let e=i(t,`utf-8`);return JSON.parse(e)}catch{return{}}}function u(t,i){let o=c(i),s=e(o);n(s)||r(s,{recursive:!0}),a(o,`${JSON.stringify(t,null,2)}\n`,`utf-8`)}function d(e,t){let n=l(t),r=n[e];if(!r)throw Error(`Evidence map not found: ${e}`);return{maps:n,state:r}}function f(e){return e.reduce((e,t)=>Math.max(e,t.id),0)+1}function p(e){let t=e.trim();if(!t)throw Error(`Claim is required`);if(/\r?\n/.test(t))throw Error(`Claim must be a single line`);return t}function m(e){return(e??``).replace(/\r?\n/g,` `).replace(/\|/g,`\\|`)}function h(e){let t=[`| # | Claim | Status | Receipt | Critical | Type | Safety |`,`|---|-------|--------|---------|----------|------|--------|`];for(let n of e.entries)t.push(`| ${n.id} | ${m(n.claim)} | ${n.status} | ${m(n.receipt)} | ${n.criticalPath?`yes`:`no`} | ${m(n.unknownType)} | ${m(n.safetyGate)} |`);return t.join(`
|
|
2
|
+
`)}function g(e){return{total:e.length,verified:e.filter(e=>e.status===`V`).length,assumed:e.filter(e=>e.status===`A`).length,unresolved:e.filter(e=>e.status===`U`).length}}function _(e){let t=[];for(let n of e.entries)n.status===`V`&&n.receipt.trim()===``&&t.push(`V entry without receipt`),n.status===`A`&&e.tier===`critical`&&n.unknownType===`contract`&&t.push(`Assumed contract at Critical tier — should be Verified`);return t}function v(e){return`FORCED DELIVERY annotation: unresolved entries remain -> ${e.filter(e=>e.status===`U`).map(e=>`#${e.id} ${e.claim}`).join(`; `)}`}function y(e){let t=[],n=e.entries.filter(e=>e.status===`V`&&!e.receipt.trim());n.length>0&&t.push(`Provenance: ${n.length} verified claim(s) lack receipts`);let r=e.entries.filter(e=>e.safetyGate===`commitment`&&e.status!==`V`);r.length>0&&t.push(`Commitment: ${r.length} commitment(s) not verified`);let i=e.entries.some(e=>e.safetyGate===`coverage`&&e.status===`U`);return i&&t.push(`Coverage: unresolved coverage entries remain`),{provenance:n.length>0?`fail`:`pass`,commitment:r.length>0?`fail`:`pass`,coverage:i?`fail`:`pass`,failures:t}}function b(e,t=0){let n=e.entries.filter(e=>e.criticalPath&&e.status===`U`),r=_(e),i=g(e.entries);return n.find(e=>e.unknownType===`contract`)?{decision:`HARD_BLOCK`,reason:`Unresolved contract unknown on critical path`,unresolvedCritical:n,warnings:r,stats:i}:n.length>0&&t===0?{decision:`HOLD`,reason:`Unresolved critical-path unknown — retry available`,unresolvedCritical:n,warnings:r,stats:i}:n.length>0&&t>=1?{decision:`FORCED_DELIVERY`,reason:`Unresolved critical-path unknown after retry`,unresolvedCritical:n,warnings:r,stats:i,annotation:v(e.entries)}:{decision:`YIELD`,reason:`All critical-path claims satisfy gate rules`,unresolvedCritical:[],warnings:r,stats:i,...x(e,r,i)}}function x(e,t,n){if(!e.entries.some(e=>e.safetyGate)||e.tier===`floor`)return{};let r=y(e);return r.failures.length>0?{safetyGates:r,decision:`HOLD`,reason:`Safety gate failure: ${r.failures.join(`; `)}`,warnings:[...t,...r.failures]}:{safetyGates:r}}function S(e,t){switch(e.action){case`create`:{let n=l(t),r=new Date().toISOString(),i={taskId:e.taskId,tier:e.tier,entries:[],createdAt:r,updatedAt:r};return n[e.taskId]=i,u(n,t),{state:i,formattedMap:h(i)}}case`add`:{let{maps:n,state:r}=d(e.taskId,t),i={id:f(r.entries),claim:p(e.claim),status:e.status,receipt:e.receipt,criticalPath:e.criticalPath??!1,unknownType:e.unknownType,safetyGate:e.safetyGate};return r.entries.push(i),r.updatedAt=new Date().toISOString(),n[e.taskId]=r,u(n,t),{state:r,entry:i,formattedMap:h(r)}}case`update`:{let{maps:n,state:r}=d(e.taskId,t),i=r.entries.find(t=>t.id===e.id);if(!i)throw Error(`Evidence entry not found: ${e.id}`);return i.status=e.status,i.receipt=e.receipt,r.updatedAt=new Date().toISOString(),n[e.taskId]=r,u(n,t),{state:r,entry:i,formattedMap:h(r)}}case`get`:{let{state:n}=d(e.taskId,t);return{state:n,formattedMap:h(n)}}case`gate`:{let{state:n}=d(e.taskId,t);return{state:n,gate:b(n,e.retryCount??0),formattedMap:h(n)}}case`list`:return{states:Object.values(l(t)).sort((e,t)=>e.createdAt.localeCompare(t.createdAt))};case`delete`:{let n=l(t);return e.taskId in n?(delete n[e.taskId],u(n,t),{deleted:!0}):{deleted:!1}}}}function C(e,t,n){let r=[];for(let i of t){let t=S({action:`add`,taskId:e,claim:`Test failure: ${i}`,status:`U`,receipt:``,criticalPath:!0},n);t.entry&&r.push(t.entry)}return r}export{C as autoClaimTestFailures,S as evidenceMap};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
async function
|
|
1
|
+
import{escapeRegExp as e}from"./regex-utils.js";async function t(t,n,r){let{query:i,limit:a=5,contentType:o}=r,s=`usage example of ${i}`,c=await t.embed(s),l=await n.search(c,{limit:a*3,contentType:o}),u=RegExp(`\\b${e(i)}\\b`,`i`),d=l.filter(e=>u.test(e.record.content));return{query:i,examples:d.map(e=>{let t=e.record.content,n=/export\s+(?:async\s+)?(?:function|class|const|interface|type)\s/.test(t),r=/^\s*import\s/m.test(t),i=/(?:^|[\\/])(test|tests|__tests__|spec)(?:[\\/]|$)/i.test(e.record.sourcePath)||/\.(test|spec)\.[jt]sx?$/i.test(e.record.sourcePath),a=0;n||(a+=.1),r||(a+=.05),i&&(a+=.05);let o=t.split(`
|
|
2
2
|
`),s=o.findIndex(e=>u.test(e)),c=Math.max(0,s-2),l=Math.min(o.length,s+5),d=o.slice(c,l).join(`
|
|
3
|
-
`);return{path:e.record.sourcePath,startLine:e.record.startLine,endLine:e.record.endLine,content:d||t.slice(0,300),relevance:Math.min(1,e.score+a),context:i?`test`:n?`definition`:`usage`}}).sort((e,t)=>t.relevance-e.relevance).slice(0,a),totalFound:d.length}}
|
|
3
|
+
`);return{path:e.record.sourcePath,startLine:e.record.startLine,endLine:e.record.endLine,content:d||t.slice(0,300),relevance:Math.min(1,e.score+a),context:i?`test`:n?`definition`:`usage`}}).sort((e,t)=>t.relevance-e.relevance).slice(0,a),totalFound:d.length}}export{t as findExamples};
|