@vpxa/aikit 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/package.json +1 -1
  2. package/packages/cli/dist/commands/init/constants.d.ts +3 -1
  3. package/packages/cli/dist/commands/init/constants.js +1 -1
  4. package/packages/cli/dist/commands/init/index.js +4 -4
  5. package/packages/cli/dist/commands/init/scaffold.d.ts +8 -1
  6. package/packages/cli/dist/commands/init/scaffold.js +1 -1
  7. package/packages/cli/dist/commands/init/user.js +4 -4
  8. package/packages/cli/dist/commands/upgrade.js +1 -1
  9. package/packages/core/dist/global-registry.js +1 -1
  10. package/packages/core/dist/types.d.ts +2 -0
  11. package/packages/flows/dist/git.js +1 -1
  12. package/packages/flows/dist/registry.d.ts +3 -3
  13. package/packages/flows/dist/registry.js +1 -1
  14. package/packages/flows/dist/symlinks.js +1 -1
  15. package/packages/indexer/dist/filesystem-crawler.js +1 -1
  16. package/packages/indexer/dist/hash-cache.js +1 -1
  17. package/packages/kb-client/dist/direct-client.d.ts +33 -34
  18. package/packages/kb-client/dist/index.d.ts +5 -4
  19. package/packages/kb-client/dist/mcp-client.d.ts +18 -18
  20. package/packages/kb-client/dist/parsers.d.ts +14 -11
  21. package/packages/kb-client/dist/types.d.ts +50 -47
  22. package/packages/present/dist/index.html +26 -26
  23. package/packages/server/dist/config.js +1 -1
  24. package/packages/server/dist/idle-timer.d.ts +4 -0
  25. package/packages/server/dist/idle-timer.js +1 -1
  26. package/packages/server/dist/index.js +1 -1
  27. package/packages/server/dist/memory-monitor.d.ts +2 -2
  28. package/packages/server/dist/memory-monitor.js +1 -1
  29. package/packages/server/dist/server.d.ts +1 -1
  30. package/packages/server/dist/server.js +2 -2
  31. package/packages/server/dist/tool-metadata.js +1 -1
  32. package/packages/server/dist/tools/config.tool.d.ts +8 -0
  33. package/packages/server/dist/tools/config.tool.js +12 -0
  34. package/packages/server/dist/tools/flow.tools.js +1 -1
  35. package/packages/server/dist/tools/present/browser.js +7 -7
  36. package/packages/server/dist/tools/present/tool.js +4 -4
  37. package/packages/server/dist/tools/search.tool.js +4 -4
  38. package/packages/server/dist/tools/status.tool.js +3 -3
  39. package/packages/store/dist/sqlite-graph-store.d.ts +3 -0
  40. package/packages/store/dist/sqlite-graph-store.js +3 -3
  41. package/packages/tools/dist/checkpoint.js +1 -1
  42. package/packages/tools/dist/evidence-map.js +2 -2
  43. package/packages/tools/dist/queue.js +1 -1
  44. package/packages/tools/dist/restore-points.js +1 -1
  45. package/packages/tools/dist/schema-validate.js +1 -1
  46. package/packages/tools/dist/snippet.js +1 -1
  47. package/packages/tools/dist/stash.js +1 -1
  48. package/packages/tools/dist/workset.js +1 -1
  49. package/packages/tui/dist/{App-B2-KJPt4.js → App-DpjN3iS-.js} +1 -1
  50. package/packages/tui/dist/App.js +1 -1
  51. package/packages/tui/dist/LogPanel-Db-SeZhR.js +3 -0
  52. package/packages/tui/dist/index.js +1 -1
  53. package/packages/tui/dist/panels/LogPanel.js +1 -1
  54. package/scaffold/general/skills/multi-agents-development/SKILL.md +435 -435
  55. package/scaffold/general/skills/present/SKILL.md +424 -424
  56. package/packages/kb-client/dist/__tests__/direct-client.test.d.ts +0 -1
  57. package/packages/kb-client/dist/__tests__/mcp-client.test.d.ts +0 -1
  58. package/packages/kb-client/dist/__tests__/parsers.test.d.ts +0 -1
  59. package/packages/tui/dist/LogPanel-E_1Do4-j.js +0 -3
@@ -1 +1 @@
1
- import{existsSync as e,readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{fileURLToPath as i}from"node:url";import{AIKIT_PATHS as a,createLogger as o,getPartitionDir as s,isUserInstalled as c,registerWorkspace as l,serializeError as u}from"../../core/dist/index.js";const d=n(i(import.meta.url)),f=o(`server`);function p(e,t,n){let i=r(e),a=r(t);if(!i.startsWith(a))throw Error(`Config ${n} path escapes workspace root: ${e} is not under ${t}`);return i}function m(){let i=process.env.AIKIT_CONFIG_PATH??(e(r(process.cwd(),`aikit.config.json`))?r(process.cwd(),`aikit.config.json`):r(d,`..`,`..`,`..`,`aikit.config.json`));try{if(!e(i))return f.info(`No config file found, using defaults`,{configPath:i}),h();let o=t(i,`utf-8`),s=JSON.parse(o);if(!s.sources||!Array.isArray(s.sources)||s.sources.length===0)throw Error(`Config must have at least one source`);if(!s.store?.path)throw Error(`Config must specify store.path`);let c=n(i);return s.sources=s.sources.map(e=>({...e,path:p(r(c,e.path),c,`source`)})),s.store.path=p(r(c,s.store.path),c,`store`),s.curated=s.curated??{path:a.aiCurated},s.curated.path=p(r(c,s.curated.path),c,`curated`),g(s,c),s}catch(e){return f.error(`Failed to load config`,{configPath:i,...u(e)}),f.warn(`Falling back to default configuration`,{configPath:i}),h()}}function h(){let e=process.env.AIKIT_WORKSPACE_ROOT??process.cwd(),t={sources:[{path:e,excludePatterns:[`node_modules/**`,`dist/**`,`.git/**`,`coverage/**`,`*.lock`,`pnpm-lock.yaml`]}],serverName:`aikit`,indexing:{chunkSize:1500,chunkOverlap:200,minChunkSize:100},embedding:{model:`mixedbread-ai/mxbai-embed-large-v1`,dimensions:1024},store:{backend:`lancedb`,path:r(e,a.data)},curated:{path:r(e,a.aiCurated)},onboardDir:r(e,a.aiKb),stateDir:r(e,a.state)};return g(t,e),t}function g(e,t){if(!c())return;let n=t,i=l(n);e.store.path=r(s(i.partition)),e.onboardDir=r(s(i.partition),`onboard`),e.stateDir=r(s(i.partition),`state`),e.curated||={path:r(n,a.aiCurated)}}function _(e,t){f.info(`Reconfiguring for workspace root`,{workspaceRoot:t});try{process.chdir(t),f.info(`Changed process cwd to workspace root`,{cwd:process.cwd()})}catch(e){f.warn(`Failed to chdir to workspace root`,{workspaceRoot:t,...u(e)})}e.sources=[{path:t,excludePatterns:e.sources[0]?.excludePatterns??[`node_modules/**`,`dist/**`,`.git/**`,`coverage/**`,`*.lock`,`pnpm-lock.yaml`]}],e.store.path=r(t,a.data),e.curated={path:r(t,a.aiCurated)},e.onboardDir=r(t,a.aiKb),e.stateDir=r(t,a.state),g(e,t)}export{m as loadConfig,_ as reconfigureForWorkspace};
1
+ import{existsSync as e,readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{fileURLToPath as i}from"node:url";import{AIKIT_PATHS as a,createLogger as o,getPartitionDir as s,isUserInstalled as c,registerWorkspace as l,serializeError as u}from"../../core/dist/index.js";const d=n(i(import.meta.url)),f=o(`server`);function p(e,t,n){let i=r(e),a=r(t);if(!i.startsWith(a))throw Error(`Config ${n} path escapes workspace root: ${e} is not under ${t}`);return i}function m(){let i=process.env.AIKIT_CONFIG_PATH??(e(r(process.cwd(),`aikit.config.json`))?r(process.cwd(),`aikit.config.json`):r(d,`..`,`..`,`..`,`aikit.config.json`));try{if(!e(i))return f.info(`No config file found, using defaults`,{configPath:i}),h();let o=t(i,`utf-8`),s=JSON.parse(o);if(!s.sources||!Array.isArray(s.sources)||s.sources.length===0)throw Error(`Config must have at least one source`);if(!s.store?.path)throw Error(`Config must specify store.path`);if(s.autoIndex!==void 0&&typeof s.autoIndex!=`boolean`)throw Error(`Config autoIndex must be a boolean`);let c=n(i);return s.sources=s.sources.map(e=>({...e,path:p(r(c,e.path),c,`source`)})),s.store.path=p(r(c,s.store.path),c,`store`),s.curated=s.curated??{path:a.aiCurated},s.curated.path=p(r(c,s.curated.path),c,`curated`),g(s,c),s}catch(e){return f.error(`Failed to load config`,{configPath:i,...u(e)}),f.warn(`Falling back to default configuration`,{configPath:i}),h()}}function h(){let e=process.env.AIKIT_WORKSPACE_ROOT??process.cwd(),t={sources:[{path:e,excludePatterns:[`node_modules/**`,`dist/**`,`.git/**`,`coverage/**`,`*.lock`,`pnpm-lock.yaml`]}],serverName:`aikit`,autoIndex:!1,indexing:{chunkSize:1500,chunkOverlap:200,minChunkSize:100},embedding:{model:`mixedbread-ai/mxbai-embed-large-v1`,dimensions:1024},store:{backend:`lancedb`,path:r(e,a.data)},curated:{path:r(e,a.aiCurated)},onboardDir:r(e,a.aiKb),stateDir:r(e,a.state)};return g(t,e),t}function g(e,t){if(!c())return;let n=t,i=l(n);e.store.path=r(s(i.partition)),e.onboardDir=r(s(i.partition),`onboard`),e.stateDir=r(s(i.partition),`state`),e.curated||={path:r(n,a.aiCurated)}}function _(t,n){if(!e(n))throw Error(`Workspace root does not exist: ${n}`);f.info(`Reconfiguring for workspace root`,{workspaceRoot:n});try{process.chdir(n),f.info(`Changed process cwd to workspace root`,{cwd:process.cwd()})}catch(e){f.warn(`Failed to chdir to workspace root`,{workspaceRoot:n,...u(e)})}t.sources=[{path:n,excludePatterns:t.sources[0]?.excludePatterns??[`node_modules/**`,`dist/**`,`.git/**`,`coverage/**`,`*.lock`,`pnpm-lock.yaml`]}],t.store.path=r(n,a.data),t.curated={path:r(n,a.aiCurated)},t.onboardDir=r(n,a.aiKb),t.stateDir=r(n,a.state),g(t,n)}export{m as loadConfig,_ as reconfigureForWorkspace};
@@ -14,7 +14,11 @@ declare class IdleTimer {
14
14
  private readonly cleanupFns;
15
15
  private readonly idleMs;
16
16
  private disposed;
17
+ /** When true, cleanup is suppressed (e.g. during long-running indexing). */
18
+ private _busy;
17
19
  constructor(opts?: IdleTimerOptions);
20
+ /** Mark the server as busy (suppresses idle cleanup while true). */
21
+ setBusy(busy: boolean): void;
18
22
  /** Register a cleanup callback that runs when idle threshold is reached. */
19
23
  onIdle(fn: () => void | Promise<void>): void;
20
24
  /** Call this on every tool invocation to reset the idle countdown. */
@@ -1 +1 @@
1
- import{createLogger as e}from"../../core/dist/index.js";const t=e(`idle-timer`);var n=class{timer=null;cleanupFns=[];idleMs;disposed=!1;constructor(e){this.idleMs=e?.idleMs??3e5}onIdle(e){this.cleanupFns.push(e)}touch(){this.disposed||(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(){t.info(`Idle for ${this.idleMs/1e3}s — running cleanup`);for(let e of this.cleanupFns)try{await e()}catch(e){t.warn(`Idle cleanup callback failed`,{error:String(e)})}}};export{n as IdleTimer};
1
+ import{createLogger as e}from"../../core/dist/index.js";const t=e(`idle-timer`);var n=class{timer=null;cleanupFns=[];idleMs;disposed=!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)}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._busy){t.info(`Skipping idle cleanup — background work in progress`);return}t.info(`Idle for ${this.idleMs/1e3}s — running cleanup`);let e=await Promise.allSettled(this.cleanupFns.map(e=>e()));for(let n of e)n.status===`rejected`&&t.warn(`Idle cleanup callback failed`,{error:String(n.reason)})}};export{n as IdleTimer};
@@ -1 +1 @@
1
- import{readFileSync as e}from"node:fs";import{dirname as t,resolve as n}from"node:path";import{fileURLToPath as r}from"node:url";import{createLogger as i,serializeError as a}from"../../core/dist/index.js";import{parseArgs as o}from"node:util";const s=t(r(import.meta.url)),c=(()=>{try{let t=n(s,`..`,`..`,`..`,`package.json`);return JSON.parse(e(t,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}})(),l=i(`server`),{values:u}=o({options:{transport:{type:`string`,default:process.env.AIKIT_TRANSPORT??`stdio`},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}});async function d(){if(process.on(`unhandledRejection`,e=>{l.error(`Unhandled rejection`,a(e))}),l.info(`Starting MCP AI Kit server`,{version:c}),u.transport===`http`){let[{default:e},{loadConfig:t},{registerDashboardRoutes:n,resolveDashboardDir:r}]=await Promise.all([import(`express`),import(`./config.js`),import(`./dashboard-static.js`)]),i=t();l.info(`Config loaded`,{sourceCount:i.sources.length,storePath:i.store.path});let o=e();o.use(e.json());let s=Number(u.port);o.use((e,t,n)=>{if(t.setHeader(`Access-Control-Allow-Origin`,process.env.AIKIT_CORS_ORIGIN??`http://localhost:${s}`),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization`),e.method===`OPTIONS`){t.status(204).end();return}n()}),n(o,r(),l),o.get(`/health`,(e,t)=>{t.json({status:`ok`})});let c=!1,d=null,f=null,p=Promise.resolve();o.post(`/mcp`,async(e,t)=>{if(!c||!d||!f){t.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let n=p,r;p=new Promise(e=>{r=e}),await n;try{let n=new f({sessionIdGenerator:void 0});await d.connect(n),await n.handleRequest(e,t,e.body),n.close()}catch(e){if(l.error(`MCP handler error`,a(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()}}),o.get(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))}),o.delete(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))});let m=o.listen(s,`127.0.0.1`,()=>{l.info(`MCP server listening`,{url:`http://127.0.0.1:${s}/mcp`,port:s}),setTimeout(async()=>{try{let[{createLazyServer:e,ALL_TOOL_NAMES:t},{StreamableHTTPServerTransport:n},{checkForUpdates:r,autoUpgradeScaffold:o}]=await Promise.all([import(`./server.js`),import(`@modelcontextprotocol/sdk/server/streamableHttp.js`),import(`./version-check.js`)]);r(),o();let s=e(i);d=s.server,f=n,c=!0,l.info(`MCP server configured (lazy — AI Kit initializing in background)`,{toolCount:t.length,resourceCount:2}),s.startInit(),process.env.AIKIT_AUTO_INDEX===`true`?s.ready.then(async()=>{try{let e=i.sources.map(e=>e.path).join(`, `);l.info(`Running initial index`,{sourcePaths:e}),await s.runInitialIndex(),l.info(`Initial index complete`)}catch(e){l.error(`Initial index failed; will retry on aikit_reindex`,a(e))}}).catch(e=>l.error(`AI Kit init or indexing failed`,a(e))):(s.ready.catch(e=>l.error(`AI Kit initialization failed`,a(e))),l.info(`Auto-index disabled in HTTP mode (set AIKIT_AUTO_INDEX=true to enable)`))}catch(e){l.error(`Failed to load server modules`,a(e))}},100)}),h=async e=>{l.info(`Shutdown signal received`,{signal:e}),m.close(),d&&await d.close(),process.exit(0)};process.on(`SIGINT`,()=>h(`SIGINT`)),process.on(`SIGTERM`,()=>h(`SIGTERM`))}else{let[{loadConfig:e,reconfigureForWorkspace:t},{createLazyServer:n},{checkForUpdates:i,autoUpgradeScaffold:o},{RootsListChangedNotificationSchema:s}]=await Promise.all([import(`./config.js`),import(`./server.js`),import(`./version-check.js`),import(`@modelcontextprotocol/sdk/types.js`)]),c=e();l.info(`Config loaded`,{sourceCount:c.sources.length,storePath:c.store.path}),i(),o();let{server:u,startInit:d,ready:f,runInitialIndex:p}=n(c),{StdioServerTransport:m}=await import(`@modelcontextprotocol/sdk/server/stdio.js`),h=new m;await u.connect(h),l.info(`MCP server started`,{transport:`stdio`});let g=e=>{if(e.length===0)return!1;let n=e[0].uri,i=n.startsWith(`file://`)?r(n):n;return l.info(`MCP roots resolved`,{rootUri:n,rootPath:i,rootCount:e.length}),t(c,i),!0},_=!1;try{_=g((await u.server.listRoots()).roots),_||l.info(`No MCP roots yet; waiting for roots/list_changed notification`)}catch(e){l.warn(`MCP roots/list not supported by client; using cwd fallback`,{cwd:process.cwd(),...a(e)}),_=!0}_||=await new Promise(e=>{let t=setTimeout(()=>{l.warn(`Timed out waiting for MCP roots/list_changed; using cwd fallback`,{cwd:process.cwd()}),e(!1)},5e3);u.server.setNotificationHandler(s,async()=>{clearTimeout(t);try{e(g((await u.server.listRoots()).roots))}catch(t){l.warn(`roots/list retry failed after notification`,a(t)),e(!1)}})}),d();let v=null,y=()=>{v&&clearTimeout(v),v=setTimeout(()=>{l.info(`Auto-shutdown: no activity for 30 minutes — exiting`),process.exit(0)},18e5),v.unref&&v.unref()};y(),process.stdin.on(`data`,()=>y()),f.catch(e=>{l.error(`Initialization failed — server will continue with limited tools`,a(e))}),process.env.AIKIT_AUTO_INDEX===`false`?l.warn(`Auto-index disabled; use aikit_reindex to index manually`):p().catch(e=>l.error(`Initial index failed`,a(e)))}}d().catch(e=>{l.error(`Fatal error`,a(e)),process.exit(1)});export{};
1
+ import{readFileSync as e}from"node:fs";import{dirname as t,resolve as n}from"node:path";import{fileURLToPath as r}from"node:url";import{createLogger as i,serializeError as a}from"../../core/dist/index.js";import{parseArgs as o}from"node:util";const s=t(r(import.meta.url)),c=(()=>{try{let t=n(s,`..`,`..`,`..`,`package.json`);return JSON.parse(e(t,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}})(),l=i(`server`),{values:u}=o({options:{transport:{type:`string`,default:process.env.AIKIT_TRANSPORT??`stdio`},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}});async function d(){if(process.on(`unhandledRejection`,e=>{l.error(`Unhandled rejection`,a(e))}),l.info(`Starting MCP AI Kit server`,{version:c}),u.transport===`http`){let[{default:e},{loadConfig:t},{registerDashboardRoutes:n,resolveDashboardDir:r}]=await Promise.all([import(`express`),import(`./config.js`),import(`./dashboard-static.js`)]),i=t();l.info(`Config loaded`,{sourceCount:i.sources.length,storePath:i.store.path});let o=e();o.use(e.json());let s=Number(u.port);o.use((e,t,n)=>{if(t.setHeader(`Access-Control-Allow-Origin`,process.env.AIKIT_CORS_ORIGIN??`http://localhost:${s}`),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization`),e.method===`OPTIONS`){t.status(204).end();return}n()}),n(o,r(),l),o.get(`/health`,(e,t)=>{t.json({status:`ok`})});let c=!1,d=null,f=null,p=Promise.resolve();o.post(`/mcp`,async(e,t)=>{if(!c||!d||!f){t.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let n=p,r;p=new Promise(e=>{r=e}),await n;try{let n=new f({sessionIdGenerator:void 0});await d.connect(n),await n.handleRequest(e,t,e.body),n.close()}catch(e){if(l.error(`MCP handler error`,a(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()}}),o.get(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))}),o.delete(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))});let m=o.listen(s,`127.0.0.1`,()=>{l.info(`MCP server listening`,{url:`http://127.0.0.1:${s}/mcp`,port:s}),setTimeout(async()=>{try{let[{createLazyServer:e,ALL_TOOL_NAMES:t},{StreamableHTTPServerTransport:n},{checkForUpdates:r,autoUpgradeScaffold:o}]=await Promise.all([import(`./server.js`),import(`@modelcontextprotocol/sdk/server/streamableHttp.js`),import(`./version-check.js`)]);r(),o();let s=e(i);d=s.server,f=n,c=!0,l.info(`MCP server configured (lazy — AI Kit initializing in background)`,{toolCount:t.length,resourceCount:2}),s.startInit(),process.env.AIKIT_AUTO_INDEX===`true`?s.ready.then(async()=>{try{let e=i.sources.map(e=>e.path).join(`, `);l.info(`Running initial index`,{sourcePaths:e}),await s.runInitialIndex(),l.info(`Initial index complete`)}catch(e){l.error(`Initial index failed; will retry on aikit_reindex`,a(e))}}).catch(e=>l.error(`AI Kit init or indexing failed`,a(e))):(s.ready.catch(e=>l.error(`AI Kit initialization failed`,a(e))),l.info(`Auto-index disabled in HTTP mode (set AIKIT_AUTO_INDEX=true to enable)`))}catch(e){l.error(`Failed to load server modules`,a(e))}},100)}),h=async e=>{l.info(`Shutdown signal received`,{signal:e}),m.close(),d&&await d.close(),process.exit(0)};process.on(`SIGINT`,()=>h(`SIGINT`)),process.on(`SIGTERM`,()=>h(`SIGTERM`))}else{let[{loadConfig:e,reconfigureForWorkspace:t},{createLazyServer:n},{checkForUpdates:i,autoUpgradeScaffold:o},{RootsListChangedNotificationSchema:s}]=await Promise.all([import(`./config.js`),import(`./server.js`),import(`./version-check.js`),import(`@modelcontextprotocol/sdk/types.js`)]),c=e();l.info(`Config loaded`,{sourceCount:c.sources.length,storePath:c.store.path}),i(),o();let{server:u,startInit:d,ready:f,runInitialIndex:p}=n(c),{StdioServerTransport:m}=await import(`@modelcontextprotocol/sdk/server/stdio.js`),h=new m;await u.connect(h),l.info(`MCP server started`,{transport:`stdio`});let g=e=>{if(e.length===0)return!1;let n=e[0].uri,i=n.startsWith(`file://`)?r(n):n;return l.info(`MCP roots resolved`,{rootUri:n,rootPath:i,rootCount:e.length}),t(c,i),!0},_=!1;try{_=g((await u.server.listRoots()).roots),_||l.info(`No MCP roots yet; waiting for roots/list_changed notification`)}catch(e){l.warn(`MCP roots/list not supported by client; using cwd fallback`,{cwd:process.cwd(),...a(e)}),_=!0}_||=await new Promise(e=>{let t=setTimeout(()=>{l.warn(`Timed out waiting for MCP roots/list_changed; using cwd fallback`,{cwd:process.cwd()}),e(!1)},5e3);u.server.setNotificationHandler(s,async()=>{clearTimeout(t);try{e(g((await u.server.listRoots()).roots))}catch(t){l.warn(`roots/list retry failed after notification`,a(t)),e(!1)}})}),d();let v=null,y=()=>{v&&clearTimeout(v),v=setTimeout(()=>{l.info(`Auto-shutdown: no activity for 30 minutes — exiting`),process.exit(0)},18e5),v.unref&&v.unref()};y(),process.stdin.on(`data`,()=>y()),f.catch(e=>{l.error(`Initialization failed — server will continue with limited tools`,a(e))}),process.env.AIKIT_AUTO_INDEX===`true`||process.env.AIKIT_AUTO_INDEX===void 0&&c.autoIndex===!0?p().catch(e=>l.error(`Initial index failed`,a(e))):l.warn(`Auto-index disabled; use aikit_reindex to index manually`)}}d().catch(e=>{l.error(`Fatal error`,a(e)),process.exit(1)});export{};
@@ -6,9 +6,9 @@
6
6
  * for triggering cache eviction or GC hints when memory is high.
7
7
  */
8
8
  interface MemoryMonitorOptions {
9
- /** RSS bytes above which a warning is logged. @default 1 GB */
9
+ /** RSS bytes above which a warning is logged. @default 4 GB */
10
10
  warningBytes?: number;
11
- /** RSS bytes above which pressure callbacks fire. @default 2 GB */
11
+ /** RSS bytes above which pressure callbacks fire. @default 8 GB */
12
12
  criticalBytes?: number;
13
13
  /** Polling interval in milliseconds. @default 60 000 */
14
14
  intervalMs?: number;
@@ -1 +1 @@
1
- import{createLogger as e}from"../../core/dist/index.js";const t=e(`memory-monitor`);var n=class{timer=null;warningBytes;criticalBytes;intervalMs;pressureFns=[];lastLevel=`normal`;constructor(e){this.warningBytes=e?.warningBytes??1073741824,this.criticalBytes=e?.criticalBytes??2147483648,this.intervalMs=e?.intervalMs??6e4}onPressure(e){this.pressureFns.push(e)}start(){this.timer||(this.timer=setInterval(()=>this.check(),this.intervalMs),this.timer.unref&&this.timer.unref(),t.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(),n=`normal`;if(e>=this.criticalBytes?n=`critical`:e>=this.warningBytes&&(n=`warning`),n!==this.lastLevel||n===`critical`){let r=Math.round(e/1024/1024);n===`critical`?t.warn(`Memory CRITICAL: ${r}MB RSS — consider restarting the server`):n===`warning`?t.warn(`Memory WARNING: ${r}MB RSS`):this.lastLevel!==`normal`&&t.info(`Memory returned to normal: ${r}MB RSS`),this.lastLevel=n}if(n!==`normal`)for(let t of this.pressureFns)try{t(n,e)}catch{}return n===`critical`&&typeof globalThis.gc==`function`&&globalThis.gc(),n}};export{n as MemoryMonitor};
1
+ import{createLogger as e}from"../../core/dist/index.js";const t=e(`memory-monitor`);var n=class{timer=null;warningBytes;criticalBytes;intervalMs;pressureFns=[];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)}start(){this.timer||(this.timer=setInterval(()=>this.check(),this.intervalMs),this.timer.unref&&this.timer.unref(),t.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(),n=`normal`;if(e>=this.criticalBytes?n=`critical`:e>=this.warningBytes&&(n=`warning`),n!==this.lastLevel||n===`critical`){let r=Math.round(e/1024/1024);n===`critical`?t.warn(`Memory CRITICAL: ${r}MB RSS — consider restarting the server`):n===`warning`?t.warn(`Memory WARNING: ${r}MB RSS`):this.lastLevel!==`normal`&&t.info(`Memory returned to normal: ${r}MB RSS`),this.lastLevel=n}if(n!==`normal`)for(let t of this.pressureFns)try{t(n,e)}catch{}return n===`critical`&&typeof globalThis.gc==`function`&&globalThis.gc(),n}};export{n as MemoryMonitor};
@@ -37,7 +37,7 @@ declare function createServer(config: KBConfig): Promise<{
37
37
  runInitialIndex: () => Promise<void>;
38
38
  shutdown: () => Promise<void>;
39
39
  }>;
40
- declare const ALL_TOOL_NAMES: readonly ["analyze_dependencies", "analyze_diagram", "analyze_entry_points", "analyze_patterns", "analyze_structure", "analyze_symbols", "audit", "batch", "blast_radius", "brainstorm", "changelog", "check", "checkpoint", "codemod", "compact", "data_transform", "dead_symbols", "delegate", "diff_parse", "digest", "encode", "env", "eval", "evidence_map", "file_summary", "find", "forge_classify", "forge_ground", "forget", "git_context", "graph", "guide", "health", "http", "lane", "list", "lookup", "measure", "onboard", "parse_output", "present", "process", "produce_knowledge", "queue", "read", "regex_test", "reindex", "remember", "rename", "replay", "restore", "schema_validate", "scope_map", "search", "snippet", "stash", "status", "stratum_card", "symbol", "test_run", "time", "trace", "update", "watch", "web_fetch", "web_search", "workset"];
40
+ declare const ALL_TOOL_NAMES: readonly ["analyze_dependencies", "analyze_diagram", "analyze_entry_points", "analyze_patterns", "analyze_structure", "analyze_symbols", "audit", "batch", "blast_radius", "brainstorm", "changelog", "check", "checkpoint", "codemod", "compact", "config", "data_transform", "dead_symbols", "delegate", "diff_parse", "digest", "encode", "env", "eval", "evidence_map", "file_summary", "find", "flow_info", "flow_list", "flow_reset", "flow_start", "flow_status", "flow_step", "forge_classify", "forge_ground", "forget", "git_context", "graph", "guide", "health", "http", "lane", "list", "lookup", "measure", "onboard", "parse_output", "present", "process", "produce_knowledge", "queue", "read", "regex_test", "reindex", "remember", "rename", "replay", "restore", "schema_validate", "scope_map", "search", "snippet", "stash", "status", "stratum_card", "symbol", "test_run", "time", "trace", "update", "watch", "web_fetch", "web_search", "workset"];
41
41
  declare function createLazyServer(config: KBConfig): {
42
42
  server: McpServer; /** Call after MCP roots are resolved (or fallback decided) to start heavy init. */
43
43
  startInit: () => void;
@@ -1,3 +1,3 @@
1
- import{BackgroundTaskScheduler as e}from"./background-task.js";import{clearCompletionCache as t}from"./completions.js";import{CuratedKnowledgeManager as n}from"./curated-manager.js";import{createElicitor as r,noopElicitor as i}from"./elicitor.js";import{IdleTimer as a}from"./idle-timer.js";import{bridgeMcpLogging as o}from"./mcp-logging.js";import{MemoryMonitor as s}from"./memory-monitor.js";import{registerPrompts as c}from"./prompts.js";import{installReplayInterceptor as l}from"./replay-interceptor.js";import{ResourceNotifier as u}from"./resources/resource-notifier.js";import{registerResources as d}from"./resources/resources.js";import{createSamplingClient as f}from"./sampling.js";import{installStructuredContentGuard as p}from"./structured-content-guard.js";import{getToolMeta as m}from"./tool-metadata.js";import{installToolPrefix as h}from"./tool-prefix.js";import{ToolTimeoutError as g,getToolTimeout as _,withTimeout as v}from"./tool-timeout.js";import{registerAnalyzeDependenciesTool as y,registerAnalyzeDiagramTool as b,registerAnalyzeEntryPointsTool as x,registerAnalyzePatternsTool as ee,registerAnalyzeStructureTool as te,registerAnalyzeSymbolsTool as S,registerBlastRadiusTool as C}from"./tools/analyze.tools.js";import{registerAuditTool as w}from"./tools/audit.tool.js";import{registerBrainstormTool as T}from"./tools/brainstorm.tool.js";import{initBridgeComponents as E,registerErPullTool as D,registerErPushTool as O,registerErSyncStatusTool as k}from"./tools/bridge.tools.js";import{registerCompactTool as A,registerDeadSymbolsTool as j,registerFileSummaryTool as M,registerFindTool as ne,registerScopeMapTool as re,registerSymbolTool as ie,registerTraceTool as ae}from"./tools/context.tools.js";import{registerErEvolveReviewTool as oe}from"./tools/evolution.tools.js";import{registerBatchTool as se,registerCheckTool as N,registerDelegateTool as ce,registerEvalTool as P,registerParseOutputTool as F,registerTestRunTool as I}from"./tools/execution.tools.js";import{registerFlowTools as le}from"./tools/flow.tools.js";import{registerDigestTool as ue,registerEvidenceMapTool as L,registerForgeClassifyTool as R,registerForgeGroundTool as de,registerStratumCardTool as fe}from"./tools/forge.tools.js";import{registerForgetTool as pe}from"./tools/forget.tool.js";import{registerGraphTool as me}from"./tools/graph.tool.js";import{registerGuideTool as z,registerHealthTool as B,registerProcessTool as V,registerWatchTool as H,registerWebFetchTool as U}from"./tools/infra.tools.js";import{registerListTool as he}from"./tools/list.tool.js";import{registerLookupTool as ge}from"./tools/lookup.tool.js";import{registerCodemodTool as W,registerDataTransformTool as G,registerDiffParseTool as K,registerGitContextTool as q,registerRenameTool as _e}from"./tools/manipulation.tools.js";import{registerOnboardTool as ve}from"./tools/onboard.tool.js";import{registerCheckpointTool as ye,registerLaneTool as be,registerQueueTool as xe,registerStashTool as Se,registerWorksetTool as Ce}from"./tools/persistence.tools.js";import{registerErUpdatePolicyTool as we}from"./tools/policy.tools.js";import{registerPresentTool as Te}from"./tools/present/tool.js";import"./tools/present/index.js";import{registerProduceKnowledgeTool as Ee}from"./tools/produce.tool.js";import{registerReadTool as De}from"./tools/read.tool.js";import{registerReindexTool as Oe}from"./tools/reindex.tool.js";import{registerRememberTool as ke}from"./tools/remember.tool.js";import{registerReplayTool as Ae}from"./tools/replay.tool.js";import{registerRestoreTool as je}from"./tools/restore.tool.js";import{registerSearchTool as Me}from"./tools/search.tool.js";import{getCurrentVersion as Ne}from"./version-check.js";import{registerEarlyStatusTool as Pe,registerStatusTool as Fe}from"./tools/status.tool.js";import{registerUpdateTool as Ie}from"./tools/update.tool.js";import{registerChangelogTool as Le,registerEncodeTool as Re,registerEnvTool as ze,registerHttpTool as Be,registerMeasureTool as Ve,registerRegexTestTool as He,registerSchemaValidateTool as Ue,registerSnippetTool as We,registerTimeTool as Ge,registerWebSearchTool as Ke}from"./tools/utility.tools.js";import{existsSync as qe,statSync as Je}from"node:fs";import{resolve as Ye}from"node:path";import{AIKIT_PATHS as Xe,createLogger as Ze,serializeError as J}from"../../core/dist/index.js";import{initializeWasm as Qe}from"../../chunker/dist/index.js";import{OnnxEmbedder as $e}from"../../embeddings/dist/index.js";import{EvolutionCollector as et,PolicyStore as tt}from"../../enterprise-bridge/dist/index.js";import{FileHashCache as nt,IncrementalIndexer as rt}from"../../indexer/dist/index.js";import{SqliteGraphStore as it,createStore as at}from"../../store/dist/index.js";import{FileCache as ot}from"../../tools/dist/index.js";import{McpServer as st}from"@modelcontextprotocol/sdk/server/mcp.js";const Y=Ze(`server`);async function X(e){Y.info(`Initializing AI Kit components`);let[t,r,i,a]=await Promise.all([(async()=>{let t=new $e({model:e.embedding.model,dimensions:e.embedding.dimensions});return await t.initialize(),Y.info(`Embedder loaded`,{modelId:t.modelId,dimensions:t.dimensions}),t})(),(async()=>{let t=await at({backend:e.store.backend,path:e.store.path});return await t.initialize(),Y.info(`Store initialized`),t})(),(async()=>{let t=new it({path:e.store.path});return await t.initialize(),Y.info(`Graph store initialized`),t})(),(async()=>{let e=await Qe();return e?Y.info(`WASM tree-sitter enabled for AST analysis`):Y.warn(`WASM tree-sitter not available; analyzers will use regex fallback`),e})()]),o=new rt(t,r),s=new nt(e.store.path);s.load(),o.setHashCache(s);let c=e.curated.path,l=new n(c,r,t);o.setGraphStore(i);let u=E(e.er),d=u?new tt(e.curated.path):void 0;d&&Y.info(`Policy store initialized`,{ruleCount:d.getRules().length});let f=u?new et:void 0,p=Ye(e.sources[0]?.path??process.cwd(),Xe.aiKb),m=qe(p),h=e.onboardDir?qe(e.onboardDir):!1,g=m||h,_,v=m?p:e.onboardDir;if(g&&v)try{_=Je(v).mtime.toISOString()}catch{}return Y.info(`Onboard state detected`,{onboardComplete:g,onboardTimestamp:_,aiKbExists:m,onboardDirExists:h}),{embedder:t,store:r,indexer:o,curated:l,graphStore:i,fileCache:new ot,bridge:u,policyStore:d,evolutionCollector:f,onboardComplete:g,onboardTimestamp:_}}function ct(e,t){let n=new st({name:t.serverName??`aikit`,version:Ne()},{capabilities:{logging:{}}});return o(n),h(n,t.toolPrefix??``),Z(n,e,t,r(n),new u(n),f(n)),c(n,{curated:e.curated,store:e.store,graphStore:e.graphStore}),n}function Z(e,t,n,r,i,a){l(e),p(e),Me(e,t.embedder,t.store,t.graphStore,t.bridge,t.evolutionCollector,a),ge(e,t.store),Fe(e,t.store,t.graphStore,t.curated,{onboardComplete:t.onboardComplete,onboardTimestamp:t.onboardTimestamp},n),Oe(e,t.indexer,n,t.curated,t.store,i),ke(e,t.curated,t.policyStore,t.evolutionCollector,i),Ie(e,t.curated,i),pe(e,t.curated,i),De(e,t.curated),he(e,t.curated),te(e,t.store,t.embedder),y(e,t.store,t.embedder),S(e,t.store,t.embedder),ee(e,t.store,t.embedder),x(e,t.store,t.embedder),b(e,t.store,t.embedder),C(e,t.store,t.embedder,t.graphStore),Ee(e,n),ve(e,t.store,t.embedder,n),me(e,t.graphStore),w(e,t.store,t.embedder);let o=n.sources[0]?.path??process.cwd();A(e,t.embedder,t.fileCache,o),re(e,t.embedder,t.store),ne(e,t.embedder,t.store),F(e),Ce(e),N(e),se(e,t.embedder,t.store),ie(e,t.embedder,t.store,t.graphStore),P(e),I(e),Se(e),q(e),K(e),_e(e),W(e),je(e),M(e,t.fileCache,o),ye(e),G(e),ae(e,t.embedder,t.store),V(e),H(e),j(e,t.embedder,t.store),ce(e,a),B(e),be(e),xe(e),U(e),z(e),L(e),ue(e,t.embedder),R(e),fe(e,t.embedder,t.fileCache),de(e,t.embedder,t.store),Te(e,r),r&&T(e,r),Ke(e),Be(e),He(e),Re(e),Ve(e),Le(e),Ue(e),We(e),ze(e),Ge(e),le(e,n),t.bridge&&(O(e,t.bridge,t.evolutionCollector),D(e,t.bridge),k(e,t.bridge)),t.policyStore&&we(e,t.policyStore),t.evolutionCollector&&oe(e,t.evolutionCollector),d(e,t.store,t.curated),Ae(e)}async function lt(e){let t=await X(e),n=ct(t,e);Y.info(`MCP server configured`,{toolCount:$.length,resourceCount:2});let r=async()=>{try{let n=e.sources.map(e=>e.path).join(`, `);Y.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&&Y.debug(`Indexing file`,{current:e.filesProcessed+1,total:e.filesTotal,file:e.currentFile}),e.phase===`cleanup`&&Y.debug(`Index cleanup`,{staleEntries:e.filesTotal-e.filesProcessed}))});Y.info(`Initial index complete`,{filesProcessed:r.filesProcessed,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated,durationMs:r.durationMs});try{await t.store.createFtsIndex()}catch(e){Y.warn(`FTS index creation failed`,J(e))}try{let e=await t.curated.reindexAll();Y.info(`Curated re-index complete`,{indexed:e.indexed})}catch(e){Y.error(`Curated re-index failed`,J(e))}}catch(e){Y.error(`Initial index failed; will retry on aikit_reindex`,J(e))}},i=async()=>{Y.info(`Shutting down`),await t.embedder.shutdown().catch(()=>{}),await t.graphStore.close().catch(()=>{}),await t.store.close(),process.exit(0)};process.on(`SIGINT`,i),process.on(`SIGTERM`,i);let a=process.ppid,o=setInterval(()=>{try{process.kill(a,0)}catch{Y.info(`Parent process died; shutting down`,{parentPid:a}),clearInterval(o),i()}},5e3);return o.unref(),{server:n,runInitialIndex:r,shutdown:i}}const ut=new Set(`batch.brainstorm.changelog.check.checkpoint.codemod.compact.data_transform.delegate.diff_parse.digest.encode.env.eval.evidence_map.file_summary.forge_classify.git_context.graph.guide.health.http.lane.measure.onboard.parse_output.present.process.produce_knowledge.queue.read.regex_test.reindex.remember.rename.replay.restore.schema_validate.scope_map.snippet.stash.status.stratum_card.test_run.time.update.forget.list.watch.web_fetch.web_search.workset`.split(`.`)),dt=5e3,Q=new Set(`brainstorm.changelog.check.checkpoint.codemod.data_transform.delegate.diff_parse.encode.env.eval.evidence_map.forge_classify.git_context.guide.present.health.http.lane.measure.parse_output.process.produce_knowledge.queue.regex_test.rename.replay.restore.schema_validate.snippet.stash.status.test_run.time.watch.web_fetch.web_search.workset`.split(`.`));function ft(e){N(e),P(e),I(e),F(e),ce(e),q(e),K(e),_e(e),W(e),G(e),Ce(e),Se(e),ye(e),je(e),be(e),xe(e),B(e),V(e),H(e),U(e),z(e),L(e),R(e),Te(e),T(e,i),Ee(e),Ae(e),Pe(e),Ke(e),Be(e),He(e),Re(e),Ve(e),Le(e),Ue(e),We(e),ze(e),Ge(e)}const $=`analyze_dependencies.analyze_diagram.analyze_entry_points.analyze_patterns.analyze_structure.analyze_symbols.audit.batch.blast_radius.brainstorm.changelog.check.checkpoint.codemod.compact.data_transform.dead_symbols.delegate.diff_parse.digest.encode.env.eval.evidence_map.file_summary.find.forge_classify.forge_ground.forget.git_context.graph.guide.health.http.lane.list.lookup.measure.onboard.parse_output.present.process.produce_knowledge.queue.read.regex_test.reindex.remember.rename.replay.restore.schema_validate.scope_map.search.snippet.stash.status.stratum_card.symbol.test_run.time.trace.update.watch.web_fetch.web_search.workset`.split(`.`);function pt(n){let i=new st({name:n.serverName??`aikit`,version:Ne()},{capabilities:{logging:{}}}),l=`initializing`,d=``,p=!1,y=()=>l===`failed`?[`❌ AI Kit initialization failed — this tool is unavailable.`,``,d?`Error: ${d}`:``,``,`**35 tools are still available** and fully functional:`,`check, eval, test_run, git_context, health, measure, web_fetch, web_search,`,`regex_test, encode, stash, checkpoint, lane, process, time, env, and more.`,``,`Try restarting the MCP server to retry initialization.`].filter(Boolean).join(`
1
+ import{BackgroundTaskScheduler as e}from"./background-task.js";import{clearCompletionCache as t}from"./completions.js";import{CuratedKnowledgeManager as n}from"./curated-manager.js";import{createElicitor as r,noopElicitor as i}from"./elicitor.js";import{IdleTimer as a}from"./idle-timer.js";import{bridgeMcpLogging as o}from"./mcp-logging.js";import{MemoryMonitor as s}from"./memory-monitor.js";import{registerPrompts as c}from"./prompts.js";import{installReplayInterceptor as l}from"./replay-interceptor.js";import{ResourceNotifier as u}from"./resources/resource-notifier.js";import{registerResources as d}from"./resources/resources.js";import{createSamplingClient as f}from"./sampling.js";import{installStructuredContentGuard as p}from"./structured-content-guard.js";import{getToolMeta as m}from"./tool-metadata.js";import{installToolPrefix as h}from"./tool-prefix.js";import{ToolTimeoutError as g,getToolTimeout as _,withTimeout as v}from"./tool-timeout.js";import{registerAnalyzeDependenciesTool as y,registerAnalyzeDiagramTool as b,registerAnalyzeEntryPointsTool as x,registerAnalyzePatternsTool as S,registerAnalyzeStructureTool as ee,registerAnalyzeSymbolsTool as te,registerBlastRadiusTool as C}from"./tools/analyze.tools.js";import{registerAuditTool as w}from"./tools/audit.tool.js";import{registerBrainstormTool as T}from"./tools/brainstorm.tool.js";import{initBridgeComponents as ne,registerErPullTool as E,registerErPushTool as D,registerErSyncStatusTool as O}from"./tools/bridge.tools.js";import{registerConfigTool as k}from"./tools/config.tool.js";import{registerCompactTool as re,registerDeadSymbolsTool as A,registerFileSummaryTool as j,registerFindTool as ie,registerScopeMapTool as ae,registerSymbolTool as oe,registerTraceTool as se}from"./tools/context.tools.js";import{registerErEvolveReviewTool as ce}from"./tools/evolution.tools.js";import{registerBatchTool as le,registerCheckTool as ue,registerDelegateTool as de,registerEvalTool as fe,registerParseOutputTool as pe,registerTestRunTool as M}from"./tools/execution.tools.js";import{registerFlowTools as me}from"./tools/flow.tools.js";import{registerDigestTool as he,registerEvidenceMapTool as N,registerForgeClassifyTool as P,registerForgeGroundTool as ge,registerStratumCardTool as _e}from"./tools/forge.tools.js";import{registerForgetTool as ve}from"./tools/forget.tool.js";import{registerGraphTool as ye}from"./tools/graph.tool.js";import{registerGuideTool as F,registerHealthTool as I,registerProcessTool as L,registerWatchTool as R,registerWebFetchTool as z}from"./tools/infra.tools.js";import{registerListTool as be}from"./tools/list.tool.js";import{registerLookupTool as xe}from"./tools/lookup.tool.js";import{registerCodemodTool as B,registerDataTransformTool as V,registerDiffParseTool as H,registerGitContextTool as U,registerRenameTool as W}from"./tools/manipulation.tools.js";import{registerOnboardTool as Se}from"./tools/onboard.tool.js";import{registerCheckpointTool as G,registerLaneTool as K,registerQueueTool as q,registerStashTool as J,registerWorksetTool as Ce}from"./tools/persistence.tools.js";import{registerErUpdatePolicyTool as we}from"./tools/policy.tools.js";import{registerPresentTool as Te}from"./tools/present/tool.js";import"./tools/present/index.js";import{registerProduceKnowledgeTool as Ee}from"./tools/produce.tool.js";import{registerReadTool as De}from"./tools/read.tool.js";import{registerReindexTool as Oe}from"./tools/reindex.tool.js";import{registerRememberTool as ke}from"./tools/remember.tool.js";import{registerReplayTool as Ae}from"./tools/replay.tool.js";import{registerRestoreTool as je}from"./tools/restore.tool.js";import{registerSearchTool as Me}from"./tools/search.tool.js";import{getCurrentVersion as Ne}from"./version-check.js";import{registerEarlyStatusTool as Pe,registerStatusTool as Fe}from"./tools/status.tool.js";import{registerUpdateTool as Ie}from"./tools/update.tool.js";import{registerChangelogTool as Le,registerEncodeTool as Re,registerEnvTool as ze,registerHttpTool as Be,registerMeasureTool as Ve,registerRegexTestTool as He,registerSchemaValidateTool as Ue,registerSnippetTool as We,registerTimeTool as Ge,registerWebSearchTool as Ke}from"./tools/utility.tools.js";import{existsSync as qe,statSync as Je}from"node:fs";import{resolve as Ye}from"node:path";import{AIKIT_PATHS as Xe,createLogger as Ze,serializeError as Y}from"../../core/dist/index.js";import{initializeWasm as Qe}from"../../chunker/dist/index.js";import{OnnxEmbedder as $e}from"../../embeddings/dist/index.js";import{EvolutionCollector as et,PolicyStore as tt}from"../../enterprise-bridge/dist/index.js";import{FileHashCache as nt,IncrementalIndexer as rt}from"../../indexer/dist/index.js";import{SqliteGraphStore as it,createStore as at}from"../../store/dist/index.js";import{FileCache as ot}from"../../tools/dist/index.js";import{McpServer as st}from"@modelcontextprotocol/sdk/server/mcp.js";const X=Ze(`server`);async function Z(e){X.info(`Initializing AI Kit components`);let[t,r,i,a]=await Promise.all([(async()=>{let t=new $e({model:e.embedding.model,dimensions:e.embedding.dimensions});return await t.initialize(),X.info(`Embedder loaded`,{modelId:t.modelId,dimensions:t.dimensions}),t})(),(async()=>{let t=await at({backend:e.store.backend,path:e.store.path});return await t.initialize(),X.info(`Store initialized`),t})(),(async()=>{let t=new it({path:e.store.path});return await t.initialize(),X.info(`Graph store initialized`),t})(),(async()=>{let e=await Qe();return e?X.info(`WASM tree-sitter enabled for AST analysis`):X.warn(`WASM tree-sitter not available; analyzers will use regex fallback`),e})()]),o=new rt(t,r),s=new nt(e.store.path);s.load(),o.setHashCache(s);let c=e.curated.path,l=new n(c,r,t);o.setGraphStore(i);let u=ne(e.er),d=u?new tt(e.curated.path):void 0;d&&X.info(`Policy store initialized`,{ruleCount:d.getRules().length});let f=u?new et:void 0,p=Ye(e.sources[0]?.path??process.cwd(),Xe.aiKb),m=qe(p),h=e.onboardDir?qe(e.onboardDir):!1,g=m||h,_,v=m?p:e.onboardDir;if(g&&v)try{_=Je(v).mtime.toISOString()}catch{}return X.info(`Onboard state detected`,{onboardComplete:g,onboardTimestamp:_,aiKbExists:m,onboardDirExists:h}),{embedder:t,store:r,indexer:o,curated:l,graphStore:i,fileCache:new ot,bridge:u,policyStore:d,evolutionCollector:f,onboardComplete:g,onboardTimestamp:_}}function ct(e,t){let n=new st({name:t.serverName??`aikit`,version:Ne()},{capabilities:{logging:{}}});return o(n),h(n,t.toolPrefix??``),Q(n,e,t,r(n),new u(n),f(n)),c(n,{curated:e.curated,store:e.store,graphStore:e.graphStore}),n}function Q(e,t,n,r,i,a){l(e),p(e),Me(e,t.embedder,t.store,t.graphStore,t.bridge,t.evolutionCollector,a),xe(e,t.store),Fe(e,t.store,t.graphStore,t.curated,{onboardComplete:t.onboardComplete,onboardTimestamp:t.onboardTimestamp},n),k(e,n),Oe(e,t.indexer,n,t.curated,t.store,i),ke(e,t.curated,t.policyStore,t.evolutionCollector,i),Ie(e,t.curated,i),ve(e,t.curated,i),De(e,t.curated),be(e,t.curated),ee(e,t.store,t.embedder),y(e,t.store,t.embedder),te(e,t.store,t.embedder),S(e,t.store,t.embedder),x(e,t.store,t.embedder),b(e,t.store,t.embedder),C(e,t.store,t.embedder,t.graphStore),Ee(e,n),Se(e,t.store,t.embedder,n),ye(e,t.graphStore),w(e,t.store,t.embedder);let o=n.sources[0]?.path??process.cwd();re(e,t.embedder,t.fileCache,o),ae(e,t.embedder,t.store),ie(e,t.embedder,t.store),pe(e),Ce(e),ue(e),le(e,t.embedder,t.store),oe(e,t.embedder,t.store,t.graphStore),fe(e),M(e),J(e),U(e),H(e),W(e),B(e),je(e),j(e,t.fileCache,o),G(e),V(e),se(e,t.embedder,t.store),L(e),R(e),A(e,t.embedder,t.store),de(e,a),I(e),K(e),q(e),z(e),F(e),N(e),he(e,t.embedder),P(e),_e(e,t.embedder,t.fileCache),ge(e,t.embedder,t.store),Te(e,r),r&&T(e,r),Ke(e),Be(e),He(e),Re(e),Ve(e),Le(e),Ue(e),We(e),ze(e),Ge(e),me(e,n),t.bridge&&(D(e,t.bridge,t.evolutionCollector),E(e,t.bridge),O(e,t.bridge)),t.policyStore&&we(e,t.policyStore),t.evolutionCollector&&ce(e,t.evolutionCollector),d(e,t.store,t.curated),Ae(e)}async function lt(e){let t=await Z(e),n=ct(t,e);X.info(`MCP server configured`,{toolCount:$.length,resourceCount:2});let r=async()=>{try{let n=e.sources.map(e=>e.path).join(`, `);X.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&&X.debug(`Indexing file`,{current:e.filesProcessed+1,total:e.filesTotal,file:e.currentFile}),e.phase===`cleanup`&&X.debug(`Index cleanup`,{staleEntries:e.filesTotal-e.filesProcessed}))});X.info(`Initial index complete`,{filesProcessed:r.filesProcessed,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated,durationMs:r.durationMs});try{await t.store.createFtsIndex()}catch(e){X.warn(`FTS index creation failed`,Y(e))}try{let e=await t.curated.reindexAll();X.info(`Curated re-index complete`,{indexed:e.indexed})}catch(e){X.error(`Curated re-index failed`,Y(e))}}catch(e){X.error(`Initial index failed; will retry on aikit_reindex`,Y(e))}},i=async()=>{X.info(`Shutting down`),await Promise.all([t.embedder.shutdown().catch(()=>{}),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{X.info(`Parent process died; shutting down`,{parentPid:a}),clearInterval(o),i()}},5e3);return o.unref(),{server:n,runInitialIndex:r,shutdown:i}}const ut=new Set(`batch.brainstorm.changelog.check.checkpoint.codemod.compact.config.data_transform.delegate.diff_parse.digest.encode.env.eval.evidence_map.file_summary.forge_classify.git_context.graph.guide.health.http.lane.measure.onboard.parse_output.present.process.produce_knowledge.queue.read.regex_test.reindex.remember.rename.replay.restore.schema_validate.scope_map.snippet.stash.status.stratum_card.test_run.time.update.forget.list.watch.web_fetch.web_search.workset`.split(`.`)),dt=5e3,ft=new Set(`brainstorm.changelog.check.checkpoint.codemod.data_transform.delegate.diff_parse.encode.env.eval.evidence_map.forge_classify.git_context.guide.present.health.http.lane.measure.parse_output.process.produce_knowledge.queue.regex_test.rename.replay.restore.schema_validate.snippet.stash.status.test_run.time.watch.web_fetch.web_search.workset`.split(`.`));function pt(e){ue(e),fe(e),M(e),pe(e),de(e),U(e),H(e),W(e),B(e),V(e),Ce(e),J(e),G(e),je(e),K(e),q(e),I(e),L(e),R(e),z(e),F(e),N(e),P(e),Te(e),T(e,i),Ee(e),Ae(e),Pe(e),Ke(e),Be(e),He(e),Re(e),Ve(e),Le(e),Ue(e),We(e),ze(e),Ge(e)}const $=`analyze_dependencies.analyze_diagram.analyze_entry_points.analyze_patterns.analyze_structure.analyze_symbols.audit.batch.blast_radius.brainstorm.changelog.check.checkpoint.codemod.compact.config.data_transform.dead_symbols.delegate.diff_parse.digest.encode.env.eval.evidence_map.file_summary.find.flow_info.flow_list.flow_reset.flow_start.flow_status.flow_step.forge_classify.forge_ground.forget.git_context.graph.guide.health.http.lane.list.lookup.measure.onboard.parse_output.present.process.produce_knowledge.queue.read.regex_test.reindex.remember.rename.replay.restore.schema_validate.scope_map.search.snippet.stash.status.stratum_card.symbol.test_run.time.trace.update.watch.web_fetch.web_search.workset`.split(`.`);function mt(n){let i=new st({name:n.serverName??`aikit`,version:Ne()},{capabilities:{logging:{}}}),l=`initializing`,d=``,p=!1,y=null,b=()=>l===`failed`?[`❌ AI Kit initialization failed — this tool is unavailable.`,``,d?`Error: ${d}`:``,``,`**35 tools are still available** and fully functional:`,`check, eval, test_run, git_context, health, measure, web_fetch, web_search,`,`regex_test, encode, stash, checkpoint, lane, process, time, env, and more.`,``,`Try restarting the MCP server to retry initialization.`].filter(Boolean).join(`
2
2
  `):[`AI Kit is still initializing (loading embeddings model & store).`,``,`**35 tools are already available** while initialization completes — including:`,`check, eval, test_run, git_context, health, measure, web_fetch, web_search,`,`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(`
3
- `);o(i),h(i,n.toolPrefix??``);let b=i.sendToolListChanged.bind(i);i.sendToolListChanged=()=>{};let x=[];for(let e of $){let t=m(e),n=i.registerTool(e,{title:t.title,description:`${t.title} — initializing, available shortly`,inputSchema:{},annotations:t.annotations},async()=>({content:[{type:`text`,text:y()}]}));Q.has(e)?n.remove():x.push(n)}ft(i),i.sendToolListChanged=b;let ee=i.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`}]})),te=i.registerPrompt(`_init`,{description:`AI Kit is initializing prompts...`},async()=>({messages:[{role:`user`,content:{type:`text`,text:y()}}]})),S,C=new Promise(e=>{S=e}),w,T=new Promise(e=>{w=e}),E=()=>w?.(),D=(async()=>{await T;let e;try{e=await X(n)}catch(e){l=`failed`,d=e instanceof Error?e.message:String(e),Y.error(`AI Kit initialization failed — server continuing with zero-dep tools only`,{error:d});return}let o=i.sendToolListChanged.bind(i);i.sendToolListChanged=()=>{};let m=i.sendPromptListChanged.bind(i);i.sendPromptListChanged=()=>{};let h=i.sendResourceListChanged.bind(i);i.sendResourceListChanged=()=>{};for(let e of x)e.remove();ee.remove(),te.remove();let y=i._registeredTools??{};for(let e of Q)y[e]?.remove();let b=new u(i),C=f(i);Z(i,e,n,r(i),b,C),c(i),i.sendToolListChanged=o,i.sendPromptListChanged=m,i.sendResourceListChanged=h,Promise.resolve(i.sendToolListChanged()).catch(()=>{}),Promise.resolve(i.sendPromptListChanged()).catch(()=>{}),Promise.resolve(i.sendResourceListChanged()).catch(()=>{});let w=i._registeredTools??{};for(let[t,n]of Object.entries(w)){if(ut.has(t))continue;let r=n.handler;n.handler=async(...n)=>{if(!e.indexer.isIndexing)return r(...n);let i=p?`re-indexing`:`running initial index`,a=new Promise(e=>setTimeout(()=>e({content:[{type:`text`,text:`⏳ AI Kit is ${i}. The tool "${t}" timed out waiting for index data (${dt/1e3}s).\n\nThe existing index may be temporarily locked. Please retry shortly — indexing will complete automatically.`}]}),dt));return Promise.race([r(...n),a])}}for(let[e,t]of Object.entries(w)){let n=t.handler,r=_(e);t.handler=async(...t)=>{try{return await v(()=>n(...t),r,e)}catch(t){if(t instanceof g)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 E=Object.keys(w).length;E!==$.length&&Y.warn(`ALL_TOOL_NAMES count mismatch`,{expectedToolCount:$.length,registeredToolCount:E}),Y.info(`MCP server configured`,{toolCount:$.length,resourceCount:4});let D=new s;D.onPressure((e,n)=>{e===`warning`&&t(),e===`critical`&&(Y.warn(`Memory pressure critical — consider restarting`,{rssMB:Math.round(n/1024/1024)}),t())}),D.start();let O=new a;O.onIdle(async()=>{Y.info(`Idle cleanup: closing store and graph connections`);try{await e.store.close().catch(()=>{}),await e.graphStore.close().catch(()=>{})}catch{}}),O.touch();for(let e of Object.values(w)){let t=e.handler;e.handler=async(...e)=>(O.touch(),t(...e))}S?.(e)})(),O=async()=>{let e=await C;try{let t=n.sources.map(e=>e.path).join(`, `);Y.info(`Running initial index`,{sourcePaths:t});let r=await e.indexer.index(n,e=>{e.phase===`crawling`||e.phase===`done`||(e.phase===`chunking`&&e.currentFile&&Y.debug(`Indexing file`,{current:e.filesProcessed+1,total:e.filesTotal,file:e.currentFile}),e.phase===`cleanup`&&Y.debug(`Index cleanup`,{staleEntries:e.filesTotal-e.filesProcessed}))});p=!0,Y.info(`Initial index complete`,{filesProcessed:r.filesProcessed,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated,durationMs:r.durationMs});try{await e.store.createFtsIndex()}catch(e){Y.warn(`FTS index creation failed`,J(e))}try{let t=await e.curated.reindexAll();Y.info(`Curated re-index complete`,{indexed:t.indexed})}catch(e){Y.error(`Curated re-index failed`,J(e))}}catch(e){Y.error(`Initial index failed; will retry on aikit_reindex`,J(e))}},k=new e,A=()=>k.schedule({name:`initial-index`,fn:O}),j=process.ppid,M=setInterval(()=>{try{process.kill(j,0)}catch{Y.info(`Parent process died; shutting down`,{parentPid:j}),clearInterval(M),C.then(async e=>{await e.embedder.shutdown().catch(()=>{}),await e.graphStore.close().catch(()=>{}),await e.store.close().catch(()=>{})}).catch(()=>{}).finally(()=>process.exit(0))}},5e3);return M.unref(),{server:i,startInit:E,ready:D,runInitialIndex:A,scheduler:k}}export{$ as ALL_TOOL_NAMES,pt as createLazyServer,ct as createMcpServer,lt as createServer,X as initializeKnowledgeBase,Z as registerMcpTools};
3
+ `);o(i),h(i,n.toolPrefix??``);let x=i.sendToolListChanged.bind(i);i.sendToolListChanged=()=>{};let S=[];for(let e of $){let t=m(e),n=i.registerTool(e,{title:t.title,description:`${t.title} — initializing, available shortly`,inputSchema:{},annotations:t.annotations},async()=>({content:[{type:`text`,text:b()}]}));ft.has(e)?n.remove():S.push(n)}pt(i),i.sendToolListChanged=x;let ee=i.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`}]})),te=i.registerPrompt(`_init`,{description:`AI Kit is initializing prompts...`},async()=>({messages:[{role:`user`,content:{type:`text`,text:b()}}]})),C,w=new Promise(e=>{C=e}),T,ne=new Promise(e=>{T=e}),E=()=>T?.(),D=(async()=>{await ne;let e;try{e=await Z(n)}catch(e){l=`failed`,d=e instanceof Error?e.message:String(e),X.error(`AI Kit initialization failed — server continuing with zero-dep tools only`,{error:d});return}let o=i.sendToolListChanged.bind(i);i.sendToolListChanged=()=>{};let m=i.sendPromptListChanged.bind(i);i.sendPromptListChanged=()=>{};let h=i.sendResourceListChanged.bind(i);i.sendResourceListChanged=()=>{};for(let e of S)e.remove();ee.remove(),te.remove();let b=i._registeredTools??{};for(let e of ft)b[e]?.remove();let x=new u(i),w=f(i);Q(i,e,n,r(i),x,w),c(i),i.sendToolListChanged=o,i.sendPromptListChanged=m,i.sendResourceListChanged=h,Promise.resolve(i.sendToolListChanged()).catch(()=>{}),Promise.resolve(i.sendPromptListChanged()).catch(()=>{}),Promise.resolve(i.sendResourceListChanged()).catch(()=>{});let T=i._registeredTools??{};for(let[t,n]of Object.entries(T)){if(ut.has(t))continue;let r=n.handler;n.handler=async(...n)=>{if(!e.indexer.isIndexing)return r(...n);let i=p?`re-indexing`:`running initial index`,a=new Promise(e=>setTimeout(()=>e({content:[{type:`text`,text:`⏳ AI Kit is ${i}. The tool "${t}" timed out waiting for index data (${dt/1e3}s).\n\nThe existing index may be temporarily locked. Please retry shortly — indexing will complete automatically.`}]}),dt));return Promise.race([r(...n),a])}}for(let[e,t]of Object.entries(T)){let n=t.handler,r=_(e);t.handler=async(...t)=>{try{return await v(()=>n(...t),r,e)}catch(t){if(t instanceof g)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 E=Object.keys(T).length;E<$.length&&X.warn(`ALL_TOOL_NAMES count mismatch`,{expectedToolCount:$.length,registeredToolCount:E}),X.info(`MCP server configured`,{toolCount:$.length,resourceCount:4});let D=new s;D.onPressure((e,n)=>{e===`warning`&&t(),e===`critical`&&(X.warn(`Memory pressure critical — consider restarting`,{rssMB:Math.round(n/1024/1024)}),t())}),D.start();let O=new a;y=O,O.onIdle(async()=>{if(k.isRunning||e.indexer.isIndexing){X.info(`Idle cleanup deferred — background tasks still running`),O.touch();return}X.info(`Idle cleanup: closing store and graph connections`);try{await Promise.all([e.store.close().catch(()=>{}),e.graphStore.close().catch(()=>{})])}catch{}}),O.touch();for(let e of Object.values(T)){let t=e.handler;e.handler=async(...e)=>(O.touch(),t(...e))}C?.(e)})(),O=async()=>{let e=await w;y?.setBusy(!0);try{let t=n.sources.map(e=>e.path).join(`, `);X.info(`Running initial index`,{sourcePaths:t});let r=await e.indexer.index(n,e=>{e.phase===`crawling`||e.phase===`done`||(e.phase===`chunking`&&e.currentFile&&X.debug(`Indexing file`,{current:e.filesProcessed+1,total:e.filesTotal,file:e.currentFile}),e.phase===`cleanup`&&X.debug(`Index cleanup`,{staleEntries:e.filesTotal-e.filesProcessed}))});p=!0,X.info(`Initial index complete`,{filesProcessed:r.filesProcessed,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated,durationMs:r.durationMs});try{await e.store.createFtsIndex()}catch(e){X.warn(`FTS index creation failed`,Y(e))}try{let t=await e.curated.reindexAll();X.info(`Curated re-index complete`,{indexed:t.indexed})}catch(e){X.error(`Curated re-index failed`,Y(e))}}catch(e){X.error(`Initial index failed; will retry on aikit_reindex`,Y(e))}finally{y?.setBusy(!1)}},k=new e,re=()=>k.schedule({name:`initial-index`,fn:O}),A=process.ppid,j=setInterval(()=>{try{process.kill(A,0)}catch{X.info(`Parent process died; shutting down`,{parentPid:A}),clearInterval(j),w.then(async e=>{await Promise.all([e.embedder.shutdown().catch(()=>{}),e.graphStore.close().catch(()=>{}),e.store.close().catch(()=>{})])}).catch(()=>{}).finally(()=>process.exit(0))}},5e3);return j.unref(),{server:i,startInit:E,ready:D,runInitialIndex:re,scheduler:k}}export{$ as ALL_TOOL_NAMES,mt as createLazyServer,ct as createMcpServer,lt as createServer,Z as initializeKnowledgeBase,Q as registerMcpTools};
@@ -1 +1 @@
1
- const e={search:{title:`Hybrid Search`,annotations:{readOnlyHint:!0,idempotentHint:!0}},find:{title:`Federated Find`,annotations:{readOnlyHint:!0,idempotentHint:!0}},symbol:{title:`Symbol Resolver`,annotations:{readOnlyHint:!0,idempotentHint:!0}},trace:{title:`Data Flow Tracer`,annotations:{readOnlyHint:!0,idempotentHint:!0}},scope_map:{title:`Task Scope Map`,annotations:{readOnlyHint:!0,idempotentHint:!0}},lookup:{title:`Chunk Lookup`,annotations:{readOnlyHint:!0,idempotentHint:!0}},dead_symbols:{title:`Dead Symbol Finder`,annotations:{readOnlyHint:!0,idempotentHint:!0}},file_summary:{title:`File Summary`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_structure:{title:`Analyze Structure`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_dependencies:{title:`Analyze Dependencies`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_symbols:{title:`Analyze Symbols`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_patterns:{title:`Analyze Patterns`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_entry_points:{title:`Analyze Entry Points`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_diagram:{title:`Analyze Diagram`,annotations:{readOnlyHint:!0,idempotentHint:!0}},blast_radius:{title:`Blast Radius`,annotations:{readOnlyHint:!0,idempotentHint:!0}},brainstorm:{title:`Brainstorm Session`,annotations:{readOnlyHint:!0,idempotentHint:!0}},remember:{title:`Remember Knowledge`,annotations:{readOnlyHint:!1}},read:{title:`Read Knowledge`,annotations:{readOnlyHint:!0,idempotentHint:!0}},update:{title:`Update Knowledge`,annotations:{readOnlyHint:!1}},forget:{title:`Forget Knowledge`,annotations:{readOnlyHint:!1,destructiveHint:!0}},list:{title:`List Knowledge`,annotations:{readOnlyHint:!0,idempotentHint:!0}},produce_knowledge:{title:`Produce Knowledge`,annotations:{readOnlyHint:!0,idempotentHint:!0}},compact:{title:`Semantic Compactor`,annotations:{readOnlyHint:!0,idempotentHint:!0}},digest:{title:`Multi-Source Digest`,annotations:{readOnlyHint:!0,idempotentHint:!0}},stratum_card:{title:`Stratum Card`,annotations:{readOnlyHint:!0,idempotentHint:!0}},forge_ground:{title:`FORGE Ground`,annotations:{readOnlyHint:!0,idempotentHint:!0}},forge_classify:{title:`FORGE Classify`,annotations:{readOnlyHint:!0,idempotentHint:!0}},evidence_map:{title:`Evidence Map`,annotations:{readOnlyHint:!1}},present:{title:`Rich Content Presenter`,annotations:{readOnlyHint:!0,idempotentHint:!0}},check:{title:`Typecheck & Lint`,annotations:{readOnlyHint:!0,openWorldHint:!0}},test_run:{title:`Run Tests`,annotations:{readOnlyHint:!0,openWorldHint:!0}},eval:{title:`Evaluate Code`,annotations:{readOnlyHint:!1,openWorldHint:!0}},batch:{title:`Batch Operations`,annotations:{readOnlyHint:!0,idempotentHint:!0}},audit:{title:`Project Audit`,annotations:{readOnlyHint:!0,idempotentHint:!0}},rename:{title:`Rename Symbol`,annotations:{readOnlyHint:!1,destructiveHint:!0}},restore:{title:`Restore`,annotations:{readOnlyHint:!1}},codemod:{title:`Codemod`,annotations:{readOnlyHint:!1,destructiveHint:!0}},data_transform:{title:`Data Transform`,annotations:{readOnlyHint:!0,idempotentHint:!0}},stash:{title:`Stash Values`,annotations:{readOnlyHint:!1}},checkpoint:{title:`Session Checkpoint`,annotations:{readOnlyHint:!1}},workset:{title:`Workset Manager`,annotations:{readOnlyHint:!1}},lane:{title:`Exploration Lane`,annotations:{readOnlyHint:!1}},git_context:{title:`Git Context`,annotations:{readOnlyHint:!0,idempotentHint:!0}},diff_parse:{title:`Diff Parser`,annotations:{readOnlyHint:!0,idempotentHint:!0}},parse_output:{title:`Parse Build Output`,annotations:{readOnlyHint:!0,idempotentHint:!0}},process:{title:`Process Manager`,annotations:{readOnlyHint:!1,openWorldHint:!0}},watch:{title:`File Watcher`,annotations:{readOnlyHint:!1,openWorldHint:!0}},delegate:{title:`Delegate Task`,annotations:{readOnlyHint:!1,openWorldHint:!0}},status:{title:`AI Kit Status`,annotations:{readOnlyHint:!0,idempotentHint:!0}},health:{title:`Health Check`,annotations:{readOnlyHint:!0,idempotentHint:!0}},reindex:{title:`Reindex`,annotations:{readOnlyHint:!1}},onboard:{title:`Onboard Codebase`,annotations:{readOnlyHint:!1}},graph:{title:`Knowledge Graph`,annotations:{readOnlyHint:!1}},guide:{title:`Tool Guide`,annotations:{readOnlyHint:!0,idempotentHint:!0}},replay:{title:`Replay History`,annotations:{readOnlyHint:!0,idempotentHint:!0}},changelog:{title:`Generate Changelog`,annotations:{readOnlyHint:!0,idempotentHint:!0}},regex_test:{title:`Regex Tester`,annotations:{readOnlyHint:!0,idempotentHint:!0}},encode:{title:`Encode / Decode`,annotations:{readOnlyHint:!0,idempotentHint:!0}},measure:{title:`Code Metrics`,annotations:{readOnlyHint:!0,idempotentHint:!0}},schema_validate:{title:`Schema Validator`,annotations:{readOnlyHint:!0,idempotentHint:!0}},snippet:{title:`Code Snippets`,annotations:{readOnlyHint:!1}},env:{title:`Environment Info`,annotations:{readOnlyHint:!0,idempotentHint:!0}},time:{title:`Date & Time`,annotations:{readOnlyHint:!0,idempotentHint:!0}},web_fetch:{title:`Web Fetch`,annotations:{readOnlyHint:!0,openWorldHint:!0}},web_search:{title:`Web Search`,annotations:{readOnlyHint:!0,openWorldHint:!0}},http:{title:`HTTP Request`,annotations:{readOnlyHint:!1,openWorldHint:!0}},queue:{title:`Operation Queue`,annotations:{readOnlyHint:!1}},bridge_push:{title:`Bridge Push`,annotations:{readOnlyHint:!1}},bridge_pull:{title:`Bridge Pull`,annotations:{readOnlyHint:!0,idempotentHint:!0}},bridge_sync:{title:`Bridge Sync Status`,annotations:{readOnlyHint:!0,idempotentHint:!0}},evolution_state:{title:`Evolution State`,annotations:{readOnlyHint:!1}},policy_check:{title:`Policy Check`,annotations:{readOnlyHint:!0,idempotentHint:!0}},flow_list:{title:`Flow List`,annotations:{readOnlyHint:!0,idempotentHint:!0}},flow_info:{title:`Flow Info`,annotations:{readOnlyHint:!0,idempotentHint:!0}},flow_start:{title:`Flow Start`,annotations:{readOnlyHint:!1}},flow_step:{title:`Flow Step`,annotations:{readOnlyHint:!1}},flow_status:{title:`Flow Status`,annotations:{readOnlyHint:!0,idempotentHint:!0}},flow_reset:{title:`Flow Reset`,annotations:{readOnlyHint:!1}}};function t(t){return e[t]??{title:t,annotations:{readOnlyHint:!1}}}export{e as TOOL_METADATA,t as getToolMeta};
1
+ const e={search:{title:`Hybrid Search`,annotations:{readOnlyHint:!0,idempotentHint:!0}},find:{title:`Federated Find`,annotations:{readOnlyHint:!0,idempotentHint:!0}},symbol:{title:`Symbol Resolver`,annotations:{readOnlyHint:!0,idempotentHint:!0}},trace:{title:`Data Flow Tracer`,annotations:{readOnlyHint:!0,idempotentHint:!0}},scope_map:{title:`Task Scope Map`,annotations:{readOnlyHint:!0,idempotentHint:!0}},lookup:{title:`Chunk Lookup`,annotations:{readOnlyHint:!0,idempotentHint:!0}},dead_symbols:{title:`Dead Symbol Finder`,annotations:{readOnlyHint:!0,idempotentHint:!0}},file_summary:{title:`File Summary`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_structure:{title:`Analyze Structure`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_dependencies:{title:`Analyze Dependencies`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_symbols:{title:`Analyze Symbols`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_patterns:{title:`Analyze Patterns`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_entry_points:{title:`Analyze Entry Points`,annotations:{readOnlyHint:!0,idempotentHint:!0}},analyze_diagram:{title:`Analyze Diagram`,annotations:{readOnlyHint:!0,idempotentHint:!0}},blast_radius:{title:`Blast Radius`,annotations:{readOnlyHint:!0,idempotentHint:!0}},brainstorm:{title:`Brainstorm Session`,annotations:{readOnlyHint:!0,idempotentHint:!0}},remember:{title:`Remember Knowledge`,annotations:{readOnlyHint:!1}},read:{title:`Read Knowledge`,annotations:{readOnlyHint:!0,idempotentHint:!0}},update:{title:`Update Knowledge`,annotations:{readOnlyHint:!1}},forget:{title:`Forget Knowledge`,annotations:{readOnlyHint:!1,destructiveHint:!0}},list:{title:`List Knowledge`,annotations:{readOnlyHint:!0,idempotentHint:!0}},produce_knowledge:{title:`Produce Knowledge`,annotations:{readOnlyHint:!0,idempotentHint:!0}},compact:{title:`Semantic Compactor`,annotations:{readOnlyHint:!0,idempotentHint:!0}},digest:{title:`Multi-Source Digest`,annotations:{readOnlyHint:!0,idempotentHint:!0}},stratum_card:{title:`Stratum Card`,annotations:{readOnlyHint:!0,idempotentHint:!0}},forge_ground:{title:`FORGE Ground`,annotations:{readOnlyHint:!0,idempotentHint:!0}},forge_classify:{title:`FORGE Classify`,annotations:{readOnlyHint:!0,idempotentHint:!0}},evidence_map:{title:`Evidence Map`,annotations:{readOnlyHint:!1}},present:{title:`Rich Content Presenter`,annotations:{readOnlyHint:!0,idempotentHint:!0}},check:{title:`Typecheck & Lint`,annotations:{readOnlyHint:!0,openWorldHint:!0}},test_run:{title:`Run Tests`,annotations:{readOnlyHint:!0,openWorldHint:!0}},eval:{title:`Evaluate Code`,annotations:{readOnlyHint:!1,openWorldHint:!0}},batch:{title:`Batch Operations`,annotations:{readOnlyHint:!0,idempotentHint:!0}},audit:{title:`Project Audit`,annotations:{readOnlyHint:!0,idempotentHint:!0}},rename:{title:`Rename Symbol`,annotations:{readOnlyHint:!1,destructiveHint:!0}},restore:{title:`Restore`,annotations:{readOnlyHint:!1}},codemod:{title:`Codemod`,annotations:{readOnlyHint:!1,destructiveHint:!0}},data_transform:{title:`Data Transform`,annotations:{readOnlyHint:!0,idempotentHint:!0}},stash:{title:`Stash Values`,annotations:{readOnlyHint:!1}},checkpoint:{title:`Session Checkpoint`,annotations:{readOnlyHint:!1}},workset:{title:`Workset Manager`,annotations:{readOnlyHint:!1}},lane:{title:`Exploration Lane`,annotations:{readOnlyHint:!1}},git_context:{title:`Git Context`,annotations:{readOnlyHint:!0,idempotentHint:!0}},diff_parse:{title:`Diff Parser`,annotations:{readOnlyHint:!0,idempotentHint:!0}},parse_output:{title:`Parse Build Output`,annotations:{readOnlyHint:!0,idempotentHint:!0}},process:{title:`Process Manager`,annotations:{readOnlyHint:!1,openWorldHint:!0}},watch:{title:`File Watcher`,annotations:{readOnlyHint:!1,openWorldHint:!0}},delegate:{title:`Delegate Task`,annotations:{readOnlyHint:!1,openWorldHint:!0}},config:{title:`Configuration Manager`,annotations:{readOnlyHint:!1}},status:{title:`AI Kit Status`,annotations:{readOnlyHint:!0,idempotentHint:!0}},health:{title:`Health Check`,annotations:{readOnlyHint:!0,idempotentHint:!0}},reindex:{title:`Reindex`,annotations:{readOnlyHint:!1}},onboard:{title:`Onboard Codebase`,annotations:{readOnlyHint:!1}},graph:{title:`Knowledge Graph`,annotations:{readOnlyHint:!1}},guide:{title:`Tool Guide`,annotations:{readOnlyHint:!0,idempotentHint:!0}},replay:{title:`Replay History`,annotations:{readOnlyHint:!0,idempotentHint:!0}},changelog:{title:`Generate Changelog`,annotations:{readOnlyHint:!0,idempotentHint:!0}},regex_test:{title:`Regex Tester`,annotations:{readOnlyHint:!0,idempotentHint:!0}},encode:{title:`Encode / Decode`,annotations:{readOnlyHint:!0,idempotentHint:!0}},measure:{title:`Code Metrics`,annotations:{readOnlyHint:!0,idempotentHint:!0}},schema_validate:{title:`Schema Validator`,annotations:{readOnlyHint:!0,idempotentHint:!0}},snippet:{title:`Code Snippets`,annotations:{readOnlyHint:!1}},env:{title:`Environment Info`,annotations:{readOnlyHint:!0,idempotentHint:!0}},time:{title:`Date & Time`,annotations:{readOnlyHint:!0,idempotentHint:!0}},web_fetch:{title:`Web Fetch`,annotations:{readOnlyHint:!0,openWorldHint:!0}},web_search:{title:`Web Search`,annotations:{readOnlyHint:!0,openWorldHint:!0}},http:{title:`HTTP Request`,annotations:{readOnlyHint:!1,openWorldHint:!0}},queue:{title:`Operation Queue`,annotations:{readOnlyHint:!1}},bridge_push:{title:`Bridge Push`,annotations:{readOnlyHint:!1}},bridge_pull:{title:`Bridge Pull`,annotations:{readOnlyHint:!0,idempotentHint:!0}},bridge_sync:{title:`Bridge Sync Status`,annotations:{readOnlyHint:!0,idempotentHint:!0}},evolution_state:{title:`Evolution State`,annotations:{readOnlyHint:!1}},policy_check:{title:`Policy Check`,annotations:{readOnlyHint:!0,idempotentHint:!0}},flow_list:{title:`Flow List`,annotations:{readOnlyHint:!0,idempotentHint:!0}},flow_info:{title:`Flow Info`,annotations:{readOnlyHint:!0,idempotentHint:!0}},flow_start:{title:`Flow Start`,annotations:{readOnlyHint:!1}},flow_step:{title:`Flow Step`,annotations:{readOnlyHint:!1}},flow_status:{title:`Flow Status`,annotations:{readOnlyHint:!0,idempotentHint:!0}},flow_reset:{title:`Flow Reset`,annotations:{readOnlyHint:!1}}};function t(t){return e[t]??{title:t,annotations:{readOnlyHint:!1}}}export{e as TOOL_METADATA,t as getToolMeta};
@@ -0,0 +1,8 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { KBConfig } from "../../../core/dist/index.js";
3
+
4
+ //#region packages/server/src/tools/config.tool.d.ts
5
+ type KBServer = McpServer;
6
+ declare function registerConfigTool(server: KBServer, config: KBConfig): void;
7
+ //#endregion
8
+ export { registerConfigTool };
@@ -0,0 +1,12 @@
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{buildDashboardHtml as t,buildFormHtml as n}from"./present/templates.js";import{existsSync as r,readFileSync as i,writeFileSync as a}from"node:fs";import{resolve as o}from"node:path";import{z as s}from"zod";import{createLogger as c}from"../../../core/dist/index.js";import{RESOURCE_MIME_TYPE as l,registerAppResource as u,registerAppTool as d}from"@modelcontextprotocol/ext-apps/server";const f=s.object({action:s.enum([`view`,`update`]).default(`view`).describe(`Action to perform: view current configuration or update it`),updates:s.record(s.string(),s.unknown()).optional().describe(`Partial configuration to merge when action is "update". Supports nested paths like { "indexing": { "chunkSize": 2000 } }`)}),p=c(`config-tool`),m=`ui://aikit/config.html`,h=[`serverName`,`toolPrefix`,`autoIndex`,`sources`,`indexing`];function g(){let e=process.env.AIKIT_CONFIG_PATH;if(e&&r(e))return e;let t=o(process.cwd(),`aikit.config.json`);return r(t)?t:``}function _(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function v(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];if(_(t)&&_(r)){n[e]=v(t,r);continue}n[e]=r}return n}function y(e){return e===void 0?`undefined`:JSON.stringify(e)}function b(e,t,n,r=``){let i=[];for(let[a,o]of Object.entries(n)){let n=r?`${r}.${a}`:a,s=e[a],c=t[a];if(_(o)&&_(s)&&_(c)){i.push(...b(s,c,o,n));continue}y(s)!==y(c)&&i.push(`- ${n}: ${y(s)} -> ${y(c)}`)}return i}function x(e){let t=[];for(let[n,r]of Object.entries(e)){if(n===`store`||n===`embedding`||n===`er`){t.push(`Field "${n}" cannot be updated through this tool because it requires a restart.`);continue}if(n===`onboardDir`||n===`stateDir`||n===`curated`){t.push(`Field "${n}" cannot be updated through this tool because it requires a restart.`);continue}if(n===`autoIndex`){typeof r!=`boolean`&&t.push(`autoIndex must be a boolean.`);continue}if(n===`serverName`||n===`toolPrefix`){typeof r!=`string`&&t.push(`${n} must be a string.`);continue}if(n===`sources`){(!Array.isArray(r)||r.length===0)&&t.push(`sources must be a non-empty array.`);continue}if(n===`indexing`){if(!_(r)){t.push(`indexing must be an object.`);continue}for(let[e,n]of Object.entries(r)){if(e!==`chunkSize`&&e!==`chunkOverlap`&&e!==`minChunkSize`&&e!==`concurrency`){t.push(`indexing.${e} is not updatable through this tool.`);continue}(typeof n!=`number`||!Number.isFinite(n)||n<=0)&&t.push(`indexing.${e} must be a positive number.`)}continue}t.push(`Field "${n}" is not updatable through this tool.`)}return t}function S(e){let t=[];if(`autoIndex`in e&&typeof e.autoIndex!=`boolean`&&t.push(`autoIndex must be a boolean.`),`serverName`in e&&e.serverName!==void 0&&typeof e.serverName!=`string`&&t.push(`serverName must be a string.`),`toolPrefix`in e&&e.toolPrefix!==void 0&&typeof e.toolPrefix!=`string`&&t.push(`toolPrefix must be a string.`),(!Array.isArray(e.sources)||e.sources.length===0)&&t.push(`sources must be a non-empty array.`),!_(e.indexing))return t.push(`indexing must be an object.`),t;for(let n of[`chunkSize`,`chunkOverlap`,`minChunkSize`,`concurrency`]){let r=e.indexing[n];r!==void 0&&(typeof r!=`number`||!Number.isFinite(r)||r<=0)&&t.push(`indexing.${n} must be a positive number.`)}return t}function C(e){let t=JSON.parse(i(e,`utf-8`));if(!_(t))throw Error(`Config file must contain a JSON object.`);return t}function w(e,t){return[`AI Kit Configuration`,`Config file: ${t}`,``,JSON.stringify(e,null,2)].join(`
2
+ `)}function T(e){return e===void 0?``:_(e)||Array.isArray(e)?JSON.stringify(e,null,2):String(e)}function E(e){return t({metrics:Object.entries(e).map(([e,t])=>({label:e,value:_(t)||Array.isArray(t)?JSON.stringify(t,null,2):String(t),status:`info`}))})}function D(e){return n({fields:h.map(t=>{let n=e[t];return typeof n==`boolean`?{name:t,label:t,type:`select`,options:[`true`,`false`],value:String(n)}:{name:t,label:t,type:_(n)||Array.isArray(n)?`textarea`:`text`,value:T(n)}})})}function O(e,t){return`<!DOCTYPE html><html><head><meta charset="utf-8"><title>${e}</title><style>:root{--aikit-bg:#1e1e1e;--aikit-surface:#252526;--aikit-surface2:#2d2d30;--aikit-border:#3c3c3c;--aikit-text:#e5e7eb;--aikit-muted:#9ca3af;--aikit-accent:#60a5fa;--aikit-success:#22c55e;font-family:system-ui,sans-serif}body{margin:0;padding:20px;background:var(--aikit-bg);color:var(--aikit-text);font-family:system-ui,sans-serif}h2{margin:0 0 16px}</style></head><body><h2>${e}</h2>${t}</body></html>`}function k(e,t,n){u(e,`AI Kit Config App`,m,{description:`View and update AI Kit configuration`},async()=>({contents:[{uri:m,mimeType:l,text:O(t,n)}]}))}function A(t,n){let r=e(`config`);d(t,`config`,{title:r.title,description:`View and update AI Kit server configuration. Use action "view" to see current settings, or "update" to modify configuration values. Changes are written to aikit.config.json and take effect on next server restart. Some settings (store, embedding) require a full restart.`,inputSchema:f,annotations:r.annotations,_meta:{ui:{resourceUri:m}}},async e=>{let{action:r,updates:i}=e;if(r===`view`){let e=g(),r=e||`(runtime config only; no aikit.config.json found)`;try{let i=e?C(e):n,a=w(i,r);return k(t,`Configuration`,E(i)),{content:[{type:`text`,text:a}],ui:{type:`resource`,uri:m}}}catch(t){return p.error(`Failed to read config for view`,{configPath:e,error:t instanceof Error?t.message:String(t)}),{content:[{type:`text`,text:`Failed to read configuration from ${r}: ${t instanceof Error?t.message:String(t)}`}]}}}if(!i)return k(t,`Configuration Form`,D(n)),{content:[{type:`text`,text:`No updates provided. Pass an updates object when action is "update".`}],ui:{type:`resource`,uri:m}};let o=g();if(!o)return k(t,`Configuration Form`,D(n)),{content:[{type:`text`,text:`No config file found to update.`}],ui:{type:`resource`,uri:m}};let s=x(i);if(s.length>0)return k(t,`Configuration Form`,D(C(o))),{content:[{type:`text`,text:`Configuration update rejected:\n${s.map(e=>`- ${e}`).join(`
3
+ `)}`}],ui:{type:`resource`,uri:m}};try{let e=C(o),n=v(e,i),r=S(n);if(r.length>0)return k(t,`Configuration Form`,D(e)),{content:[{type:`text`,text:`Configuration update rejected:\n${r.map(e=>`- ${e}`).join(`
4
+ `)}`}],ui:{type:`resource`,uri:m}};a(o,JSON.stringify(n,null,2),`utf-8`);let s=b(e,n,i),c=`Configuration updated successfully.
5
+
6
+ Config file: ${o}
7
+
8
+ Changed values:
9
+ ${s.length>0?s.join(`
10
+ `):`- No effective changes; requested values already matched the file.`}
11
+
12
+ These changes take effect on the next server restart.`;return k(t,`Configuration`,E(n)),{content:[{type:`text`,text:c}],ui:{type:`resource`,uri:m}}}catch(e){return p.error(`Failed to update config`,{configPath:o,error:e instanceof Error?e.message:String(e)}),{content:[{type:`text`,text:`Failed to update configuration in ${o}: ${e instanceof Error?e.message:String(e)}`}]}}})}export{A as registerConfigTool};
@@ -1 +1 @@
1
- import{getToolMeta as e}from"../tool-metadata.js";import{join as t}from"node:path";import{z as n}from"zod";import{createLogger as r,serializeError as i}from"../../../core/dist/index.js";const a=r(`flow-tools`);function o(e){return{content:[{type:`text`,text:e}]}}function s(e){return e instanceof Error?e.message:String(e)}function c(r,c){let l=t(c.sources[0].path,`.aikit-state`,`flows`),u=t(l,`registry.json`),d=t(l,`state.json`);async function f(){let{FlowRegistryManager:e,FlowStateMachine:t}=await import(`../../../flows/dist/index.js`);return{registry:new e(u),stateMachine:new t(d)}}let p=e(`flow_list`);r.registerTool(`flow_list`,{title:p.title,description:`List all installed flows and their steps`,annotations:p.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await f(),n=e.list(),r=t.getStatus(),i={flows:n.map(e=>({name:e.name,version:e.version,source:e.source,sourceType:e.sourceType,format:e.format,steps:e.manifest.steps.map(e=>e.id)})),activeFlow:r.success&&r.data?{flow:r.data.flow,status:r.data.status,currentStep:r.data.currentStep}:null};return o(JSON.stringify(i,null,2))}catch(e){return a.error(`flow_list failed`,i(e)),o(`Error: ${s(e)}`)}});let m=e(`flow_info`);r.registerTool(`flow_info`,{title:m.title,description:`Show detailed information about a specific flow`,annotations:m.annotations,inputSchema:{name:n.string().describe(`Flow name to get info for`)}},async({name:e})=>{try{let{registry:t}=await f(),n=t.get(e);if(!n)return o(`Flow "${e}" not found. Use flow_list to see available flows.`);let r={name:n.name,version:n.version,description:n.manifest.description,source:n.source,sourceType:n.sourceType,format:n.format,installPath:n.installPath,registeredAt:n.registeredAt,updatedAt:n.updatedAt,steps:n.manifest.steps.map(e=>({id:e.id,name:e.name,skill:e.skill,produces:e.produces,requires:e.requires,description:e.description})),agents:n.manifest.agents,artifactsDir:n.manifest.artifacts_dir,install:n.manifest.install};return o(JSON.stringify(r,null,2))}catch(e){return a.error(`flow_info failed`,i(e)),o(`Error: ${s(e)}`)}});let h=e(`flow_start`);r.registerTool(`flow_start`,{title:h.title,description:`Start a flow. Sets the active flow and positions at the first step.`,annotations:h.annotations,inputSchema:{flow:n.string().describe(`Flow name to start (use flow_list to see options)`)}},async({flow:e})=>{try{let{registry:t,stateMachine:n}=await f(),r=t.get(e);if(!r)return o(`Flow "${e}" not found. Use flow_list to see available flows.`);let i=n.start(r.name,r.manifest);if(!i.success||!i.data)return o(`Cannot start: ${i.error}`);let a=i.data,s=r.manifest.steps.find(e=>e.id===a.currentStep),c={started:!0,flow:a.flow,currentStep:a.currentStep,currentStepSkill:s?.skill??null,currentStepDescription:s?.description??null,totalSteps:r.manifest.steps.length,stepSequence:r.manifest.steps.map(e=>e.id),artifactsDir:r.manifest.artifacts_dir};return o(JSON.stringify(c,null,2))}catch(e){return a.error(`flow_start failed`,i(e)),o(`Error: ${s(e)}`)}});let g=e(`flow_step`);r.registerTool(`flow_step`,{title:g.title,description:`Advance the active flow: complete current step and move to next, skip current step, or redo current step.`,annotations:g.annotations,inputSchema:{action:n.enum([`next`,`skip`,`redo`]).describe(`next: mark current step done and advance. skip: skip current step. redo: repeat current step.`)}},async({action:e})=>{try{let{registry:t,stateMachine:n}=await f(),r=n.load();if(!r)return o(`No active flow. Use flow_start first.`);let i=t.get(r.flow);if(!i)return o(`Flow "${r.flow}" not found in registry.`);let a=n.step(e,i.manifest);if(!a.success||!a.data)return o(`Cannot ${e}: ${a.error}`);let s=a.data,c=s.currentStep?i.manifest.steps.find(e=>e.id===s.currentStep):null,l={flow:s.flow,status:s.status,action:e,currentStep:s.currentStep,currentStepSkill:c?.skill??null,currentStepDescription:c?.description??null,completedSteps:s.completedSteps,skippedSteps:s.skippedSteps,totalSteps:i.manifest.steps.length,remaining:i.manifest.steps.filter(e=>!s.completedSteps.includes(e.id)&&!s.skippedSteps.includes(e.id)&&e.id!==s.currentStep).map(e=>e.id)};return o(JSON.stringify(l,null,2))}catch(e){return a.error(`flow_step failed`,i(e)),o(`Error: ${s(e)}`)}});let _=e(`flow_status`);r.registerTool(`flow_status`,{title:_.title,description:`Show the current flow execution state — which flow is active, current step, completed steps, and artifacts.`,annotations:_.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await f(),n=t.getStatus();if(!n.success||!n.data)return o(`No active flow. Use flow_start to begin one, or flow_list to see available flows.`);let r=n.data,i=e.get(r.flow),a=i?.manifest.steps.find(e=>e.id===r.currentStep),s={flow:r.flow,status:r.status,currentStep:r.currentStep,currentStepSkill:a?.skill??null,currentStepDescription:a?.description??null,completedSteps:r.completedSteps,skippedSteps:r.skippedSteps,artifacts:r.artifacts,startedAt:r.startedAt,updatedAt:r.updatedAt,totalSteps:i?.manifest.steps.length??0,progress:i?`${r.completedSteps.length+r.skippedSteps.length}/${i.manifest.steps.length}`:`unknown`};return o(JSON.stringify(s,null,2))}catch(e){return a.error(`flow_status failed`,i(e)),o(`Error: ${s(e)}`)}});let v=e(`flow_reset`);r.registerTool(`flow_reset`,{title:v.title,description:`Reset the active flow, clearing all state. Use to start over or switch to a different flow.`,annotations:v.annotations,inputSchema:{}},async()=>{try{let{stateMachine:e}=await f(),t=e.reset();return t.success?o(`Flow state reset. Use flow_start to begin a new flow.`):o(`Reset failed: ${t.error}`)}catch(e){return a.error(`flow_reset failed`,i(e)),o(`Error: ${s(e)}`)}})}export{c as registerFlowTools};
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{join as t}from"node:path";import{z as n}from"zod";import{createLogger as r,serializeError as i}from"../../../core/dist/index.js";const a=r(`flow-tools`);function o(e){return{content:[{type:`text`,text:e}]}}function s(e){return e instanceof Error?e.message:String(e)}function c(r,c){let l=t(c.stateDir??t(c.sources[0].path,`.aikit-state`),`flows`),u=t(l,`registry.json`),d=t(l,`state.json`);async function f(){let{FlowRegistryManager:e,FlowStateMachine:t}=await import(`../../../flows/dist/index.js`);return{registry:new e(u),stateMachine:new t(d)}}let p=e(`flow_list`);r.registerTool(`flow_list`,{title:p.title,description:`List all installed flows and their steps`,annotations:p.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await f(),n=e.list(),r=t.getStatus(),i={flows:n.map(e=>({name:e.name,version:e.version,source:e.source,sourceType:e.sourceType,format:e.format,steps:e.manifest.steps.map(e=>e.id)})),activeFlow:r.success&&r.data?{flow:r.data.flow,status:r.data.status,currentStep:r.data.currentStep}:null};return o(JSON.stringify(i,null,2))}catch(e){return a.error(`flow_list failed`,i(e)),o(`Error: ${s(e)}`)}});let m=e(`flow_info`);r.registerTool(`flow_info`,{title:m.title,description:`Show detailed information about a specific flow`,annotations:m.annotations,inputSchema:{name:n.string().describe(`Flow name to get info for`)}},async({name:e})=>{try{let{registry:t}=await f(),n=t.get(e);if(!n)return o(`Flow "${e}" not found. Use flow_list to see available flows.`);let r={name:n.name,version:n.version,description:n.manifest.description,source:n.source,sourceType:n.sourceType,format:n.format,installPath:n.installPath,registeredAt:n.registeredAt,updatedAt:n.updatedAt,steps:n.manifest.steps.map(e=>({id:e.id,name:e.name,skill:e.skill,produces:e.produces,requires:e.requires,description:e.description})),agents:n.manifest.agents,artifactsDir:n.manifest.artifacts_dir,install:n.manifest.install};return o(JSON.stringify(r,null,2))}catch(e){return a.error(`flow_info failed`,i(e)),o(`Error: ${s(e)}`)}});let h=e(`flow_start`);r.registerTool(`flow_start`,{title:h.title,description:`Start a flow. Sets the active flow and positions at the first step.`,annotations:h.annotations,inputSchema:{flow:n.string().describe(`Flow name to start (use flow_list to see options)`)}},async({flow:e})=>{try{let{registry:t,stateMachine:n}=await f(),r=t.get(e);if(!r)return o(`Flow "${e}" not found. Use flow_list to see available flows.`);let i=n.start(r.name,r.manifest);if(!i.success||!i.data)return o(`Cannot start: ${i.error}`);let a=i.data,s=r.manifest.steps.find(e=>e.id===a.currentStep),c={started:!0,flow:a.flow,currentStep:a.currentStep,currentStepSkill:s?.skill??null,currentStepDescription:s?.description??null,totalSteps:r.manifest.steps.length,stepSequence:r.manifest.steps.map(e=>e.id),artifactsDir:r.manifest.artifacts_dir};return o(JSON.stringify(c,null,2))}catch(e){return a.error(`flow_start failed`,i(e)),o(`Error: ${s(e)}`)}});let g=e(`flow_step`);r.registerTool(`flow_step`,{title:g.title,description:`Advance the active flow: complete current step and move to next, skip current step, or redo current step.`,annotations:g.annotations,inputSchema:{action:n.enum([`next`,`skip`,`redo`]).describe(`next: mark current step done and advance. skip: skip current step. redo: repeat current step.`)}},async({action:e})=>{try{let{registry:t,stateMachine:n}=await f(),r=n.load();if(!r)return o(`No active flow. Use flow_start first.`);let i=t.get(r.flow);if(!i)return o(`Flow "${r.flow}" not found in registry.`);let a=n.step(e,i.manifest);if(!a.success||!a.data)return o(`Cannot ${e}: ${a.error}`);let s=a.data,c=s.currentStep?i.manifest.steps.find(e=>e.id===s.currentStep):null,l={flow:s.flow,status:s.status,action:e,currentStep:s.currentStep,currentStepSkill:c?.skill??null,currentStepDescription:c?.description??null,completedSteps:s.completedSteps,skippedSteps:s.skippedSteps,totalSteps:i.manifest.steps.length,remaining:i.manifest.steps.filter(e=>!s.completedSteps.includes(e.id)&&!s.skippedSteps.includes(e.id)&&e.id!==s.currentStep).map(e=>e.id)};return o(JSON.stringify(l,null,2))}catch(e){return a.error(`flow_step failed`,i(e)),o(`Error: ${s(e)}`)}});let _=e(`flow_status`);r.registerTool(`flow_status`,{title:_.title,description:`Show the current flow execution state — which flow is active, current step, completed steps, and artifacts.`,annotations:_.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await f(),n=t.getStatus();if(!n.success||!n.data)return o(`No active flow. Use flow_start to begin one, or flow_list to see available flows.`);let r=n.data,i=e.get(r.flow),a=i?.manifest.steps.find(e=>e.id===r.currentStep),s={flow:r.flow,status:r.status,currentStep:r.currentStep,currentStepSkill:a?.skill??null,currentStepDescription:a?.description??null,completedSteps:r.completedSteps,skippedSteps:r.skippedSteps,artifacts:r.artifacts,startedAt:r.startedAt,updatedAt:r.updatedAt,totalSteps:i?.manifest.steps.length??0,progress:i?`${r.completedSteps.length+r.skippedSteps.length}/${i.manifest.steps.length}`:`unknown`};return o(JSON.stringify(s,null,2))}catch(e){return a.error(`flow_status failed`,i(e)),o(`Error: ${s(e)}`)}});let v=e(`flow_reset`);r.registerTool(`flow_reset`,{title:v.title,description:`Reset the active flow, clearing all state. Use to start over or switch to a different flow.`,annotations:v.annotations,inputSchema:{}},async()=>{try{let{stateMachine:e}=await f(),t=e.reset();return t.success?o(`Flow state reset. Use flow_start to begin a new flow.`):o(`Reset failed: ${t.error}`)}catch(e){return a.error(`flow_reset failed`,i(e)),o(`Error: ${s(e)}`)}})}export{c as registerFlowTools};
@@ -1,23 +1,23 @@
1
- import{FONT_LINK as e,getDesignSystemCSS as t}from"../present-theme.js";import{escHtml as n}from"../present-utils.js";import{contentToHtml as r}from"./html.js";import{buildTemplateHtml as i}from"./templates.js";function a(a,o,s,c){let l=c&&c!==`auto`?i(c,o):r(a,o);return`<!DOCTYPE html>
1
+ import{escHtml as e}from"../present-utils.js";import{buildTemplateHtml as t}from"./templates.js";import{FONT_LINK as n,getDesignSystemCSS as r}from"../present-theme.js";import{contentToHtml as i}from"./html.js";function a(a,o,s,c){let l=c&&c!==`auto`?t(c,o):i(a,o);return`<!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
6
- <title>${n(a??`AI Kit Dashboard`)}</title>
7
- ${e}
8
- <style>${t()}</style>
6
+ <title>${e(a??`AI Kit Dashboard`)}</title>
7
+ ${n}
8
+ <style>${r()}</style>
9
9
  </head>
10
10
  <body>
11
11
  <div class="dashboard">
12
12
  <div class="header">
13
- <h1>${n(a??`AI Kit Dashboard`)}</h1>
13
+ <h1>${e(a??`AI Kit Dashboard`)}</h1>
14
14
  <div class="subtitle">AI Kit</div>
15
15
  </div>
16
16
  ${l}
17
- ${(()=>{let e=Array.isArray(s)?s:[];return e.length===0?``:`
17
+ ${(()=>{let t=Array.isArray(s)?s:[];return t.length===0?``:`
18
18
  <div class="actions-bar">
19
19
  <h2>Actions</h2>
20
- <div class="actions-grid">${e.map(e=>{let t=String(e.id??``);if(e.type===`select`&&Array.isArray(e.options)){let r=e.options.map(e=>{let t=typeof e==`string`?e:e.label;return`<option value="${n(typeof e==`string`?e:e.value)}">${n(t)}</option>`}).join(``);return`<div class="action-group"><label>${n(String(e.label??``))}</label><select data-action-id="${n(t)}" onchange="sendCallback(${n(JSON.stringify(t))},this.value)">${r}</select></div>`}return`<button class="action-btn action-${String(e.variant??`default`)}" onclick="sendCallback(${n(JSON.stringify(t))},'clicked')">${n(String(e.label??``))}</button>`}).join(`
20
+ <div class="actions-grid">${t.map(t=>{let n=String(t.id??``);if(t.type===`select`&&Array.isArray(t.options)){let r=t.options.map(t=>{let n=typeof t==`string`?t:t.label;return`<option value="${e(typeof t==`string`?t:t.value)}">${e(n)}</option>`}).join(``);return`<div class="action-group"><label>${e(String(t.label??``))}</label><select data-action-id="${e(n)}" onchange="sendCallback(${e(JSON.stringify(n))},this.value)">${r}</select></div>`}return`<button class="action-btn action-${String(t.variant??`default`)}" onclick="sendCallback(${e(JSON.stringify(n))},'clicked')">${e(String(t.label??``))}</button>`}).join(`
21
21
  `)}</div>
22
22
  <div id="action-feedback" class="action-feedback"></div>
23
23
  </div>
@@ -1,4 +1,4 @@
1
- import{getToolMeta as e}from"../../tool-metadata.js";import{buildBrowserHtml as t}from"./browser.js";import{buildMarkdown as n}from"./markdown.js";import{readFileSync as r}from"node:fs";import{dirname as i,join as a}from"node:path";import{fileURLToPath as o}from"node:url";import{z as s}from"zod";import{exec as c}from"node:child_process";import{createServer as l}from"node:http";import{createUIResource as u}from"@mcp-ui/server";import{RESOURCE_MIME_TYPE as d,registerAppResource as f,registerAppTool as p}from"@modelcontextprotocol/ext-apps/server";const m=import.meta.dirname??i(o(import.meta.url)),h=`ui://kb/present.html`,g=s.object({type:s.enum([`button`,`select`]).describe(`Action type`),id:s.string().describe(`Unique action identifier`),label:s.string().describe(`Display label`),variant:s.enum([`primary`,`danger`,`default`]).optional().describe(`Button style variant`),options:s.array(s.union([s.string(),s.object({label:s.string(),value:s.string()})])).optional().describe(`Select options (for type=select)`)}),_={format:s.enum([`html`,`browser`]).default(`html`).describe(`Output format.
1
+ import{getToolMeta as e}from"../../tool-metadata.js";import{buildBrowserHtml as t}from"./browser.js";import{buildMarkdown as n}from"./markdown.js";import{readFileSync as r}from"node:fs";import{dirname as i,join as a}from"node:path";import{fileURLToPath as o}from"node:url";import{z as s}from"zod";import{RESOURCE_MIME_TYPE as c,registerAppResource as l,registerAppTool as u}from"@modelcontextprotocol/ext-apps/server";import{exec as d}from"node:child_process";import{createServer as f}from"node:http";import{createUIResource as p}from"@mcp-ui/server";const m=import.meta.dirname??i(o(import.meta.url)),h=`ui://kb/present.html`,g=s.object({type:s.enum([`button`,`select`]).describe(`Action type`),id:s.string().describe(`Unique action identifier`),label:s.string().describe(`Display label`),variant:s.enum([`primary`,`danger`,`default`]).optional().describe(`Button style variant`),options:s.array(s.union([s.string(),s.object({label:s.string(),value:s.string()})])).optional().describe(`Select options (for type=select)`)}),_={format:s.enum([`html`,`browser`]).default(`html`).describe(`Output format.
2
2
  - "html" (default): Rich markdown in chat + embedded UIResource for MCP-UI hosts. Actions shown as numbered choices.
3
3
  - "browser": Rich markdown in chat + opens beautiful themed dashboard in the browser. When actions are provided, the browser shows interactive buttons and the tool blocks until user clicks, returning their selection.`),title:s.string().optional().describe(`Optional heading`),content:s.any().describe(`Content to present. Accepts: markdown string, array of objects (→ table), { nodes, edges } (→ mermaid graph), typed blocks [{ type, value }], or any JSON (→ tree).`),actions:s.array(g).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:s.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.
4
4
  - auto (default): detect from content shape
@@ -11,9 +11,9 @@ import{getToolMeta as e}from"../../tool-metadata.js";import{buildBrowserHtml as
11
11
  - kanban: drag-drop board — content: { columns: [{id, label, color?}], cards: [{id, title, column, tags?[], priority?}] }
12
12
  - tree: collapsible tree view — content: { root: {label, children?:[...]} | [...] }
13
13
  - diff-view: side-by-side diff — content: { files: [{path, status, additions, deletions, hunks:[{header, changes:[{type, content}]}]}] }
14
- - dashboard: metric cards grid — content: { metrics: [{label, value, trend?, status?, type?}] }`)};let v,y=!1,b=null;process.on(`exit`,()=>{if(b){try{b.close()}catch{}b=null}});function x(){return a(m,`..`,`..`,`..`,`..`,`present`,`dist`,`index.html`)}function S(){if(!v)try{v=r(x(),`utf-8`)}catch{v=``}return v}function C(t,n){let r=e(`present`);y||=(f(t,`AI Kit Present App`,h,{description:`Rich interactive content viewer for AI Kit tools`},async()=>({contents:[{uri:h,mimeType:d,text:S()}]})),!0),p(t,`present`,{title:r.title,description:`Present content to the user in the best format. Two modes:
14
+ - dashboard: metric cards grid — content: { metrics: [{label, value, trend?, status?, type?}] }`)};let v,y=!1,b=null;process.on(`exit`,()=>{if(b){try{b.close()}catch{}b=null}});function x(){return a(m,`..`,`..`,`..`,`..`,`present`,`dist`,`index.html`)}function S(){if(!v)try{v=r(x(),`utf-8`)}catch{v=``}return v}function C(t,n){let r=e(`present`);y||=(l(t,`AI Kit Present App`,h,{description:`Rich interactive content viewer for AI Kit tools`},async()=>({contents:[{uri:h,mimeType:c,text:S()}]})),!0),u(t,`present`,{title:r.title,description:`Present content to the user in the best format. Two modes:
15
15
  - "html" (default): Rich markdown in chat + embedded UIResource. Use for display-only content (tables, charts, reports, status boards) where no user interaction is needed.
16
16
  - "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.
17
17
  FORMAT RULE: If no user interaction is needed → use "html". If you need user input back → use "browser".
18
- BROWSER WORKFLOW: After calling present with format "browser", you MUST extract the URL from the response and call openBrowserPage({ url }) to open it in VS Code Simple Browser. A system browser fallback also opens automatically, but always call openBrowserPage yourself.`,annotations:r.annotations,inputSchema:_,_meta:{ui:{resourceUri:h}}},async({format:e,title:t,content:r,actions:i,template:a})=>(e??`html`)===`browser`?await w(t,r,i,n,a):T(t,r,i,a))}async function w(e,r,i,a,o){let s=n(e,r),d=t(e,r,i,o),f=u({uri:`ui://kb/present-browser.html`,content:{type:`rawHtml`,htmlString:d},encoding:`text`,adapters:{mcpApps:{enabled:!0}}}),p,m,h=Array.isArray(i)?i:[],g=``,_;try{b&&=(b.close(),null),h.length>0&&(p=new Promise(e=>{m=e}));let e=!1;g=await new Promise((t,n)=>{let r=l((t,n)=>{if(e||(e=!0,_&&clearTimeout(_)),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);m?.(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}n.writeHead(200,{"Content-Type":`text/html; charset=utf-8`}),n.end(d)});r.listen(0,`127.0.0.1`,()=>{let i=r.address();if(typeof i==`object`&&i){b=r;let n=`http://127.0.0.1:${i.port}`;_=setTimeout(()=>{if(!e)try{c(process.platform===`win32`?`start "" "${n}"`:process.platform===`darwin`?`open "${n}"`:`xdg-open "${n}"`)}catch{}},8e3),_.unref(),t(n)}else n(Error(`Failed to start present server`))}),setTimeout(()=>{r.close(),b===r&&(b=null)},300*1e3).unref()})}catch{}let v=g?`${s}\n\n---\n🌐 **Dashboard opened in browser:** ${g}\n\n**IMPORTANT:** You MUST now open this URL using the \`openBrowserPage\` tool (Simple Browser). 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.`:s;if(h.length>0&&a?.available&&p)try{let e=await Promise.race([p,new Promise((e,t)=>setTimeout(()=>t(Error(`timeout`)),300*1e3))]);return{content:[{type:`text`,text:`${v}\n\n✅ **Selected:** ${e.actionId} = \`${e.value}\``},f]}}catch{return{content:[{type:`text`,text:`${v}\n\n⚠️ *No selection received (timed out).*`},f]}}return{content:[{type:`text`,text:v},f]}}function T(e,r,i,a){let o=Array.isArray(i)?i:[],s=n(e,r);if(o.length>0){let e=[``];for(let t=0;t<o.length;t++){let n=o[t],r=typeof n.label==`string`?n.label:`Action ${t+1}`;if(n.type===`select`&&Array.isArray(n.options)){let i=n.options.map(e=>typeof e==`string`?e:e.label).join(`, `);e.push(`${t+1}. **${r}** — choose: ${i}`)}else e.push(`${t+1}. **${r}**`)}s+=`\n${e.join(`
19
- `)}`}let c=u({uri:`ui://kb/present-static.html`,content:{type:`rawHtml`,htmlString:t(e,r,i,a)},encoding:`text`,adapters:{mcpApps:{enabled:!0}}});return{content:[{type:`text`,text:s},c],structuredContent:{title:e,content:r,actions:o}}}export{w as formatAsBrowser,T as formatAsHtml,S as getPresentHtml,C as registerPresentTool,x as resolvePresentHtml};
18
+ BROWSER WORKFLOW: After calling present with format "browser", you MUST extract the URL from the response and call openBrowserPage({ url }) to open it in VS Code Simple Browser. A system browser fallback also opens automatically, but always call openBrowserPage yourself.`,annotations:r.annotations,inputSchema:_,_meta:{ui:{resourceUri:h}}},async({format:e,title:t,content:r,actions:i,template:a})=>(e??`html`)===`browser`?await w(t,r,i,n,a):T(t,r,i,a))}async function w(e,r,i,a,o){let s=n(e,r),c=t(e,r,i,o),l=p({uri:`ui://kb/present-browser.html`,content:{type:`rawHtml`,htmlString:c},encoding:`text`,adapters:{mcpApps:{enabled:!0}}}),u,m,h=Array.isArray(i)?i:[],g=``,_;try{b&&=(b.close(),null),h.length>0&&(u=new Promise(e=>{m=e}));let e=!1;g=await new Promise((t,n)=>{let r=f((t,n)=>{if(e||(e=!0,_&&clearTimeout(_)),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);m?.(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}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){b=r;let n=`http://127.0.0.1:${i.port}`;_=setTimeout(()=>{if(!e)try{d(process.platform===`win32`?`start "" "${n}"`:process.platform===`darwin`?`open "${n}"`:`xdg-open "${n}"`)}catch{}},8e3),_.unref(),t(n)}else n(Error(`Failed to start present server`))}),setTimeout(()=>{r.close(),b===r&&(b=null)},300*1e3).unref()})}catch{}let v=g?`${s}\n\n---\n🌐 **Dashboard opened in browser:** ${g}\n\n**IMPORTANT:** You MUST now open this URL using the \`openBrowserPage\` tool (Simple Browser). 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.`:s;if(h.length>0&&a?.available&&u)try{let e=await Promise.race([u,new Promise((e,t)=>setTimeout(()=>t(Error(`timeout`)),300*1e3))]);return{content:[{type:`text`,text:`${v}\n\n✅ **Selected:** ${e.actionId} = \`${e.value}\``},l]}}catch{return{content:[{type:`text`,text:`${v}\n\n⚠️ *No selection received (timed out).*`},l]}}return{content:[{type:`text`,text:v},l]}}function T(e,r,i,a){let o=Array.isArray(i)?i:[],s=n(e,r);if(o.length>0){let e=[``];for(let t=0;t<o.length;t++){let n=o[t],r=typeof n.label==`string`?n.label:`Action ${t+1}`;if(n.type===`select`&&Array.isArray(n.options)){let i=n.options.map(e=>typeof e==`string`?e:e.label).join(`, `);e.push(`${t+1}. **${r}** — choose: ${i}`)}else e.push(`${t+1}. **${r}**`)}s+=`\n${e.join(`
19
+ `)}`}let c=p({uri:`ui://kb/present-static.html`,content:{type:`rawHtml`,htmlString:t(e,r,i,a)},encoding:`text`,adapters:{mcpApps:{enabled:!0}}});return{content:[{type:`text`,text:s},c],structuredContent:{title:e,content:r,actions:o}}}export{w as formatAsBrowser,T as formatAsHtml,S as getPresentHtml,C as registerPresentTool,x as resolvePresentHtml};
@@ -1,10 +1,10 @@
1
- import{getToolMeta as e}from"../tool-metadata.js";import{SearchOutputSchema as t}from"../output-schemas.js";import{fanOutFtsSearch as n,fanOutSearch as r,openWorkspaceStores as i,resolveWorkspaces as a}from"../cross-workspace.js";import{curatedResourceLink as o,extractCuratedPath as s}from"../resource-links.js";import{basename as c}from"node:path";import{stat as l}from"node:fs/promises";import{z as u}from"zod";import{CONTENT_TYPES as d,KNOWLEDGE_ORIGINS as f,SOURCE_TYPES as p,computePartitionKey as m,createLogger as h,serializeError as g}from"../../../core/dist/index.js";import{bookendReorder as _,graphAugmentSearch as v,stashGet as y,truncateToTokenBudget as ee}from"../../../tools/dist/index.js";import{mergeResults as b}from"../../../enterprise-bridge/dist/index.js";const x=h(`tools`);function S(e){let t=[],n=c(process.cwd());n&&t.push(`[project: ${n}]`);let r=y(`__context_boost`);return r&&t.push(`[focus: ${r.value}]`),t.length===0?e:`${t.join(` `)} ${e}`}async function C(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:b(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 x.warn(`ER fallback failed`,g(e)),{results:n,triggered:!0,cacheHit:a}}}function te(e,t,n=60){let r=new Map;for(let t=0;t<e.length;t++){let i=e[t];r.set(i.record.id,{record:i.record,score:1/(n+t+1)})}for(let e=0;e<t.length;e++){let i=t[e],a=r.get(i.record.id);a?a.score+=1/(n+e+1):r.set(i.record.id,{record:i.record,score:1/(n+e+1)})}return[...r.values()].sort((e,t)=>t.score-e.score).map(({record:e,score:t})=>({record:e,score:t}))}function w(e,t){let n=t.toLowerCase().split(/\s+/).filter(e=>e.length>=2);return n.length<2?e:e.map(e=>{let t=e.record.content.toLowerCase(),r=n.map(e=>{let n=[],r=t.indexOf(e);for(;r!==-1;)n.push(r),r=t.indexOf(e,r+1);return n});if(r.some(e=>e.length===0))return e;let i=t.length;for(let e of r[0]){let t=e,a=e+n[0].length;for(let i=1;i<r.length;i++){let o=r[i][0],s=Math.abs(o-e);for(let t=1;t<r[i].length;t++){let n=Math.abs(r[i][t]-e);n<s&&(s=n,o=r[i][t])}t=Math.min(t,o),a=Math.max(a,o+n[i].length)}i=Math.min(i,a-t)}let a=1+.25/(1+i/200);return{record:e.record,score:e.score*a}}).sort((e,t)=>t.score-e.score)}function T(e,t,n=8){let r=new Set(t.toLowerCase().split(/\s+/).filter(e=>e.length>=2)),i=new Map,a=e.length;for(let t of e){let e=new Set(t.record.content.split(/[^a-zA-Z0-9_]+/).filter(e=>e.length>=3&&!E.has(e.toLowerCase())));for(let t of e){let e=t.toLowerCase();/[_A-Z]/.test(t)&&i.set(`__id__${e}`,1)}let n=new Set(t.record.content.toLowerCase().split(/[^a-zA-Z0-9_]+/).filter(e=>e.length>=3&&!E.has(e)));for(let e of n)i.set(e,(i.get(e)??0)+1)}let o=[];for(let[e,t]of i){if(e.startsWith(`__id__`)||r.has(e)||t>a*.8)continue;let n=Math.log(a/t),s=i.has(`__id__${e}`)?1:0,c=e.length>8?.5:0;o.push({term:e,score:n+s+c})}return o.sort((e,t)=>t.score-e.score).slice(0,n).map(e=>e.term)}const E=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 D(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 l(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 O(c,l,h,y,b,E,O){let k=e(`search`);c.registerTool(`search`,{title:k.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:t,inputSchema:{query:u.string().max(5e3).describe(`Natural language search query`),limit:u.number().min(1).max(20).default(5).describe(`Maximum results to return`),search_mode:u.enum([`hybrid`,`semantic`,`keyword`]).default(`hybrid`).describe(`Search strategy: hybrid (vector + FTS + RRF fusion, default), semantic (vector only), keyword (FTS only)`),content_type:u.enum(d).optional().describe(`Filter by content type`),source_type:u.enum(p).optional().describe(`Coarse filter: "source" (code only), "documentation" (md, curated), "test", "config". Overrides content_type if both set.`),origin:u.enum(f).optional().describe(`Filter by knowledge origin`),category:u.string().optional().describe(`Filter by category (e.g., decisions, patterns, conventions)`),tags:u.array(u.string()).optional().describe(`Filter by tags (returns results matching ANY of the specified tags)`),min_score:u.number().min(0).max(1).default(.25).describe(`Minimum similarity score`),graph_hops:u.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:u.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`),dedup:u.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:u.array(u.string()).optional().describe(`Cross-workspace search: partition names or folder basenames to include. Use ["*"] for all registered workspaces. Only works in user-level install mode.`)},annotations:k.annotations},async({query:e,limit:t,search_mode:c,content_type:u,source_type:d,origin:f,category:p,tags:k,min_score:ne,graph_hops:A,max_tokens:j,dedup:M,workspaces:N})=>{try{let P={limit:t,minScore:ne,contentType:u,sourceType:d,origin:f,category:p,tags:k},F,I=!1,L=!1,R=``,z=S(e);if(c===`keyword`)F=await h.ftsSearch(e,P),F=F.slice(0,t);else if(c===`semantic`){let n=await l.embedQuery(z);F=await h.search(n,P);let r=await C(b,F[0]?.score??0,F,e,t);F=r.results,I=r.triggered,L=r.cacheHit}else{let n=await l.embedQuery(z),[r,i]=await Promise.all([h.search(n,{...P,limit:t*2}),h.ftsSearch(e,{...P,limit:t*2}).catch(()=>[])]);F=te(r,i).slice(0,t);let a=await C(b,r[0]?.score??0,F,e,t);F=a.results,I=a.triggered,L=a.cacheHit}E&&E.recordSearch(e,I,L),F.length>1&&(F=w(F,e));let B=``;if(N&&N.length>0){let o=a(N,m(process.cwd()));if(o.length>0){let{stores:a,closeAll:s}=await i(o);try{let i;i=c===`keyword`?await n(a,e,{...P,limit:t}):await r(a,await l.embedQuery(e),{...P,limit:t});for(let e of i)F.push({record:{...e.record,sourcePath:`[${e.workspace}] ${e.record.sourcePath}`},score:e.score});F=F.sort((e,t)=>t.score-e.score).slice(0,t),B=` + ${o.length} workspace(s)`}finally{await s()}}}if(M===`file`&&F.length>1){let e=new Map;for(let t of F){let n=t.record.sourcePath,r=e.get(n);r?(t.score>r.best.score&&(r.best=t),r.ranges.push({start:t.record.startLine,end:t.record.endLine})):e.set(n,{best:t,ranges:[{start:t.record.startLine,end:t.record.endLine}]})}F=[...e.values()].sort((e,t)=>t.best.score-e.best.score).map(({best:e,ranges:t})=>({record:{...e.record,content:t.length>1?`${e.record.content}\n\n_Matched ${t.length} sections: ${t.sort((e,t)=>e.start-t.start).map(e=>`L${e.start}-${e.end}`).join(`, `)}_`:e.record.content},score:e.score}))}if(F.length===0){if(O?.available)try{let t=(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(`
2
- `)[0].slice(0,500);if(t&&t!==e){let n=await l.embedQuery(t),r=await h.search(n,P);r.length>0&&(F=r,R=`> _Original query "${e}" returned 0 results. Auto-reformulated to "${t}"._\n\n`,x.info(`Smart search fallback succeeded`,{originalQuery:e,altQuery:t,resultCount:r.length}))}}catch(e){x.debug(`Smart search fallback failed`,{error:String(e)})}if(F.length===0)return{content:[{type:`text`,text:`No results found for the given query.`}],structuredContent:{results:[],totalResults:0,searchMode:c,query:e}}}let V,H;if(A>0&&!y&&(H="> **Note:** `graph_hops` was set but no graph store is available. Graph augmentation skipped."),A>0&&y)try{let e=await v(y,F.map(e=>({recordId:e.record.id,score:e.score,sourcePath:e.record.sourcePath})),{hops:A,maxPerHit:5});V=new Map;for(let t of e)if(t.graphContext.nodes.length>0){let e=t.graphContext.nodes.slice(0,5).map(e=>` - **${e.name}** (${e.type})`).join(`
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{SearchOutputSchema as t}from"../output-schemas.js";import{fanOutFtsSearch as n,fanOutSearch as r,openWorkspaceStores as i,resolveWorkspaces as a}from"../cross-workspace.js";import{curatedResourceLink as o,extractCuratedPath as s}from"../resource-links.js";import{basename as c}from"node:path";import{stat as l}from"node:fs/promises";import{z as u}from"zod";import{CONTENT_TYPES as d,KNOWLEDGE_ORIGINS as f,SOURCE_TYPES as p,computePartitionKey as m,createLogger as h,serializeError as g}from"../../../core/dist/index.js";import{bookendReorder as _,graphAugmentSearch as v,stashGet as y,truncateToTokenBudget as b}from"../../../tools/dist/index.js";import{mergeResults as x}from"../../../enterprise-bridge/dist/index.js";const S=h(`tools`);function ee(e){let t=[],n=c(process.cwd());n&&t.push(`[project: ${n}]`);let r=y(`__context_boost`);return r&&t.push(`[focus: ${r.value}]`),t.length===0?e:`${t.join(` `)} ${e}`}async function C(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:x(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 S.warn(`ER fallback failed`,g(e)),{results:n,triggered:!0,cacheHit:a}}}function te(e,t,n=60){let r=new Map;for(let t=0;t<e.length;t++){let i=e[t];r.set(i.record.id,{record:i.record,score:1/(n+t+1)})}for(let e=0;e<t.length;e++){let i=t[e],a=r.get(i.record.id);a?a.score+=1/(n+e+1):r.set(i.record.id,{record:i.record,score:1/(n+e+1)})}return[...r.values()].sort((e,t)=>t.score-e.score).map(({record:e,score:t})=>({record:e,score:t}))}function w(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 T(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&&!E.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}`)?1:0,c=e.length>8?.5:0;o.push({term:e,score:n+s+c})}return o.sort((e,t)=>t.score-e.score).slice(0,n).map(e=>e.term)}const E=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 D(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 l(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 O(c,l,h,y,x,E,O){let k=e(`search`);c.registerTool(`search`,{title:k.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:t,inputSchema:{query:u.string().max(5e3).describe(`Natural language search query`),limit:u.number().min(1).max(20).default(5).describe(`Maximum results to return`),search_mode:u.enum([`hybrid`,`semantic`,`keyword`]).default(`hybrid`).describe(`Search strategy: hybrid (vector + FTS + RRF fusion, default), semantic (vector only), keyword (FTS only)`),content_type:u.enum(d).optional().describe(`Filter by content type`),source_type:u.enum(p).optional().describe(`Coarse filter: "source" (code only), "documentation" (md, curated), "test", "config". Overrides content_type if both set.`),origin:u.enum(f).optional().describe(`Filter by knowledge origin`),category:u.string().optional().describe(`Filter by category (e.g., decisions, patterns, conventions)`),tags:u.array(u.string()).optional().describe(`Filter by tags (returns results matching ANY of the specified tags)`),min_score:u.number().min(0).max(1).default(.25).describe(`Minimum similarity score`),graph_hops:u.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:u.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`),dedup:u.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:u.array(u.string()).optional().describe(`Cross-workspace search: partition names or folder basenames to include. Use ["*"] for all registered workspaces. Only works in user-level install mode.`)},annotations:k.annotations},async({query:e,limit:t,search_mode:c,content_type:u,source_type:d,origin:f,category:p,tags:k,min_score:ne,graph_hops:A,max_tokens:j,dedup:M,workspaces:N})=>{try{let P={limit:t,minScore:ne,contentType:u,sourceType:d,origin:f,category:p,tags:k},F,I=!1,L=!1,R=``,z=ee(e);if(c===`keyword`)F=await h.ftsSearch(e,P),F=F.slice(0,t);else if(c===`semantic`){let n=await l.embedQuery(z);F=await h.search(n,P);let r=await C(x,F[0]?.score??0,F,e,t);F=r.results,I=r.triggered,L=r.cacheHit}else{let n=await l.embedQuery(z),[r,i]=await Promise.all([h.search(n,{...P,limit:t*2}),h.ftsSearch(e,{...P,limit:t*2}).catch(()=>[])]);F=te(r,i).slice(0,t);let a=await C(x,r[0]?.score??0,F,e,t);F=a.results,I=a.triggered,L=a.cacheHit}E&&E.recordSearch(e,I,L),F.length>1&&(F=w(F,e));let B=``;if(N&&N.length>0){let o=a(N,m(process.cwd()));if(o.length>0){let{stores:a,closeAll:s}=await i(o);try{let i;i=c===`keyword`?await n(a,e,{...P,limit:t}):await r(a,await l.embedQuery(e),{...P,limit:t});for(let e of i)F.push({record:{...e.record,sourcePath:`[${e.workspace}] ${e.record.sourcePath}`},score:e.score});F=F.sort((e,t)=>t.score-e.score).slice(0,t),B=` + ${o.length} workspace(s)`}finally{await s()}}}if(M===`file`&&F.length>1){let e=new Map;for(let t of F){let n=t.record.sourcePath,r=e.get(n);r?(t.score>r.best.score&&(r.best=t),r.ranges.push({start:t.record.startLine,end:t.record.endLine})):e.set(n,{best:t,ranges:[{start:t.record.startLine,end:t.record.endLine}]})}F=[...e.values()].sort((e,t)=>t.best.score-e.best.score).map(({best:e,ranges:t})=>({record:{...e.record,content:t.length>1?`${e.record.content}\n\n_Matched ${t.length} sections: ${t.sort((e,t)=>e.start-t.start).map(e=>`L${e.start}-${e.end}`).join(`, `)}_`:e.record.content},score:e.score}))}if(F.length===0){if(O?.available)try{let t=(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(`
2
+ `)[0].slice(0,500);if(t&&t!==e){let n=await l.embedQuery(t),r=await h.search(n,P);r.length>0&&(F=r,R=`> _Original query "${e}" returned 0 results. Auto-reformulated to "${t}"._\n\n`,S.info(`Smart search fallback succeeded`,{originalQuery:e,altQuery:t,resultCount:r.length}))}}catch(e){S.debug(`Smart search fallback failed`,{error:String(e)})}if(F.length===0)return{content:[{type:`text`,text:`No results found for the given query.`}],structuredContent:{results:[],totalResults:0,searchMode:c,query:e}}}let V,H;if(A>0&&!y&&(H="> **Note:** `graph_hops` was set but no graph store is available. Graph augmentation skipped."),A>0&&y)try{let e=await v(y,F.map(e=>({recordId:e.record.id,score:e.score,sourcePath:e.record.sourcePath})),{hops:A,maxPerHit:5});V=new Map;for(let t of e)if(t.graphContext.nodes.length>0){let e=t.graphContext.nodes.slice(0,5).map(e=>` - **${e.name}** (${e.type})`).join(`
3
3
  `),n=t.graphContext.edges.slice(0,5).map(e=>` - ${e.fromId} —[${e.type}]→ ${e.toId}`).join(`
4
4
  `),r=[`- **Graph Context** (${A} hop${A>1?`s`:``}):`];e&&r.push(` Entities:\n${e}`),n&&r.push(` Relationships:\n${n}`),V.set(t.recordId,r.join(`
5
- `))}}catch(e){x.warn(`Graph augmentation failed`,g(e)),H=`> **Note:** Graph augmentation failed. Results shown without graph context.`}let U=Date.now();for(let e of F)if(e.record.origin===`curated`&&e.record.indexedAt){let t=U-new Date(e.record.indexedAt).getTime(),n=Math.max(0,t/864e5);e.score*=.95**n}F.sort((e,t)=>t.score-e.score),F=_(F);let W=F.map((e,t)=>{let n=e.record;return`${`### Result ${t+1} (score: ${e.score.toFixed(3)})`}\n${[`- **Source**: ${n.sourcePath}`,n.headingPath?`- **Section**: ${n.headingPath}`:null,`- **Type**: ${n.contentType}`,n.startLine?`- **Lines**: ${n.startLine}-${n.endLine}`:null,n.origin===`indexed`?null:`- **Origin**: ${n.origin}`,n.category?`- **Category**: ${n.category}`:null,n.tags?.length?`- **Tags**: ${n.tags.join(`, `)}`:null,V?.get(n.id)??null].filter(Boolean).join(`
5
+ `))}}catch(e){S.warn(`Graph augmentation failed`,g(e)),H=`> **Note:** Graph augmentation failed. Results shown without graph context.`}let U=Date.now();for(let e of F)if(e.record.origin===`curated`&&e.record.indexedAt){let t=U-new Date(e.record.indexedAt).getTime(),n=Math.max(0,t/864e5);e.score*=.95**n}F.sort((e,t)=>t.score-e.score),F=_(F);let W=F.map((e,t)=>{let n=e.record;return`${`### Result ${t+1} (score: ${e.score.toFixed(3)})`}\n${[`- **Source**: ${n.sourcePath}`,n.headingPath?`- **Section**: ${n.headingPath}`:null,`- **Type**: ${n.contentType}`,n.startLine?`- **Lines**: ${n.startLine}-${n.endLine}`:null,n.origin===`indexed`?null:`- **Origin**: ${n.origin}`,n.category?`- **Category**: ${n.category}`:null,n.tags?.length?`- **Tags**: ${n.tags.join(`, `)}`:null,V?.get(n.id)??null].filter(Boolean).join(`
6
6
  `)}\n\n${n.content}`}).join(`
7
7
 
8
8
  ---
9
9
 
10
- `),G=(c===`hybrid`?`hybrid (vector + keyword RRF)`:c===`keyword`?`keyword (FTS)`:`semantic (vector)`)+B,K=T(F,e),q=K.length>0?`\n_Distinctive terms: ${K.map(e=>`\`${e}\``).join(`, `)}_`:``,J=await D(h,F),Y=[];if(F.length===0)Y.push("`reindex` — no results found, index may be stale"),Y.push("`find` — try federated search with glob/regex");else{let e=F[0]?.record.sourcePath;e&&Y.push(`\`lookup\` — see all chunks from \`${e}\``),Y.push("`symbol` — resolve a specific symbol from the results"),Y.push("`compact` — compress a result file for focused reading")}let X=[H?`${H}\n\n`:``,J?`${J}\n\n`:``,W,`\n\n---\n_Search mode: ${G} | ${F.length} results_${q}`,`\n_Next: ${Y.join(` | `)}_`],Z=R+X.join(``);j&&(Z=ee(Z,j));let Q=new Set,$=[];for(let e of F){if(e.record.origin!==`curated`||e.record.sourcePath.startsWith(`[`))continue;let t=s(e.record.sourcePath);if(!t)continue;let n=o(t,e.record.headingPath??t);n&&!Q.has(n.uri)&&(Q.add(n.uri),$.push(n))}return{content:[{type:`text`,text:Z},...$],structuredContent:{results:F.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:F.length,searchMode:c,query:e}}}catch(e){return x.error(`Search failed`,g(e)),{content:[{type:`text`,text:`Search failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{O as registerSearchTool};
10
+ `),G=(c===`hybrid`?`hybrid (vector + keyword RRF)`:c===`keyword`?`keyword (FTS)`:`semantic (vector)`)+B,K=T(F,e),q=K.length>0?`\n_Distinctive terms: ${K.map(e=>`\`${e}\``).join(`, `)}_`:``,J=await D(h,F),Y=[];if(F.length===0)Y.push("`reindex` — no results found, index may be stale"),Y.push("`find` — try federated search with glob/regex");else{let e=F[0]?.record.sourcePath;e&&Y.push(`\`lookup\` — see all chunks from \`${e}\``),Y.push("`symbol` — resolve a specific symbol from the results"),Y.push("`compact` — compress a result file for focused reading")}let X=[H?`${H}\n\n`:``,J?`${J}\n\n`:``,W,`\n\n---\n_Search mode: ${G} | ${F.length} results_${q}`,`\n_Next: ${Y.join(` | `)}_`],Z=R+X.join(``);j&&(Z=b(Z,j));let Q=new Set,$=[];for(let e of F){if(e.record.origin!==`curated`||e.record.sourcePath.startsWith(`[`))continue;let t=s(e.record.sourcePath);if(!t)continue;let n=o(t,e.record.headingPath??t);n&&!Q.has(n.uri)&&(Q.add(n.uri),$.push(n))}return{content:[{type:`text`,text:Z},...$],structuredContent:{results:F.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:F.length,searchMode:c,query:e}}}catch(e){return S.error(`Search failed`,g(e)),{content:[{type:`text`,text:`Search failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{O as registerSearchTool};
@@ -1,3 +1,3 @@
1
- import{getGcStatus as e}from"../auto-gc.js";import{getToolTelemetry as t}from"../replay-interceptor.js";import{getToolMeta as n}from"../tool-metadata.js";import{StatusOutputSchema as r}from"../output-schemas.js";import{autoUpgradeScaffold as i,getCurrentVersion as a,getUpgradeState as o}from"../version-check.js";import{existsSync as s,readFileSync as c,statSync as l}from"node:fs";import{resolve as u}from"node:path";import{AIKIT_PATHS as d,createLogger as f,serializeError as p}from"../../../core/dist/index.js";import{WasmRuntime as m}from"../../../chunker/dist/index.js";import{homedir as h}from"node:os";const g=f(`tools`);function _(e,t,n,r=4e3){let i,a=new Promise(e=>{i=setTimeout(()=>{g.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),g.warn(`Status sub-operation "${n}" failed: ${e instanceof Error?e.message:String(e)}`),{value:t,timedOut:!1})),a])}function v(){try{let e=u(h(),`.copilot`,`.aikit-scaffold.json`);return s(e)?JSON.parse(c(e,`utf-8`)).version??null:null}catch{return null}}function y(){try{let e=u(process.cwd(),`.github`,`.aikit-scaffold.json`);return s(e)?JSON.parse(c(e,`utf-8`)).version??null:null}catch{return null}}function b(e){let t=n(`status`);e.registerTool(`status`,{title:t.title,description:`Get the current status and statistics of the AI Kit index.`,outputSchema:r,annotations:t.annotations},async()=>{let e=a(),t=v(),n=y(),r=t!=null&&t!==e,s=n!=null&&n!==e,c=[`## AI Kit Status`,``,`⏳ **AI Kit is initializing** — index stats will be available shortly.`,``,`### Runtime`,`- **Tree-sitter (WASM)**: ${m.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`,``,`### Version`,`- **Server**: ${e}`,`- **Scaffold (user)**: ${t??`not installed`}`,`- **Scaffold (workspace)**: ${n??`not installed`}`];if(r||s){let a=o(),l=[];r&&l.push(`user scaffold v${t}`),s&&l.push(`workspace scaffold v${n}`);let u=l.join(`, `);a.state===`success`?c.push(``,`### ✅ Upgrade Applied`,`- Server v${e} — ${u} auto-upgraded successfully.`,`- _Restart the MCP server to use the updated version._`):a.state===`pending`?c.push(``,`### ⏳ Upgrade In Progress`,`- Server v${e} ≠ ${u}`,`- Auto-upgrade is running in the background…`):a.state===`failed`?(i(),c.push(``,`### ⬆ Upgrade Available (auto-upgrade failed, retrying)`,`- Server v${e} ≠ ${u}`,`- Error: ${a.error??`unknown`}`)):(i(),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:!!m.get(),graphStats:null,curatedCount:0,serverVersion:e,scaffoldVersion:t??null,workspaceScaffoldVersion:n??null,upgradeAvailable:r||s};return{content:[{type:`text`,text:c.join(`
2
- `)}],structuredContent:l}})}function x(c,f,h,b,x,S){let C=n(`status`);c.registerTool(`status`,{title:C.title,description:`Get the current status and statistics of the AI Kit index.`,outputSchema:r,annotations:C.annotations},async()=>{let n=[];try{let r=await _(f.getStats(),{totalRecords:0,totalFiles:0,lastIndexedAt:null,contentTypeBreakdown:{}},`store.getStats`),c=r.value;r.timedOut&&n.push(`⚠ Index stats timed out — values may be incomplete`);let p=await _(f.listSourcePaths(),[],`store.listSourcePaths`),g=p.value;p.timedOut&&n.push(`⚠ File listing timed out`);let C=null,w=0,T=[`## AI Kit Status`,``,`- **Total Records**: ${c.totalRecords}`,`- **Total Files**: ${c.totalFiles}`,`- **Last Indexed**: ${c.lastIndexedAt??`Never`}`,``,`### Content Types`,...Object.entries(c.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(h)try{let e=await _(h.getStats(),{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}},`graphStore.getStats`);if(e.timedOut)n.push(`⚠ Graph stats timed out`),T.push(``,`### Knowledge Graph`,`- Graph stats timed out`);else{let t=e.value;C={nodes:t.nodeCount,edges:t.edgeCount},T.push(``,`### Knowledge Graph`,`- **Nodes**: ${t.nodeCount}`,`- **Edges**: ${t.edgeCount}`,...Object.entries(t.nodeTypes).map(([e,t])=>` - ${e}: ${t}`));try{let e=await _(h.validate(),{valid:!0,danglingEdges:[],orphanNodes:[],stats:{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}}},`graphStore.validate`);if(!e.timedOut){let t=e.value;t.valid||T.push(`- **⚠ Integrity Issues**: ${t.danglingEdges.length} dangling edges`),t.orphanNodes.length>0&&T.push(`- **Orphan nodes**: ${t.orphanNodes.length}`)}}catch{}}}catch{T.push(``,`### Knowledge Graph`,`- Graph store unavailable`)}let E=S?.onboardDir??u(process.cwd(),d.aiKb),D=s(E),O=x?.onboardComplete??D;if(T.push(``,`### Onboard Status`,O?`- ✅ Complete${x?.onboardTimestamp?` (last: ${x.onboardTimestamp})`:``}`:'- ❌ Not run — call `onboard({ path: "." })` to analyze the codebase',`- **Onboard Directory**: \`${E}\``),b)try{let e=await _(b.list(),[],`curated.list`);if(e.timedOut)n.push(`⚠ Curated knowledge listing timed out`),T.push(``,`### Curated Knowledge`,`- Listing timed out`);else{let t=e.value;w=t.length,T.push(``,`### Curated Knowledge`,t.length>0?`- ${t.length} entries`:"- Empty — use `remember()` to persist decisions")}}catch{T.push(``,`### Curated Knowledge`,`- Unable to read curated entries`)}let k=0;if(c.lastIndexedAt){k=new Date(c.lastIndexedAt).getTime();let e=(Date.now()-k)/(1e3*60*60);T.push(``,`### Index Freshness`,e>24?`- ⚠ Last indexed ${Math.floor(e)}h ago — may be stale. Run \`reindex({})\``:`- ✅ Last indexed ${e<1?`less than 1h`:`${Math.floor(e)}h`} ago`)}{try{let e=u(process.cwd(),d.data,`stash`);if(s(e)){let t=l(e).mtimeMs;t>k&&(k=t)}}catch{}let e=[];if(b)try{let t=w>0?await b.list():[];for(let e of t){let t=new Date(e.updated||e.created).getTime();t>k&&(k=t)}e.push(...t.sort((e,t)=>new Date(t.updated).getTime()-new Date(e.updated).getTime()).slice(0,5))}catch{}let t=k>0?Date.now()-k:0;if(t>=144e5){let n=Math.floor(t/36e5);if(T.push(``,`### 🌅 Session Briefing`,`_${n}+ hours since last activity — here's what to pick up:_`,``),e.length>0){T.push(`**Recent decisions/notes:**`);for(let t of e)T.push(`- **${t.title}** (${t.category??`note`}) — ${(t.contentPreview??``).slice(0,80)}…`)}T.push(``,`**Suggested next steps:**`,'- `search({ query: "SESSION CHECKPOINT", origin: "curated" })` — find your last checkpoint',"- `restore({})` — resume from a saved checkpoint","- `list()` — browse all stored knowledge")}}T.push(``,`### Runtime`,`- **Tree-sitter (WASM)**: ${m.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`);let A=v(),j=y(),M=a(),N=A!=null&&A!==M,P=j!=null&&j!==M;if(N||P){let e=o(),t=[];N&&t.push(`user scaffold v${A}`),P&&t.push(`workspace scaffold v${j}`);let n=t.join(`, `);e.state===`success`?T.push(``,`### ✅ Upgrade Applied`,`- Server v${M} — ${n} auto-upgraded successfully.`,`- _Restart the MCP server to use the updated version._`):e.state===`pending`?T.push(``,`### ⏳ Upgrade In Progress`,`- Server v${M} ≠ ${n}`,`- Auto-upgrade is running in the background…`):e.state===`failed`?(i(),T.push(``,`### ⬆ Upgrade Available (auto-upgrade failed, retrying)`,`- Server v${M} ≠ ${n}`,`- Error: ${e.error??`unknown`}`)):(i(),T.push(``,`### ⬆ Upgrade Available`,`- Server v${M} ≠ ${n}`,`- Auto-upgrade triggered — check again shortly.`))}n.length>0&&T.push(``,`### ⚠ Warnings`,...n.map(e=>`- ${e}`));let F=t();if(F.length>0){let e=F.sort((e,t)=>t.callCount-e.callCount);T.push(``,`### Tool Usage This Session`,``),T.push(`| Tool | Calls | Tokens In | Tokens Out | Errors | Avg Latency |`),T.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);T.push(`| ${t.tool} | ${t.callCount} | ${e.toLocaleString()} | ${n.toLocaleString()} | ${t.errorCount} | ${r}ms |`)}}let I=e();if(I.bufferSize>=10){let e=I.state===`healthy`?`🟢`:I.state===`degraded`?`🔴`:`🟡`;T.push(``,`### Auto-GC: ${e} ${I.state}`),T.push(`- p95 latency: ${I.p95}ms | buffer: ${I.bufferSize} samples`),I.gcCount>0&&T.push(`- GC cycles triggered: ${I.gcCount}`)}let L=T.join(`
3
- `),R={totalRecords:c.totalRecords,totalFiles:c.totalFiles,lastIndexedAt:c.lastIndexedAt??null,onboarded:O,onboardDir:E,contentTypes:c.contentTypeBreakdown,wasmAvailable:!!m.get(),graphStats:C,curatedCount:w,serverVersion:M,scaffoldVersion:A??null,workspaceScaffoldVersion:j??null,upgradeAvailable:N||P};return{content:[{type:`text`,text:L+"\n\n---\n_Next: Use `search` to query indexed content, `graph(stats)` to explore the knowledge graph, or `reindex` to refresh the index._"}],structuredContent:R}}catch(e){return g.error(`Status failed`,p(e)),{content:[{type:`text`,text:`Status check failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{v as getScaffoldVersion,y as getWorkspaceScaffoldVersion,b as registerEarlyStatusTool,x as registerStatusTool};
1
+ import{getGcStatus as e}from"../auto-gc.js";import{getToolTelemetry as t}from"../replay-interceptor.js";import{getToolMeta as n}from"../tool-metadata.js";import{StatusOutputSchema as r}from"../output-schemas.js";import{autoUpgradeScaffold as i,getCurrentVersion as a,getUpgradeState as o}from"../version-check.js";import{existsSync as s,readFileSync as c,statSync as l}from"node:fs";import{resolve as u}from"node:path";import{AIKIT_PATHS as d,createLogger as f,serializeError as p}from"../../../core/dist/index.js";import{WasmRuntime as m}from"../../../chunker/dist/index.js";import{homedir as h}from"node:os";const g=f(`tools`);function _(e,t,n,r=15e3){let i,a=new Promise(e=>{i=setTimeout(()=>{g.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),g.warn(`Status sub-operation "${n}" failed: ${e instanceof Error?e.message:String(e)}`),{value:t,timedOut:!1})),a])}const v=5*6e4;let y=null,b=null;function x(){let e=Date.now();if(y&&e-y.ts<v)return y.value;try{let t=u(h(),`.copilot`,`.aikit-scaffold.json`);if(!s(t))return y={value:null,ts:e},null;let n=JSON.parse(c(t,`utf-8`)).version??null;return y={value:n,ts:e},n}catch{return y={value:null,ts:e},null}}function S(){let e=Date.now();if(b&&e-b.ts<v)return b.value;try{let t=u(process.cwd(),`.github`,`.aikit-scaffold.json`);if(!s(t))return b={value:null,ts:e},null;let n=JSON.parse(c(t,`utf-8`)).version??null;return b={value:n,ts:e},n}catch{return b={value:null,ts:e},null}}function C(e){let t=n(`status`);e.registerTool(`status`,{title:t.title,description:`Get the current status and statistics of the AI Kit index.`,outputSchema:r,annotations:t.annotations},async()=>{let e=a(),t=x(),n=S(),r=t!=null&&t!==e,s=n!=null&&n!==e,c=[`## AI Kit Status`,``,`⏳ **AI Kit is initializing** — index stats will be available shortly.`,``,`### Runtime`,`- **Tree-sitter (WASM)**: ${m.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`,``,`### Version`,`- **Server**: ${e}`,`- **Scaffold (user)**: ${t??`not installed`}`,`- **Scaffold (workspace)**: ${n??`not installed`}`];if(r||s){let a=o(),l=[];r&&l.push(`user scaffold v${t}`),s&&l.push(`workspace scaffold v${n}`);let u=l.join(`, `);a.state===`success`?c.push(``,`### ✅ Upgrade Applied`,`- Server v${e} — ${u} auto-upgraded successfully.`,`- _Restart the MCP server to use the updated version._`):a.state===`pending`?c.push(``,`### ⏳ Upgrade In Progress`,`- Server v${e} ≠ ${u}`,`- Auto-upgrade is running in the background…`):a.state===`failed`?(i(),c.push(``,`### ⬆ Upgrade Available (auto-upgrade failed, retrying)`,`- Server v${e} ≠ ${u}`,`- Error: ${a.error??`unknown`}`)):(i(),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:!!m.get(),graphStats:null,curatedCount:0,serverVersion:e,scaffoldVersion:t??null,workspaceScaffoldVersion:n??null,upgradeAvailable:r||s};return{content:[{type:`text`,text:c.join(`
2
+ `)}],structuredContent:l}})}function w(c,f,h,v,y,b){let C=n(`status`);c.registerTool(`status`,{title:C.title,description:`Get the current status and statistics of the AI Kit index.`,outputSchema:r,annotations:C.annotations},async()=>{let n=[];try{let[r,c]=await Promise.all([_(f.getStats(),{totalRecords:0,totalFiles:0,lastIndexedAt:null,contentTypeBreakdown:{}},`store.getStats`),_(f.listSourcePaths(),[],`store.listSourcePaths`)]),p=r.value;r.timedOut&&n.push(`⚠ Index stats timed out — values may be incomplete`);let g=c.value;c.timedOut&&n.push(`⚠ File listing timed out`);let C=null,w=0,T=[`## AI Kit Status`,``,`- **Total Records**: ${p.totalRecords}`,`- **Total Files**: ${p.totalFiles}`,`- **Last Indexed**: ${p.lastIndexedAt??`Never`}`,``,`### Content Types`,...Object.entries(p.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(h)try{let e=await _(h.getStats(),{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}},`graphStore.getStats`);if(e.timedOut)n.push(`⚠ Graph stats timed out`),T.push(``,`### Knowledge Graph`,`- Graph stats timed out`);else{let t=e.value;C={nodes:t.nodeCount,edges:t.edgeCount},T.push(``,`### Knowledge Graph`,`- **Nodes**: ${t.nodeCount}`,`- **Edges**: ${t.edgeCount}`,...Object.entries(t.nodeTypes).map(([e,t])=>` - ${e}: ${t}`));try{let e=await _(h.validate(),{valid:!0,danglingEdges:[],orphanNodes:[],stats:{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}}},`graphStore.validate`);if(!e.timedOut){let t=e.value;t.valid||T.push(`- **⚠ Integrity Issues**: ${t.danglingEdges.length} dangling edges`),t.orphanNodes.length>0&&T.push(`- **Orphan nodes**: ${t.orphanNodes.length}`)}}catch{}}}catch{T.push(``,`### Knowledge Graph`,`- Graph store unavailable`)}let E=b?.onboardDir??u(process.cwd(),d.aiKb),D=s(E),O=y?.onboardComplete??D;if(T.push(``,`### Onboard Status`,O?`- ✅ Complete${y?.onboardTimestamp?` (last: ${y.onboardTimestamp})`:``}`:'- ❌ Not run — call `onboard({ path: "." })` to analyze the codebase',`- **Onboard Directory**: \`${E}\``),v)try{let e=await _(v.list(),[],`curated.list`);if(e.timedOut)n.push(`⚠ Curated knowledge listing timed out`),T.push(``,`### Curated Knowledge`,`- Listing timed out`);else{let t=e.value;w=t.length,T.push(``,`### Curated Knowledge`,t.length>0?`- ${t.length} entries`:"- Empty — use `remember()` to persist decisions")}}catch{T.push(``,`### Curated Knowledge`,`- Unable to read curated entries`)}let k=0;if(p.lastIndexedAt){k=new Date(p.lastIndexedAt).getTime();let e=(Date.now()-k)/(1e3*60*60);T.push(``,`### Index Freshness`,e>24?`- ⚠ Last indexed ${Math.floor(e)}h ago — may be stale. Run \`reindex({})\``:`- ✅ Last indexed ${e<1?`less than 1h`:`${Math.floor(e)}h`} ago`)}{try{let e=u(process.cwd(),d.data,`stash`);if(s(e)){let t=l(e).mtimeMs;t>k&&(k=t)}}catch{}let e=[];if(v)try{let t=w>0?await v.list():[];for(let e of t){let t=new Date(e.updated||e.created).getTime();t>k&&(k=t)}e.push(...t.sort((e,t)=>new Date(t.updated).getTime()-new Date(e.updated).getTime()).slice(0,5))}catch{}let t=k>0?Date.now()-k:0;if(t>=144e5){let n=Math.floor(t/36e5);if(T.push(``,`### 🌅 Session Briefing`,`_${n}+ hours since last activity — here's what to pick up:_`,``),e.length>0){T.push(`**Recent decisions/notes:**`);for(let t of e)T.push(`- **${t.title}** (${t.category??`note`}) — ${(t.contentPreview??``).slice(0,80)}…`)}T.push(``,`**Suggested next steps:**`,'- `search({ query: "SESSION CHECKPOINT", origin: "curated" })` — find your last checkpoint',"- `restore({})` — resume from a saved checkpoint","- `list()` — browse all stored knowledge")}}T.push(``,`### Runtime`,`- **Tree-sitter (WASM)**: ${m.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`);let A=x(),j=S(),M=a(),N=A!=null&&A!==M,P=j!=null&&j!==M;if(N||P){let e=o(),t=[];N&&t.push(`user scaffold v${A}`),P&&t.push(`workspace scaffold v${j}`);let n=t.join(`, `);e.state===`success`?T.push(``,`### ✅ Upgrade Applied`,`- Server v${M} — ${n} auto-upgraded successfully.`,`- _Restart the MCP server to use the updated version._`):e.state===`pending`?T.push(``,`### ⏳ Upgrade In Progress`,`- Server v${M} ≠ ${n}`,`- Auto-upgrade is running in the background…`):e.state===`failed`?(i(),T.push(``,`### ⬆ Upgrade Available (auto-upgrade failed, retrying)`,`- Server v${M} ≠ ${n}`,`- Error: ${e.error??`unknown`}`)):(i(),T.push(``,`### ⬆ Upgrade Available`,`- Server v${M} ≠ ${n}`,`- Auto-upgrade triggered — check again shortly.`))}n.length>0&&T.push(``,`### ⚠ Warnings`,...n.map(e=>`- ${e}`));let F=t();if(F.length>0){let e=F.sort((e,t)=>t.callCount-e.callCount);T.push(``,`### Tool Usage This Session`,``),T.push(`| Tool | Calls | Tokens In | Tokens Out | Errors | Avg Latency |`),T.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);T.push(`| ${t.tool} | ${t.callCount} | ${e.toLocaleString()} | ${n.toLocaleString()} | ${t.errorCount} | ${r}ms |`)}}let I=e();if(I.bufferSize>=10){let e=I.state===`healthy`?`🟢`:I.state===`degraded`?`🔴`:`🟡`;T.push(``,`### Auto-GC: ${e} ${I.state}`),T.push(`- p95 latency: ${I.p95}ms | buffer: ${I.bufferSize} samples`),I.gcCount>0&&T.push(`- GC cycles triggered: ${I.gcCount}`)}let L=T.join(`
3
+ `),R={totalRecords:p.totalRecords,totalFiles:p.totalFiles,lastIndexedAt:p.lastIndexedAt??null,onboarded:O,onboardDir:E,contentTypes:p.contentTypeBreakdown,wasmAvailable:!!m.get(),graphStats:C,curatedCount:w,serverVersion:M,scaffoldVersion:A??null,workspaceScaffoldVersion:j??null,upgradeAvailable:N||P};return{content:[{type:`text`,text:L+"\n\n---\n_Next: Use `search` to query indexed content, `graph(stats)` to explore the knowledge graph, or `reindex` to refresh the index._"}],structuredContent:R}}catch(e){return g.error(`Status failed`,p(e)),{content:[{type:`text`,text:`Status check failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{x as getScaffoldVersion,S as getWorkspaceScaffoldVersion,C as registerEarlyStatusTool,w as registerStatusTool};
@@ -4,11 +4,14 @@ import { GraphEdge, GraphNode, GraphStats, GraphTraversalOptions, GraphTraversal
4
4
  declare class SqliteGraphStore implements IGraphStore {
5
5
  private db;
6
6
  private readonly dbPath;
7
+ private sqlFactory;
7
8
  private dirty;
8
9
  constructor(options?: {
9
10
  path?: string;
10
11
  });
11
12
  initialize(): Promise<void>;
13
+ private configureDb;
14
+ private createTables;
12
15
  private ensureDb;
13
16
  private persist;
14
17
  private markDirty;
@@ -1,4 +1,4 @@
1
- import{AIKIT_PATHS as e}from"../../core/dist/index.js";import{existsSync as t,mkdirSync as n,readFileSync as r,writeFileSync as i}from"node:fs";import{dirname as a,join as o}from"node:path";var s=class{db=null;dbPath;dirty=!1;constructor(t){this.dbPath=o(t?.path??e.data,`graph.db`)}async initialize(){let e=a(this.dbPath);t(e)||n(e,{recursive:!0});let i=(await import(`sql.js`)).default,o=await i();if(t(this.dbPath)){let e=r(this.dbPath);this.db=new o.Database(e)}else this.db=new o.Database;this.db.run(`PRAGMA journal_mode = WAL`),this.db.exec(`PRAGMA foreign_keys = ON;`),this.db.run(`
1
+ import{AIKIT_PATHS as e}from"../../core/dist/index.js";import{existsSync as t,mkdirSync as n,readFileSync as r,writeFileSync as i}from"node:fs";import{dirname as a,join as o}from"node:path";var s=class{db=null;dbPath;sqlFactory=null;dirty=!1;constructor(t){this.dbPath=o(t?.path??e.data,`graph.db`)}async initialize(){let e=a(this.dbPath);t(e)||n(e,{recursive:!0});let i=(await import(`sql.js`)).default,o=await i();if(this.sqlFactory=o,t(this.dbPath)){let e=r(this.dbPath);this.db=new o.Database(e)}else this.db=new o.Database;this.configureDb(this.db),this.createTables(this.db),this.persist()}configureDb(e){e.run(`PRAGMA journal_mode = WAL`),e.exec(`PRAGMA foreign_keys = ON;`)}createTables(e){e.run(`
2
2
  CREATE TABLE IF NOT EXISTS nodes (
3
3
  id TEXT PRIMARY KEY,
4
4
  type TEXT NOT NULL,
@@ -8,7 +8,7 @@ import{AIKIT_PATHS as e}from"../../core/dist/index.js";import{existsSync as t,mk
8
8
  source_path TEXT,
9
9
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
10
10
  )
11
- `),this.db.run(`
11
+ `),e.run(`
12
12
  CREATE TABLE IF NOT EXISTS edges (
13
13
  id TEXT PRIMARY KEY,
14
14
  from_id TEXT NOT NULL,
@@ -19,7 +19,7 @@ import{AIKIT_PATHS as e}from"../../core/dist/index.js";import{existsSync as t,mk
19
19
  FOREIGN KEY (from_id) REFERENCES nodes(id) ON DELETE CASCADE,
20
20
  FOREIGN KEY (to_id) REFERENCES nodes(id) ON DELETE CASCADE
21
21
  )
22
- `),this.db.run(`CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type)`),this.db.run(`CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name)`),this.db.run(`CREATE INDEX IF NOT EXISTS idx_nodes_source_path ON nodes(source_path)`),this.db.run(`CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id)`),this.db.run(`CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id)`),this.db.run(`CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type)`),this.persist()}ensureDb(){if(!this.db)throw Error(`Graph store not initialized — call initialize() first`);return this.db}persist(){if(!this.db)return;let e=this.db.export();try{i(this.dbPath,Buffer.from(e))}finally{this.db.exec(`PRAGMA foreign_keys = ON;`)}this.dirty=!1}markDirty(){this.dirty=!0}flushIfDirty(){this.dirty&&this.persist()}query(e,t=[]){let n=this.ensureDb().prepare(e);n.bind(t);let r=[];try{for(;n.step();)r.push(n.getAsObject())}finally{n.free()}return r}run(e,t=[]){this.ensureDb().run(e,t)}async upsertNode(e){this.run(`INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at)
22
+ `),e.run(`CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type)`),e.run(`CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name)`),e.run(`CREATE INDEX IF NOT EXISTS idx_nodes_source_path ON nodes(source_path)`),e.run(`CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id)`),e.run(`CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id)`),e.run(`CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type)`)}ensureDb(){if(!this.db){if(!this.sqlFactory)throw Error(`Graph store not initialized — call initialize() first`);this.db=t(this.dbPath)?new this.sqlFactory.Database(r(this.dbPath)):new this.sqlFactory.Database,this.configureDb(this.db),this.createTables(this.db)}return this.db}persist(){if(!this.db)return;let e=this.db.export();try{i(this.dbPath,Buffer.from(e))}finally{this.db.exec(`PRAGMA foreign_keys = ON;`)}this.dirty=!1}markDirty(){this.dirty=!0}flushIfDirty(){this.dirty&&this.persist()}query(e,t=[]){let n=this.ensureDb().prepare(e);n.bind(t);let r=[];try{for(;n.step();)r.push(n.getAsObject())}finally{n.free()}return r}run(e,t=[]){this.ensureDb().run(e,t)}async upsertNode(e){this.run(`INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at)
23
23
  VALUES (?, ?, ?, ?, ?, ?, ?)
24
24
  ON CONFLICT(id) DO UPDATE SET
25
25
  type = excluded.type, name = excluded.name, properties = excluded.properties,
@@ -1 +1 @@
1
- import{resolve as e}from"node:path";import{existsSync as t,mkdirSync as n,readFileSync as r,readdirSync as i,writeFileSync as a}from"node:fs";import{resolveStateDir as o}from"../../core/dist/index.js";function s(r){let i=e(o(r??process.cwd()),`checkpoints`);return t(i)||n(i,{recursive:!0}),i}function c(t,n,r){let i=t.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-|-$/g,``)||`checkpoint`,o={id:`${Date.now()}-${i}`,label:t,createdAt:new Date().toISOString(),data:n,files:r?.files,notes:r?.notes};return a(e(s(r?.cwd),`${o.id}.json`),`${JSON.stringify(o,null,2)}\n`,`utf-8`),o}function l(n,i){let a=s(i),o=e(a,`${n}.json`);if(o.startsWith(e(a))&&t(o))try{return JSON.parse(r(o,`utf-8`))}catch{return}}function u(t){let n=s(t);return i(n).filter(e=>e.endsWith(`.json`)).flatMap(t=>{try{return[JSON.parse(r(e(n,t),`utf-8`))]}catch{return[]}}).sort((e,t)=>t.createdAt.localeCompare(e.createdAt))}function d(e){return u(e)[0]}export{d as checkpointLatest,u as checkpointList,l as checkpointLoad,c as checkpointSave};
1
+ import{resolve as e}from"node:path";import{existsSync as t,mkdirSync as n,readFileSync as r,readdirSync as i,renameSync as a,writeFileSync as o}from"node:fs";import{resolveStateDir as s}from"../../core/dist/index.js";function c(r){let i=e(s(r??process.cwd()),`checkpoints`);return t(i)||n(i,{recursive:!0}),i}function l(t,n,r){let i=t.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-|-$/g,``)||`checkpoint`,s={id:`${Date.now()}-${i}`,label:t,createdAt:new Date().toISOString(),data:n,files:r?.files,notes:r?.notes},l=e(c(r?.cwd),`${s.id}.json`),u=`${l}.tmp`;return o(u,`${JSON.stringify(s,null,2)}\n`,`utf-8`),a(u,l),s}function u(n,i){let a=c(i),o=e(a,`${n}.json`);if(o.startsWith(e(a))&&t(o))try{return JSON.parse(r(o,`utf-8`))}catch(e){if(e?.code===`ENOENT`)return;console.warn(`Corrupt state file ${o}: ${e instanceof Error?e.message:String(e)}`);return}}function d(t){let n=c(t);return i(n).filter(e=>e.endsWith(`.json`)).flatMap(t=>{let i=e(n,t);try{return[JSON.parse(r(i,`utf-8`))]}catch(e){return e?.code===`ENOENT`||console.warn(`Corrupt state file ${i}: ${e instanceof Error?e.message:String(e)}`),[]}}).sort((e,t)=>t.createdAt.localeCompare(e.createdAt))}function f(e){return d(e)[0]}export{f as checkpointLatest,d as checkpointList,u as checkpointLoad,l as checkpointSave};