@vpxa/aikit 0.1.133 → 0.1.134
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/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./curated-manager-BkSgtNC2.js";import{readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{fileURLToPath as i,pathToFileURL as a}from"node:url";import{parseArgs as o}from"node:util";import{createLogger as s,serializeError as c}from"../../core/dist/index.js";const l=n(i(import.meta.url)),u=(()=>{try{let e=r(l,`..`,`..`,`..`,`package.json`);return JSON.parse(t(e,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}})(),d=s(`server`);function f(){return process.env.AIKIT_TRANSPORT?process.env.AIKIT_TRANSPORT:process.stdin.isTTY?`http`:`stdio`}const{values:p}=(()=>{let e=process.argv[1];if(!e)return!1;try{return import.meta.url===a(e).href}catch{return!1}})()?o({allowPositionals:!0,options:{transport:{type:`string`,default:f()},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}}):{values:{transport:f(),port:process.env.AIKIT_PORT??`3210`}};async function m(){if(process.on(`unhandledRejection`,e=>{d.error(`Unhandled rejection`,c(e))}),d.info(`Starting MCP AI Kit server`,{version:u}),p.transport===`http`){let[{default:e},{loadConfig:t,resolveIndexMode:n},{registerDashboardRoutes:r,resolveDashboardDir:i},{registerSettingsRoutes:a,resolveSettingsDir:o},{createSettingsRouter:s}]=await Promise.all([import(`express`),import(`./config-D4z6-EcI.js`),import(`./dashboard-static-BfIe0Si1.js`),import(`./settings-static-BosGZSPf.js`),import(`./routes-OaSHcA6x.js`)]),l=t();d.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path});let u=e();u.use(e.json());let f=Number(p.port);u.use((e,t,n)=>{if(t.setHeader(`Access-Control-Allow-Origin`,process.env.AIKIT_CORS_ORIGIN??`http://localhost:${f}`),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, PATCH, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization`),e.method===`OPTIONS`){t.status(204).end();return}n()}),r(u,i(),d);let m=new Date().toISOString();u.use(`/settings/api`,s({log:d,mcpInfo:()=>({transport:`http`,port:f,pid:process.pid,startedAt:m})})),a(u,o(),d),u.get(`/health`,(e,t)=>{t.json({status:`ok`})});let h=!1,g=null,_=null,v=null,y=Promise.resolve();u.post(`/mcp`,async(e,t)=>{if(!h||!_||!v){t.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let n=y,r;y=new Promise(e=>{r=e}),await n;try{let n=new v({sessionIdGenerator:void 0});await _.connect(n),await n.handleRequest(e,t,e.body),n.close()}catch(e){if(d.error(`MCP handler error`,c(e)),!t.headersSent){let n=e instanceof Error?e.message:String(e),r=n.includes(`Not Acceptable`);t.status(r?406:500).json({jsonrpc:`2.0`,error:{code:r?-32e3:-32603,message:r?n:`Internal server error`},id:null})}}finally{r()}}),u.get(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))}),u.delete(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))});let b=u.listen(f,`127.0.0.1`,()=>{d.info(`MCP server listening`,{url:`http://127.0.0.1:${f}/mcp`,port:f}),setTimeout(async()=>{try{let[{createLazyServer:e,ALL_TOOL_NAMES:t},{StreamableHTTPServerTransport:r},{checkForUpdates:i,autoUpgradeScaffold:a}]=await Promise.all([import(`./server-
|
|
1
|
+
import{t as e}from"./curated-manager-BkSgtNC2.js";import{readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{fileURLToPath as i,pathToFileURL as a}from"node:url";import{parseArgs as o}from"node:util";import{createLogger as s,serializeError as c}from"../../core/dist/index.js";const l=n(i(import.meta.url)),u=(()=>{try{let e=r(l,`..`,`..`,`..`,`package.json`);return JSON.parse(t(e,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}})(),d=s(`server`);function f(){return process.env.AIKIT_TRANSPORT?process.env.AIKIT_TRANSPORT:process.stdin.isTTY?`http`:`stdio`}const{values:p}=(()=>{let e=process.argv[1];if(!e)return!1;try{return import.meta.url===a(e).href}catch{return!1}})()?o({allowPositionals:!0,options:{transport:{type:`string`,default:f()},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}}):{values:{transport:f(),port:process.env.AIKIT_PORT??`3210`}};async function m(){if(process.on(`unhandledRejection`,e=>{d.error(`Unhandled rejection`,c(e))}),d.info(`Starting MCP AI Kit server`,{version:u}),p.transport===`http`){let[{default:e},{loadConfig:t,resolveIndexMode:n},{registerDashboardRoutes:r,resolveDashboardDir:i},{registerSettingsRoutes:a,resolveSettingsDir:o},{createSettingsRouter:s}]=await Promise.all([import(`express`),import(`./config-D4z6-EcI.js`),import(`./dashboard-static-BfIe0Si1.js`),import(`./settings-static-BosGZSPf.js`),import(`./routes-OaSHcA6x.js`)]),l=t();d.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path});let u=e();u.use(e.json());let f=Number(p.port);u.use((e,t,n)=>{if(t.setHeader(`Access-Control-Allow-Origin`,process.env.AIKIT_CORS_ORIGIN??`http://localhost:${f}`),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, PATCH, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization`),e.method===`OPTIONS`){t.status(204).end();return}n()}),r(u,i(),d);let m=new Date().toISOString();u.use(`/settings/api`,s({log:d,mcpInfo:()=>({transport:`http`,port:f,pid:process.pid,startedAt:m})})),a(u,o(),d),u.get(`/health`,(e,t)=>{t.json({status:`ok`})});let h=!1,g=null,_=null,v=null,y=Promise.resolve();u.post(`/mcp`,async(e,t)=>{if(!h||!_||!v){t.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let n=y,r;y=new Promise(e=>{r=e}),await n;try{let n=new v({sessionIdGenerator:void 0});await _.connect(n),await n.handleRequest(e,t,e.body),n.close()}catch(e){if(d.error(`MCP handler error`,c(e)),!t.headersSent){let n=e instanceof Error?e.message:String(e),r=n.includes(`Not Acceptable`);t.status(r?406:500).json({jsonrpc:`2.0`,error:{code:r?-32e3:-32603,message:r?n:`Internal server error`},id:null})}}finally{r()}}),u.get(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))}),u.delete(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))});let b=u.listen(f,`127.0.0.1`,()=>{d.info(`MCP server listening`,{url:`http://127.0.0.1:${f}/mcp`,port:f}),setTimeout(async()=>{try{let[{createLazyServer:e,ALL_TOOL_NAMES:t},{StreamableHTTPServerTransport:r},{checkForUpdates:i,autoUpgradeScaffold:a}]=await Promise.all([import(`./server-Cn7iAvm9.js`),import(`@modelcontextprotocol/sdk/server/streamableHttp.js`),import(`./version-check-Bj07vc5x.js`)]);i(),a();let o=n(l),s=e(l,o);_=s.server,v=r,h=!0,d.info(`MCP server configured (lazy — AI Kit initializing in background)`,{toolCount:t.length,resourceCount:2}),s.startInit(),o===`auto`?s.ready.then(async()=>{try{let e=l.sources.map(e=>e.path).join(`, `);d.info(`Running initial index`,{sourcePaths:e}),await s.runInitialIndex(),d.info(`Initial index complete`)}catch(e){d.error(`Initial index failed; will retry on aikit_reindex`,c(e))}}).catch(e=>d.error(`AI Kit init or indexing failed`,c(e))):o===`smart`?s.ready.then(async()=>{try{if(!s.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(s.aikit.indexer,l,s.aikit.store),n=s.aikit.store;g=t,t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),s.setSmartScheduler(t),d.info(`Smart index scheduler started (HTTP mode)`)}catch(e){d.error(`Failed to start smart index scheduler`,c(e))}}).catch(e=>d.error(`AI Kit initialization failed`,c(e))):(s.ready.catch(e=>d.error(`AI Kit initialization failed`,c(e))),d.info(`Initial full indexing skipped in HTTP mode`,{indexMode:o}))}catch(e){d.error(`Failed to load server modules`,c(e))}},100)}),x=async e=>{d.info(`Shutdown signal received`,{signal:e}),g?.stop(),b.close(),_&&await _.close(),process.exit(0)};process.on(`SIGINT`,()=>x(`SIGINT`)),process.on(`SIGTERM`,()=>x(`SIGTERM`))}else{let[{loadConfig:e,reconfigureForWorkspace:t,resolveIndexMode:n},{createLazyServer:r},{checkForUpdates:a,autoUpgradeScaffold:o},{RootsListChangedNotificationSchema:s}]=await Promise.all([import(`./config-D4z6-EcI.js`),import(`./server-Cn7iAvm9.js`),import(`./version-check-Bj07vc5x.js`),import(`@modelcontextprotocol/sdk/types.js`)]),l=e();d.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path}),a(),o();let u=n(l),f=r(l,u),{server:p,startInit:m,ready:h,runInitialIndex:g}=f,{StdioServerTransport:_}=await import(`@modelcontextprotocol/sdk/server/stdio.js`),v=new _;await p.connect(v),d.info(`MCP server started`,{transport:`stdio`});let y=e=>{if(e.length===0)return!1;let n=e[0].uri,r=n.startsWith(`file://`)?i(n):n;return d.info(`MCP roots resolved`,{rootUri:n,rootPath:r,rootCount:e.length}),t(l,r),l.allRoots=e.map(e=>{let t=e.uri;return t.startsWith(`file://`)?i(t):t}),!0},b=!1;try{b=y((await p.server.listRoots()).roots),b||d.info(`No MCP roots yet; waiting for roots/list_changed notification`)}catch(e){d.warn(`MCP roots/list not supported by client; using cwd fallback`,{cwd:process.cwd(),...c(e)}),b=!0}b||=await new Promise(e=>{let t=setTimeout(()=>{d.warn(`Timed out waiting for MCP roots/list_changed; using cwd fallback`,{cwd:process.cwd()}),e(!1)},5e3);p.server.setNotificationHandler(s,async()=>{clearTimeout(t);try{e(y((await p.server.listRoots()).roots))}catch(t){d.warn(`roots/list retry failed after notification`,c(t)),e(!1)}})}),m();let x=null,S=()=>{x&&clearTimeout(x),x=setTimeout(()=>{d.info(`Auto-shutdown: no activity for 30 minutes — exiting`),process.exit(0)},18e5),x.unref&&x.unref()};S(),process.stdin.on(`data`,()=>S()),h.catch(e=>{d.error(`Initialization failed — server will continue with limited tools`,c(e))}),u===`auto`?g().catch(e=>d.error(`Initial index failed`,c(e))):u===`smart`?h.then(async()=>{try{if(!f.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(f.aikit.indexer,l,f.aikit.store),n=f.aikit.store;t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),f.setSmartScheduler(t),d.info(`Smart index scheduler started (stdio mode)`)}catch(e){d.error(`Failed to start smart index scheduler`,c(e))}}).catch(e=>d.error(`AI Kit init failed for smart scheduler`,c(e))):d.warn(`Initial full indexing skipped; use aikit_reindex to index manually`,{indexMode:u})}}m().catch(e=>{d.error(`Fatal error`,c(e)),process.exit(1)});export{e as CuratedKnowledgeManager};
|
|
@@ -347,9 +347,9 @@ $3`),n.push(t);break}case`code`:n.push(`\`\`\`${e.language??``}\n${String(e.valu
|
|
|
347
347
|
`)}function Kl(e){return e.map(e=>`- **${e.label}**: ${e.value}`).join(`
|
|
348
348
|
`)}function ql(e){let t=["```mermaid",`graph LR`];for(let n of e.nodes){let e=Ia(String(n.id??n.name??``)),r=String(n.label??n.name??e);t.push(` ${e}["${r}"]`)}for(let n of e.edges){let e=Ia(String(n.source??n.from??``)),r=Ia(String(n.target??n.to??``)),i=n.label?`|${String(n.label)}|`:``;t.push(` ${e} -->${i} ${r}`)}return t.push("```"),t.join(`
|
|
349
349
|
`)}function Jl(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(Jl(a,t+1))):r.push(`${n}- **${i}**: ${Fa(a)}`);return r.join(`
|
|
350
|
-
`)}function Yl(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Xl(e){return e.replace(/<table\b/g,`<div class="table-wrap"><table`).replace(/<\/table>/g,`</table></div>`)}function Zl(e
|
|
351
|
-
`);return i.includes(`class="mermaid"`)&&!i.includes(`mermaid.min.js`)?`${i}\n<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"><\/script>\n<script>mermaid.run();<\/script>`:i}function
|
|
352
|
-
`)}const
|
|
350
|
+
`)}function Yl(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Xl(e){return e.replace(/<table\b/g,`<div class="table-wrap"><table`).replace(/<\/table>/g,`</table></div>`)}function Zl(e,t){if(typeof e!=`object`||!e)return`<p>${U(String(e))}</p>`;let n=e;return typeof n.type==`string`?vu(Jc(n),t):`<pre>${U(JSON.stringify(e,null,2))}</pre>`}function Ql(e,t,n=`inline`){let r=[];if(e&&r.push(`<h1>${U(e)}</h1>`),typeof t==`string`)r.push(`<div class="md-content">${Xl(An.parse(t))}</div>`);else if(Array.isArray(t))if(t.length===0)r.push(`<p><em>empty</em></p>`);else if(Xc(t[0]))for(let e of t)r.push(Zl(e,n));else typeof t[0]==`object`&&t[0]!==null?r.push(Fl(t)):r.push(`<ul>${t.map(e=>`<li>${U(String(e))}</li>`).join(``)}</ul>`);else if(typeof t==`object`&&t){let e=t;if(Array.isArray(e.blocks)&&e.blocks.length>0)for(let t of e.blocks)r.push(Zl(t,n));else Array.isArray(e.metrics)?r.push(Il(e.metrics)):Array.isArray(e.nodes)&&Array.isArray(e.edges)?r.push(`<pre class="mermaid">${U(Bl(e))}</pre>`):r.push(Rl(e))}else r.push(`<p>${U(String(t))}</p>`);let i=r.join(`
|
|
351
|
+
`);return i.includes(`class="mermaid"`)&&!i.includes(`mermaid.min.js`)?`${i}\n<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"><\/script>\n<script>mermaid.run();<\/script>`:i}function $l(e){let t=String(e.value??``);return/^\s*</.test(t)?`<div class="md-content">${t}</div>`:`<div class="md-content">${Xl(An.parse(t))}</div>`}function eu(e){return`<pre><code>${U(String(e.value??``))}</code></pre>`}function tu(e){return`<pre class="mermaid">${U(String(e.value??``))}</pre>`}function nu(e){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);return Fl(e.slice(1).map(e=>Object.fromEntries(n.map((t,n)=>[t,e[n]]))))}return Fl(t)}if(e.value&&typeof e.value==`object`&&`headers`in e.value&&`rows`in e.value){let{headers:t,rows:n}=e.value;return Fl(n.map(e=>Object.fromEntries(t.map((t,n)=>[t,e[n]]))))}return``}function ru(e){let t;return 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?Il(t):``}function iu(e){return Array.isArray(e.value)?Ll(e.value):``}function au(e){return e.value&&typeof e.value==`object`?Rl(e.value):``}function ou(e,t){return!e.value||typeof e.value!=`object`?``:`<pre class="mermaid">${U(Bl(e.value))}</pre>`}function su(e){let t=e.value;return 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?fl(t):``}function cu(e){return e.value?pl(Array.isArray(e.value)?{items:e.value}:e.value):``}function lu(e){return e.value?ml(Array.isArray(e.value)?{columns:e.value}:e.value):``}function uu(e){return e.value?hl(Array.isArray(e.value)?{items:e.value}:e.value):``}function du(e){if(!e.value)return``;let t=e.value;return Array.isArray(t)?t={items:t}:Yl(t)&&!(`items`in t)&&`label`in t&&`value`in t&&(t={items:[t]}),_l(t)}function fu(e){return`<div class="md-content">${An.parse(String(e.value??``))}</div>`}function pu(e){let t=Math.min(Math.max(Number(e.level)||2,1),6);return`<h${t}>${U(String(e.value??``))}</h${t}>`}function mu(e){return`<p>${U(String(e.value??``))}</p>`}function hu(e){return`<div class="action-bar">${(Array.isArray(e.value)?e.value:[]).map(e=>{if(e.type===`select`){let t=Array.isArray(e.options)?e.options.map(e=>`<option value="${U(String(e.value??e.label??``))}">${U(String(e.label??e.value??``))}</option>`).join(``):``;return`<select class="action-select"><option value="">${U(String(e.label??`Select...`))}</option>${t}</select>`}return`<button class="action-btn action-${String(e.variant??`secondary`)}">${U(String(e.label??``))}</button>`}).join(``)}</div>`}function gu(e){return`<pre>${U(JSON.stringify(e.value,null,2))}</pre>`}const _u=new Map([[`markdown`,e=>$l(e)],[`code`,e=>eu(e)],[`mermaid`,e=>tu(e)],[`table`,e=>nu(e)],[`metrics`,e=>ru(e)],[`cards`,e=>iu(e)],[`tree`,e=>au(e)],[`graph`,(e,t)=>ou(e,t)],[`chart`,e=>Sl(e)],[`timeline`,e=>su(e)],[`checklist`,e=>cu(e)],[`comparison`,e=>lu(e)],[`status-board`,e=>uu(e)],[`prompt`,e=>e.value?gl(e.value):``],[`progress`,e=>du(e)],[`docs-browser`,e=>e.value?vl(e.value):``],[`text`,e=>fu(e)],[`heading`,e=>pu(e)],[`paragraph`,e=>mu(e)],[`separator`,()=>`<hr class="separator">`],[`actions`,e=>hu(e)]]);function vu(e,t=`inline`){let n=[];e.title&&n.push(`<h2>${U(e.title)}</h2>`);let r=_u.get(e.type);return n.push(r?r(e,t):gu(e)),n.join(`
|
|
352
|
+
`)}const yu=import.meta.dirname??g(b(import.meta.url));function bu(e){let t=e;for(let e=0;e<10;e++){try{let e=v(t,`package.json`);if(o(e)&&JSON.parse(c(e,`utf8`)).name===`@vpxa/aikit`)return t}catch{}let e=g(t);if(e===t)break;t=e}return y(e,`..`,`..`,`..`)}const xu=`ui://aikit/present.html`;function Su(e){return Array.isArray(e)?e:[]}function Cu(e){return e.length===0?``:`<section class="present-inline-actions"><div class="action-bar">${e.map(e=>{let t=U(String(e.id??``)),n=U(String(e.label??`Action`));return e.type===`select`?`<label class="action-select-wrap"><span>${n}</span><select class="action-select" data-present-action="select" data-action-id="${t}"><option value="">${n}</option>${Array.isArray(e.options)?e.options.map(e=>{if(typeof e==`string`){let t=U(e);return`<option value="${t}">${t}</option>`}return`<option value="${U(String(e.value??e.label??``))}">${U(String(e.label??e.value??``))}</option>`}).join(``):``}</select></label>`:`<button type="button" class="action-btn action-${U(String(e.variant??`default`))}" data-present-action="button" data-action-id="${t}" data-action-value="clicked">${n}</button>`}).join(``)}</div><div id="action-feedback" class="action-feedback" aria-live="polite"></div></section>`}function wu(e,t,n){return`<!DOCTYPE html>
|
|
353
353
|
<html lang="en">
|
|
354
354
|
<head>
|
|
355
355
|
<meta charset="utf-8">
|
|
@@ -427,8 +427,8 @@ $3`),n.push(t);break}case`code`:n.push(`\`\`\`${e.language??``}\n${String(e.valu
|
|
|
427
427
|
</head>
|
|
428
428
|
<body>
|
|
429
429
|
<div class="present-inline-root">
|
|
430
|
-
${
|
|
431
|
-
${
|
|
430
|
+
${Ql(e,t,`inline`)}
|
|
431
|
+
${Cu(n)}
|
|
432
432
|
</div>
|
|
433
433
|
<script>
|
|
434
434
|
function sendCallback(actionId, value) {
|
|
@@ -463,7 +463,7 @@ $3`),n.push(t);break}case`code`:n.push(`\`\`\`${e.language??``}\n${String(e.valu
|
|
|
463
463
|
});
|
|
464
464
|
<\/script>
|
|
465
465
|
</body>
|
|
466
|
-
</html>`}const
|
|
466
|
+
</html>`}const Tu=F.object({type:F.enum([`button`,`select`]).describe(`Action type`),id:F.string().describe(`Unique action identifier`),label:F.string().describe(`Display label`),variant:F.enum([`primary`,`danger`,`default`]).optional().describe(`Button style variant`),options:F.array(F.union([F.string(),F.object({label:F.string(),value:F.string()})])).optional().describe(`Select options (for type=select)`)}),Eu={format:F.enum([`html`,`browser`]).default(`html`).describe(`Output format.
|
|
467
467
|
- "html" (default): Rich markdown in chat + embedded UIResource for MCP-UI hosts. Actions shown as numbered choices.
|
|
468
468
|
- "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 user clicks, returning their selection.`),title:F.string().optional().describe(`Optional heading`),content:F.any().describe(`Content to present. Accepts these shapes:
|
|
469
469
|
• markdown string — rendered as rich text
|
|
@@ -471,7 +471,7 @@ $3`),n.push(t);break}case`code`:n.push(`\`\`\`${e.language??``}\n${String(e.valu
|
|
|
471
471
|
• { nodes, edges } — rendered as mermaid graph
|
|
472
472
|
• typed blocks array [{ type, title?, value }] — the primary format:
|
|
473
473
|
${Ec()}\n• any JSON — rendered as collapsible tree
|
|
474
|
-
IMPORTANT: For charts, use the ChartValue format above. Do NOT use Chart.js format ({labels, datasets}) — it will be auto-converted but the native format is preferred.`),actions:F.array(
|
|
474
|
+
IMPORTANT: For charts, use the ChartValue format above. Do NOT use Chart.js format ({labels, datasets}) — it will be auto-converted but the native format is preferred.`),actions:F.array(Tu).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.`),template:F.enum([`auto`,`list-sort`,`data-table`,`picker`,`flame-graph`,`form`,`timeline`,`kanban`,`tree`,`diff-view`,`dashboard`]).optional().describe(`UI template for interactive display in MCP Apps hosts.
|
|
475
475
|
- auto (default): detect from content shape
|
|
476
476
|
- list-sort: drag-drop reorderable list — content: { items: [{id, label}] }
|
|
477
477
|
- data-table: filterable sortable table — content: { columns: [{key, label}], rows: [{...}], stats?: [{label, value}] }
|
|
@@ -482,15 +482,15 @@ IMPORTANT: For charts, use the ChartValue format above. Do NOT use Chart.js form
|
|
|
482
482
|
- kanban: drag-drop board — content: { columns: [{id, label, color?}], cards: [{id, title, column, tags?[], priority?}] }
|
|
483
483
|
- tree: collapsible tree view — content: { root: {label, children?:[...]} | [...] }
|
|
484
484
|
- diff-view: side-by-side diff — content: { files: [{path, status, additions, deletions, hunks:[{header, changes:[{type, content}]}]}] }
|
|
485
|
-
- dashboard: metric cards grid — content: { metrics: [{label, value, trend?, status?, type?}] }`)};let Ou
|
|
485
|
+
- dashboard: metric cards grid — content: { metrics: [{label, value, trend?, status?, type?}] }`)};let Du,Ou=!1,ku=null;process.on(`exit`,()=>{if(ku){try{ku.close()}catch{}ku=null}});function Au(){let e=bu(yu),t=v(e,`packages`,`present`,`dist`,`index.html`);return o(t)?t:v(e,`packages`,`present`,`index.html`)}function ju(){if(!Du)try{Du=c(Au(),`utf-8`)}catch{Du=``}return Du}function Mu(e,t){let n=z(`present`),r=ju(),i=`Present content to the user in the best format. Two modes:
|
|
486
486
|
- "html" (default): Rich markdown in chat + embedded UIResource. Use for display-only content (tables, charts, reports, status boards) where no user interaction is needed.
|
|
487
487
|
- "browser": Serves a themed dashboard on a local URL. Use ONLY when you need user interaction back (confirmations, selections, form input). The tool blocks until user clicks an action button, then returns their selection.
|
|
488
488
|
FORMAT RULE: If no user interaction is needed → use "html". If you need user input back → use "browser".
|
|
489
489
|
CONTENT GUIDE: Pass typed blocks [{ type, title?, value }] for structured content. See the \`content\` parameter description for all supported block types and their value shapes. For charts: use {chartType, data:Record[], xKey, yKeys} — NOT Chart.js format.
|
|
490
|
-
BROWSER WORKFLOW: After calling present with format "browser", you MUST extract the URL from the response and call openBrowserPage({ url }) tool - PlayWright MCP to open it in VS Code Simple Browser. A system browser fallback also opens automatically, but always call openBrowserPage tool - PlayWright MCP yourself.`,a=async({format:e,title:n,content:r,actions:i,template:a})=>{let o=La(r);return(e??`html`)===`browser`||Array.isArray(i)&&i.length>0?await
|
|
490
|
+
BROWSER WORKFLOW: After calling present with format "browser", you MUST extract the URL from the response and call openBrowserPage({ url }) tool - PlayWright MCP to open it in VS Code Simple Browser. A system browser fallback also opens automatically, but always call openBrowserPage tool - PlayWright MCP yourself.`,a=async({format:e,title:n,content:r,actions:i,template:a})=>{let o=La(r);return(e??`html`)===`browser`||Array.isArray(i)&&i.length>0?await Nu(n,o,i,t,a):Pu(n,o,i)};if(r){Ou||=(bn(e,`AI Kit Present App`,xu,{description:`Rich interactive content viewer for AI Kit tools`},async()=>({contents:[{uri:xu,mimeType:yn,text:r}]})),!0),xn(e,`present`,{title:n.title,description:i,annotations:n.annotations,inputSchema:Eu,_meta:{ui:{resourceUri:xu}}},a);return}e.tool(`present`,i,Eu,n.annotations,a)}async function Nu(e,t,n,r,i){let a=Vl(e,t,{compactTables:!0}),o=Su(n),s=wu(e,t,o),{html:c,assets:l}=ul(e,t,n,i),u=kn({uri:`ui://aikit/present-browser.html`,content:{type:`rawHtml`,htmlString:s},encoding:`text`,adapters:{mcpApps:{enabled:!0}}}),d,f,p=``,m;try{ku&&=(ku.close(),null),o.length>0&&(d=new Promise(e=>{f=e}));let e=!1;p=await new Promise((t,n)=>{let r=On((t,n)=>{if(e||(e=!0,m&&clearTimeout(m)),t.method===`POST`&&t.url===`/callback`){let e=``;t.on(`data`,t=>{e+=t.toString()}),t.on(`end`,()=>{n.writeHead(200,{"Content-Type":`application/json`,"Access-Control-Allow-Origin":`*`}),n.end(`{"ok":true}`);try{let t=JSON.parse(e);f?.(t)}catch{}});return}if(t.method===`OPTIONS`){n.writeHead(204,{"Access-Control-Allow-Origin":`*`,"Access-Control-Allow-Methods":`POST`,"Access-Control-Allow-Headers":`Content-Type`}),n.end();return}let r=l.get(t.url??``);if(r){n.writeHead(200,{"Content-Type":r.contentType,"Cache-Control":`no-cache`}),n.end(r.content);return}n.writeHead(200,{"Content-Type":`text/html; charset=utf-8`}),n.end(c)});r.listen(0,`127.0.0.1`,()=>{let i=r.address();if(typeof i==`object`&&i){ku=r;let n=`http://127.0.0.1:${i.port}`;m=setTimeout(()=>{if(!e)try{Tn(process.platform===`win32`?`start "" "${n}"`:process.platform===`darwin`?`open "${n}"`:`xdg-open "${n}"`)}catch{}},8e3),m.unref(),t(n)}else n(Error(`Failed to start present server`))}),setTimeout(()=>{r.close(),ku===r&&(ku=null)},300*1e3).unref()})}catch{}let h=p?`${a}\n\n---\n🌐 **Dashboard opened in browser:** ${p}\n\n**IMPORTANT:** You MUST now open this URL using the \`openBrowserPage\` tool - PlayWright MCP. If that tool is unavailable, open the URL in the system browser as a fallback. If neither works, ask the user to open the URL manually.`:a;if(o.length>0&&r?.available&&d)try{let e=await Promise.race([d,new Promise((e,t)=>setTimeout(()=>t(Error(`timeout`)),300*1e3))]);return{content:[{type:`text`,text:`${h}\n\n✅ **Selected:** ${e.actionId} = \`${e.value}\``},u]}}catch{return{content:[{type:`text`,text:`${h}\n\n⚠️ *No selection received (timed out).*`},u]}}return{content:[{type:`text`,text:h},u]}}function Pu(e,t,n){let r=Su(n),i=Vl(e,t,{compactTables:!0}),a=kn({uri:xu,content:{type:`rawHtml`,htmlString:Ql(e,t)},encoding:`text`,adapters:{mcpApps:{enabled:!0}}});return{content:[{type:`text`,text:i},a],structuredContent:{title:e,content:Qc(t),actions:r}}}const Fu=k(`tools`);function Iu(e,t){let n=new on({structure:new cn,dependencies:new nn,symbols:new ln,patterns:new sn,entryPoints:new an,diagrams:new rn}),r=z(`produce_knowledge`);e.registerTool(`produce_knowledge`,{title:r.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:F.string().optional().describe(`Root path to analyze (defaults to workspace root)`),aspects:F.array(F.enum([`all`,`structure`,`dependencies`,`symbols`,`patterns`,`entry-points`,`diagrams`])).default([`all`]).describe(`Which analysis aspects to run`)},annotations:r.annotations},async({scope:e,aspects:r})=>{try{let i=e??`.`;Fu.info(`Running knowledge production`,{rootPath:i,aspects:r});let a=await n.runExtraction(i,r);try{let e=t?.onboardDir??v(i,`.ai`,`context`);s(e,{recursive:!0});let n=`<!-- Generated by produce_knowledge at ${new Date().toISOString()} -->\n\n`;for(let[t,r]of Object.entries(a))r&&typeof r==`string`&&p(v(e,`${t}.md`),n+r,`utf-8`);Fu.info(`Knowledge persisted to .ai/context/`,{files:Object.keys(a).length})}catch(e){Fu.warn(`Failed to persist knowledge to .ai/context/`,{error:j(e)})}return{content:[{type:`text`,text:n.buildSynthesisInstructions(a,r)+`
|
|
491
491
|
|
|
492
492
|
---
|
|
493
|
-
_Next: Review the baselines above and use \`remember\` to store synthesized knowledge entries._`}]}}catch(e){return
|
|
493
|
+
_Next: Review the baselines above and use \`remember\` to store synthesized knowledge entries._`}]}}catch(e){return Fu.error(`Knowledge production failed`,j(e)),H(`INTERNAL`,`Knowledge production failed: ${e instanceof Error?e.message:String(e)}`)}})}const X=k(`tools`);function Lu(e,t,n,r,i,a,o){let s=z(`reindex`);e.registerTool(`reindex`,{title:s.title,description:`Trigger re-indexing of the AI Kit index. Can do incremental (only changed files) or full re-index. When smart indexing is active, use force: true to override the automatic trickle indexer.`,inputSchema:{full:F.boolean().default(!1).describe(`If true, force full re-index ignoring file hashes`),force:F.boolean().default(!1).describe(`If true, override smart indexing guard and run reindex anyway`)},annotations:s.annotations},async({full:e,force:s},c)=>{try{if(t.isIndexing)return{content:[{type:`text`,text:`## Reindex Already in Progress
|
|
494
494
|
|
|
495
495
|
A reindex operation is currently running. Search and other tools continue to work with existing data. Use \`status({})\` to check when it completes.`}]};if(o===`smart`&&!s)return{content:[{type:`text`,text:`## Smart Indexing Active
|
|
496
496
|
|
|
@@ -498,38 +498,38 @@ Smart indexing (trickle mode) is enabled — files are automatically indexed as
|
|
|
498
498
|
|
|
499
499
|
**If the index is severely outdated**, use \`reindex({ force: true })\` to override.
|
|
500
500
|
|
|
501
|
-
Use \`status({})\` to check smart indexing queue status.`}]};let l=Ea(c).createTask(`Reindex`,1);l.progress(0,`Starting ${e?`full`:`incremental`} reindex`),X.info(`Starting background re-index`,{mode:e?`full`:`incremental`});let u=e=>t=>{t.phase===`chunking`&&t.currentFile&&X.debug(`Re-index progress`,{prefix:e,current:t.filesProcessed+1,total:t.filesTotal,file:t.currentFile})};return(e?t.reindexAll(n,u(`Reindex`)):t.index(n,u(`Index`))).then(async e=>{if(X.info(`Background re-index complete`,{filesProcessed:e.filesProcessed,chunksCreated:e.chunksCreated,durationMs:e.durationMs}),l.complete(`Reindex complete: ${e.filesProcessed} files, ${e.chunksCreated} chunks in ${e.durationMs}ms`),i)try{await i.createFtsIndex(),X.info(`FTS index rebuilt after reindex`)}catch(e){X.warn(`FTS index rebuild failed`,j(e))}try{let e=await r.reindexAll();X.info(`Curated re-index complete`,{indexed:e.indexed})}catch(e){X.warn(`Curated re-index failed`,j(e))}if(a)try{await a.notifyAfterReindex()}catch(e){X.warn(`Post-reindex resource notification failed`,j(e))}}).catch(e=>{l.fail(`Reindex failed: ${e instanceof Error?e.message:String(e)}`),X.error(`Background reindex failed`,j(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 X.error(`Reindex failed`,j(e)),H(`INTERNAL`,`Reindex failed: ${e instanceof Error?e.message:String(e)}`)}})}const
|
|
501
|
+
Use \`status({})\` to check smart indexing queue status.`}]};let l=Ea(c).createTask(`Reindex`,1);l.progress(0,`Starting ${e?`full`:`incremental`} reindex`),X.info(`Starting background re-index`,{mode:e?`full`:`incremental`});let u=e=>t=>{t.phase===`chunking`&&t.currentFile&&X.debug(`Re-index progress`,{prefix:e,current:t.filesProcessed+1,total:t.filesTotal,file:t.currentFile})};return(e?t.reindexAll(n,u(`Reindex`)):t.index(n,u(`Index`))).then(async e=>{if(X.info(`Background re-index complete`,{filesProcessed:e.filesProcessed,chunksCreated:e.chunksCreated,durationMs:e.durationMs}),l.complete(`Reindex complete: ${e.filesProcessed} files, ${e.chunksCreated} chunks in ${e.durationMs}ms`),i)try{await i.createFtsIndex(),X.info(`FTS index rebuilt after reindex`)}catch(e){X.warn(`FTS index rebuild failed`,j(e))}try{let e=await r.reindexAll();X.info(`Curated re-index complete`,{indexed:e.indexed})}catch(e){X.warn(`Curated re-index failed`,j(e))}if(a)try{await a.notifyAfterReindex()}catch(e){X.warn(`Post-reindex resource notification failed`,j(e))}}).catch(e=>{l.fail(`Reindex failed: ${e instanceof Error?e.message:String(e)}`),X.error(`Background reindex failed`,j(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 X.error(`Reindex failed`,j(e)),H(`INTERNAL`,`Reindex failed: ${e instanceof Error?e.message:String(e)}`)}})}const Ru=k(`tools`);function zu(e){let t=z(`replay`);e.registerTool(`replay`,{title:t.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:F.enum([`list`,`clear`]).default(`list`).describe(`Action: "list" (default) to view entries, "clear" to wipe the log`),last:F.number().optional().describe(`Number of entries to return (default: 20, list only)`),tool:F.string().optional().describe(`Filter by tool name (list only)`),source:F.enum([`mcp`,`cli`]).optional().describe(`Filter by source: "mcp" or "cli" (list only)`),since:F.string().optional().describe(`ISO timestamp — only show entries after this time (list only)`)},annotations:t.annotations},async({action:e,last:t,tool:n,source:r,since:i})=>{try{if(e===`clear`)return St(),{content:[{type:`text`,text:`Replay log cleared.`}]};let a=Ct({last:t,tool:n,source:r,since:i});if(a.length===0)return{content:[{type:`text`,text:`No replay entries found. Activity is logged when tools are invoked via MCP or CLI.`}]};let o=a.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 wt().catch(()=>{}),{content:[{type:`text`,text:`**Replay Log** (${a.length} entries)\n\n${o.join(`
|
|
502
502
|
|
|
503
|
-
`)}`}]}}catch(e){return
|
|
503
|
+
`)}`}]}}catch(e){return Ru.error(`Replay failed`,j(e)),H(`INTERNAL`,`Replay failed: ${e instanceof Error?e.message:String(e)}`)}})}const Bu=k(`tools`);function Vu(e){let t=z(`restore`);e.registerTool(`restore`,{title:t.title,description:`List and restore file snapshots taken before destructive operations (codemod, rename, forget). Use action=list to see available restore points, action=restore with an id to undo.`,inputSchema:{action:F.enum([`list`,`restore`]).describe(`list: show restore points, restore: apply a restore point`),id:F.string().optional().describe(`Restore point ID (required for action=restore)`),limit:F.number().min(1).max(50).default(10).describe(`Max restore points to list`)},annotations:t.annotations},async({action:e,id:t,limit:n})=>{try{if(e===`list`){let e=Ze().slice(0,n);return e.length===0?{content:[{type:`text`,text:`No restore points found.`}]}:{content:[{type:`text`,text:`## Restore Points\n\n${e.map(e=>`- **${e.id}** (${e.timestamp}) — ${e.operation}: ${e.description} (${e.files.length} files)`).join(`
|
|
504
504
|
`)}`}]}}if(!t)throw Error(`id is required for restore action`);let r=await Tt(t);return{content:[{type:`text`,text:`Restored ${r.length} files:\n${r.map(e=>`- \`${e}\``).join(`
|
|
505
|
-
`)}`}]}}catch(e){return
|
|
506
|
-
`)[0].slice(0,500);if(r&&r!==e){let i=await t.embedQuery(r),a=await n.search(i,y);a.length>0&&(b=a,C=`> _Original query "${e}" returned 0 results. Auto-reformulated to "${r}"._\n\n`,
|
|
505
|
+
`)}`}]}}catch(e){return Bu.error(`Restore failed`,j(e)),H(`INTERNAL`,`Restore failed: ${e instanceof Error?e.message:String(e)}`)}})}const Hu=/<\/?curated-context>/gi;function Uu(e){return e.replace(Hu,``)}function Wu(e){return`<curated-context>\n${Uu(e)}\n</curated-context>`}const Gu=k(`tools`);function Ku(e){let t=[],n=h(process.cwd());n&&t.push(`[project: ${n}]`);let r=Nt(`__context_boost`);return r&&t.push(`[focus: ${r.value}]`),t.length===0?e:`${t.join(` `)} ${e}`}async function qu(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:vn(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 Gu.warn(`ER fallback failed`,j(e)),{results:n,triggered:!0,cacheHit:a}}}function Ju(e,t,n=60){let r=new Map,i=e[0]?.score||1,a=t[0]?.score||1;for(let t=0;t<e.length;t++){let a=e[t],o=a.score/i;r.set(a.record.id,{record:a.record,score:1/(n+t+1)*o})}for(let e=0;e<t.length;e++){let i=t[e],o=i.score/a,s=r.get(i.record.id);s?s.score+=1/(n+e+1)*o:r.set(i.record.id,{record:i.record,score:1/(n+e+1)*o})}return[...r.values()].sort((e,t)=>t.score-e.score).map(({record:e,score:t})=>({record:e,score:t}))}function Yu(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();if(t.length>5e3)return e;let r=n.map(e=>{let n=[],r=t.indexOf(e);for(;r!==-1&&n.length<10;)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 Xu(e){if(e.length<=1)return e;let t=new Set;return e.filter(e=>{let n=e.record.contentHash;return n?t.has(n)?!1:(t.add(n),!0):!0})}function Zu(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=t.record.content.split(/[^a-zA-Z0-9_]+/).filter(e=>e.length>=3&&!Qu.has(e.toLowerCase())),n=new Set;for(let t of e){let e=t.toLowerCase();/[_A-Z]/.test(t)&&i.set(`__id__${e}`,1),n.has(e)||(n.add(e),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}`),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 Qu=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 $u(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 Yt(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 ed(e,t,n,r,i,a,o){let s=z(`search`);e.registerTool(`search`,{title:s.title,description:`Search AI Kit 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:Ei,inputSchema:{query:F.string().max(5e3).describe(`Natural language search query`),limit:F.number().min(1).max(20).default(5).describe(`Maximum results to return`),search_mode:F.enum([`hybrid`,`semantic`,`keyword`]).default(`hybrid`).describe(`Search strategy: hybrid (vector + FTS + RRF fusion, default), semantic (vector only), keyword (FTS only)`),content_type:F.enum(S).optional().describe(`Filter by content type`),source_type:F.enum(T).optional().describe(`Coarse filter: "source" (code only), "documentation" (md, curated), "test", "config". Overrides content_type if both set.`),origin:F.enum(w).optional().describe(`Filter by knowledge origin`),category:F.string().optional().describe(`Filter by category (e.g., decisions, patterns, conventions)`),tags:F.array(F.string()).optional().describe(`Filter by tags (returns results matching ANY of the specified tags)`),min_score:F.number().min(0).max(1).default(.25).describe(`Minimum similarity score`),graph_hops:F.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:F.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`),dedup:F.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:F.array(F.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:s.annotations},async({query:e,limit:s,search_mode:c,content_type:l,source_type:u,origin:d,category:f,tags:p,min_score:m,graph_hops:h,max_tokens:g,dedup:_,workspaces:v})=>{try{let y={limit:s,minScore:m,contentType:l,sourceType:u,origin:d,category:f,tags:p},b,x=!1,S=!1,C=``,w=Ku(e);if(c===`keyword`)b=await n.ftsSearch(e,y),b=b.slice(0,s);else if(c===`semantic`){let r=await t.embedQuery(w);b=await n.search(r,y);let a=await qu(i,b[0]?.score??0,b,e,s);b=a.results,x=a.triggered,S=a.cacheHit}else{let r=await t.embedQuery(w),a=n.coarseSearch,o=a?a.bind(n):n.search.bind(n),[c,l]=await Promise.all([o(r,{...y,limit:s*2}),n.ftsSearch(e,{...y,limit:s*2}).catch(()=>[])]);c.length===0&&l.length>0?(b=l.slice(0,s),C=` (FTS-only: vector index rebuilding)`):b=l.length===0&&c.length>0?c.slice(0,s):Ju(c,l).slice(0,s);let u=await qu(i,c[0]?.score??0,b,e,s);b=u.results,x=u.triggered,S=u.cacheHit}a&&a.recordSearch(e,x,S),b.length>1&&(b=Yu(b,e)),b=Xu(b);let T=``;if(v&&v.length>0){let n=io(v,O(process.cwd()));if(n.length>0){let{stores:r,closeAll:i}=await ao(n);try{let i;i=c===`keyword`?await so(r,e,{...y,limit:s}):await oo(r,await t.embedQuery(e),{...y,limit:s});for(let e of i)b.push({record:{...e.record,sourcePath:`[${e.workspace}] ${e.record.sourcePath}`},score:e.score});b=b.sort((e,t)=>t.score-e.score).slice(0,s),T=` + ${n.length} workspace(s)`}finally{await i()}}}if(_===`file`&&b.length>1){let e=new Map;for(let t of b){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}]})}b=[...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(b.length>1){let e=b[0].score,t=Math.max(e*.4,.1);b=b.filter(e=>e.score>=t)}if(b.length===0){if(o?.available)try{let r=(await o.createMessage({prompt:`The search query "${e}" returned 0 results in AI Kit code search. 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 AI Kit code search. Generate a single alternative query.`,maxTokens:100})).text.trim().split(`
|
|
506
|
+
`)[0].slice(0,500);if(r&&r!==e){let i=await t.embedQuery(r),a=await n.search(i,y);a.length>0&&(b=a,C=`> _Original query "${e}" returned 0 results. Auto-reformulated to "${r}"._\n\n`,Gu.info(`Smart search fallback succeeded`,{originalQuery:e,altQuery:r,resultCount:a.length}))}}catch(e){Gu.debug(`Smart search fallback failed`,{error:String(e)})}if(b.length===0)return{content:[{type:`text`,text:`No results found for the given query.`}],structuredContent:{results:[],totalResults:0,searchMode:c,query:e}}}let E,D;if(h>0&&!r&&(D="> **Note:** `graph_hops` was set but no graph store is available. Graph augmentation skipped."),h>0&&r)try{let e=await ze(r,b.map(e=>({recordId:e.record.id,score:e.score,sourcePath:e.record.sourcePath})),{hops:h,maxPerHit:5});E=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(`
|
|
507
507
|
`),n=t.graphContext.edges.slice(0,5).map(e=>` - ${e.fromId} —[${e.type}]→ ${e.toId}`).join(`
|
|
508
508
|
`),r=[`- **Graph Context** (${h} hop${h>1?`s`:``}):`];e&&r.push(` Entities:\n${e}`),n&&r.push(` Relationships:\n${n}`),E.set(t.recordId,r.join(`
|
|
509
|
-
`))}}catch(e){
|
|
510
|
-
`)}\n\n${n.origin===`curated`?
|
|
509
|
+
`))}}catch(e){Gu.warn(`Graph augmentation failed`,j(e)),D=`> **Note:** Graph augmentation failed. Results shown without graph context.`}let k=Date.now();for(let e of b)if(e.record.origin===`curated`&&e.record.indexedAt){let t=k-new Date(e.record.indexedAt).getTime(),n=Math.max(0,t/864e5);e.score*=.95**n}b.sort((e,t)=>t.score-e.score),b=se(b);let ee=b.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,E?.get(n.id)??null].filter(Boolean).join(`
|
|
510
|
+
`)}\n\n${n.origin===`curated`?Wu(n.content):n.content}`}).join(`
|
|
511
511
|
|
|
512
512
|
---
|
|
513
513
|
|
|
514
|
-
`),A=(c===`hybrid`?`hybrid (vector + keyword RRF)`:c===`keyword`?`keyword (FTS)`:`semantic (vector)`)+T,te=
|
|
514
|
+
`),A=(c===`hybrid`?`hybrid (vector + keyword RRF)`:c===`keyword`?`keyword (FTS)`:`semantic (vector)`)+T,te=Zu(b,e),ne=te.length>0?`\n_Distinctive terms: ${te.map(e=>`\`${e}\``).join(`, `)}_`:``,M=await $u(n,b),N=[];if(b.length===0)N.push("`reindex` — no results found, index may be stale"),N.push("`find` — try federated search with glob/regex");else{let e=b[0]?.record.sourcePath;e&&N.push(`\`lookup\` — see all chunks from \`${e}\``),N.push("`symbol` — resolve a specific symbol from the results"),N.push("`compact` — compress a result file for focused reading")}let re=[D?`${D}\n\n`:``,M?`${M}\n\n`:``,ee,`\n\n---\n_Search mode: ${A} | ${b.length} results_${ne}`,`\n_Next: ${N.join(` | `)}_`],ie=C+re.join(``);g&&(ie=Ht(ie,g));let ae=new Set,oe=[];for(let e of b){if(e.record.origin!==`curated`||e.record.sourcePath.startsWith(`[`))continue;let t=Cs(e.record.sourcePath);if(!t)continue;let n=xs(t,e.record.headingPath??t);n&&!ae.has(n.uri)&&(ae.add(n.uri),oe.push(n))}return{content:[{type:`text`,text:ie},...oe],structuredContent:{results:b.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:b.length,searchMode:c,query:e}}}catch(e){return Gu.error(`Search failed`,j(e)),H(`INTERNAL`,`Search failed: ${e instanceof Error?e.message:String(e)}`)}})}const td=k(`tools`);function nd(e,t){let n=z(`session_digest`);e.registerTool(`session_digest`,{title:n.title,description:`Compress the current session's tool trajectory into a focused digest. Aggregates replay log, stash state, and checkpoints. Supports deterministic and LLM-assisted (sampling) modes with configurable token budget.`,inputSchema:{scope:F.enum([`tools`,`stash`,`all`]).default(`all`).describe(`What to include: tools (replay only), stash (stash + checkpoints only), or all`),since:F.string().optional().describe(`ISO timestamp — only include activity after this time`),last:F.number().min(1).max(500).optional().describe(`Max replay entries to consider (default: 50)`),focus:F.string().optional().describe(`Focus query — prioritize entries matching this topic`),mode:F.enum([`deterministic`,`sampling`]).default(`deterministic`).describe(`Summary mode: deterministic (fast, template-based) or sampling (LLM-assisted, richer)`),token_budget:F.number().min(100).max(8e3).default(2e3).describe(`Target token budget for the digest output`),persist:F.boolean().default(!0).describe(`Auto-save digest to stash for crash recovery`)},annotations:n.annotations},async({scope:e,since:n,last:r,focus:i,mode:a,token_budget:o,persist:s})=>{try{let c={scope:e,since:n,last:r,focus:i,mode:a,tokenBudget:o,persist:s};return{content:[{type:`text`,text:(a===`sampling`&&t?.available?await At(c,async(e,n,r)=>(await t.createMessage({prompt:e,systemPrompt:n,maxTokens:r})).text):kt(c)).digest}]}}catch(e){return td.error(`Session digest failed`,j(e)),H(`INTERNAL`,`Session digest failed: ${e instanceof Error?e.message:String(e)}`)}})}const rd=k(`tools`);function id(e,t,n,r=15e3){let i,a=new Promise(e=>{i=setTimeout(()=>{rd.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),rd.warn(`Status sub-operation "${n}" failed: ${e instanceof Error?e.message:String(e)}`),{value:t,timedOut:!1})),a])}function ad(){let e=dn.get(),t=un.get();if(e)return`- **Tree-sitter (WASM)**: ✅ Available (${t.grammarCount} grammars, dir: ${t.wasmDir})`;let n=t.pathsChecked.length?t.pathsChecked.map(e=>` ${e.exists?`✓`:`✗`} ${e.path}`).join(`
|
|
515
515
|
`):` none`,r=t.healAttempted?` Auto-heal: ${t.healSuccess?`✓ succeeded`:`✗ failed (${t.healError??`unknown`})`}`:` Auto-heal: not attempted`;return[`- **Tree-sitter (WASM)**: ⚠ Unavailable (regex fallback)`,` Reason: ${t.reason||`unknown`}`,` Paths checked:`,n,r,` OS: ${t.os} ${t.arch} | Node: ${t.nodeVersion}`,` Fix: Reinstall package or run vendor:wasm script`].join(`
|
|
516
|
-
`)}const
|
|
517
|
-
`)}],structuredContent:l}})}function
|
|
518
|
-
`),re={totalRecords:h.totalRecords,totalFiles:h.totalFiles,lastIndexedAt:h.lastIndexedAt??null,onboarded:w,onboardDir:S,contentTypes:h.contentTypeBreakdown,wasmAvailable:!!dn.get(),wasmDiagnostics:un.get(),graphStats:_,curatedCount:v,serverVersion:A,scaffoldVersion:k??null,workspaceScaffoldVersion:ee??null,upgradeAvailable:te||ne,storeBackend:l?.store?.backend,storeDiagnostics:D??null,contextPressure:T};return{content:[{type:`text`,text:N+(u===`smart`?"\n\n---\n_Next: Use `search` to query indexed content or `graph({action:'find_nodes', name_pattern:'<top-level-module>'})` → then `graph({action:'neighbors', node_id})` for relationships. Smart indexing handles updates automatically._":"\n\n---\n_Next: Use `search` to query indexed content, `graph({action:'find_nodes', name_pattern:'<top-level-module>'})` → then `graph({action:'neighbors', node_id})` for relationships, or `reindex` to refresh the index._")}],structuredContent:re}}catch(e){return
|
|
519
|
-
`)};if(i.length===1)try{return{content:[{type:`text`,text:`${await a(i[0])}\n---\n_Next: Use \`web_fetch\` to read any of these pages in full._`}]}}catch(e){return
|
|
516
|
+
`)}const od=5*6e4;let sd=null,cd=null;function ld(e,t,n,r){let i=Math.min(e/2e4,1),a=Math.min((t+n)/5e4,1),o=Math.min(r/200,1);return Math.round(i*40+a*35+o*25)}function ud(){let e=Date.now();if(sd&&e-sd.ts<od)return sd.value;try{let t=y(Dn(),`.copilot`,`.aikit-scaffold.json`);if(!o(t))return sd={value:null,ts:e},null;let n=JSON.parse(c(t,`utf-8`)).version??null;return sd={value:n,ts:e},n}catch{return sd={value:null,ts:e},null}}function dd(){let e=Date.now();if(cd&&e-cd.ts<od)return cd.value;try{let t=y(process.cwd(),`.github`,`.aikit-scaffold.json`);if(!o(t))return cd={value:null,ts:e},null;let n=JSON.parse(c(t,`utf-8`)).version??null;return cd={value:n,ts:e},n}catch{return cd={value:null,ts:e},null}}function fd(e){let t=z(`status`);e.registerTool(`status`,{title:t.title,description:`Get the current status and statistics of the AI Kit index.`,outputSchema:_i,annotations:t.annotations},async()=>{let e=r(),t=ud(),a=dd(),o=t!=null&&t!==e,s=a!=null&&a!==e,c=[`## AI Kit Status`,``,`⏳ **AI Kit is initializing** — index stats will be available shortly.`,``,`### Runtime`,`- **Tree-sitter (WASM)**: ${dn.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`,``,`### Version`,`- **Server**: ${e}`,`- **Scaffold (user)**: ${t??`not installed`}`,`- **Scaffold (workspace)**: ${a??`not installed`}`];if(o||s){let r=i(),l=[];o&&l.push(`user scaffold v${t}`),s&&l.push(`workspace scaffold v${a}`);let u=l.join(`, `);r.state===`success`?c.push(``,`### ✅ Upgrade Applied`,`- Server v${e} — ${u} auto-upgraded successfully.`,`- _Restart the MCP server to use the updated version._`):r.state===`pending`?c.push(``,`### ⏳ Upgrade In Progress`,`- Server v${e} ≠ ${u}`,`- Auto-upgrade is running in the background…`):r.state===`failed`?(n(),c.push(``,`### ⬆ Upgrade Available (auto-upgrade failed, retrying)`,`- Server v${e} ≠ ${u}`,`- Error: ${r.error??`unknown`}`)):(n(),c.push(``,`### ⬆ Upgrade Available`,`- Server v${e} ≠ ${u}`,`- Auto-upgrade triggered — check again shortly.`))}let l={totalRecords:0,totalFiles:0,lastIndexedAt:null,onboarded:!1,onboardDir:``,contentTypes:{},wasmAvailable:!!dn.get(),graphStats:null,curatedCount:0,serverVersion:e,scaffoldVersion:t??null,workspaceScaffoldVersion:a??null,upgradeAvailable:o||s,contextPressure:0};return{content:[{type:`text`,text:c.join(`
|
|
517
|
+
`)}],structuredContent:l}})}function pd(e,t,a,s,c,l,u,d){let p=z(`status`);e.registerTool(`status`,{title:p.title,description:`Get the current status and statistics of the AI Kit index.`,outputSchema:_i,annotations:p.annotations},async()=>{let e=[];try{let[p,m]=await Promise.all([id(t.getStats(),{totalRecords:0,totalFiles:0,lastIndexedAt:null,contentTypeBreakdown:{}},`store.getStats`),id(t.listSourcePaths(),[],`store.listSourcePaths`)]),h=p.value;p.timedOut&&e.push(`⚠ Index stats timed out — values may be incomplete`);let g=m.value;m.timedOut&&e.push(`⚠ File listing timed out`);let _=null,v=0,b=[`## AI Kit Status`,``,`- **Total Records**: ${h.totalRecords}`,`- **Total Files**: ${h.totalFiles}`,`- **Last Indexed**: ${h.lastIndexedAt??`Never`}`,``,`### Content Types`,...Object.entries(h.contentTypeBreakdown).map(([e,t])=>`- ${e}: ${t}`),``,`### Indexed Files`,...g.slice(0,50).map(e=>`- ${e}`),g.length>50?`\n... and ${g.length-50} more files`:``];if(a)try{let t=await id(a.getStats(),{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}},`graphStore.getStats`);if(t.timedOut)e.push(`⚠ Graph stats timed out`),b.push(``,`### Knowledge Graph`,`- Graph stats timed out`);else{let e=t.value;_={nodes:e.nodeCount,edges:e.edgeCount},b.push(``,`### Knowledge Graph`,`- **Nodes**: ${e.nodeCount}`,`- **Edges**: ${e.edgeCount}`,...Object.entries(e.nodeTypes).map(([e,t])=>` - ${e}: ${t}`));try{let e=await id(a.validate(),{valid:!0,danglingEdges:[],orphanNodes:[],stats:{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}}},`graphStore.validate`);if(!e.timedOut){let t=e.value;t.valid||b.push(`- **⚠ Integrity Issues**: ${t.danglingEdges.length} dangling edges`),t.orphanNodes.length>0&&b.push(`- **Orphan nodes**: ${t.orphanNodes.length}`)}}catch{}}}catch{b.push(``,`### Knowledge Graph`,`- Graph store unavailable`)}let S=l?.onboardDir??y(process.cwd(),x.aiContext),C=o(S),w=c?.onboardComplete||C;if(b.push(``,`### Onboard Status`,w?`- ✅ Complete${c?.onboardTimestamp?` (last: ${c.onboardTimestamp})`:``}`:'- ❌ Not run — call `onboard({ path: "." })` to analyze the codebase',`- **Onboard Directory**: \`${S}\``),s)try{let t=await id(s.list(),[],`curated.list`);if(t.timedOut)e.push(`⚠ Curated knowledge listing timed out`),b.push(``,`### Curated Knowledge`,`- Listing timed out`);else{let e=t.value;v=e.length,b.push(``,`### Curated Knowledge`,e.length>0?`- ${e.length} entries`:'- Empty — use `knowledge({ action: "remember", ... })` to persist decisions')}}catch{b.push(``,`### Curated Knowledge`,`- Unable to read curated entries`)}let T=ld(h.totalRecords,_?.nodes??0,_?.edges??0,v);b.push(``),b.push(`## 📊 Context Pressure: ${T}/100`),T>=80?b.push(`⚠️ High pressure — consider pruning stale entries or compacting context.`):T>=50?b.push(`ℹ️ Moderate pressure — AI Kit memory is well-populated.`):b.push(`✅ Low pressure — plenty of headroom for more content.`);let E=0;if(h.lastIndexedAt){E=new Date(h.lastIndexedAt).getTime();let e=(Date.now()-E)/(1e3*60*60);b.push(``,`### Index Freshness`,e>24?u===`smart`?`- ⚠ Last indexed ${Math.floor(e)}h ago — smart indexing will refresh automatically`:`- ⚠ Last indexed ${Math.floor(e)}h ago — may be stale. Run \`reindex({})\``:`- ✅ Last indexed ${e<1?`less than 1h`:`${Math.floor(e)}h`} ago`)}let D=null,O=t;if(typeof O.getDiagnostics==`function`)try{D=O.getDiagnostics(),b.push(``,`### Storage`,`- **Backend**: ${l?.store?.backend??`unknown`}`,`- **Adapter**: ${D.adapterType}`,`- **Vector search**: ${D.vectorSearchEnabled?`✅ enabled`:`⚠ disabled (FTS-only fallback)`}`,D.dbPath?`- **DB**: ${D.dbPath}`:``,D.dbSizeBytes==null?``:`- **DB size**: ${(D.dbSizeBytes/1024/1024).toFixed(2)} MB`,`- **Embedding dim**: ${D.embeddingDim}`,`- **Vector dtype**: ${D.vectorDtype}`)}catch{}if(u===`smart`)if(b.push(``,`### Smart Indexing`),d){let e=d();e?b.push(`- **Mode**: Smart (trickle)`,`- **Status**: ${e.running?`✅ Running`:`⏸ Stopped`}`,`- **Queue**: ${e.queueSize} files pending`,`- **Changed files**: ${e.changedFilesSize} detected`,`- **Interval**: ${Math.round(e.intervalMs/1e3)}s per batch of ${e.batchSize}`):b.push(`- **Mode**: Smart (trickle)`,`- **Status**: scheduler state unavailable (init may have failed)`)}else b.push(`- **Mode**: Smart (trickle) — scheduler state unavailable`);{try{let e=y(process.cwd(),x.data,`stash`);if(o(e)){let t=f(e).mtimeMs;t>E&&(E=t)}}catch{}let e=[];if(s)try{let t=v>0?await s.list():[];for(let e of t){let t=new Date(e.updated||e.created).getTime();t>E&&(E=t)}e.push(...t.sort((e,t)=>new Date(t.updated).getTime()-new Date(e.updated).getTime()).slice(0,5))}catch{}let t=E>0?Date.now()-E:0;if(t>=144e5){let n=Math.floor(t/36e5);if(b.push(``,`### 🌅 Session Briefing`,`_${n}+ hours since last activity — here's what to pick up:_`,``),e.length>0){b.push(`**Recent decisions/notes:**`);for(let t of e)b.push(`- **${t.title}** (${t.category??`note`}) — ${(t.contentPreview??``).slice(0,80)}…`)}b.push(``,`**Suggested next steps:**`,'- `search({ query: "SESSION CHECKPOINT", origin: "curated" })` — find your last checkpoint',"- `restore({})` — resume from a saved checkpoint",'- `knowledge({ action: "list" })` — browse all stored knowledge')}}b.push(``,`### Runtime`,ad());let k=ud(),ee=dd(),A=r(),te=k!=null&&k!==A,ne=ee!=null&&ee!==A;if(te||ne){let e=i(),t=[];te&&t.push(`user scaffold v${k}`),ne&&t.push(`workspace scaffold v${ee}`);let r=t.join(`, `);e.state===`success`?b.push(``,`### ✅ Upgrade Applied`,`- Server v${A} — ${r} auto-upgraded successfully.`,`- _Restart the MCP server to use the updated version._`):e.state===`pending`?b.push(``,`### ⏳ Upgrade In Progress`,`- Server v${A} ≠ ${r}`,`- Auto-upgrade is running in the background…`):e.state===`failed`?(n(),b.push(``,`### ⬆ Upgrade Available (auto-upgrade failed, retrying)`,`- Server v${A} ≠ ${r}`,`- Error: ${e.error??`unknown`}`)):(n(),b.push(``,`### ⬆ Upgrade Available`,`- Server v${A} ≠ ${r}`,`- Auto-upgrade triggered — check again shortly.`))}e.length>0&&b.push(``,`### ⚠ Warnings`,...e.map(e=>`- ${e}`));let j=Rr();if(j.length>0){let e=j.sort((e,t)=>t.callCount-e.callCount);b.push(``,`### Tool Usage This Session`,``),b.push(`| Tool | Calls | Tokens In | Tokens Out | Errors | Avg Latency |`),b.push(`|------|-------|-----------|------------|--------|-------------|`);for(let t of e.slice(0,15)){let e=Math.round(t.totalInputChars/4),n=Math.round(t.totalOutputChars/4),r=Math.round(t.totalDurationMs/t.callCount);b.push(`| ${t.tool} | ${t.callCount} | ${e.toLocaleString()} | ${n.toLocaleString()} | ${t.errorCount} | ${r}ms |`)}}let M=jr();if(M.bufferSize>=10){let e=M.state===`healthy`?`🟢`:M.state===`degraded`?`🔴`:`🟡`;b.push(``,`### Auto-GC: ${e} ${M.state}`),b.push(`- p95 latency: ${M.p95}ms | buffer: ${M.bufferSize} samples`),M.gcCount>0&&b.push(`- GC cycles triggered: ${M.gcCount}`)}let N=b.join(`
|
|
518
|
+
`),re={totalRecords:h.totalRecords,totalFiles:h.totalFiles,lastIndexedAt:h.lastIndexedAt??null,onboarded:w,onboardDir:S,contentTypes:h.contentTypeBreakdown,wasmAvailable:!!dn.get(),wasmDiagnostics:un.get(),graphStats:_,curatedCount:v,serverVersion:A,scaffoldVersion:k??null,workspaceScaffoldVersion:ee??null,upgradeAvailable:te||ne,storeBackend:l?.store?.backend,storeDiagnostics:D??null,contextPressure:T};return{content:[{type:`text`,text:N+(u===`smart`?"\n\n---\n_Next: Use `search` to query indexed content or `graph({action:'find_nodes', name_pattern:'<top-level-module>'})` → then `graph({action:'neighbors', node_id})` for relationships. Smart indexing handles updates automatically._":"\n\n---\n_Next: Use `search` to query indexed content, `graph({action:'find_nodes', name_pattern:'<top-level-module>'})` → then `graph({action:'neighbors', node_id})` for relationships, or `reindex` to refresh the index._")}],structuredContent:re}}catch(e){return rd.error(`Status failed`,j(e)),H(`INTERNAL`,`Status check failed: ${e instanceof Error?e.message:String(e)}`)}})}const md=k(`tools`);function hd(e){let t=z(`web_search`);e.registerTool(`web_search`,{title:t.title,description:`PREFERRED web search — fans out to multiple keyless providers (DuckDuckGo + Bing-HTML + Mojeek) by default, returning a deduplicated, consensus-ranked union within a 10s deadline. Optional providers (SearXNG, Google, Brave, Bing API) join the fan-out automatically when their env vars are set. Pass one query or multiple for parallel searching.`,inputSchema:{queries:F.array(F.string().max(2e3)).min(1).max(5).describe('Search queries (1–5). Single: `["react hooks"]`. Multiple searched in parallel.'),limit:F.number().min(1).max(20).default(5).describe(`Max results per query`),site:F.string().optional().describe(`Restrict to domain (e.g., "docs.aws.amazon.com")`),provider:F.enum([`multi`,`duckduckgo`,`bing-html`,`mojeek`,`searxng`,`google`,`brave`,`bing`]).optional().describe("Search provider. Defaults to env AIKIT_SEARCH_PROVIDER, then `multi` (fan-out). Single keyless: `duckduckgo`, `bing-html`, `mojeek`. Self-hosted: `searxng` (requires SEARXNG_URL). Keyed APIs: `google` (GOOGLE_API_KEY+GOOGLE_CSE_ID), `brave` (BRAVE_API_KEY), `bing` (BING_API_KEY). Missing keys auto-fall back to duckduckgo.")},annotations:t.annotations},async({queries:e,limit:t,site:n,provider:r})=>{let i=e,a=async e=>{let i=await qt({query:e,limit:t,site:n,provider:r}),a=[`## Search: ${i.query} _(via ${i.provider})_`,``];if(i.results.length===0)a.push(`No results found.`);else for(let e of i.results)a.push(`### [${e.title}](${e.url})`,e.snippet,``);return a.join(`
|
|
519
|
+
`)};if(i.length===1)try{return{content:[{type:`text`,text:`${await a(i[0])}\n---\n_Next: Use \`web_fetch\` to read any of these pages in full._`}]}}catch(e){return md.error(`Web search failed`,j(e)),H(`INTERNAL`,`Web search failed: ${e instanceof Error?e.message:String(e)}`)}let o=await Promise.allSettled(i.map(e=>a(e))),s=[],c=0;for(let e=0;e<o.length;e++){let t=o[e];if(t.status===`fulfilled`)s.push(t.value);else{c++;let n=t.reason instanceof Error?t.reason.message:String(t.reason);md.error(`Web search failed`,{query:i[e],error:n}),s.push(`## ❌ Search failed: ${i[e]}\n\n${n}`)}}let l=`_Searched ${o.length-c}/${o.length} queries successfully._`;s.push(``,`---`,l,"_Next: Use `web_fetch` to read any of these pages in full._");let u=s.join(`
|
|
520
520
|
|
|
521
|
-
`);return c===o.length?H(`INTERNAL`,u):{content:[{type:`text`,text:u}]}})}function
|
|
522
|
-
`)}]}}catch(e){return
|
|
523
|
-
`)}]}})}function
|
|
524
|
-
`)}],structuredContent:i}}catch(e){return
|
|
521
|
+
`);return c===o.length?H(`INTERNAL`,u):{content:[{type:`text`,text:u}]}})}function gd(e){let t=z(`http`);e.registerTool(`http`,{title:t.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:F.string().url().describe(`Request URL (http/https only)`),method:F.enum([`GET`,`POST`,`PUT`,`PATCH`,`DELETE`,`HEAD`]).default(`GET`).describe(`HTTP method`),headers:F.record(F.string(),F.string()).optional().describe(`Request headers as key-value pairs`),body:F.string().optional().describe(`Request body (for POST/PUT/PATCH)`),timeout:F.number().min(1e3).max(6e4).default(15e3).describe(`Timeout in milliseconds`)},annotations:t.annotations},async({url:e,method:t,headers:n,body:r,timeout:i})=>{try{let a=await Ue({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(`
|
|
522
|
+
`)}]}}catch(e){return md.error(`HTTP request failed`,j(e)),H(`INTERNAL`,`HTTP request failed: ${e instanceof Error?e.message:String(e)}`)}})}function _d(e){let t=z(`regex_test`);e.registerTool(`regex_test`,{title:t.title,description:`Test a regex pattern against sample strings. Supports match, replace, and split modes.`,inputSchema:{pattern:F.string().max(500).describe(`Regex pattern (without delimiters)`),flags:F.string().max(10).regex(/^[gimsuy]*$/).default(``).describe(`Regex flags (g, i, m, s, etc.)`),test_strings:F.array(F.string().max(1e4)).max(50).describe(`Strings to test the pattern against`),mode:F.enum([`match`,`replace`,`split`]).default(`match`).describe(`Test mode`),replacement:F.string().optional().describe(`Replacement string (for replace mode)`)},annotations:t.annotations},async({pattern:e,flags:t,test_strings:n,mode:r,replacement:i})=>{let a=_t({pattern:e,flags:t,testStrings:n,mode:r,replacement:i});if(!a.valid)return H(`VALIDATION`,`Invalid regex: ${a.error}`);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(`
|
|
523
|
+
`)}]}})}function vd(e){let t=z(`encode`);e.registerTool(`encode`,{title:t.title,description:`Encode, decode, or hash text. Supports base64, URL encoding, SHA-256, MD5, JWT decode, hex.`,inputSchema:{operation:F.enum([`base64_encode`,`base64_decode`,`url_encode`,`url_decode`,`sha256`,`md5`,`jwt_decode`,`hex_encode`,`hex_decode`]).describe(`Operation to perform`),input:F.string().max(1e6).describe(`Input text`)},annotations:t.annotations},async({operation:e,input:t})=>{try{let n=De({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 md.error(`Encode failed`,j(e)),H(`INTERNAL`,`Encode failed: ${e instanceof Error?e.message:String(e)}`)}})}function yd(e){let t=z(`measure`);e.registerTool(`measure`,{title:t.title,description:`Measure code complexity, line counts, and function counts for a file or directory. Returns per-file metrics sorted by complexity.`,outputSchema:yi,inputSchema:{path:F.string().describe(`File or directory path to measure`),extensions:F.array(F.string()).optional().describe(`File extensions to include (default: .ts,.tsx,.js,.jsx)`)},annotations:t.annotations},async({path:e,extensions:t})=>{try{let n=await $e({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(`
|
|
524
|
+
`)}],structuredContent:i}}catch(e){return md.error(`Measure failed`,j(e)),H(`INTERNAL`,`Measure failed: ${e instanceof Error?e.message:String(e)}`)}})}function bd(e){let t=z(`changelog`);e.registerTool(`changelog`,{title:t.title,description:`Generate a changelog from git history between two refs. Groups by conventional commit type.`,inputSchema:{from:F.string().max(200).describe(`Start ref (tag, SHA, HEAD~N)`),to:F.string().max(200).default(`HEAD`).describe(`End ref (default: HEAD)`),format:F.enum([`grouped`,`chronological`,`per-scope`]).default(`grouped`).describe(`Output format`),include_breaking:F.boolean().default(!0).describe(`Highlight breaking changes`),cwd:F.string().optional().describe(`Repository root or working directory`)},annotations:t.annotations},async({from:e,to:t,format:n,include_breaking:r,cwd:i})=>{try{let a=ce({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 md.error(`Changelog failed`,j(e)),H(`INTERNAL`,`Changelog failed: ${e instanceof Error?e.message:String(e)}`)}})}function xd(e){let t=z(`schema_validate`);e.registerTool(`schema_validate`,{title:t.title,description:`Validate JSON data against a JSON Schema. Supports type, required, properties, items, enum, pattern, min/max.`,inputSchema:{data:F.string().max(5e5).describe(`JSON data to validate (as string)`),schema:F.string().max(5e5).describe(`JSON Schema to validate against (as string)`)},annotations:t.annotations},async({data:e,schema:t})=>{try{let n=Dt({data:JSON.parse(e),schema:JSON.parse(t)});if(n.valid)return{content:[{type:`text`,text:`## Validation: PASSED
|
|
525
525
|
|
|
526
526
|
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(`
|
|
527
|
-
`)}]}}catch(e){return
|
|
528
|
-
`)}],structuredContent:a}})}function
|
|
529
|
-
`)}],structuredContent:o}}catch(e){return
|
|
527
|
+
`)}]}}catch(e){return md.error(`Schema validation failed`,j(e)),H(`INTERNAL`,`Schema validation failed: ${e instanceof Error?e.message:String(e)}`)}})}function Sd(e){let t=z(`env`);e.registerTool(`env`,{title:t.title,description:`Get system and runtime environment info. Sensitive env vars are redacted by default.`,outputSchema:bi,inputSchema:{include_env:F.boolean().default(!1).describe(`Include environment variables`),filter_env:F.string().optional().describe(`Filter env vars by name substring`),show_sensitive:F.boolean().default(!1).describe(`Show sensitive values (keys, tokens, etc.) — redacted by default`)},annotations:t.annotations},async({include_env:e,filter_env:t,show_sensitive:n})=>{let r=Oe({includeEnv:e,filterEnv:t,showSensitive:n}),i=[`## Environment`,``,`**Platform:** ${r.system.platform} ${r.system.arch}`,`**OS:** ${r.system.type} ${r.system.release}`,`**Host:** ${r.system.hostname}`,`**CPUs:** ${r.system.cpus}`,`**Memory:** ${r.system.memoryFreeGb}GB free / ${r.system.memoryTotalGb}GB total`,``,`**Node:** ${r.runtime.node}`,`**V8:** ${r.runtime.v8}`,`**CWD:** ${r.cwd}`];if(r.env){i.push(``,`### Environment Variables`,``);for(let[e,t]of Object.entries(r.env))i.push(`- \`${e}\`: ${t}`)}let a={platform:r.system.platform,arch:r.system.arch,nodeVersion:r.runtime.node,cwd:r.cwd,cpus:r.system.cpus,memoryFreeGb:r.system.memoryFreeGb,memoryTotalGb:r.system.memoryTotalGb};return{content:[{type:`text`,text:i.join(`
|
|
528
|
+
`)}],structuredContent:a}})}function Cd(e){let t=z(`time`);e.registerTool(`time`,{title:t.title,description:`Parse dates, convert timezones, calculate durations, add time. Supports ISO 8601, unix timestamps, and human-readable formats.`,outputSchema:xi,inputSchema:{operation:F.enum([`now`,`parse`,`convert`,`diff`,`add`]).describe(`now: current time | parse: parse a date string | convert: timezone conversion | diff: duration between two dates | add: add duration to date`),input:F.string().optional().describe(`Date input (ISO, unix timestamp, or parseable string). For diff: two comma-separated dates`),timezone:F.string().optional().describe(`Target timezone (e.g., "America/New_York", "Asia/Tokyo")`),duration:F.string().optional().describe(`Duration to add (e.g., "2h30m", "1d", "30s") — for add operation`)},annotations:t.annotations},async({operation:e,input:t,timezone:n,duration:r})=>{try{let i=Bt({operation:e,input:t,timezone:n,duration:r}),a=[`**${i.output}**`,``,`ISO: ${i.iso}`,`Unix: ${i.unix}`];i.details&&a.push(``,"```json",JSON.stringify(i.details),"```");let o={iso:i.iso,unix:i.unix,timezone:n??Intl.DateTimeFormat().resolvedOptions().timeZone,formatted:i.output};return{content:[{type:`text`,text:a.join(`
|
|
529
|
+
`)}],structuredContent:o}}catch(e){return md.error(`Time failed`,j(e)),H(`INTERNAL`,`Time failed: ${e instanceof Error?e.message:String(e)}`)}})}function wd(e,t,n,r,i,a,o,s,c){let l=new wr,u=new dr;u.register(cr),u.register(ir),u.register(ar),u.register(tr),u.register(Zn),u.register(Qn),u.register(ur);let d=new gr(u,t.curated);l.use(mr(d),{order:5,name:`auto-knowledge`}),l.use(Br(),{order:10,name:`replay`}),l.use(Xr(),{order:50,name:`structured-content-guard`}),l.use(yr(vr(n.tokenBudget)),{order:90,name:`compression`}),ti(e,l,n.toolPrefix??``);let f=c??hi(n,[...L,...Wr],R,Kr(n)),p=e=>f.has(e),m=[...f].filter(e=>Gr.has(e)?Ur.includes(e)?!!t.bridge:e===`er_update_policy`?!!t.policyStore:e===`er_evolve_review`?!!t.evolutionCollector:!1:!0);p(`search`)&&ed(e,t.embedder,t.store,t.graphStore,t.bridge,t.evolutionCollector,a);let h={store:t.store,graphStore:t.graphStore,embedder:t.embedder};p(`lookup`)&&Zs(e,t.store,h);let g={onboardComplete:t.onboardComplete,onboardTimestamp:t.onboardTimestamp};p(`status`)&&pd(e,t.store,t.graphStore,t.curated,g,n,o,s),p(`config`)&&no(e,n),p(`reindex`)&&Lu(e,t.indexer,n,t.curated,t.store,i,o),p(`knowledge`)&&Ys(e,t.curated,t.policyStore,t.evolutionCollector,i),p(`analyze`)&&Sa(e,t.store,t.embedder,h),p(`blast_radius`)&&Ca(e,t.store,t.embedder,t.graphStore,h),p(`produce_knowledge`)&&Iu(e,n),p(`onboard`)&&fc(e,t.store,t.embedder,n,g,h),p(`graph`)&&hs(e,t.graphStore),p(`audit`)&&Oa(e,t.store,t.embedder,n.tokenBudget);let _=n.sources[0]?.path??process.cwd();p(`compact`)&&uo(e,t.embedder,t.fileCache,_,n.allRoots,h),p(`scope_map`)&&fo(e,t.embedder,t.store,h),p(`find`)&&po(e,t.embedder,t.store,_,h),p(`parse_output`)&&Do(e),p(`workset`)&&mc(e),p(`check`)&&wo(e,h,n.tokenBudget),p(`symbol`)&&mo(e,t.embedder,t.store,t.graphStore),p(`eval`)&&To(e),p(`test_run`)&&Eo(e,h),p(`stash`)&&hc(e),p(`git_context`)&&$s(e),p(`diff_parse`)&&ec(e),p(`rename`)&&tc(e),p(`codemod`)&&nc(e),p(`restore`)&&Vu(e),p(`file_summary`)&&ho(e,t.fileCache,_,n.allRoots,h),p(`checkpoint`)&&gc(e),p(`data_transform`)&&rc(e),p(`trace`)&&go(e,t.embedder,t.store,t.graphStore),p(`process`)&&gs(e),p(`watch`)&&_s(e),p(`dead_symbols`)&&_o(e,t.embedder,t.store,_,n.allRoots,h),p(`delegate`)&&Oo(e,a),p(`health`)&&vs(e),p(`lane`)&&_c(e),p(`queue`)&&vc(e),p(`web_fetch`)&&ys(e),p(`guide`)&&bs(e,o),oc.some(e=>p(e))&&sc(e,n,m),p(`evidence_map`)&&ss(e),p(`digest`)&&cs(e,t.embedder),p(`forge_classify`)&&ls(e),p(`stratum_card`)&&us(e,t.embedder,t.fileCache),p(`forge_ground`)&&ds(e,t.embedder,t.store),p(`present`)&&Mu(e,r),p(`web_search`)&&hd(e),p(`http`)&&gd(e),p(`regex_test`)&&_d(e),p(`encode`)&&vd(e),p(`measure`)&&yd(e),p(`changelog`)&&bd(e),p(`schema_validate`)&&xd(e),p(`env`)&&Sd(e),p(`time`)&&Cd(e),p(`flow`)&&as(e,n),t.bridge&&Ur.some(e=>p(e))&&(Ma(e,t.bridge,t.evolutionCollector),Na(e,t.bridge),Pa(e,t.bridge)),t.policyStore&&p(`er_update_policy`)&&wc(e,t.policyStore),t.evolutionCollector&&p(`er_evolve_review`)&&So(e,t.evolutionCollector),Hr(e,t.store,t.curated),p(`replay`)&&zu(e),p(`session_digest`)&&nd(e,a)}function Td(e,t,n){let r=e=>!n||n.has(e);r(`check`)&&wo(e,void 0,t.tokenBudget),r(`eval`)&&To(e),r(`test_run`)&&Eo(e),r(`parse_output`)&&Do(e),r(`delegate`)&&Oo(e),r(`git_context`)&&$s(e),r(`diff_parse`)&&ec(e),r(`rename`)&&tc(e),r(`codemod`)&&nc(e),r(`data_transform`)&&rc(e),r(`workset`)&&mc(e),r(`stash`)&&hc(e),r(`checkpoint`)&&gc(e),r(`restore`)&&Vu(e),r(`lane`)&&_c(e),r(`queue`)&&vc(e),r(`session_digest`)&&nd(e),r(`health`)&&vs(e),r(`process`)&&gs(e),r(`watch`)&&_s(e),r(`web_fetch`)&&ys(e),r(`guide`)&&bs(e),oc.some(e=>r(e))&&sc(e,t,[...n??new Set(L)]),r(`evidence_map`)&&ss(e),r(`forge_classify`)&&ls(e),r(`present`)&&Mu(e),r(`produce_knowledge`)&&Iu(e),r(`replay`)&&zu(e),r(`status`)&&fd(e),r(`flow`)&&as(e,t),r(`web_search`)&&hd(e),r(`http`)&&gd(e),r(`regex_test`)&&_d(e),r(`encode`)&&vd(e),r(`measure`)&&yd(e),r(`changelog`)&&bd(e),r(`schema_validate`)&&xd(e),r(`env`)&&Sd(e),r(`time`)&&Cd(e)}const Ed=k(`resource-notifier`);var Dd=class{mcpServer;constructor(e){this.mcpServer=e}async notifyStatusChanged(){await this.sendUpdate(`aikit://status`)}async notifyFileTreeChanged(){await this.sendUpdate(`aikit://file-tree`)}async notifyCuratedIndexChanged(){await this.sendUpdate(`aikit://curated`)}async notifyCuratedEntryChanged(e){await this.sendUpdate(`aikit://curated/${e}`)}async notifyResourceListChanged(){try{await this.mcpServer.server.sendResourceListChanged()}catch(e){Ed.debug(`sendResourceListChanged failed`,{error:String(e)})}}async notifyAfterReindex(){await Promise.allSettled([this.notifyStatusChanged(),this.notifyFileTreeChanged()])}async notifyAfterCuratedWrite(e){let t=[this.notifyStatusChanged(),this.notifyCuratedIndexChanged()];e&&t.push(this.notifyCuratedEntryChanged(e)),await Promise.allSettled(t)}async sendUpdate(e){try{await this.mcpServer.server.sendResourceUpdated({uri:e})}catch(t){Ed.debug(`sendResourceUpdated failed`,{uri:e,error:String(t)})}}};const Z=k(`server`);async function Od(n){Z.info(`Initializing AI Kit components`);let r=n.store.backend,i=n.store.path,a=null;if(r===`sqlite-vec`){let e=v(i,`aikit.db`);a=await Cn(e),Z.info(`SQLite adapter ready`,{type:a.type,vectorCapable:a.vectorCapable,dbPath:e}),a.vectorCapable||Z.warn(`┌──────────────────────────────────────────────────────────────────┐
|
|
530
530
|
│ ⚠ SQLite vector extension unavailable — DEGRADED MODE │
|
|
531
531
|
│ Vector search is disabled. Hybrid search returns FTS only. │
|
|
532
532
|
│ To enable: install/rebuild better-sqlite3 (native module). │
|
|
533
|
-
└──────────────────────────────────────────────────────────────────┘`);let t=v(i,`lance`);o(t)&&Z.info(`Old LanceDB data found at ${t} — ignored. Safe to delete after verifying sqlite-vec works.`)}let[s,c,l,u]=await Promise.all([(async()=>{if(n.embedding.childProcess!==!1){let e=new jn({model:n.embedding.model,dimensions:n.embedding.dimensions,interOpNumThreads:n.embedding.interOpNumThreads,intraOpNumThreads:n.embedding.intraOpNumThreads,idleTimeoutMs:n.embedding.idleTimeoutMs});return await e.initialize(),Z.info(`Embedder loaded (child process)`,{modelId:e.modelId,dimensions:e.dimensions}),e}let{OnnxEmbedder:e}=await import(`../../embeddings/dist/index.js`),t=new e({model:n.embedding.model,dimensions:n.embedding.dimensions,interOpNumThreads:n.embedding.interOpNumThreads,intraOpNumThreads:n.embedding.intraOpNumThreads});return await t.initialize(),Z.info(`Embedder loaded (in-process)`,{modelId:t.modelId,dimensions:t.dimensions}),t})(),(async()=>{let e=await wn({backend:r,path:i,adapter:a??void 0,embeddingDim:n.embedding.dimensions});return await e.initialize(),Z.info(`Store initialized`,{backend:r}),e})(),(async()=>{let e=a?new Sn({adapter:a}):new Sn({path:i});return await e.initialize(),Z.info(`Graph store initialized`,{shared:!!a}),e})(),(async()=>{let e=await fn();if(e){let e=un.get();Z.info(`WASM tree-sitter enabled`,{grammars:e.grammarCount,dir:e.wasmDir})}else{let e=un.get();Z.warn(`WASM tree-sitter not available; analyzers will use regex fallback`,{reason:e.reason,os:e.os,arch:e.arch,healAttempted:e.healAttempted,healSuccess:e.healSuccess,healError:e.healError,pathsChecked:e.pathsChecked.map(e=>`${e.path} (${e.exists?`found`:`missing`})`)})}return e})()]),d=new Nn(s,c),p=new Mn(n.store.path);p.load(),d.setHashCache(p);let m=n.curated.path,h=new e(m);await h.initialize();let g=new t(m,c,s,h);d.setGraphStore(l);let _=ja(n.er),b=_?new gn(n.curated.path):void 0;b&&Z.info(`Policy store initialized`,{ruleCount:b.getRules().length});let S=_?new hn:void 0,C=y(n.sources[0]?.path??process.cwd(),x.aiContext),w=o(C),T=n.onboardDir?o(n.onboardDir):!1,E=w||T,D,O=w?C:n.onboardDir;if(E&&O)try{D=f(O).mtime.toISOString()}catch{}return Z.info(`Onboard state detected`,{onboardComplete:E,onboardTimestamp:D,aiKbExists:w,onboardDirExists:T}),{embedder:s,store:c,indexer:d,curated:g,graphStore:l,fileCache:new re,bridge:_,policyStore:b,evolutionCollector:S,onboardComplete:E,onboardTimestamp:D}}function
|
|
533
|
+
└──────────────────────────────────────────────────────────────────┘`);let t=v(i,`lance`);o(t)&&Z.info(`Old LanceDB data found at ${t} — ignored. Safe to delete after verifying sqlite-vec works.`)}let[s,c,l,u]=await Promise.all([(async()=>{if(n.embedding.childProcess!==!1){let e=new jn({model:n.embedding.model,dimensions:n.embedding.dimensions,interOpNumThreads:n.embedding.interOpNumThreads,intraOpNumThreads:n.embedding.intraOpNumThreads,idleTimeoutMs:n.embedding.idleTimeoutMs});return await e.initialize(),Z.info(`Embedder loaded (child process)`,{modelId:e.modelId,dimensions:e.dimensions}),e}let{OnnxEmbedder:e}=await import(`../../embeddings/dist/index.js`),t=new e({model:n.embedding.model,dimensions:n.embedding.dimensions,interOpNumThreads:n.embedding.interOpNumThreads,intraOpNumThreads:n.embedding.intraOpNumThreads});return await t.initialize(),Z.info(`Embedder loaded (in-process)`,{modelId:t.modelId,dimensions:t.dimensions}),t})(),(async()=>{let e=await wn({backend:r,path:i,adapter:a??void 0,embeddingDim:n.embedding.dimensions});return await e.initialize(),Z.info(`Store initialized`,{backend:r}),e})(),(async()=>{let e=a?new Sn({adapter:a}):new Sn({path:i});return await e.initialize(),Z.info(`Graph store initialized`,{shared:!!a}),e})(),(async()=>{let e=await fn();if(e){let e=un.get();Z.info(`WASM tree-sitter enabled`,{grammars:e.grammarCount,dir:e.wasmDir})}else{let e=un.get();Z.warn(`WASM tree-sitter not available; analyzers will use regex fallback`,{reason:e.reason,os:e.os,arch:e.arch,healAttempted:e.healAttempted,healSuccess:e.healSuccess,healError:e.healError,pathsChecked:e.pathsChecked.map(e=>`${e.path} (${e.exists?`found`:`missing`})`)})}return e})()]),d=new Nn(s,c),p=new Mn(n.store.path);p.load(),d.setHashCache(p);let m=n.curated.path,h=new e(m);await h.initialize();let g=new t(m,c,s,h);d.setGraphStore(l);let _=ja(n.er),b=_?new gn(n.curated.path):void 0;b&&Z.info(`Policy store initialized`,{ruleCount:b.getRules().length});let S=_?new hn:void 0,C=y(n.sources[0]?.path??process.cwd(),x.aiContext),w=o(C),T=n.onboardDir?o(n.onboardDir):!1,E=w||T,D,O=w?C:n.onboardDir;if(E&&O)try{D=f(O).mtime.toISOString()}catch{}return Z.info(`Onboard state detected`,{onboardComplete:E,onboardTimestamp:D,aiKbExists:w,onboardDirExists:T}),{embedder:s,store:c,indexer:d,curated:g,graphStore:l,fileCache:new re,bridge:_,policyStore:b,evolutionCollector:S,onboardComplete:E,onboardTimestamp:D}}function kd(e,t,n){if(e.serverInstructions)return e.serverInstructions;let r=new Set;for(let e of t){let t=n[e];if(t?.category)for(let e of t.category)r.add(e)}let i=[`This server provides ${t.size} tools across ${r.size} categories: ${[...r].sort().join(`, `)}.`];return e.readOnly&&i.push(`Server is in read-only mode. Mutating operations are disabled.`),e.features?.length&&i.push(`Active feature groups: ${e.features.join(`, `)}.`),i.join(` `)}const Ad=k(`background-task`);var jd=class{queue=[];running=null;get isRunning(){return this.running!==null}get currentTask(){return this.running}get pendingCount(){return this.queue.length}schedule(e){return new Promise((t,n)=>{this.queue.push({...e,resolve:t,reject:n}),this.running||this.processQueue()})}async processQueue(){for(;this.queue.length>0;){let e=this.queue.shift();if(!e)break;this.running=e.name,Ad.info(`Background task started`,{task:e.name,pending:this.queue.length});let t=Date.now();try{await e.fn();let n=Date.now()-t;Ad.info(`Background task completed`,{task:e.name,durationMs:n}),e.resolve()}catch(n){let r=Date.now()-t;Ad.error(`Background task failed`,{task:e.name,durationMs:r,err:n}),e.reject(n instanceof Error?n:Error(String(n)))}}this.running=null}};const Md=k(`idle-timer`);var Nd=class{timer=null;cleanupFns=[];idleMs;disposed=!1;sessionActive=!1;_busy=!1;constructor(e){this.idleMs=e?.idleMs??3e5}setBusy(e){this._busy=e,e?this.cancel():this.touch()}onIdle(e){this.cleanupFns.push(e)}markSessionActive(){this.sessionActive=!0}touch(){this.disposed||this._busy||(this.cancel(),this.timer=setTimeout(()=>{this.runCleanup()},this.idleMs),this.timer.unref&&this.timer.unref())}cancel(){this.timer&&=(clearTimeout(this.timer),null)}dispose(){this.cancel(),this.cleanupFns.length=0,this.disposed=!0}async runCleanup(){if(!this.sessionActive){Md.info(`Idle timeout reached with no active session — skipping cleanup (waiting for first tool call)`);return}if(this._busy){Md.info(`Skipping idle cleanup — background work in progress`);return}Md.info(`Idle for ${this.idleMs/1e3}s — running cleanup`);let e=await Promise.allSettled(this.cleanupFns.map(e=>e()));for(let t of e)t.status===`rejected`&&Md.warn(`Idle cleanup callback failed`,{error:String(t.reason)})}};const Pd=k(`memory-monitor`);var Fd=class{timer=null;warningBytes;criticalBytes;intervalMs;pressureFns=[];memoryPressureFns=[];lastLevel=`normal`;constructor(e){this.warningBytes=e?.warningBytes??4294967296,this.criticalBytes=e?.criticalBytes??8589934592,this.intervalMs=e?.intervalMs??6e4}onPressure(e){this.pressureFns.push(e)}registerMemoryPressureCallback(e){this.memoryPressureFns.push(e)}start(){this.timer||(this.timer=setInterval(()=>this.check(),this.intervalMs),this.timer.unref&&this.timer.unref(),Pd.info(`Memory monitor started`,{warningMB:Math.round(this.warningBytes/1024/1024),criticalMB:Math.round(this.criticalBytes/1024/1024),intervalSec:Math.round(this.intervalMs/1e3)}))}stop(){this.timer&&=(clearInterval(this.timer),null)}getRssBytes(){return process.memoryUsage.rss()}check(){let e=this.getRssBytes(),t=`normal`;if(e>=this.criticalBytes?t=`critical`:e>=this.warningBytes&&(t=`warning`),t!==this.lastLevel||t===`critical`){let n=Math.round(e/1024/1024);t===`critical`?Pd.warn(`Memory CRITICAL: ${n}MB RSS — consider restarting the server`):t===`warning`?Pd.warn(`Memory WARNING: ${n}MB RSS`):this.lastLevel!==`normal`&&Pd.info(`Memory returned to normal: ${n}MB RSS`),this.lastLevel=t}if(t!==`normal`)for(let n of this.pressureFns)try{n(t,e)}catch{}if(t===`critical`)for(let e of this.memoryPressureFns)try{let t=e();t&&typeof t.catch==`function`&&t.catch(()=>{})}catch{}return t===`critical`&&typeof globalThis.gc==`function`&&globalThis.gc(),t}};const Id=k(`tool-timeout`),Ld=new Set([`onboard`,`reindex`,`produce_knowledge`,`analyze`,`codemod`,`audit`]);var Rd=class extends Error{toolName;timeoutMs;constructor(e,t){super(`Tool "${e}" timed out after ${t}ms`),this.toolName=e,this.timeoutMs=t,this.name=`ToolTimeoutError`}};function zd(e){return Ld.has(e)?6e5:12e4}function Bd(e,t,n){return new Promise((r,i)=>{let a=!1,o=setTimeout(()=>{if(!a){a=!0;let e=new Rd(n,t);Id.warn(e.message),i(e)}},t);o.unref&&o.unref(),e().then(e=>{a||(a=!0,clearTimeout(o),r(e))},e=>{a||(a=!0,clearTimeout(o),i(e))})})}const Q=k(`server`);function Vd(e){let t=e.toLowerCase();return[`protobuf`,`invalid model`,`invalid onnx`,`unexpected end`,`unexpected token`,`failed to load`,`failed to initialize embedding`,`checksum`,`corrupt`,`malformed`,`could not load`,`onnx`,`database disk image is malformed`,`file is not a database`,`lance`,`cannot find module`,`module not found`].some(e=>t.includes(e))}async function Hd(e,t){let n=t.toLowerCase(),r;try{({rm:r}=await import(`node:fs/promises`))}catch{return}if(n.includes(`embedding`)||n.includes(`onnx`)||n.includes(`protobuf`)||n.includes(`model`)){let t=e.embedding?.model??C.model,n=v(Dn(),`.cache`,`huggingface`,`transformers-js`,t);try{await r(n,{recursive:!0,force:!0}),Q.info(`Auto-heal: cleared embedding model cache`,{path:n})}catch{}}if(n.includes(`lance`)||n.includes(`database`)||n.includes(`store`)){let t=v(e.store.path,`lance`);try{await r(t,{recursive:!0,force:!0}),Q.info(`Auto-heal: cleared LanceDB store`,{path:t})}catch{}}if(n.includes(`sqlite`)||n.includes(`database disk image`)||n.includes(`graph`)){let t=v(e.store.path,`graph.db`);try{await r(t,{force:!0}),Q.info(`Auto-heal: cleared graph database`,{path:t})}catch{}}}function Ud(e,t){let n=hi(e,L,R,Kr(e)),i=kd(e,n,R),a=new Xt({name:e.serverName??`aikit`,version:r()},{capabilities:{logging:{},completions:{},prompts:{}},instructions:i}),o=`initializing`,s=``,c=!1,l=null,u=null,d=null;function f(e){if(!e||typeof e!=`object`)return[];let t=e,n=[];for(let e of[`path`,`file`,`source_path`,`sourcePath`,`filePath`]){let r=t[e];typeof r==`string`&&r&&n.push(r)}for(let e of[`changed_files`,`paths`,`files`]){let r=t[e];if(Array.isArray(r))for(let e of r){if(typeof e==`string`){n.push(e);continue}e&&typeof e==`object`&&typeof e.path==`string`&&n.push(e.path)}}if(Array.isArray(t.sources))for(let e of t.sources)e&&typeof e==`object`&&typeof e.path==`string`&&n.push(e.path);return n}let p=()=>o===`failed`?[`❌ AI Kit initialization failed — this tool is unavailable.`,``,s?`Error: ${s}`:``,``,`**${Yr.size} tools are still available** and fully functional:`,`check, eval, test_run, git_context, health, measure, web_fetch, web_search,`,`flow, regex_test, encode,`,`stash, checkpoint, lane, process, time, env, and more.`,``,`To fix embedding errors, try deleting the cached model:`,` rm -rf ~/.cache/huggingface/transformers-js/mixedbread-ai/`,`Then restart the server to re-download a fresh copy.`,``,`Try restarting the MCP server to retry initialization.`].filter(Boolean).join(`
|
|
534
534
|
`):[`AI Kit is still initializing (loading embeddings model & store).`,``,`**${Yr.size} tools are already available** while initialization completes — including:`,`check, eval, test_run, git_context, health, measure, web_fetch, web_search,`,`flow, regex_test, encode,`,`stash, checkpoint, lane, process, time, env, and more.`,``,`This tool requires the AI Kit index. Please retry in a few seconds,`,`or use one of the available tools above in the meantime.`].join(`
|
|
535
|
-
`);In(a),ti(a,new wr,e.toolPrefix??``);let m=a.sendToolListChanged.bind(a);a.sendToolListChanged=()=>{};let h=[];for(let e of L){if(!n.has(e))continue;let t=z(e),r=a.registerTool(e,{title:t.title,description:`${t.title} — initializing, available shortly`,inputSchema:{},annotations:t.annotations},async()=>({content:[{type:`text`,text:p()}]}));Yr.has(e)?r.remove():h.push(r)}
|
|
535
|
+
`);In(a),ti(a,new wr,e.toolPrefix??``);let m=a.sendToolListChanged.bind(a);a.sendToolListChanged=()=>{};let h=[];for(let e of L){if(!n.has(e))continue;let t=z(e),r=a.registerTool(e,{title:t.title,description:`${t.title} — initializing, available shortly`,inputSchema:{},annotations:t.annotations},async()=>({content:[{type:`text`,text:p()}]}));Yr.has(e)?r.remove():h.push(r)}Td(a,e,n),a.sendToolListChanged=m;let g=a.registerResource(`aikit-status`,`aikit://status`,{description:`AI Kit status (initializing...)`,mimeType:`text/plain`},async()=>({contents:[{uri:`aikit://status`,text:`AI Kit is initializing...`,mimeType:`text/plain`}]})),_=a.registerPrompt(`_init`,{description:`Initializing AI Kit…`,argsSchema:{_dummy:P(F.string(),()=>[])}},async()=>({messages:[]})),v,y,b=new Promise((e,t)=>{v=e,y=t}),x,S=new Promise(e=>{x=e}),C=()=>x?.(),w=(async()=>{await S;try{let{createRequire:e}=await import(`node:module`),{readFileSync:t}=await import(`node:fs`),{fileURLToPath:n}=await import(`node:url`),{resolve:r,dirname:i}=await import(`node:path`),a=e(import.meta.url),o=r(i(n(import.meta.url)),`..`,`package.json`),s=JSON.parse(t(o,`utf8`)),c=Object.keys(s.dependencies??{}),l=[];for(let e of c)try{a.resolve(e)}catch{l.push(e)}l.length>0&&Q.warn(`${l.length} dependencies not resolvable — init may fail`,{missing:l,hint:`Corrupted npx cache from interrupted downloads. Try: npx clear-npx-cache`})}catch{}let n;try{n=await Od(e)}catch(t){let r=t instanceof Error?t.message:String(t);if(Vd(r)){Q.warn(`AI Kit initialization failed with recoverable error — attempting auto-heal retry`,{error:r}),await Hd(e,r);try{n=await Od(e),Q.info(`AI Kit auto-heal successful — initialization recovered after retry`)}catch(e){o=`failed`,s=e instanceof Error?e.message:String(e),Q.error(`AI Kit initialization failed after auto-heal attempt — server continuing with zero-dep tools only`,{error:s,originalError:r}),y?.(e instanceof Error?e:Error(s));return}}else{o=`failed`,s=r,Q.error(`AI Kit initialization failed — server continuing with zero-dep tools only`,{error:s}),y?.(t instanceof Error?t:Error(s));return}}let r=a.sendToolListChanged.bind(a);a.sendToolListChanged=()=>{};let i=a.sendPromptListChanged.bind(a);a.sendPromptListChanged=()=>{};let p=a.sendResourceListChanged.bind(a);a.sendResourceListChanged=()=>{};for(let e of h)e.remove();g.remove(),_.remove();let m=a._registeredTools??{};for(let e of Yr)m[e]?.remove();let b=new Dd(a),x=No(a);wd(a,n,e,Pn(a),b,x,t,t===`smart`?(()=>{let e=d;return e?.getState?e.getState():null}):null),qn(a,{curated:n.curated,store:n.store,graphStore:n.graphStore},t),a.sendToolListChanged=r,a.sendPromptListChanged=i,a.sendResourceListChanged=p,Promise.resolve(a.sendToolListChanged()).catch(()=>{}),Promise.resolve(a.sendPromptListChanged()).catch(()=>{}),Promise.resolve(a.sendResourceListChanged()).catch(()=>{});let C=a._registeredTools??{};for(let[e,t]of Object.entries(C)){if(qr.has(e))continue;let r=t.handler;t.handler=async(...t)=>{if(!n.indexer.isIndexing)return r(...t);let i=c?`re-indexing`:`running initial index`,a=new Promise(t=>setTimeout(()=>t({content:[{type:`text`,text:`⏳ AI Kit is ${i}. The tool "${e}" timed out waiting for index data (${Jr/1e3}s).\n\nThe existing index may be temporarily locked. Please retry shortly — indexing will complete automatically.`}]}),Jr));return Promise.race([r(...t),a])}}for(let[e,t]of Object.entries(C)){let n=t.handler,r=zd(e);t.handler=async(...t)=>{try{return await Bd(()=>n(...t),r,e)}catch(t){if(t instanceof Rd)return{content:[{type:`text`,text:`⏳ Tool "${e}" timed out after ${r/1e3}s. This may indicate a long-running operation. Please retry or break the task into smaller steps.`}]};throw t}}}let w=Object.keys(C).length;w<L.length&&Q.warn(`ALL_TOOL_NAMES count mismatch`,{expectedToolCount:L.length,registeredToolCount:w}),Q.info(`MCP server configured`,{toolCount:L.length,resourceCount:4});let T=new Fd;T.onPressure((e,t)=>{e===`warning`&&Bn(),e===`critical`&&(Q.warn(`Memory pressure critical — consider restarting`,{rssMB:Math.round(t/1024/1024)}),Bn())}),T.registerMemoryPressureCallback(()=>n.embedder.shutdown?.()),T.start();let D=new Nd;u=D,D.onIdle(async()=>{if(E.isRunning||n.indexer.isIndexing){Q.info(`Idle cleanup deferred — background tasks still running`),D.touch();return}Q.info(`Idle cleanup: releasing cached memory (connections stay open)`);try{n.store.releaseMemory?.(),n.graphStore.releaseMemory?.()}catch{}}),D.touch();let O=!1;for(let e of Object.values(C)){let t=e.handler;e.handler=async(...e)=>{if(O||(O=!0,D.markSessionActive()),D.touch(),d){let t=f(e[0]);t.length>0&&d.prioritize(...t)}return t(...e)}}process.stdin.on(`end`,()=>(Q.info(`stdin closed — MCP client disconnected. Shutting down.`),process.exit(0))),process.stdin.on(`error`,()=>(Q.info(`stdin error — MCP client disconnected. Shutting down.`),process.exit(0))),l=n,v?.(n)})(),T=async()=>{let t;try{t=await b}catch{Q.warn(`Skipping initial index — AI Kit initialization failed`);return}u?.setBusy(!0);try{let n=e.sources.map(e=>e.path).join(`, `);Q.info(`Running initial index`,{sourcePaths:n});let r=await t.indexer.index(e,e=>{e.phase===`crawling`||e.phase===`done`||(e.phase===`chunking`&&e.currentFile&&Q.debug(`Indexing file`,{current:e.filesProcessed+1,total:e.filesTotal,file:e.currentFile}),e.phase===`cleanup`&&Q.debug(`Index cleanup`,{staleEntries:e.filesTotal-e.filesProcessed}))});c=!0,Q.info(`Initial index complete`,{filesProcessed:r.filesProcessed,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated,durationMs:r.durationMs});try{await t.store.createFtsIndex()}catch(e){Q.warn(`FTS index creation failed`,j(e))}try{let e=await t.curated.reindexAll();Q.info(`Curated re-index complete`,{indexed:e.indexed})}catch(e){Q.error(`Curated re-index failed`,j(e))}}catch(e){Q.error(`Initial index failed; will retry on aikit_reindex`,j(e))}finally{u?.setBusy(!1)}},E=new jd,D=()=>E.schedule({name:`initial-index`,fn:T}),O=process.ppid,k=setInterval(()=>{try{process.kill(O,0)}catch{Q.info(`Parent process died; shutting down`,{parentPid:O}),clearInterval(k),d?.stop&&d.stop(),b.then(async e=>{await Promise.all([e.embedder.shutdown?.().catch(()=>{})??Promise.resolve(),e.graphStore.close().catch(()=>{}),e.store.close().catch(()=>{})])}).catch(()=>{}).finally(()=>process.exit(0))}},5e3);return k.unref(),{server:a,startInit:C,ready:w,runInitialIndex:D,get aikit(){return l},scheduler:E,setSmartScheduler(e){d=e}}}const $=k(`server`);function Wd(e,t){let n=hi(t,[...L,...Wr],R,Kr(t)),i=kd(t,n,R),a=new Xt({name:t.serverName??`aikit`,version:r()},{capabilities:{logging:{},completions:{},prompts:{}},instructions:i});return In(a),wd(a,e,t,Pn(a),new Dd(a),No(a),void 0,null,n),qn(a,{curated:e.curated,store:e.store,graphStore:e.graphStore},t.indexMode),a}async function Gd(e){let t=await Od(e),n=Wd(t,e);$.info(`MCP server configured`,{toolCount:L.length,resourceCount:2});let r=async()=>{try{let n=e.sources.map(e=>e.path).join(`, `);$.info(`Running initial index`,{sourcePaths:n});let r=await t.indexer.index(e,e=>{e.phase===`crawling`||e.phase===`done`||(e.phase===`chunking`&&e.currentFile&&$.debug(`Indexing file`,{current:e.filesProcessed+1,total:e.filesTotal,file:e.currentFile}),e.phase===`cleanup`&&$.debug(`Index cleanup`,{staleEntries:e.filesTotal-e.filesProcessed}))});$.info(`Initial index complete`,{filesProcessed:r.filesProcessed,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated,durationMs:r.durationMs});try{await t.store.createFtsIndex()}catch(e){$.warn(`FTS index creation failed`,j(e))}try{let e=await t.curated.reindexAll();$.info(`Curated re-index complete`,{indexed:e.indexed})}catch(e){$.error(`Curated re-index failed`,j(e))}}catch(e){$.error(`Initial index failed; will retry on aikit_reindex`,j(e))}},i=async()=>{$.info(`Shutting down`),await Promise.all([t.embedder.shutdown?.().catch(()=>{})??Promise.resolve(),t.graphStore.close().catch(()=>{}),t.store.close().catch(()=>{})]),process.exit(0)};process.on(`SIGINT`,i),process.on(`SIGTERM`,i);let a=process.ppid,o=setInterval(()=>{try{process.kill(a,0)}catch{$.info(`Parent process died; shutting down`,{parentPid:a}),clearInterval(o),i()}},5e3);return o.unref(),{server:n,runInitialIndex:r,shutdown:i}}export{L as ALL_TOOL_NAMES,Ud as createLazyServer,Wd as createMcpServer,Gd as createServer,Od as initializeAikit,wd as registerMcpTools};
|
|
@@ -1626,6 +1626,25 @@ Icons appear automatically in step nodes. No configuration needed — the viewer
|
|
|
1626
1626
|
3. Order by dependency graph — a step should only reference concepts from prior steps
|
|
1627
1627
|
4. Aim for 5-12 steps per tour (more → split into multiple tours)
|
|
1628
1628
|
5. Each step teaches exactly ONE concept
|
|
1629
|
+
|
|
1630
|
+
### Interactive C4 Architecture Visualization
|
|
1631
|
+
|
|
1632
|
+
For architecture documentation, generate interactive C4 diagrams using the shipped **c4-viewer.html** from the \`c4-architecture\` skill.
|
|
1633
|
+
|
|
1634
|
+
**Integration with docs skill:**
|
|
1635
|
+
- Architecture docs in \`docs/architecture/\` MUST have interactive HTML companions in \`docs/architecture/interactive/\`
|
|
1636
|
+
- Use the \`c4-architecture\` skill to generate C4 viewer HTML — it handles JSON schema, ReactFlow rendering, and ELK auto-layout
|
|
1637
|
+
- The \`c4-architecture\` skill provides: zoom/pan, node search, detail panels, drag-to-rearrange, and professional styling
|
|
1638
|
+
|
|
1639
|
+
**Workflow:**
|
|
1640
|
+
1. During Phase 5 (Domain Docs), identify system-level architecture views
|
|
1641
|
+
2. For EACH architecture view (system context, container, component):
|
|
1642
|
+
- Generate C4 JSON data: \`{nodes: [{id, label, type, description, technology}], edges: [{from, to, label}]}\`
|
|
1643
|
+
- Use the \`c4-architecture\` skill to render interactive HTML
|
|
1644
|
+
- Save to \`docs/architecture/interactive/{view-name}.html\`
|
|
1645
|
+
3. Cross-reference: link from markdown docs to interactive viewers
|
|
1646
|
+
|
|
1647
|
+
**CRITICAL:** NEVER generate architecture HTML from scratch. ALWAYS use the shipped c4-viewer.html via the \`c4-architecture\` skill. Hand-crafted HTML will be inconsistent and unprofessional.
|
|
1629
1648
|
## Documentation Generation Prompts
|
|
1630
1649
|
|
|
1631
1650
|
Structured LLM prompt templates for generating high-quality documentation. Each produces strict JSON for consistent, parseable output.
|
|
@@ -1785,7 +1804,7 @@ graph({ action: "find_nodes" }) # Full module graph
|
|
|
1785
1804
|
4. Output: layers.json used by tour generation
|
|
1786
1805
|
\`\`\`
|
|
1787
1806
|
|
|
1788
|
-
### Phase 4 — Generate Tours (
|
|
1807
|
+
### Phase 4 — Generate Tours (3-phase)
|
|
1789
1808
|
\`\`\`
|
|
1790
1809
|
# Phase 4a: Deterministic ranking
|
|
1791
1810
|
1. Compute node rankings (in-degree, centrality, layer)
|
|
@@ -1794,8 +1813,17 @@ graph({ action: "find_nodes" }) # Full module graph
|
|
|
1794
1813
|
|
|
1795
1814
|
# Phase 4b: LLM narrative
|
|
1796
1815
|
1. Apply Tour Generation Prompt with rankings from 4a
|
|
1797
|
-
2. Generate
|
|
1798
|
-
3.
|
|
1816
|
+
2. Generate Mermaid tour diagram for markdown docs
|
|
1817
|
+
3. Generate tour JSON data matching the shipped viewer schema
|
|
1818
|
+
4. Output: docs/tours/{name}.md (markdown with Mermaid diagram)
|
|
1819
|
+
|
|
1820
|
+
# Phase 4c: Interactive HTML generation (MANDATORY)
|
|
1821
|
+
1. For EACH tour generated in 4b:
|
|
1822
|
+
- Read the shipped tour-viewer.html from assets
|
|
1823
|
+
- Inject the tour JSON into the viewer's data block
|
|
1824
|
+
- Save to docs/tours/interactive/{name}.html
|
|
1825
|
+
2. These interactive HTML files are MANDATORY — never skip this step
|
|
1826
|
+
3. The result is a professional ReactFlow-based tour with step navigation, code panels, and BFS layout
|
|
1799
1827
|
\`\`\`
|
|
1800
1828
|
|
|
1801
1829
|
### Phase 5 — Generate Domain Docs (LLM-assisted)
|
|
@@ -1807,13 +1835,33 @@ graph({ action: "find_nodes" }) # Full module graph
|
|
|
1807
1835
|
4. Output: docs/architecture/domains/{domain}.md
|
|
1808
1836
|
\`\`\`
|
|
1809
1837
|
|
|
1810
|
-
### Phase 6 —
|
|
1838
|
+
### Phase 6 — Interactive Architecture HTML (MANDATORY)
|
|
1839
|
+
\`\`\`
|
|
1840
|
+
# Generate professional interactive C4 viewers for architecture documentation
|
|
1841
|
+
1. Identify architecture views from Phase 3 (layers) and Phase 5 (domain analysis):
|
|
1842
|
+
- System Context: overall system boundaries and external actors
|
|
1843
|
+
- Container: major deployable units and their relationships
|
|
1844
|
+
- Component: internal structure of key containers
|
|
1845
|
+
2. For EACH architecture view:
|
|
1846
|
+
- Generate C4 JSON data (nodes + edges with types and descriptions)
|
|
1847
|
+
- Use the c4-architecture skill to produce interactive HTML with ELK auto-layout
|
|
1848
|
+
- Save to docs/architecture/interactive/{view-name}.html
|
|
1849
|
+
3. Add navigation links:
|
|
1850
|
+
- From docs/architecture/overview.md → link to interactive viewers
|
|
1851
|
+
- From tour steps that reference architecture → link to relevant C4 view
|
|
1852
|
+
4. Generate documentation hub:
|
|
1853
|
+
- Use the present tool's docs-browser block type to create a navigable index
|
|
1854
|
+
- Include all markdown docs with status indicators and links to interactive companions
|
|
1855
|
+
\`\`\`
|
|
1856
|
+
|
|
1857
|
+
### Phase 7 — Validate & Cross-Reference
|
|
1811
1858
|
\`\`\`
|
|
1812
1859
|
# Ensure consistency
|
|
1813
1860
|
1. Check all internal doc links resolve
|
|
1814
1861
|
2. Verify code references still exist (file:line citations)
|
|
1815
1862
|
3. Cross-reference tour steps with actual files
|
|
1816
1863
|
4. check({}) to ensure no build breaks
|
|
1864
|
+
5. Verify all interactive HTML files open correctly and contain valid JSON data
|
|
1817
1865
|
\`\`\`
|
|
1818
1866
|
|
|
1819
1867
|
### Output Structure
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// AUTO-GENERATED - do not edit manually.
|
|
2
2
|
// Source: packages/server/src/tools/present/block-registry.ts
|
|
3
|
-
// Generated at: 2026-05-
|
|
3
|
+
// Generated at: 2026-05-10T17:01:50.322Z
|
|
4
4
|
|
|
5
5
|
export const ALL_BLOCK_DOCS = "| Type | Description | Value Shape |\n|------|-------------|-------------|\n| `markdown` | Markdown content rendered with the marked parser. | `string` |\n| `code` | Formatted code block rendered inside pre/code tags. | `string` |\n| `mermaid` | Mermaid diagram source rendered in a mermaid pre block. | `string` |\n| `table` | Tabular data rendered from records or explicit headers and rows. | `Record<string, unknown>[] | { headers: string[]; rows: unknown[][] }` |\n| `metrics` | Metric cards showing label/value pairs with optional trend and status. | `Array<{ label: string; value: string | number; trend?: string | number; status?: string }>` |\n| `cards` | Card grid for titled items with optional body, badge, and status. | `Array<{ title: string; body?: string; badge?: string; status?: string; description?: string }>` |\n| `tree` | Hierarchical object or name/children tree rendered recursively. | `{ name: string; children?: unknown[] } | Record<string, unknown>` |\n| `graph` | Node and edge graph rendered as a Mermaid flow graph in HTML mode. | `{ nodes: Array<{ id: string; label?: string }>; edges: Array<{ from: string; to: string; label?: string }> }` |\n| `chart` | Structured chart definition rendered as SVG. | `{ chartType: string; data: Record<string, unknown>[]; xKey: string; yKeys: string[] }` |\n| `timeline` | Timeline entries rendered as a vertical sequence of events. | `Array<{ title: string; description?: string; timestamp?: string; status?: string }>` |\n| `checklist` | Checklist items with boolean checked state. | `Array<{label, checked}> | {items: Array<{label, checked}>}` |\n| `comparison` | Side-by-side comparison columns with titled item lists. | `Array<{title, items}> | {columns: Array<{title, items}>}` |\n| `status-board` | Status categories containing labeled status items. | `Array<{category, items}> | {items: Array<{category, items}>}` |\n| `prompt` | Prompt payload rendered through the prompt display helper. | `unknown` |\n| `progress` | Progress bar with current value and optional maximum. | `{label, value, max?} | {items: Array<{label, value, max?, color?}>}` |\n| `docs-browser` | Documentation file list with inline content previews for chat-safe rendering. | `{ files: Array<{ path: string; title?: string; content?: string; status?: \"current\" | \"stale\" | \"missing\" }>; title?: string }` |\n| `text` | Plain text content rendered through the markdown parser. | `string` |\n| `heading` | Single heading with configurable level from h1 to h6. | `string` |\n| `paragraph` | Single paragraph rendered inside a p tag. | `string` |\n| `separator` | Horizontal rule used to separate adjacent blocks. | `undefined` |\n| `actions` | Action bar containing button and select action definitions. | `Array<{ type: string; id: string; label: string; variant?: string; options?: Array<string | { label: string; value: string }> }>` |\n\n### Usage Examples\n\n#### `docs-browser`\n\n```typescript\n{\n type: 'docs-browser',\n value: {\n title: 'Project Docs',\n files: [\n { path: 'docs/README.md', title: 'Overview', status: 'current' },\n { path: 'docs/api.md', title: 'API Reference', status: 'stale' },\n ],\n },\n}\n```";
|
|
6
6
|
|