@vpxa/aikit 0.1.9 → 0.1.10

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 (28) hide show
  1. package/package.json +1 -1
  2. package/packages/server/dist/server.js +2 -2
  3. package/packages/server/dist/tools/analyze.tools.js +3 -3
  4. package/packages/server/dist/tools/flow.tools.js +1 -1
  5. package/packages/server/dist/tools/onboard.tool.js +1 -1
  6. package/packages/server/dist/tools/present/templates.js +6 -6
  7. package/packages/server/dist/tools/search.tool.js +2 -2
  8. package/packages/store/dist/lance-store.js +1 -1
  9. package/scaffold/adapters/copilot.mjs +4 -1
  10. package/scaffold/definitions/agents.mjs +32 -8
  11. package/scaffold/definitions/bodies.mjs +6 -2
  12. package/scaffold/definitions/protocols.mjs +12 -0
  13. package/scaffold/general/agents/Code-Reviewer-Alpha.agent.md +7 -0
  14. package/scaffold/general/agents/Code-Reviewer-Beta.agent.md +7 -0
  15. package/scaffold/general/agents/Debugger.agent.md +7 -0
  16. package/scaffold/general/agents/Documenter.agent.md +1 -0
  17. package/scaffold/general/agents/Explorer.agent.md +6 -0
  18. package/scaffold/general/agents/Frontend.agent.md +9 -0
  19. package/scaffold/general/agents/Implementer.agent.md +7 -0
  20. package/scaffold/general/agents/Orchestrator.agent.md +35 -51
  21. package/scaffold/general/agents/README.md +3 -3
  22. package/scaffold/general/agents/Refactor.agent.md +1 -0
  23. package/scaffold/general/agents/Researcher-Beta.agent.md +2 -2
  24. package/scaffold/general/agents/Researcher-Delta.agent.md +2 -2
  25. package/scaffold/general/agents/Researcher-Gamma.agent.md +2 -2
  26. package/scaffold/general/agents/Security.agent.md +7 -0
  27. package/scaffold/general/agents/_shared/code-agent-base.md +38 -18
  28. package/scaffold/general/skills/aikit/SKILL.md +73 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vpxa/aikit",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "description": "Local-first AI developer toolkit — knowledge base, code analysis, context management, and developer tools for LLM agents",
6
6
  "license": "MIT",
@@ -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 S,registerAnalyzeStructureTool as ee,registerAnalyzeSymbolsTool as C,registerBlastRadiusTool as w}from"./tools/analyze.tools.js";import{registerAuditTool as T}from"./tools/audit.tool.js";import{registerBrainstormTool as E}from"./tools/brainstorm.tool.js";import{initBridgeComponents as te,registerErPullTool as D,registerErPushTool as O,registerErSyncStatusTool as k}from"./tools/bridge.tools.js";import{registerConfigTool as ne}from"./tools/config.tool.js";import{registerCompactTool as A,registerDeadSymbolsTool as j,registerFileSummaryTool as M,registerFindTool as N,registerScopeMapTool as re,registerSymbolTool as P,registerTraceTool as F}from"./tools/context.tools.js";import{registerErEvolveReviewTool as ie}from"./tools/evolution.tools.js";import{registerBatchTool as ae,registerCheckTool as oe,registerDelegateTool as se,registerEvalTool as ce,registerParseOutputTool as le,registerTestRunTool as I}from"./tools/execution.tools.js";import{registerFlowTools as ue}from"./tools/flow.tools.js";import{registerDigestTool as de,registerEvidenceMapTool as L,registerForgeClassifyTool as R,registerForgeGroundTool as fe,registerStratumCardTool as pe}from"./tools/forge.tools.js";import{registerForgetTool as me}from"./tools/forget.tool.js";import{registerGraphTool as he}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 ge}from"./tools/list.tool.js";import{registerLookupTool as _e}from"./tools/lookup.tool.js";import{registerCodemodTool as W,registerDataTransformTool as G,registerDiffParseTool as K,registerGitContextTool as q,registerRenameTool as ve}from"./tools/manipulation.tools.js";import{registerOnboardTool as ye}from"./tools/onboard.tool.js";import{registerCheckpointTool as be,registerLaneTool as xe,registerQueueTool as Se,registerStashTool as Ce,registerWorksetTool as we}from"./tools/persistence.tools.js";import{registerErUpdatePolicyTool as Te}from"./tools/policy.tools.js";import{registerPresentTool as Ee}from"./tools/present/tool.js";import"./tools/present/index.js";import{registerProduceKnowledgeTool as De}from"./tools/produce.tool.js";import{registerReadTool as Oe}from"./tools/read.tool.js";import{registerReindexTool as ke}from"./tools/reindex.tool.js";import{registerRememberTool as Ae}from"./tools/remember.tool.js";import{registerReplayTool as je}from"./tools/replay.tool.js";import{registerRestoreTool as Me}from"./tools/restore.tool.js";import{registerSearchTool as Ne}from"./tools/search.tool.js";import{getCurrentVersion as Pe}from"./version-check.js";import{registerEarlyStatusTool as Fe,registerStatusTool as Ie}from"./tools/status.tool.js";import{registerUpdateTool as Le}from"./tools/update.tool.js";import{registerChangelogTool as Re,registerEncodeTool as ze,registerEnvTool as Be,registerHttpTool as Ve,registerMeasureTool as He,registerRegexTestTool as Ue,registerSchemaValidateTool as We,registerSnippetTool as Ge,registerTimeTool as J,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=te(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:Pe()},{capabilities:{logging:{},completions:{}}});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},t.indexMode),n}function Q(e,t,n,r,i,a,o,s){l(e),p(e),Ne(e,t.embedder,t.store,t.graphStore,t.bridge,t.evolutionCollector,a),_e(e,t.store),Ie(e,t.store,t.graphStore,t.curated,{onboardComplete:t.onboardComplete,onboardTimestamp:t.onboardTimestamp},n,o,s),ne(e,n),ke(e,t.indexer,n,t.curated,t.store,i,o),Ae(e,t.curated,t.policyStore,t.evolutionCollector,i),Le(e,t.curated,i),me(e,t.curated,i),Oe(e,t.curated),ge(e,t.curated),ee(e,t.store,t.embedder),y(e,t.store,t.embedder),C(e,t.store,t.embedder),S(e,t.store,t.embedder),x(e,t.store,t.embedder),b(e,t.store,t.embedder),w(e,t.store,t.embedder,t.graphStore),De(e,n),ye(e,t.store,t.embedder,n),he(e,t.graphStore),T(e,t.store,t.embedder);let c=n.sources[0]?.path??process.cwd();A(e,t.embedder,t.fileCache,c),re(e,t.embedder,t.store),N(e,t.embedder,t.store),le(e),we(e),oe(e),ae(e,t.embedder,t.store),P(e,t.embedder,t.store,t.graphStore),ce(e),I(e),Ce(e),q(e),K(e),ve(e),W(e),Me(e),M(e,t.fileCache,c),be(e),G(e),F(e,t.embedder,t.store,t.graphStore),V(e),H(e),j(e,t.embedder,t.store),se(e,a),B(e),xe(e),Se(e),U(e),z(e,o),L(e),de(e,t.embedder),R(e),pe(e,t.embedder,t.fileCache),fe(e,t.embedder,t.store),Ee(e,r),r&&E(e,r),Ke(e),Ve(e),Ue(e),ze(e),He(e),Re(e),We(e),Ge(e),Be(e),J(e),ue(e,n),t.bridge&&(O(e,t.bridge,t.evolutionCollector),D(e,t.bridge),k(e,t.bridge)),t.policyStore&&Te(e,t.policyStore),t.evolutionCollector&&ie(e,t.evolutionCollector),d(e,t.store,t.curated),je(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){oe(e),ce(e),I(e),le(e),se(e),q(e),K(e),ve(e),W(e),G(e),we(e),Ce(e),be(e),Me(e),xe(e),Se(e),B(e),V(e),H(e),U(e),z(e),L(e),R(e),Ee(e),E(e,i),De(e),je(e),Fe(e),Ke(e),Ve(e),Ue(e),ze(e),He(e),Re(e),We(e),Ge(e),Be(e),J(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,i){let l=new st({name:n.serverName??`aikit`,version:Pe()},{capabilities:{logging:{},completions:{}}}),d=`initializing`,p=``,y=!1,b=null,x=null,S=null;function ee(e){if(!e||typeof e!=`object`)return[];let t=e,n=[];for(let e of[`path`,`file`,`source_path`,`sourcePath`,`filePath`]){let r=t[e];typeof r==`string`&&r&&n.push(r)}for(let e of[`changed_files`,`paths`,`files`]){let r=t[e];if(Array.isArray(r))for(let e of r){if(typeof e==`string`){n.push(e);continue}e&&typeof e==`object`&&typeof e.path==`string`&&n.push(e.path)}}if(Array.isArray(t.sources))for(let e of t.sources)e&&typeof e==`object`&&typeof e.path==`string`&&n.push(e.path);return n}let C=()=>d===`failed`?[`❌ AI Kit initialization failed — this tool is unavailable.`,``,p?`Error: ${p}`:``,``,`**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 C,registerBlastRadiusTool as w}from"./tools/analyze.tools.js";import{registerAuditTool as T}from"./tools/audit.tool.js";import{registerBrainstormTool as E}from"./tools/brainstorm.tool.js";import{initBridgeComponents as te,registerErPullTool as D,registerErPushTool as O,registerErSyncStatusTool as k}from"./tools/bridge.tools.js";import{registerConfigTool as ne}from"./tools/config.tool.js";import{registerCompactTool as A,registerDeadSymbolsTool as j,registerFileSummaryTool as M,registerFindTool as N,registerScopeMapTool as re,registerSymbolTool as P,registerTraceTool as F}from"./tools/context.tools.js";import{registerErEvolveReviewTool as ie}from"./tools/evolution.tools.js";import{registerBatchTool as ae,registerCheckTool as oe,registerDelegateTool as se,registerEvalTool as ce,registerParseOutputTool as le,registerTestRunTool as I}from"./tools/execution.tools.js";import{registerFlowTools as ue}from"./tools/flow.tools.js";import{registerDigestTool as de,registerEvidenceMapTool as L,registerForgeClassifyTool as R,registerForgeGroundTool as fe,registerStratumCardTool as pe}from"./tools/forge.tools.js";import{registerForgetTool as me}from"./tools/forget.tool.js";import{registerGraphTool as he}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 ge}from"./tools/list.tool.js";import{registerLookupTool as _e}from"./tools/lookup.tool.js";import{registerCodemodTool as W,registerDataTransformTool as G,registerDiffParseTool as K,registerGitContextTool as q,registerRenameTool as ve}from"./tools/manipulation.tools.js";import{registerOnboardTool as ye}from"./tools/onboard.tool.js";import{registerCheckpointTool as be,registerLaneTool as xe,registerQueueTool as Se,registerStashTool as Ce,registerWorksetTool as we}from"./tools/persistence.tools.js";import{registerErUpdatePolicyTool as Te}from"./tools/policy.tools.js";import{registerPresentTool as Ee}from"./tools/present/tool.js";import"./tools/present/index.js";import{registerProduceKnowledgeTool as De}from"./tools/produce.tool.js";import{registerReadTool as Oe}from"./tools/read.tool.js";import{registerReindexTool as ke}from"./tools/reindex.tool.js";import{registerRememberTool as Ae}from"./tools/remember.tool.js";import{registerReplayTool as je}from"./tools/replay.tool.js";import{registerRestoreTool as Me}from"./tools/restore.tool.js";import{registerSearchTool as Ne}from"./tools/search.tool.js";import{getCurrentVersion as Pe}from"./version-check.js";import{registerEarlyStatusTool as Fe,registerStatusTool as Ie}from"./tools/status.tool.js";import{registerUpdateTool as Le}from"./tools/update.tool.js";import{registerChangelogTool as Re,registerEncodeTool as ze,registerEnvTool as Be,registerHttpTool as Ve,registerMeasureTool as He,registerRegexTestTool as Ue,registerSchemaValidateTool as We,registerSnippetTool as Ge,registerTimeTool as J,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{completable as st}from"@modelcontextprotocol/sdk/server/completable.js";import{McpServer as ct}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as lt}from"zod";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=te(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 ut(e,t){let n=new ct({name:t.serverName??`aikit`,version:Pe()},{capabilities:{logging:{},completions:{},prompts:{}}});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},t.indexMode),n}function Q(e,t,n,r,i,a,o,s){l(e),p(e),Ne(e,t.embedder,t.store,t.graphStore,t.bridge,t.evolutionCollector,a),_e(e,t.store),Ie(e,t.store,t.graphStore,t.curated,{onboardComplete:t.onboardComplete,onboardTimestamp:t.onboardTimestamp},n,o,s),ne(e,n),ke(e,t.indexer,n,t.curated,t.store,i,o),Ae(e,t.curated,t.policyStore,t.evolutionCollector,i),Le(e,t.curated,i),me(e,t.curated,i),Oe(e,t.curated),ge(e,t.curated),ee(e,t.store,t.embedder),y(e,t.store,t.embedder),C(e,t.store,t.embedder),S(e,t.store,t.embedder),x(e,t.store,t.embedder),b(e,t.store,t.embedder),w(e,t.store,t.embedder,t.graphStore),De(e,n),ye(e,t.store,t.embedder,n),he(e,t.graphStore),T(e,t.store,t.embedder);let c=n.sources[0]?.path??process.cwd();A(e,t.embedder,t.fileCache,c),re(e,t.embedder,t.store),N(e,t.embedder,t.store),le(e),we(e),oe(e),ae(e,t.embedder,t.store),P(e,t.embedder,t.store,t.graphStore),ce(e),I(e),Ce(e),q(e),K(e),ve(e),W(e),Me(e),M(e,t.fileCache,c),be(e),G(e),F(e,t.embedder,t.store,t.graphStore),V(e),H(e),j(e,t.embedder,t.store),se(e,a),B(e),xe(e),Se(e),U(e),z(e,o),L(e),de(e,t.embedder),R(e),pe(e,t.embedder,t.fileCache),fe(e,t.embedder,t.store),Ee(e,r),r&&E(e,r),Ke(e),Ve(e),Ue(e),ze(e),He(e),Re(e),We(e),Ge(e),Be(e),J(e),ue(e,n),t.bridge&&(O(e,t.bridge,t.evolutionCollector),D(e,t.bridge),k(e,t.bridge)),t.policyStore&&Te(e,t.policyStore),t.evolutionCollector&&ie(e,t.evolutionCollector),d(e,t.store,t.curated),je(e)}async function dt(e){let t=await Z(e),n=ut(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 ft=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(`.`)),pt=5e3,mt=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 ht(e){oe(e),ce(e),I(e),le(e),se(e),q(e),K(e),ve(e),W(e),G(e),we(e),Ce(e),be(e),Me(e),xe(e),Se(e),B(e),V(e),H(e),U(e),z(e),L(e),R(e),Ee(e),E(e,i),De(e),je(e),Fe(e),Ke(e),Ve(e),Ue(e),ze(e),He(e),Re(e),We(e),Ge(e),Be(e),J(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 gt(n,i){let l=new ct({name:n.serverName??`aikit`,version:Pe()},{capabilities:{logging:{},completions:{},prompts:{}}}),d=`initializing`,p=``,y=!1,b=null,x=null,S=null;function ee(e){if(!e||typeof e!=`object`)return[];let t=e,n=[];for(let e of[`path`,`file`,`source_path`,`sourcePath`,`filePath`]){let r=t[e];typeof r==`string`&&r&&n.push(r)}for(let e of[`changed_files`,`paths`,`files`]){let r=t[e];if(Array.isArray(r))for(let e of r){if(typeof e==`string`){n.push(e);continue}e&&typeof e==`object`&&typeof e.path==`string`&&n.push(e.path)}}if(Array.isArray(t.sources))for(let e of t.sources)e&&typeof e==`object`&&typeof e.path==`string`&&n.push(e.path);return n}let C=()=>d===`failed`?[`❌ AI Kit initialization failed — this tool is unavailable.`,``,p?`Error: ${p}`:``,``,`**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(l),h(l,n.toolPrefix??``);let w=l.sendToolListChanged.bind(l);l.sendToolListChanged=()=>{};let T=[];for(let e of $){let t=m(e),n=l.registerTool(e,{title:t.title,description:`${t.title} — initializing, available shortly`,inputSchema:{},annotations:t.annotations},async()=>({content:[{type:`text`,text:C()}]}));ft.has(e)?n.remove():T.push(n)}pt(l),l.sendToolListChanged=w;let E=l.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=l.registerPrompt(`_init`,{description:`AI Kit is initializing prompts...`},async()=>({messages:[{role:`user`,content:{type:`text`,text:C()}}]})),D,O=new Promise(e=>{D=e}),k,ne=new Promise(e=>{k=e}),A=()=>k?.(),j=(async()=>{await ne;let e;try{e=await Z(n)}catch(e){d=`failed`,p=e instanceof Error?e.message:String(e),X.error(`AI Kit initialization failed — server continuing with zero-dep tools only`,{error:p});return}let o=l.sendToolListChanged.bind(l);l.sendToolListChanged=()=>{};let m=l.sendPromptListChanged.bind(l);l.sendPromptListChanged=()=>{};let h=l.sendResourceListChanged.bind(l);l.sendResourceListChanged=()=>{};for(let e of T)e.remove();E.remove(),te.remove();let C=l._registeredTools??{};for(let e of ft)C[e]?.remove();let w=new u(l),O=f(l);Q(l,e,n,r(l),w,O,i,i===`smart`?(()=>{let e=S;return e?.getState?e.getState():null}):null),c(l,{curated:e.curated,store:e.store,graphStore:e.graphStore},i),l.sendToolListChanged=o,l.sendPromptListChanged=m,l.sendResourceListChanged=h,Promise.resolve(l.sendToolListChanged()).catch(()=>{}),Promise.resolve(l.sendPromptListChanged()).catch(()=>{}),Promise.resolve(l.sendResourceListChanged()).catch(()=>{});let k=l._registeredTools??{};for(let[t,n]of Object.entries(k)){if(ut.has(t))continue;let r=n.handler;n.handler=async(...n)=>{if(!e.indexer.isIndexing)return r(...n);let i=y?`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(k)){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 A=Object.keys(k).length;A<$.length&&X.warn(`ALL_TOOL_NAMES count mismatch`,{expectedToolCount:$.length,registeredToolCount:A}),X.info(`MCP server configured`,{toolCount:$.length,resourceCount:4});let j=new s;j.onPressure((e,n)=>{e===`warning`&&t(),e===`critical`&&(X.warn(`Memory pressure critical — consider restarting`,{rssMB:Math.round(n/1024/1024)}),t())}),j.start();let M=new a;x=M,M.onIdle(async()=>{if(N.isRunning||e.indexer.isIndexing){X.info(`Idle cleanup deferred — background tasks still running`),M.touch();return}X.info(`Idle cleanup: closing store and graph connections`);try{await Promise.all([e.store.close().catch(()=>{}),e.graphStore.close().catch(()=>{})])}catch{}}),M.touch();for(let e of Object.values(k)){let t=e.handler;e.handler=async(...e)=>{if(M.touch(),S){let t=ee(e[0]);t.length>0&&S.prioritize(...t)}return t(...e)}}b=e,D?.(e)})(),M=async()=>{let e=await O;x?.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}))});y=!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{x?.setBusy(!1)}},N=new e,re=()=>N.schedule({name:`initial-index`,fn:M}),P=process.ppid,F=setInterval(()=>{try{process.kill(P,0)}catch{X.info(`Parent process died; shutting down`,{parentPid:P}),clearInterval(F),O.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 F.unref(),{server:l,startInit:A,ready:j,runInitialIndex:re,get kb(){return b},scheduler:N,setSmartScheduler(e){S=e}}}export{$ as ALL_TOOL_NAMES,mt as createLazyServer,ct as createMcpServer,lt as createServer,Z as initializeKnowledgeBase,Q as registerMcpTools};
3
+ `);o(l),h(l,n.toolPrefix??``);let w=l.sendToolListChanged.bind(l);l.sendToolListChanged=()=>{};let T=[];for(let e of $){let t=m(e),n=l.registerTool(e,{title:t.title,description:`${t.title} — initializing, available shortly`,inputSchema:{},annotations:t.annotations},async()=>({content:[{type:`text`,text:C()}]}));mt.has(e)?n.remove():T.push(n)}ht(l),l.sendToolListChanged=w;let E=l.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=l.registerPrompt(`_init`,{description:`Initializing AI Kit…`,argsSchema:{_dummy:st(lt.string(),()=>[])}},async()=>({messages:[]})),D,O=new Promise(e=>{D=e}),k,ne=new Promise(e=>{k=e}),A=()=>k?.(),j=(async()=>{await ne;let e;try{e=await Z(n)}catch(e){d=`failed`,p=e instanceof Error?e.message:String(e),X.error(`AI Kit initialization failed — server continuing with zero-dep tools only`,{error:p});return}let o=l.sendToolListChanged.bind(l);l.sendToolListChanged=()=>{};let m=l.sendPromptListChanged.bind(l);l.sendPromptListChanged=()=>{};let h=l.sendResourceListChanged.bind(l);l.sendResourceListChanged=()=>{};for(let e of T)e.remove();E.remove(),te.remove();let C=l._registeredTools??{};for(let e of mt)C[e]?.remove();let w=new u(l),O=f(l);Q(l,e,n,r(l),w,O,i,i===`smart`?(()=>{let e=S;return e?.getState?e.getState():null}):null),c(l,{curated:e.curated,store:e.store,graphStore:e.graphStore},i),l.sendToolListChanged=o,l.sendPromptListChanged=m,l.sendResourceListChanged=h,Promise.resolve(l.sendToolListChanged()).catch(()=>{}),Promise.resolve(l.sendPromptListChanged()).catch(()=>{}),Promise.resolve(l.sendResourceListChanged()).catch(()=>{});let k=l._registeredTools??{};for(let[t,n]of Object.entries(k)){if(ft.has(t))continue;let r=n.handler;n.handler=async(...n)=>{if(!e.indexer.isIndexing)return r(...n);let i=y?`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 (${pt/1e3}s).\n\nThe existing index may be temporarily locked. Please retry shortly — indexing will complete automatically.`}]}),pt));return Promise.race([r(...n),a])}}for(let[e,t]of Object.entries(k)){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 A=Object.keys(k).length;A<$.length&&X.warn(`ALL_TOOL_NAMES count mismatch`,{expectedToolCount:$.length,registeredToolCount:A}),X.info(`MCP server configured`,{toolCount:$.length,resourceCount:4});let j=new s;j.onPressure((e,n)=>{e===`warning`&&t(),e===`critical`&&(X.warn(`Memory pressure critical — consider restarting`,{rssMB:Math.round(n/1024/1024)}),t())}),j.start();let M=new a;x=M,M.onIdle(async()=>{if(N.isRunning||e.indexer.isIndexing){X.info(`Idle cleanup deferred — background tasks still running`),M.touch();return}X.info(`Idle cleanup: closing store and graph connections`);try{await Promise.all([e.store.close().catch(()=>{}),e.graphStore.close().catch(()=>{})])}catch{}}),M.touch();for(let e of Object.values(k)){let t=e.handler;e.handler=async(...e)=>{if(M.touch(),S){let t=ee(e[0]);t.length>0&&S.prioritize(...t)}return t(...e)}}b=e,D?.(e)})(),M=async()=>{let e=await O;x?.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}))});y=!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{x?.setBusy(!1)}},N=new e,re=()=>N.schedule({name:`initial-index`,fn:M}),P=process.ppid,F=setInterval(()=>{try{process.kill(P,0)}catch{X.info(`Parent process died; shutting down`,{parentPid:P}),clearInterval(F),O.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 F.unref(),{server:l,startInit:A,ready:j,runInitialIndex:re,get kb(){return b},scheduler:N,setSmartScheduler(e){S=e}}}export{$ as ALL_TOOL_NAMES,gt as createLazyServer,ut as createMcpServer,dt as createServer,Z as initializeKnowledgeBase,Q as registerMcpTools};
@@ -1,8 +1,8 @@
1
- import{getToolMeta as e}from"../tool-metadata.js";import{AnalyzeStructureOutputSchema as t,BlastRadiusOutputSchema as n}from"../output-schemas.js";import{createHash as r}from"node:crypto";import{z as i}from"zod";import{createLogger as a,serializeError as o}from"../../../core/dist/index.js";import{BlastRadiusAnalyzer as s,DependencyAnalyzer as c,DiagramGenerator as l,EntryPointAnalyzer as u,PatternAnalyzer as d,StructureAnalyzer as f,SymbolAnalyzer as p}from"../../../analyzers/dist/index.js";import{WasmRuntime as m}from"../../../chunker/dist/index.js";import{gitContext as h,truncateToTokenBudget as g}from"../../../tools/dist/index.js";const _=a(`tools`),v=i.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`);function y(e,t){return t?g(e,t):e}function b(){let e=[];return m.get()||e.push(`Tree-sitter unavailable — using regex fallback, symbol/pattern confidence reduced`),e.length===0?``:`\n\n> **⚠ Caveats:** ${e.join(`; `)}`}function x(e){return(e??[]).map(e=>{if(typeof e==`string`)return e;if(e&&typeof e==`object`&&`path`in e)return typeof e.path==`string`?e.path:void 0}).filter(e=>!!e)}function S(e){let t=[],n=e.filter(e=>/\.(ts|tsx|js|jsx)$/.test(e)&&/(service|store|model|schema|migration)/i.test(e)),r=e.filter(e=>/\.(ts|tsx|js|jsx)$/.test(e)&&!n.includes(e)),i=e.filter(e=>!/\.(ts|tsx|js|jsx)$/.test(e));return(n.length>0||r.length>0||i.length>0)&&(t.push(`
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{AnalyzeStructureOutputSchema as t,BlastRadiusOutputSchema as n}from"../output-schemas.js";import{z as r}from"zod";import{createHash as i}from"node:crypto";import{createLogger as a,serializeError as o}from"../../../core/dist/index.js";import{BlastRadiusAnalyzer as s,DependencyAnalyzer as c,DiagramGenerator as l,EntryPointAnalyzer as u,PatternAnalyzer as d,StructureAnalyzer as f,SymbolAnalyzer as p}from"../../../analyzers/dist/index.js";import{WasmRuntime as m}from"../../../chunker/dist/index.js";import{gitContext as h,truncateToTokenBudget as g}from"../../../tools/dist/index.js";const _=a(`tools`),v=r.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`);function y(e,t){return t?g(e,t):e}function b(){let e=[];return m.get()||e.push(`Tree-sitter unavailable — using regex fallback, symbol/pattern confidence reduced`),e.length===0?``:`\n\n> **⚠ Caveats:** ${e.join(`; `)}`}function x(e){return(e??[]).map(e=>{if(typeof e==`string`)return e;if(e&&typeof e==`object`&&`path`in e)return typeof e.path==`string`?e.path:void 0}).filter(e=>!!e)}function S(e){let t=[],n=e.filter(e=>/\.(ts|tsx|js|jsx)$/.test(e)&&/(service|store|model|schema|migration)/i.test(e)),r=e.filter(e=>/\.(ts|tsx|js|jsx)$/.test(e)&&!n.includes(e)),i=e.filter(e=>!/\.(ts|tsx|js|jsx)$/.test(e));return(n.length>0||r.length>0||i.length>0)&&(t.push(`
2
2
 
3
3
  ### Risk Assessment`),n.length>0&&t.push(`- 🔴 **High risk** (${n.length}): ${n.slice(0,5).map(e=>`\`${e}\``).join(`, `)}`),r.length>0&&t.push(`- 🟡 **Medium risk** (${r.length}): source files`),i.length>0&&t.push(`- 🟢 **Low risk** (${i.length}): non-source files`)),t.join(`
4
4
  `)}function C(e){let t=e.replace(/\\/g,`/`);return/(^|\/)__tests__\/|\.(test|spec)\.[jt]sx?$/i.test(t)?`Tests`:/(controller|route|handler|api)/i.test(t)?`API`:/(service|store|model|schema|migration|repo|repository|db|database)/i.test(t)?`Core/Data`:/\.(ts|tsx|js|jsx)$/.test(t)?`Source`:`Config/Docs`}function w(e){if(e.length===0)return``;let t=[`Core/Data`,`API`,`Source`,`Tests`,`Config/Docs`],n=new Map;for(let t of e){let e=C(t),r=n.get(e)??[];r.push(t),n.set(e,r)}let r=[`
5
5
 
6
6
  ### Layer Classification`];for(let e of t){let t=n.get(e);if(!t?.length)continue;let i=t.slice(0,5).map(e=>`\`${e}\``).join(`, `),a=t.length>5?`, ... and ${t.length-5} more`:``;r.push(`- **${e}** (${t.length}): ${i}${a}`)}return r.join(`
7
- `)}async function T(e,t,n,i,a){try{let o=`produced/analysis/${n}/${r(`sha256`).update(i).digest(`hex`).slice(0,12)}.md`,s=r(`sha256`).update(a).digest(`hex`).slice(0,16),c=new Date().toISOString(),l=a.length>2e3?a.split(/(?=^## )/m).filter(e=>e.trim().length>0):[a],u=l.map((e,t)=>({id:r(`sha256`).update(`${o}::${t}`).digest(`hex`).slice(0,16),content:e.trim(),sourcePath:o,contentType:`produced-knowledge`,chunkIndex:t,totalChunks:l.length,startLine:0,endLine:0,fileHash:s,indexedAt:c,origin:`produced`,tags:[`analysis`,n],category:`analysis`,version:1})),d=await t.embedBatch(u.map(e=>e.content));await e.upsert(u,d),_.info(`Auto-persisted analysis`,{analyzerName:n,chunkCount:u.length})}catch(e){_.warn(`Auto-persist analysis failed`,{analyzerName:n,...o(e)})}}function E(n,r,a){let s=new f,c=e(`analyze_structure`);n.registerTool(`analyze_structure`,{title:c.title,description:`Analyze the file/directory structure of a codebase. Returns an annotated tree with language stats.`,outputSchema:t,inputSchema:{path:i.string().describe(`Root path to analyze`),max_depth:i.number().min(1).max(10).default(6).describe(`Maximum directory depth`),format:i.enum([`json`,`markdown`]).default(`markdown`).describe(`Output format`),max_tokens:v},annotations:c.annotations},async({path:e,max_depth:t,format:n,max_tokens:i})=>{try{let o=await s.analyze(e,{format:n,maxDepth:t,maxTokens:i});T(r,a,`structure`,e,o.output);let c=o.data;return{content:[{type:`text`,text:y(o.output+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_dependencies` for import graphs, or `analyze_patterns` to detect architecture patterns._",i)}],structuredContent:{files:c.fileCount??o.meta.fileCount,packages:c.packageCount??0,languages:c.languages??{},tree:o.output.slice(0,2e3)}}}catch(e){return _.error(`Analysis failed`,o(e)),{content:[{type:`text`,text:`Analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function D(t,n,r){let a=new c,s=e(`analyze_dependencies`);t.registerTool(`analyze_dependencies`,{title:s.title,description:`Analyze import/require dependencies across a codebase. Shows external packages and internal module graph.`,inputSchema:{path:i.string().describe(`Root path to analyze`),format:i.enum([`json`,`markdown`,`mermaid`]).default(`markdown`).describe(`Output format`),max_tokens:v},annotations:s.annotations},async({path:e,format:t,max_tokens:i})=>{try{let o=await a.analyze(e,{format:t});return T(n,r,`dependencies`,e,o.output),{content:[{type:`text`,text:y(o.output+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_symbols` to explore exported symbols, or `analyze_diagram` for visual representation._",i)}]}}catch(e){return _.error(`Analysis failed`,o(e)),{content:[{type:`text`,text:`Analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function O(t,n,r){let a=new p,s=e(`analyze_symbols`);t.registerTool(`analyze_symbols`,{title:s.title,description:`Extract exported and local symbols (functions, classes, interfaces, types, constants) from a codebase.`,inputSchema:{path:i.string().describe(`Root path to analyze`),filter:i.string().optional().describe(`Filter symbols by name substring`),format:i.enum([`json`,`markdown`]).default(`markdown`).describe(`Output format`)},annotations:s.annotations},async({path:e,filter:t,format:i})=>{try{let o=await a.analyze(e,{format:i,filter:t});return T(n,r,`symbols`,e,o.output),{content:[{type:`text`,text:o.output+b()+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_dependencies` to see import relationships, or `search` to find usage patterns._"}]}}catch(e){return _.error(`Analysis failed`,o(e)),{content:[{type:`text`,text:`Analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function k(t,n,r){let a=new d,s=e(`analyze_patterns`);t.registerTool(`analyze_patterns`,{title:s.title,description:`Detect architectural patterns, frameworks, and conventions in a codebase using directory structure and code heuristics.`,inputSchema:{path:i.string().describe(`Root path to analyze`)},annotations:s.annotations},async({path:e})=>{try{let t=await a.analyze(e);return T(n,r,`patterns`,e,t.output),{content:[{type:`text`,text:t.output+b()+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_entry_points` to find Lambda handlers and main exports, or `produce_knowledge` for full analysis._"}]}}catch(e){return _.error(`Analysis failed`,o(e)),{content:[{type:`text`,text:`Analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function A(t,n,r){let a=new u,s=e(`analyze_entry_points`);t.registerTool(`analyze_entry_points`,{title:s.title,description:`Find entry points: Lambda handlers, main exports, CLI bins, and server start scripts.`,inputSchema:{path:i.string().describe(`Root path to analyze`)},annotations:s.annotations},async({path:e})=>{try{let t=await a.analyze(e);return T(n,r,`entry-points`,e,t.output),{content:[{type:`text`,text:t.output+b()+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_dependencies` to see what each entry point imports, or `produce_knowledge` for comprehensive analysis._"}]}}catch(e){return _.error(`Analysis failed`,o(e)),{content:[{type:`text`,text:`Analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function j(t,n,r){let a=new l,s=e(`analyze_diagram`);t.registerTool(`analyze_diagram`,{title:s.title,description:`Generate a Mermaid diagram of the codebase architecture or dependency graph. Returns Mermaid flowchart syntax — paste into any Markdown renderer or Mermaid editor to visualize.`,inputSchema:{path:i.string().describe(`Root path to analyze`),diagram_type:i.enum([`architecture`,`dependencies`]).default(`architecture`).describe(`Type of diagram`)},annotations:s.annotations},async({path:e,diagram_type:t})=>{try{let i=await a.analyze(e,{diagramType:t});return T(n,r,`diagram`,e,i.output),{content:[{type:`text`,text:i.output+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_structure` for detailed file tree, or `produce_knowledge` for comprehensive analysis._"}]}}catch(e){return _.error(`Diagram generation failed`,o(e)),{content:[{type:`text`,text:`Diagram generation failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function M(t,r,a,c){let l=new s,u=e(`blast_radius`);t.registerTool(`blast_radius`,{title:u.title,description:`Given a list of changed files, trace the dependency graph to find all affected files (direct + transitive importers) and their tests. Useful for scoping code reviews and impact analysis.`,outputSchema:n,inputSchema:{path:i.string().describe(`Root path of the codebase`),files:i.array(i.string()).optional().describe(`Changed file paths (relative to root). If omitted, auto-detects from git status.`),max_depth:i.number().min(1).max(20).default(5).describe(`Maximum transitive dependency depth`),format:i.enum([`json`,`markdown`]).default(`markdown`).describe(`Output format`),max_tokens:v},annotations:u.annotations},async({path:e,files:t,max_depth:n,format:i,max_tokens:s})=>{try{let o=t??[];if(o.length===0)try{let t=await h({cwd:e,includeDiff:!1});if(o=Array.from(new Set([...x(t.status?.staged),...x(t.status?.modified),...x(t.status?.untracked)])),o.length===0)return{content:[{type:`text`,text:"No changed files detected from git status. Provide `files` explicitly or make changes first."}]}}catch{return{content:[{type:`text`,text:"Could not detect changed files from git. Provide `files` explicitly."}],isError:!0}}let u=await l.analyze(e,{files:o,maxDepth:n,format:i}),d=``;if(c)try{let e=new Set;for(let t of o){let n=await c.findNodes({sourcePath:t,limit:10});for(let t of n){let n=await c.getNeighbors(t.id,{direction:`incoming`,edgeType:`imports`});for(let t of n.nodes){let n=t.sourcePath??t.name;o.includes(n)||e.add(n)}}}e.size>0&&(d=`\n\n### Graph-discovered importers (${e.size})\n`+[...e].slice(0,20).map(e=>`- \`${e}\``).join(`
8
- `),e.size>20&&(d+=`\n- ... and ${e.size-20} more`))}catch{}let f=w(o),p=S(o),m=u.output+d+f+p+b()+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_dependencies` to see the full import graph, or `analyze_symbols` to inspect affected exports._";T(r,a,`blast-radius`,e,m);let g=new Set;if(c)for(let e of o)try{let t=await c.findNodes({sourcePath:e,limit:10});for(let e of t){let t=await c.getNeighbors(e.id,{direction:`incoming`,edgeType:`imports`});for(let e of t.nodes){let t=e.sourcePath??e.name;o.includes(t)||g.add(t)}}}catch{}let _=[...g].map(e=>({path:e,impact:`transitive`,reason:`imports changed file`})),v=o.length>10?`high`:o.length>3?`medium`:`low`;return{content:[{type:`text`,text:y(m,s)}],structuredContent:{changedFiles:o,affectedFiles:_,totalAffected:_.length,riskLevel:v}}}catch(e){return _.error(`Blast radius analysis failed`,o(e)),{content:[{type:`text`,text:`Blast radius analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{D as registerAnalyzeDependenciesTool,j as registerAnalyzeDiagramTool,A as registerAnalyzeEntryPointsTool,k as registerAnalyzePatternsTool,E as registerAnalyzeStructureTool,O as registerAnalyzeSymbolsTool,M as registerBlastRadiusTool};
7
+ `)}async function T(e,t,n,r,a){try{let o=`produced/analysis/${n}/${i(`sha256`).update(r).digest(`hex`).slice(0,12)}.md`,s=i(`sha256`).update(a).digest(`hex`).slice(0,16),c=new Date().toISOString(),l=a.length>2e3?a.split(/(?=^## )/m).filter(e=>e.trim().length>0):[a],u=l.map((e,t)=>({id:i(`sha256`).update(`${o}::${t}`).digest(`hex`).slice(0,16),content:e.trim(),sourcePath:o,contentType:`produced-knowledge`,chunkIndex:t,totalChunks:l.length,startLine:0,endLine:0,fileHash:s,indexedAt:c,origin:`produced`,tags:[`analysis`,n],category:`analysis`,version:1})),d=await t.embedBatch(u.map(e=>e.content));await e.upsert(u,d),_.info(`Auto-persisted analysis`,{analyzerName:n,chunkCount:u.length})}catch(e){_.warn(`Auto-persist analysis failed`,{analyzerName:n,...o(e)})}}function E(n,i,a){let s=new f,c=e(`analyze_structure`);n.registerTool(`analyze_structure`,{title:c.title,description:`Analyze the file/directory structure of a codebase. Returns an annotated tree with language stats.`,outputSchema:t,inputSchema:{path:r.string().describe(`Root path to analyze`),max_depth:r.number().min(1).max(10).default(6).describe(`Maximum directory depth`),format:r.enum([`json`,`markdown`]).default(`markdown`).describe(`Output format`),max_tokens:v},annotations:c.annotations},async({path:e,max_depth:t,format:n,max_tokens:r})=>{try{let o=await s.analyze(e,{format:n,maxDepth:t,maxTokens:r});T(i,a,`structure`,e,o.output);let c=o.data;return{content:[{type:`text`,text:y(o.output+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_dependencies` for import graphs, or `analyze_patterns` to detect architecture patterns._",r)}],structuredContent:{files:c.fileCount??o.meta.fileCount,packages:c.packageCount??0,languages:c.languages??{},tree:o.output.slice(0,2e3)}}}catch(e){return _.error(`Analysis failed`,o(e)),{content:[{type:`text`,text:`Analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function D(t,n,i){let a=new c,s=e(`analyze_dependencies`);t.registerTool(`analyze_dependencies`,{title:s.title,description:`Analyze import/require dependencies across a codebase. Shows external packages and internal module graph.`,inputSchema:{path:r.string().describe(`Root path to analyze`),format:r.enum([`json`,`markdown`,`mermaid`]).default(`markdown`).describe(`Output format`),max_tokens:v},annotations:s.annotations},async({path:e,format:t,max_tokens:r})=>{try{let o=await a.analyze(e,{format:t});return T(n,i,`dependencies`,e,o.output),{content:[{type:`text`,text:y(o.output+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_symbols` to explore exported symbols, or `analyze_diagram` for visual representation._",r)}]}}catch(e){return _.error(`Analysis failed`,o(e)),{content:[{type:`text`,text:`Analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function O(t,n,i){let a=new p,s=e(`analyze_symbols`);t.registerTool(`analyze_symbols`,{title:s.title,description:`Extract exported and local symbols (functions, classes, interfaces, types, constants) from a codebase.`,inputSchema:{path:r.string().describe(`Root path to analyze`),filter:r.string().optional().describe(`Filter symbols by name substring`),format:r.enum([`json`,`markdown`]).default(`markdown`).describe(`Output format`)},annotations:s.annotations},async({path:e,filter:t,format:r})=>{try{let o=await a.analyze(e,{format:r,filter:t});return T(n,i,`symbols`,e,o.output),{content:[{type:`text`,text:o.output+b()+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_dependencies` to see import relationships, or `search` to find usage patterns._"}]}}catch(e){return _.error(`Analysis failed`,o(e)),{content:[{type:`text`,text:`Analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function k(t,n,i){let a=new d,s=e(`analyze_patterns`);t.registerTool(`analyze_patterns`,{title:s.title,description:`Detect architectural patterns, frameworks, and conventions in a codebase using directory structure and code heuristics.`,inputSchema:{path:r.string().describe(`Root path to analyze`)},annotations:s.annotations},async({path:e})=>{try{let t=await a.analyze(e);return T(n,i,`patterns`,e,t.output),{content:[{type:`text`,text:t.output+b()+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_entry_points` to find Lambda handlers and main exports, or `produce_knowledge` for full analysis._"}]}}catch(e){return _.error(`Analysis failed`,o(e)),{content:[{type:`text`,text:`Analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function A(t,n,i){let a=new u,s=e(`analyze_entry_points`);t.registerTool(`analyze_entry_points`,{title:s.title,description:`Find entry points: Lambda handlers, main exports, CLI bins, and server start scripts.`,inputSchema:{path:r.string().describe(`Root path to analyze`)},annotations:s.annotations},async({path:e})=>{try{let t=await a.analyze(e);return T(n,i,`entry-points`,e,t.output),{content:[{type:`text`,text:t.output+b()+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_dependencies` to see what each entry point imports, or `produce_knowledge` for comprehensive analysis._"}]}}catch(e){return _.error(`Analysis failed`,o(e)),{content:[{type:`text`,text:`Analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function j(t,n,i){let a=new l,s=e(`analyze_diagram`);t.registerTool(`analyze_diagram`,{title:s.title,description:`Generate a Mermaid diagram of the codebase architecture or dependency graph. Returns Mermaid flowchart syntax — paste into any Markdown renderer or Mermaid editor to visualize.`,inputSchema:{path:r.string().describe(`Root path to analyze`),diagram_type:r.enum([`architecture`,`dependencies`]).default(`architecture`).describe(`Type of diagram`)},annotations:s.annotations},async({path:e,diagram_type:t})=>{try{let r=await a.analyze(e,{diagramType:t});return T(n,i,`diagram`,e,r.output),{content:[{type:`text`,text:r.output+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_structure` for detailed file tree, or `produce_knowledge` for comprehensive analysis._"}]}}catch(e){return _.error(`Diagram generation failed`,o(e)),{content:[{type:`text`,text:`Diagram generation failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function M(t,i,a,c){let l=new s,u=e(`blast_radius`);t.registerTool(`blast_radius`,{title:u.title,description:`Given a list of changed files, trace the dependency graph to find all affected files (direct + transitive importers) and their tests. Useful for scoping code reviews and impact analysis.`,outputSchema:n,inputSchema:{path:r.string().describe(`Root path of the codebase`),files:r.array(r.string()).optional().describe(`Changed file paths (relative to root). If omitted, auto-detects from git status.`),max_depth:r.number().min(1).max(20).default(5).describe(`Maximum transitive dependency depth`),format:r.enum([`json`,`markdown`]).default(`markdown`).describe(`Output format`),max_tokens:v},annotations:u.annotations},async({path:e,files:t,max_depth:n,format:r,max_tokens:s})=>{try{let o=t??[];if(o.length===0)try{let t=await h({cwd:e,includeDiff:!1});if(o=Array.from(new Set([...x(t.status?.staged),...x(t.status?.modified),...x(t.status?.untracked)])),o.length===0)return{content:[{type:`text`,text:"No changed files detected from git status. Provide `files` explicitly or make changes first."}]}}catch{return{content:[{type:`text`,text:"Could not detect changed files from git. Provide `files` explicitly."}],isError:!0}}let u=await l.analyze(e,{files:o,maxDepth:n,format:r}),d=``;if(c)try{let e=new Set;for(let t of o){let n=await c.findNodes({sourcePath:t,limit:10});for(let t of n){let n=await c.getNeighbors(t.id,{direction:`incoming`,edgeType:`imports`});for(let t of n.nodes){let n=t.sourcePath??t.name;o.includes(n)||e.add(n)}}}e.size>0&&(d=`\n\n### Graph-discovered importers (${e.size})\n`+[...e].slice(0,20).map(e=>`- \`${e}\``).join(`
8
+ `),e.size>20&&(d+=`\n- ... and ${e.size-20} more`))}catch{}let f=w(o),p=S(o),m=u.output+d+f+p+b()+"\n\n---\n_Analysis auto-saved to KB. Next: Use `analyze_dependencies` to see the full import graph, or `analyze_symbols` to inspect affected exports._";T(i,a,`blast-radius`,e,m);let g=new Set;if(c)for(let e of o)try{let t=await c.findNodes({sourcePath:e,limit:10});for(let e of t){let t=await c.getNeighbors(e.id,{direction:`incoming`,edgeType:`imports`});for(let e of t.nodes){let t=e.sourcePath??e.name;o.includes(t)||g.add(t)}}}catch{}let _=[...g].map(e=>({path:e,impact:`transitive`,reason:`imports changed file`})),v=o.length>10?`high`:o.length>3?`medium`:`low`;return{content:[{type:`text`,text:y(m,s)}],structuredContent:{changedFiles:o,affectedFiles:_,totalAffected:_.length,riskLevel:v}}}catch(e){return _.error(`Blast radius analysis failed`,o(e)),{content:[{type:`text`,text:`Blast radius analysis failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{D as registerAnalyzeDependenciesTool,j as registerAnalyzeDiagramTool,A as registerAnalyzeEntryPointsTool,k as registerAnalyzePatternsTool,E as registerAnalyzeStructureTool,O as registerAnalyzeSymbolsTool,M as registerBlastRadiusTool};
@@ -1 +1 @@
1
- import{getToolMeta as e}from"../tool-metadata.js";import{join as t,resolve as n}from"node:path";import{readFile as r}from"node:fs/promises";import{z as i}from"zod";import{createLogger as a,serializeError as o}from"../../../core/dist/index.js";const s=a(`flow-tools`);function c(e){return{content:[{type:`text`,text:e}]}}function l(e){return e instanceof Error?e.message:String(e)}function u(a,u){let d=t(u.stateDir??t(u.sources[0].path,`.aikit-state`),`flows`),f=t(d,`registry.json`),p=t(d,`state.json`);async function m(){let{FlowRegistryManager:e,FlowStateMachine:t}=await import(`../../../flows/dist/index.js`);return{registry:new e(f),stateMachine:new t(p)}}let h=e(`flow_list`);a.registerTool(`flow_list`,{title:h.title,description:`List all installed flows and their steps`,annotations:h.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await m(),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 c(JSON.stringify(i,null,2))}catch(e){return s.error(`flow_list failed`,o(e)),c(`Error: ${l(e)}`)}});let g=e(`flow_info`);a.registerTool(`flow_info`,{title:g.title,description:`Show detailed information about a specific flow`,annotations:g.annotations,inputSchema:{name:i.string().describe(`Flow name to get info for`)}},async({name:e})=>{try{let{registry:t}=await m(),r=t.get(e);if(!r)return c(`Flow "${e}" not found. Use flow_list to see available flows.`);let i={name:r.name,version:r.version,description:r.manifest.description,source:r.source,sourceType:r.sourceType,format:r.format,installPath:r.installPath,registeredAt:r.registeredAt,updatedAt:r.updatedAt,steps:r.manifest.steps.map(e=>({id:e.id,name:e.name,skill:n(r.installPath,e.skill),produces:e.produces,requires:e.requires,description:e.description})),agents:r.manifest.agents,artifactsDir:r.manifest.artifacts_dir,install:r.manifest.install};return c(JSON.stringify(i,null,2))}catch(e){return s.error(`flow_info failed`,o(e)),c(`Error: ${l(e)}`)}});let _=e(`flow_start`);a.registerTool(`flow_start`,{title:_.title,description:`Start a flow. Sets the active flow and positions at the first step.`,annotations:_.annotations,inputSchema:{flow:i.string().describe(`Flow name to start (use flow_list to see options)`)}},async({flow:e})=>{try{let{registry:t,stateMachine:n}=await m(),r=t.get(e);if(!r)return c(`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 c(`Cannot start: ${i.error}`);let a=i.data,o=r.manifest.steps.find(e=>e.id===a.currentStep),s={started:!0,flow:a.flow,currentStep:a.currentStep,currentStepSkill:o?.skill??null,currentStepDescription:o?.description??null,totalSteps:r.manifest.steps.length,stepSequence:r.manifest.steps.map(e=>e.id),artifactsDir:r.manifest.artifacts_dir};return c(JSON.stringify(s,null,2))}catch(e){return s.error(`flow_start failed`,o(e)),c(`Error: ${l(e)}`)}});let v=e(`flow_step`);a.registerTool(`flow_step`,{title:v.title,description:`Advance the active flow: complete current step and move to next, skip current step, or redo current step.`,annotations:v.annotations,inputSchema:{action:i.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 m(),r=n.load();if(!r)return c(`No active flow. Use flow_start first.`);let i=t.get(r.flow);if(!i)return c(`Flow "${r.flow}" not found in registry.`);let a=n.step(e,i.manifest);if(!a.success||!a.data)return c(`Cannot ${e}: ${a.error}`);let o=a.data,s=o.currentStep?i.manifest.steps.find(e=>e.id===o.currentStep):null,l={flow:o.flow,status:o.status,action:e,currentStep:o.currentStep,currentStepSkill:s?.skill??null,currentStepDescription:s?.description??null,completedSteps:o.completedSteps,skippedSteps:o.skippedSteps,totalSteps:i.manifest.steps.length,remaining:i.manifest.steps.filter(e=>!o.completedSteps.includes(e.id)&&!o.skippedSteps.includes(e.id)&&e.id!==o.currentStep).map(e=>e.id)};return c(JSON.stringify(l,null,2))}catch(e){return s.error(`flow_step failed`,o(e)),c(`Error: ${l(e)}`)}});let y=e(`flow_status`);a.registerTool(`flow_status`,{title:y.title,description:`Show the current flow execution state — which flow is active, current step, completed steps, and artifacts.`,annotations:y.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await m(),r=t.getStatus();if(!r.success||!r.data)return c(`No active flow. Use flow_start to begin one, or flow_list to see available flows.`);let i=r.data,a=e.get(i.flow),o=a?.manifest.steps.find(e=>e.id===i.currentStep),s=a&&o?n(a.installPath,o.skill):null,l={flow:i.flow,status:i.status,currentStep:i.currentStep,currentStepSkill:o?.skill??null,skillPath:s,currentStepDescription:o?.description??null,completedSteps:i.completedSteps,skippedSteps:i.skippedSteps,artifacts:i.artifacts,startedAt:i.startedAt,updatedAt:i.updatedAt,totalSteps:a?.manifest.steps.length??0,progress:a?`${i.completedSteps.length+i.skippedSteps.length}/${a.manifest.steps.length}`:`unknown`};return c(JSON.stringify(l,null,2))}catch(e){return s.error(`flow_status failed`,o(e)),c(`Error: ${l(e)}`)}});let b=e(`flow_read_skill`);a.registerTool(`flow_read_skill`,{title:b.title===`flow_read_skill`?`Flow Read Skill`:b.title,description:`Read the skill or instruction content for a flow step. If step is omitted, reads the current step.`,annotations:b.title===`flow_read_skill`?{readOnlyHint:!0,idempotentHint:!0}:b.annotations,inputSchema:{step:i.string().optional().describe(`Step id or name to read. Defaults to the current step.`)}},async({step:e})=>{try{let{registry:t,stateMachine:i}=await m(),a=i.getStatus();if(!a.success||!a.data)return c(`No active flow. Use flow_start to begin one, or flow_list to see available flows.`);let o=a.data,s=t.get(o.flow);if(!s)return c(`Flow "${o.flow}" not found in registry.`);let l=e??o.currentStep;if(!l)return c(`No current step is available for the active flow.`);let u=s.manifest.steps.find(e=>e.id===l||e.name===l);return c(u?await r(n(s.installPath,u.skill),`utf-8`):`Step "${l}" not found in flow "${o.flow}".`)}catch(e){return s.error(`flow_read_skill failed`,o(e)),e instanceof Error&&`code`in e&&e.code===`ENOENT`?c(`Could not read skill file: ${e.message}`):c(`Error: ${l(e)}`)}});let x=e(`flow_reset`);a.registerTool(`flow_reset`,{title:x.title,description:`Reset the active flow, clearing all state. Use to start over or switch to a different flow.`,annotations:x.annotations,inputSchema:{}},async()=>{try{let{stateMachine:e}=await m(),t=e.reset();return t.success?c(`Flow state reset. Use flow_start to begin a new flow.`):c(`Reset failed: ${t.error}`)}catch(e){return s.error(`flow_reset failed`,o(e)),c(`Error: ${l(e)}`)}})}export{u as registerFlowTools};
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{basename as t,join as n,resolve as r}from"node:path";import{z as i}from"zod";import{readFile as a}from"node:fs/promises";import{createLogger as o,serializeError as s}from"../../../core/dist/index.js";const c=o(`flow-tools`);function l(e){return{content:[{type:`text`,text:e}]}}function u(e){return e instanceof Error?e.message:String(e)}function d(o,d){let f=d.sources?.[0]?.path??process.cwd(),p=n(d.stateDir??n(d.sources[0].path,`.aikit-state`),`flows`),m=n(p,`registry.json`),h=n(p,`state.json`);function g(e,n){let i;return i=e.sourceType===`builtin`?r(f,`.github`,`flows`,t(e.installPath),n):r(e.installPath,n),i.replaceAll(`\\`,`/`)}function _(e){return e.sourceType===`builtin`?r(f,`.github`,`flows`,t(e.installPath)).replaceAll(`\\`,`/`):e.installPath.replaceAll(`\\`,`/`)}async function v(){let{FlowRegistryManager:e,FlowStateMachine:t}=await import(`../../../flows/dist/index.js`);return{registry:new e(m),stateMachine:new t(h)}}let y=e(`flow_list`);o.registerTool(`flow_list`,{title:y.title,description:`List all installed flows and their steps`,annotations:y.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await v(),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 l(JSON.stringify(i,null,2))}catch(e){return c.error(`flow_list failed`,s(e)),l(`Error: ${u(e)}`)}});let b=e(`flow_info`);o.registerTool(`flow_info`,{title:b.title,description:`Show detailed information about a specific flow`,annotations:b.annotations,inputSchema:{name:i.string().describe(`Flow name to get info for`)}},async({name:e})=>{try{let{registry:t}=await v(),n=t.get(e);if(!n)return l(`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),registeredAt:n.registeredAt,updatedAt:n.updatedAt,steps:n.manifest.steps.map(e=>({id:e.id,name:e.name,skill:g(n,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 l(JSON.stringify(r,null,2))}catch(e){return c.error(`flow_info failed`,s(e)),l(`Error: ${u(e)}`)}});let x=e(`flow_start`);o.registerTool(`flow_start`,{title:x.title,description:`Start a flow. Sets the active flow and positions at the first step.`,annotations:x.annotations,inputSchema:{flow:i.string().describe(`Flow name to start (use flow_list to see options)`)}},async({flow:e})=>{try{let{registry:t,stateMachine:n}=await v(),r=t.get(e);if(!r)return l(`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 l(`Cannot start: ${i.error}`);let a=i.data,o=r.manifest.steps.find(e=>e.id===a.currentStep),s={started:!0,flow:a.flow,currentStep:a.currentStep,currentStepSkill:r&&o?g(r,o.skill):null,currentStepDescription:o?.description??null,totalSteps:r.manifest.steps.length,stepSequence:r.manifest.steps.map(e=>e.id),artifactsDir:r.manifest.artifacts_dir};return l(JSON.stringify(s,null,2))}catch(e){return c.error(`flow_start failed`,s(e)),l(`Error: ${u(e)}`)}});let S=e(`flow_step`);o.registerTool(`flow_step`,{title:S.title,description:`Advance the active flow: complete current step and move to next, skip current step, or redo current step.`,annotations:S.annotations,inputSchema:{action:i.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 v(),r=n.load();if(!r)return l(`No active flow. Use flow_start first.`);let i=t.get(r.flow);if(!i)return l(`Flow "${r.flow}" not found in registry.`);let a=n.step(e,i.manifest);if(!a.success||!a.data)return l(`Cannot ${e}: ${a.error}`);let o=a.data,s=o.currentStep?i.manifest.steps.find(e=>e.id===o.currentStep):null,c={flow:o.flow,status:o.status,action:e,currentStep:o.currentStep,currentStepSkill:i&&s?g(i,s.skill):null,currentStepDescription:s?.description??null,completedSteps:o.completedSteps,skippedSteps:o.skippedSteps,totalSteps:i.manifest.steps.length,remaining:i.manifest.steps.filter(e=>!o.completedSteps.includes(e.id)&&!o.skippedSteps.includes(e.id)&&e.id!==o.currentStep).map(e=>e.id)};return l(JSON.stringify(c,null,2))}catch(e){return c.error(`flow_step failed`,s(e)),l(`Error: ${u(e)}`)}});let C=e(`flow_status`);o.registerTool(`flow_status`,{title:C.title,description:`Show the current flow execution state — which flow is active, current step, completed steps, and artifacts.`,annotations:C.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await v(),n=t.getStatus();if(!n.success||!n.data)return l(`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),o=i&&a?g(i,a.skill):null,s={flow:r.flow,status:r.status,currentStep:r.currentStep,currentStepSkill:o,skillPath:o,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 l(JSON.stringify(s,null,2))}catch(e){return c.error(`flow_status failed`,s(e)),l(`Error: ${u(e)}`)}});let w=e(`flow_read_skill`);o.registerTool(`flow_read_skill`,{title:w.title===`flow_read_skill`?`Flow Read Skill`:w.title,description:`Read the skill or instruction content for a flow step. If step is omitted, reads the current step.`,annotations:w.title===`flow_read_skill`?{readOnlyHint:!0,idempotentHint:!0}:w.annotations,inputSchema:{step:i.string().optional().describe(`Step id or name to read. Defaults to the current step.`)}},async({step:e})=>{try{let{registry:t,stateMachine:n}=await v(),r=n.getStatus();if(!r.success||!r.data)return l(`No active flow. Use flow_start to begin one, or flow_list to see available flows.`);let i=r.data,o=t.get(i.flow);if(!o)return l(`Flow "${i.flow}" not found in registry.`);let s=e??i.currentStep;if(!s)return l(`No current step is available for the active flow.`);let c=o.manifest.steps.find(e=>e.id===s||e.name===s);return l(c?await a(g(o,c.skill),`utf-8`):`Step "${s}" not found in flow "${i.flow}".`)}catch(e){return c.error(`flow_read_skill failed`,s(e)),e instanceof Error&&`code`in e&&e.code===`ENOENT`?l(`Could not read skill file: ${e.message}`):l(`Error: ${u(e)}`)}});let T=e(`flow_reset`);o.registerTool(`flow_reset`,{title:T.title,description:`Reset the active flow, clearing all state. Use to start over or switch to a different flow.`,annotations:T.annotations,inputSchema:{}},async()=>{try{let{stateMachine:e}=await v(),t=e.reset();return t.success?l(`Flow state reset. Use flow_start to begin a new flow.`):l(`Reset failed: ${t.error}`)}catch(e){return c.error(`flow_reset failed`,s(e)),l(`Error: ${u(e)}`)}})}export{d as registerFlowTools};
@@ -1,2 +1,2 @@
1
- import{getToolMeta as e}from"../tool-metadata.js";import{createTaskRunner as t}from"../task-manager.js";import{createHash as n}from"node:crypto";import{z as r}from"zod";import{createLogger as i,serializeError as a}from"../../../core/dist/index.js";import{onboard as o}from"../../../tools/dist/index.js";const s=i(`tools`);let c=!1;async function l(e,t,r){for(let i of r.steps)if(!(i.status!==`success`||!i.output))try{let a=n(`sha256`).update(r.path).digest(`hex`).slice(0,12),o=`produced/onboard/${i.name}/${a}.md`,s=n(`sha256`).update(i.output).digest(`hex`).slice(0,16),c=new Date().toISOString(),l=i.output.length>2e3?i.output.split(/(?=^## )/m).filter(e=>e.trim().length>0):[i.output],u=l.map((e,t)=>({id:n(`sha256`).update(`${o}::${t}`).digest(`hex`).slice(0,16),content:e.trim(),sourcePath:o,contentType:`produced-knowledge`,chunkIndex:t,totalChunks:l.length,startLine:0,endLine:0,fileHash:s,indexedAt:c,origin:`produced`,tags:[`onboard`,i.name],category:`analysis`,version:1})),d=await t.embedBatch(u.map(e=>e.content));await e.upsert(u,d)}catch(e){s.warn(`Auto-persist onboard step failed`,{stepName:i.name,...a(e)})}}async function u(e,t,r){if(r.autoRemember?.length)for(let i of r.autoRemember)try{let r=n(`sha256`).update(`onboard-remember::${i.title}`).digest(`hex`).slice(0,16),a=new Date().toISOString(),o={id:r,content:`# ${i.title}\n\n${i.content}`,sourcePath:`curated/onboard/${i.category}/${r}.md`,contentType:`curated`,chunkIndex:0,totalChunks:1,startLine:0,endLine:0,fileHash:n(`sha256`).update(i.content).digest(`hex`).slice(0,16),indexedAt:a,origin:`curated`,tags:i.tags,category:i.category,version:1},[s]=await t.embedBatch([o.content]);await e.upsert([o],[s])}catch(e){s.warn(`Auto-persist remember entry failed`,{title:i.title,...a(e)})}}function d(n,i,d,f){let p=e(`onboard`);n.registerTool(`onboard`,{title:p.title,description:`First-time codebase onboarding: runs all analysis tools (structure, dependencies, entry-points, symbols, patterns, diagram) in one command. Results are auto-persisted to KB. Use mode=generate to also write structured output to .ai/kb/ directory.`,inputSchema:{path:r.string().describe(`Root path of the codebase to onboard`),mode:r.enum([`memory`,`generate`]).default(`generate`).describe(`Output mode: generate (default) = persist to AI Kit + write .ai/kb/ files; memory = AI Kit vector store only`),out_dir:r.string().optional().describe(`Custom output directory for generate mode (default: <path>/.ai/kb)`)},annotations:p.annotations},async({path:e,mode:n,out_dir:r},p)=>{try{if(c)return{content:[{type:`text`,text:`Onboard is already running. Please wait for it to complete before starting another.`}]};c=!0,s.info(`Starting onboard`,{path:e,mode:n});let m=await o({path:e,mode:n,outDir:r??f?.onboardDir}),h=t(p).createTask(`Onboard`,m.steps.length);for(let e=0;e<m.steps.length;e++){let t=m.steps[e];h.progress(e,`${t.name}: ${t.status}`)}h.complete(`Onboard complete: ${m.steps.filter(e=>e.status===`success`).length}/${m.steps.length} steps succeeded`),l(i,d,m),m.autoRemember?.length&&u(i,d,m).catch(e=>{s.warn(`Auto-persist autoRemember failed`,a(e))});let g=[`## Onboard Complete`,``,`**Path:** \`${m.path}\``,`**Mode:** ${m.mode}`,`**Duration:** ${m.totalDurationMs}ms`,``];m.outDir&&(g.push(`**Output directory:** \`${m.outDir}\``),g.push(``)),g.push(`### Analysis Results`,``);let _=[],v=[];for(let e of m.steps)e.status===`success`?_.push(`- ✓ **${e.name}** (${e.durationMs}ms) — ${e.output.length} chars`):v.push(`- ✗ **${e.name}** — ${e.error}`);g.push(..._),v.length>0&&g.push(``,`### Failed`,``,...v),g.push(``,`---`,``);for(let e of m.steps)e.status===`success`&&g.push(`### ${e.name}`,``,e.output,``,`---`,``);return g.push(`_All results auto-saved to KB.`,m.mode===`generate`?` Files written to \`${m.outDir}\`.`:``," Next: Use `search` to query the knowledge, or `remember` to add custom insights._"),{content:[{type:`text`,text:g.join(`
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{createTaskRunner as t}from"../task-manager.js";import{z as n}from"zod";import{createHash as r}from"node:crypto";import{createLogger as i,serializeError as a}from"../../../core/dist/index.js";import{onboard as o}from"../../../tools/dist/index.js";const s=i(`tools`);let c=!1;async function l(e,t,n){for(let i of n.steps)if(!(i.status!==`success`||!i.output))try{let a=r(`sha256`).update(n.path).digest(`hex`).slice(0,12),o=`produced/onboard/${i.name}/${a}.md`,s=r(`sha256`).update(i.output).digest(`hex`).slice(0,16),c=new Date().toISOString(),l=i.output.length>2e3?i.output.split(/(?=^## )/m).filter(e=>e.trim().length>0):[i.output],u=l.map((e,t)=>({id:r(`sha256`).update(`${o}::${t}`).digest(`hex`).slice(0,16),content:e.trim(),sourcePath:o,contentType:`produced-knowledge`,chunkIndex:t,totalChunks:l.length,startLine:0,endLine:0,fileHash:s,indexedAt:c,origin:`produced`,tags:[`onboard`,i.name],category:`analysis`,version:1})),d=await t.embedBatch(u.map(e=>e.content));await e.upsert(u,d)}catch(e){s.warn(`Auto-persist onboard step failed`,{stepName:i.name,...a(e)})}}async function u(e,t,n){if(n.autoRemember?.length)for(let i of n.autoRemember)try{let n=r(`sha256`).update(`onboard-remember::${i.title}`).digest(`hex`).slice(0,16),a=new Date().toISOString(),o={id:n,content:`# ${i.title}\n\n${i.content}`,sourcePath:`curated/onboard/${i.category}/${n}.md`,contentType:`curated`,chunkIndex:0,totalChunks:1,startLine:0,endLine:0,fileHash:r(`sha256`).update(i.content).digest(`hex`).slice(0,16),indexedAt:a,origin:`curated`,tags:i.tags,category:i.category,version:1},[s]=await t.embedBatch([o.content]);await e.upsert([o],[s])}catch(e){s.warn(`Auto-persist remember entry failed`,{title:i.title,...a(e)})}}function d(r,i,d,f){let p=e(`onboard`);r.registerTool(`onboard`,{title:p.title,description:`First-time codebase onboarding: runs all analysis tools (structure, dependencies, entry-points, symbols, patterns, diagram) in one command. Results are auto-persisted to KB. Use mode=generate to also write structured output to .ai/kb/ directory.`,inputSchema:{path:n.string().describe(`Root path of the codebase to onboard`),mode:n.enum([`memory`,`generate`]).default(`generate`).describe(`Output mode: generate (default) = persist to AI Kit + write .ai/kb/ files; memory = AI Kit vector store only`),out_dir:n.string().optional().describe(`Custom output directory for generate mode (default: <path>/.ai/kb)`)},annotations:p.annotations},async({path:e,mode:n,out_dir:r},p)=>{try{if(c)return{content:[{type:`text`,text:`Onboard is already running. Please wait for it to complete before starting another.`}]};c=!0,s.info(`Starting onboard`,{path:e,mode:n});let m=await o({path:e,mode:n,outDir:r??f?.onboardDir}),h=t(p).createTask(`Onboard`,m.steps.length);for(let e=0;e<m.steps.length;e++){let t=m.steps[e];h.progress(e,`${t.name}: ${t.status}`)}h.complete(`Onboard complete: ${m.steps.filter(e=>e.status===`success`).length}/${m.steps.length} steps succeeded`),l(i,d,m),m.autoRemember?.length&&u(i,d,m).catch(e=>{s.warn(`Auto-persist autoRemember failed`,a(e))});let g=[`## Onboard Complete`,``,`**Path:** \`${m.path}\``,`**Mode:** ${m.mode}`,`**Duration:** ${m.totalDurationMs}ms`,``];m.outDir&&(g.push(`**Output directory:** \`${m.outDir}\``),g.push(``)),g.push(`### Analysis Results`,``);let _=[],v=[];for(let e of m.steps)e.status===`success`?_.push(`- ✓ **${e.name}** (${e.durationMs}ms) — ${e.output.length} chars`):v.push(`- ✗ **${e.name}** — ${e.error}`);g.push(..._),v.length>0&&g.push(``,`### Failed`,``,...v),g.push(``,`---`,``);for(let e of m.steps)e.status===`success`&&g.push(`### ${e.name}`,``,e.output,``,`---`,``);return g.push(`_All results auto-saved to KB.`,m.mode===`generate`?` Files written to \`${m.outDir}\`.`:``," Next: Use `search` to query the knowledge, or `remember` to add custom insights._"),{content:[{type:`text`,text:g.join(`
2
2
  `)}]}}catch(e){return s.error(`Onboard failed`,a(e)),{content:[{type:`text`,text:`Onboard failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}finally{c=!1}})}export{d as registerOnboardTool};
@@ -63,8 +63,8 @@ import{escHtml as e}from"../present-utils.js";function t(t,f){let p=typeof f==`s
63
63
  });
64
64
  const order = [...list.children].map(c => c.dataset.id);
65
65
  document.getElementById('sortStatus').textContent = 'Reordered: ' + order.join(', ');
66
- if(window.__kbCallback) {
67
- fetch(window.__kbCallback, {method:'POST',headers:{'Content-Type':'application/json'},
66
+ if(window.__aikitCallback) {
67
+ fetch(window.__aikitCallback, {method:'POST',headers:{'Content-Type':'application/json'},
68
68
  body: JSON.stringify({actionId:'reorder',value:JSON.stringify(order)})}).catch(()=>{});
69
69
  }
70
70
  });
@@ -211,8 +211,8 @@ ${a}
211
211
  });
212
212
  document.getElementById('pkApply').addEventListener('click', () => {
213
213
  const selected = [...list.querySelectorAll('input:checked')].map(cb => cb.dataset.id);
214
- if(window.__kbCallback) {
215
- fetch(window.__kbCallback, {method:'POST',headers:{'Content-Type':'application/json'},
214
+ if(window.__aikitCallback) {
215
+ fetch(window.__aikitCallback, {method:'POST',headers:{'Content-Type':'application/json'},
216
216
  body:JSON.stringify({actionId:'pick',value:JSON.stringify(selected)})}).catch(()=>{});
217
217
  }
218
218
  });
@@ -347,8 +347,8 @@ ${a}
347
347
  updatePreview();
348
348
 
349
349
  document.getElementById('fmSubmit').addEventListener('click', () => {
350
- if(window.__kbCallback) {
351
- fetch(window.__kbCallback, {method:'POST',headers:{'Content-Type':'application/json'},
350
+ if(window.__aikitCallback) {
351
+ fetch(window.__aikitCallback, {method:'POST',headers:{'Content-Type':'application/json'},
352
352
  body:JSON.stringify({actionId:'submit',value:JSON.stringify(getValues())})}).catch(()=>{});
353
353
  }
354
354
  });
@@ -1,5 +1,5 @@
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(`
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{z as l}from"zod";import{stat as u}from"node:fs/promises";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 u(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,u,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:l.string().max(5e3).describe(`Natural language search query`),limit:l.number().min(1).max(20).default(5).describe(`Maximum results to return`),search_mode:l.enum([`hybrid`,`semantic`,`keyword`]).default(`hybrid`).describe(`Search strategy: hybrid (vector + FTS + RRF fusion, default), semantic (vector only), keyword (FTS only)`),content_type:l.enum(d).optional().describe(`Filter by content type`),source_type:l.enum(p).optional().describe(`Coarse filter: "source" (code only), "documentation" (md, curated), "test", "config". Overrides content_type if both set.`),origin:l.enum(f).optional().describe(`Filter by knowledge origin`),category:l.string().optional().describe(`Filter by category (e.g., decisions, patterns, conventions)`),tags:l.array(l.string()).optional().describe(`Filter by tags (returns results matching ANY of the specified tags)`),min_score:l.number().min(0).max(1).default(.25).describe(`Minimum similarity score`),graph_hops:l.number().min(0).max(3).default(1).describe(`Number of graph hops to augment results with connected entities (0 = disabled, 1 = direct connections, 2-3 = deeper traversal). Default 1 provides module/symbol context automatically.`),max_tokens:l.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`),dedup:l.enum([`file`,`chunk`]).default(`chunk`).describe(`Deduplication mode: "chunk" (default, show all matching chunks) or "file" (collapse chunks from same file into single result with merged line ranges)`),workspaces:l.array(l.string()).optional().describe(`Cross-workspace search: partition names or folder basenames to include. Use ["*"] for all registered workspaces. Only works in user-level install mode.`)},annotations:k.annotations},async({query:e,limit:t,search_mode:c,content_type:l,source_type: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:l,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 u.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 u.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 u.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 u.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
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(`
@@ -1 +1 @@
1
- import{EMBEDDING_DEFAULTS as e,SEARCH_DEFAULTS as t,STORE_DEFAULTS as n,createLogger as r,serializeError as i,sourceTypeContentTypes as a}from"../../core/dist/index.js";import{Index as o,connect as s}from"@lancedb/lancedb";function c(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}const l=/^[\w.\-/ ]+$/,u=r(`store`);function d(e,t){if(!l.test(e))throw Error(`Invalid ${t} filter value: contains disallowed characters`);return e.replace(/'/g,`''`)}var f=class{db=null;table=null;dbPath;tableName;_draining=!1;_priorityQueue=[];_normalQueue=[];_ftsReady=!1;enqueueWrite(e,t=!1){return new Promise((n,r)=>{let i=async()=>{try{n(await e())}catch(e){r(e)}};t?this._priorityQueue.push(i):this._normalQueue.push(i),this._drain()})}async _drain(){if(!this._draining){this._draining=!0;try{for(;this._priorityQueue.length>0||this._normalQueue.length>0;){let e=this._priorityQueue.shift()??this._normalQueue.shift();e&&await e()}}finally{this._draining=!1}}}constructor(e){this.dbPath=e?.path??n.path,this.tableName=e?.tableName??n.tableName}async initialize(){this.db=await s(this.dbPath),(await this.db.tableNames()).includes(this.tableName)&&(this.table=await this.db.openTable(this.tableName),await this.createFtsIndex())}async upsert(e,t){if(e.length!==0){if(e.length!==t.length)throw Error(`Record count (${e.length}) does not match vector count (${t.length})`);return this.enqueueWrite(()=>this._upsertImpl(e,t))}}async upsertInteractive(e,t){if(e.length!==0){if(e.length!==t.length)throw Error(`Record count (${e.length}) does not match vector count (${t.length})`);return this.enqueueWrite(()=>this._upsertImpl(e,t),!0)}}async _upsertImpl(e,t){let n=e.map((e,n)=>({id:e.id,vector:Array.from(t[n]),content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath??``,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,indexedAt:e.indexedAt,origin:e.origin,tags:JSON.stringify(e.tags),category:e.category??``,version:e.version}));if(this.table){let t=[...new Set(e.map(e=>e.sourcePath))];for(let e of t)try{await this.table.delete(`sourcePath = '${d(e,`sourcePath`)}'`)}catch{}await this.table.add(n)}else try{this.table=await this.db?.createTable(this.tableName,n)??null}catch(e){if(String(e).includes(`already exists`)&&this.db)this.table=await this.db.openTable(this.tableName),await this.table.add(n);else throw e}}async search(e,n){if(!this.table)return[];let r=n?.limit??t.maxResults,i=n?.minScore??t.minScore,a=this.table.search(e).limit(r*2),o=this.buildFilterString(n);return o&&(a=a.where(o)),(await a.toArray()).map(e=>({record:this.fromLanceRecord(e),score:1-(e._distance??1)})).filter(e=>e.score>=i).slice(0,r)}async createFtsIndex(){return this.enqueueWrite(()=>this._createFtsIndexImpl())}async _createFtsIndexImpl(){if(this.table)try{await this.table.createIndex(`content`,{config:o.fts(),replace:!0}),this._ftsReady=!0,u.info(`FTS index created/updated`,{column:`content`})}catch(e){u.warn(`FTS index creation failed`,i(e))}}async ftsSearch(e,n){if(!this.table||!this._ftsReady)return[];let r=n?.limit??t.maxResults;try{let t=this.table.search(e).limit(r*2),i=this.buildFilterString(n);return i&&(t=t.where(i)),(await t.toArray()).map(e=>({record:this.fromLanceRecord(e),score:e._score??e._relevance_score??0}))}catch(e){return(e instanceof Error?e.message:String(e)).includes(`INVERTED index`)?(u.debug(`FTS search skipped — index not yet available`),this._ftsReady=!1):u.warn(`FTS search failed`,i(e)),[]}}async getById(e){if(!this.table)return null;let t=await this.table.query().where(`id = '${d(e,`id`)}'`).limit(1).toArray();return t.length===0?null:this.fromLanceRecord(t[0])}async deleteBySourcePath(e){return this.enqueueWrite(()=>this._deleteBySourcePathImpl(e))}async _deleteBySourcePathImpl(e){if(!this.table)return 0;let t=await this.getBySourcePath(e);return t.length===0?0:(await this.table.delete(`sourcePath = '${d(e,`sourcePath`)}'`),t.length)}async deleteById(e){return this.enqueueWrite(()=>this._deleteByIdImpl(e))}async deleteByIdInteractive(e){return this.enqueueWrite(()=>this._deleteByIdImpl(e),!0)}async _deleteByIdImpl(e){return!this.table||!await this.getById(e)?!1:(await this.table.delete(`id = '${d(e,`id`)}'`),!0)}async getBySourcePath(e){return this.table?(await this.table.query().where(`sourcePath = '${d(e,`sourcePath`)}'`).limit(1e3).toArray()).map(e=>this.fromLanceRecord(e)):[]}async getStats(){if(!this.table)return{totalRecords:0,totalFiles:0,contentTypeBreakdown:{},lastIndexedAt:null,storeBackend:`lancedb`,embeddingModel:e.model};let t=await this.table.countRows(),n=await this.table.query().select([`sourcePath`,`contentType`,`indexedAt`]).limit(1e5).toArray(),r={},i=new Set,a=null;for(let e of n){let t=e;r[t.contentType]=(r[t.contentType]??0)+1,i.add(t.sourcePath),(!a||t.indexedAt>a)&&(a=t.indexedAt)}return{totalRecords:t,totalFiles:i.size,contentTypeBreakdown:r,lastIndexedAt:a,storeBackend:`lancedb`,embeddingModel:e.model}}async listSourcePaths(){if(!this.table)return[];let e=await this.table.query().select([`sourcePath`]).limit(1e5).toArray();return[...new Set(e.map(e=>e.sourcePath))]}async dropTable(){return this.enqueueWrite(()=>this._dropTableImpl())}async _dropTableImpl(){if(this.db&&(await this.db.tableNames()).includes(this.tableName))for(let e=1;e<=3;e++)try{await this.db.dropTable(this.tableName);break}catch(t){if(e===3)throw t;let n=e*500;u.warn(`dropTable attempt failed, retrying`,{attempt:e,delayMs:n}),await new Promise(e=>setTimeout(e,n))}this.table=null}async close(){try{this.db&&typeof this.db.close==`function`&&await this.db.close()}catch{}this.table=null,this.db=null}buildFilterString(e){let t=[];if(e?.contentType&&t.push(`contentType = '${d(e.contentType,`contentType`)}'`),e?.sourceType){let n=a(e.sourceType);if(n.length>0){let e=n.map(e=>`'${d(e,`sourceType`)}'`).join(`, `);t.push(`contentType IN (${e})`)}}if(e?.origin&&t.push(`origin = '${d(e.origin,`origin`)}'`),e?.category&&t.push(`category = '${d(e.category,`category`)}'`),e?.tags&&e.tags.length>0){let n=e.tags.map(e=>`tags LIKE '%${d(e,`tag`)}%'`);t.push(`(${n.join(` OR `)})`)}return t.length>0?t.join(` AND `):null}fromLanceRecord(e){return{id:e.id,content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath||void 0,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,indexedAt:e.indexedAt,origin:e.origin,tags:c(e.tags),category:e.category||void 0,version:e.version}}};export{f as LanceStore};
1
+ import{EMBEDDING_DEFAULTS as e,SEARCH_DEFAULTS as t,STORE_DEFAULTS as n,createLogger as r,serializeError as i,sourceTypeContentTypes as a}from"../../core/dist/index.js";import{Index as o,connect as s}from"@lancedb/lancedb";function c(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}const l=/^[\w.\-/ ]+$/,u=r(`store`);function d(e,t){if(!l.test(e))throw Error(`Invalid ${t} filter value: contains disallowed characters`);return e.replace(/'/g,`''`)}var f=class{db=null;table=null;dbPath;tableName;_draining=!1;_priorityQueue=[];_normalQueue=[];_ftsReady=!1;enqueueWrite(e,t=!1){return new Promise((n,r)=>{let i=async()=>{try{n(await e())}catch(e){r(e)}};t?this._priorityQueue.push(i):this._normalQueue.push(i),this._drain()})}async _drain(){if(!this._draining){this._draining=!0;try{for(;this._priorityQueue.length>0||this._normalQueue.length>0;){let e=this._priorityQueue.shift()??this._normalQueue.shift();e&&await e()}}finally{this._draining=!1}}}constructor(e){this.dbPath=e?.path??n.path,this.tableName=e?.tableName??n.tableName}async initialize(){this.db=await s(this.dbPath),(await this.db.tableNames()).includes(this.tableName)&&(this.table=await this.db.openTable(this.tableName),await this.createFtsIndex())}async upsert(e,t){if(e.length!==0){if(e.length!==t.length)throw Error(`Record count (${e.length}) does not match vector count (${t.length})`);return this.enqueueWrite(()=>this._upsertImpl(e,t))}}async upsertInteractive(e,t){if(e.length!==0){if(e.length!==t.length)throw Error(`Record count (${e.length}) does not match vector count (${t.length})`);return this.enqueueWrite(()=>this._upsertImpl(e,t),!0)}}async _upsertImpl(e,t){let n=e.map((e,n)=>({id:e.id,vector:Array.from(t[n]),content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath??``,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,indexedAt:e.indexedAt,origin:e.origin,tags:JSON.stringify(e.tags),category:e.category??``,version:e.version}));if(this.table){let t=[...new Set(e.map(e=>e.sourcePath))];for(let e of t)try{await this.table.delete(`sourcePath = '${d(e,`sourcePath`)}'`)}catch{}await this.table.add(n)}else try{this.table=await this.db?.createTable(this.tableName,n)??null}catch(e){if(String(e).includes(`already exists`)&&this.db)this.table=await this.db.openTable(this.tableName),await this.table.add(n);else throw e}}async search(e,n){if(!this.table)return[];let r=n?.limit??t.maxResults,i=n?.minScore??t.minScore,a=this.table.search(e).limit(r*2),o=this.buildFilterString(n);return o&&(a=a.where(o)),(await a.toArray()).map(e=>({record:this.fromLanceRecord(e),score:1-(e._distance??1)})).filter(e=>e.score>=i).slice(0,r)}async createFtsIndex(){return this.enqueueWrite(()=>this._createFtsIndexImpl())}async _createFtsIndexImpl(){if(this.table)try{await this.table.createIndex(`content`,{config:o.fts({withPosition:!0}),replace:!0}),this._ftsReady=!0,u.info(`FTS index created/updated`,{column:`content`})}catch(e){u.warn(`FTS index creation failed`,i(e))}}async ftsSearch(e,n){if(!this.table||!this._ftsReady)return[];let r=n?.limit??t.maxResults;try{let t=this.table.search(e).limit(r*2),i=this.buildFilterString(n);return i&&(t=t.where(i)),(await t.toArray()).map(e=>({record:this.fromLanceRecord(e),score:e._score??e._relevance_score??0}))}catch(e){return(e instanceof Error?e.message:String(e)).includes(`INVERTED index`)?(u.debug(`FTS search skipped — index not yet available`),this._ftsReady=!1):u.warn(`FTS search failed`,i(e)),[]}}async getById(e){if(!this.table)return null;let t=await this.table.query().where(`id = '${d(e,`id`)}'`).limit(1).toArray();return t.length===0?null:this.fromLanceRecord(t[0])}async deleteBySourcePath(e){return this.enqueueWrite(()=>this._deleteBySourcePathImpl(e))}async _deleteBySourcePathImpl(e){if(!this.table)return 0;let t=await this.getBySourcePath(e);return t.length===0?0:(await this.table.delete(`sourcePath = '${d(e,`sourcePath`)}'`),t.length)}async deleteById(e){return this.enqueueWrite(()=>this._deleteByIdImpl(e))}async deleteByIdInteractive(e){return this.enqueueWrite(()=>this._deleteByIdImpl(e),!0)}async _deleteByIdImpl(e){return!this.table||!await this.getById(e)?!1:(await this.table.delete(`id = '${d(e,`id`)}'`),!0)}async getBySourcePath(e){return this.table?(await this.table.query().where(`sourcePath = '${d(e,`sourcePath`)}'`).limit(1e3).toArray()).map(e=>this.fromLanceRecord(e)):[]}async getStats(){if(!this.table)return{totalRecords:0,totalFiles:0,contentTypeBreakdown:{},lastIndexedAt:null,storeBackend:`lancedb`,embeddingModel:e.model};let t=await this.table.countRows(),n=await this.table.query().select([`sourcePath`,`contentType`,`indexedAt`]).limit(1e5).toArray(),r={},i=new Set,a=null;for(let e of n){let t=e;r[t.contentType]=(r[t.contentType]??0)+1,i.add(t.sourcePath),(!a||t.indexedAt>a)&&(a=t.indexedAt)}return{totalRecords:t,totalFiles:i.size,contentTypeBreakdown:r,lastIndexedAt:a,storeBackend:`lancedb`,embeddingModel:e.model}}async listSourcePaths(){if(!this.table)return[];let e=await this.table.query().select([`sourcePath`]).limit(1e5).toArray();return[...new Set(e.map(e=>e.sourcePath))]}async dropTable(){return this.enqueueWrite(()=>this._dropTableImpl())}async _dropTableImpl(){if(this.db&&(await this.db.tableNames()).includes(this.tableName))for(let e=1;e<=3;e++)try{await this.db.dropTable(this.tableName);break}catch(t){if(e===3)throw t;let n=e*500;u.warn(`dropTable attempt failed, retrying`,{attempt:e,delayMs:n}),await new Promise(e=>setTimeout(e,n))}this.table=null}async close(){try{this.db&&typeof this.db.close==`function`&&await this.db.close()}catch{}this.table=null,this.db=null}buildFilterString(e){let t=[];if(e?.contentType&&t.push(`contentType = '${d(e.contentType,`contentType`)}'`),e?.sourceType){let n=a(e.sourceType);if(n.length>0){let e=n.map(e=>`'${d(e,`sourceType`)}'`).join(`, `);t.push(`contentType IN (${e})`)}}if(e?.origin&&t.push(`origin = '${d(e.origin,`origin`)}'`),e?.category&&t.push(`category = '${d(e.category,`category`)}'`),e?.tags&&e.tags.length>0){let n=e.tags.map(e=>`tags LIKE '%${d(e,`tag`)}%'`);t.push(`(${n.join(` OR `)})`)}return t.length>0?t.join(` AND `):null}fromLanceRecord(e){return{id:e.id,content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath||void 0,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,indexedAt:e.indexedAt,origin:e.origin,tags:c(e.tags),category:e.category||void 0,version:e.version}}};export{f as LanceStore};
@@ -143,6 +143,9 @@ function generateSingleAgent(name, def) {
143
143
  : AGENT_BODIES[name] || '';
144
144
 
145
145
  const title = def.title || name;
146
+ const skillsSection = def.skills?.length
147
+ ? `\n## Skills (load on demand)\n\n| Skill | When to load |\n|-------|--------------|\n${def.skills.map(([s, w]) => `| ${s} | ${w} |`).join('\n')}\n`
148
+ : '';
146
149
 
147
150
  return `---
148
151
  description: '${def.description}'
@@ -154,7 +157,7 @@ model: ${model}
154
157
 
155
158
  You are the **${name}**, ${def.description.toLowerCase().replace(/^./, (c) => c.toLowerCase())}
156
159
 
157
- ${body}
160
+ ${body}${skillsSection}
158
161
 
159
162
  ${FLOWS_SECTION}
160
163
  `;
@@ -42,6 +42,10 @@ export const AGENTS = {
42
42
  toolRole: 'codeAgent',
43
43
  sharedBase: 'code-agent-base',
44
44
  category: 'implementation',
45
+ skills: [
46
+ ['aikit', '**Always** — AI Kit tool signatures, search, analysis'],
47
+ ['typescript', 'When writing TypeScript code — type patterns, generics, utility types'],
48
+ ],
45
49
  },
46
50
 
47
51
  Frontend: {
@@ -52,6 +56,15 @@ export const AGENTS = {
52
56
  toolRole: 'codeAgent',
53
57
  sharedBase: 'code-agent-base',
54
58
  category: 'implementation',
59
+ skills: [
60
+ ['aikit', '**Always** — AI Kit tool signatures, search, analysis'],
61
+ ['react', 'When building React components — hooks, patterns, Server Components'],
62
+ ['typescript', 'When writing TypeScript code — type patterns, generics, utility types'],
63
+ [
64
+ 'frontend-design',
65
+ 'When implementing UI/UX — design systems, accessibility, responsive patterns',
66
+ ],
67
+ ],
55
68
  },
56
69
 
57
70
  Refactor: {
@@ -73,6 +86,10 @@ export const AGENTS = {
73
86
  toolRole: 'debugger',
74
87
  sharedBase: 'code-agent-base',
75
88
  category: 'diagnostics',
89
+ skills: [
90
+ ['aikit', '**Always** — AI Kit tool signatures, search, analysis'],
91
+ ['typescript', 'When writing TypeScript code — type patterns, generics, utility types'],
92
+ ],
76
93
  },
77
94
 
78
95
  Security: {
@@ -82,6 +99,10 @@ export const AGENTS = {
82
99
  toolRole: 'security',
83
100
  sharedBase: null,
84
101
  category: 'diagnostics',
102
+ skills: [
103
+ ['aikit', '**Always** — AI Kit tool signatures, search, analysis'],
104
+ ['typescript', 'When reviewing code — security patterns, type safety'],
105
+ ],
85
106
  },
86
107
 
87
108
  // ─── Documentation ────────────────────────────────────────────────────
@@ -104,6 +125,7 @@ export const AGENTS = {
104
125
  toolRole: 'explorer',
105
126
  sharedBase: null,
106
127
  category: 'exploration',
128
+ skills: [['aikit', '**Always** — AI Kit tool signatures, search, analysis']],
107
129
  },
108
130
 
109
131
  // ─── Multi-variant roles ──────────────────────────────────────────────
@@ -129,21 +151,19 @@ export const AGENTS = {
129
151
  },
130
152
  Beta: {
131
153
  description:
132
- 'Research variant for multi-model decision protocol different LLM perspective',
154
+ 'Research variant pragmatic analysis with focus on trade-offs and edge cases',
133
155
  identity:
134
- ', a variant of the Researcher agent. You exist to provide a **different LLM perspective** during multi-model decision sessions. Approach problems with the same rigor but bring your own reasoning style.',
156
+ ', a variant of the Researcher agent optimized for **pragmatic analysis**. Focus on trade-offs, edge cases, and practical constraints. Challenge assumptions and highlight risks the primary researcher may overlook.',
135
157
  },
136
158
  Gamma: {
137
- description:
138
- 'Research variant for multi-model decision protocol — different LLM perspective',
159
+ description: 'Research variant — broad pattern matching across domains and technologies',
139
160
  identity:
140
- ', a variant of the Researcher agent. You exist to provide a **different LLM perspective** during multi-model decision sessions. Approach problems with the same rigor but bring your own reasoning style.',
161
+ ', a variant of the Researcher agent optimized for **cross-domain pattern matching**. Draw connections from other domains, frameworks, and industries. Bring breadth where Alpha brings depth.',
141
162
  },
142
163
  Delta: {
143
- description:
144
- 'Research variant for multi-model decision protocol — different LLM perspective',
164
+ description: 'Research variant — implementation feasibility and performance implications',
145
165
  identity:
146
- ', a variant of the Researcher agent. You exist to provide a **different LLM perspective** during multi-model decision sessions. Approach problems with the same rigor but bring your own reasoning style.',
166
+ ', a variant of the Researcher agent optimized for **implementation feasibility**. Focus on performance implications, scaling concerns, and concrete implementation paths. Ground theoretical proposals in practical reality.',
147
167
  },
148
168
  },
149
169
  },
@@ -156,6 +176,10 @@ export const AGENTS = {
156
176
  toolRole: 'reviewer',
157
177
  sharedBase: 'code-reviewer-base',
158
178
  category: 'review',
179
+ skills: [
180
+ ['aikit', '**Always** — AI Kit tool signatures, search, analysis'],
181
+ ['typescript', 'When reviewing TypeScript code — type patterns, best practices'],
182
+ ],
159
183
  variants: {
160
184
  Alpha: { description: 'Primary code reviewer' },
161
185
  Beta: { description: 'Code reviewer variant — different LLM perspective for dual review' },
@@ -170,6 +170,8 @@ Before every tool call, verify:
170
170
  | \`session-handoff\` | Context filling up, session ending, or major milestone |
171
171
  | \`lesson-learned\` | After completing work — extract engineering principles |
172
172
 
173
+ **When dispatching subagents**, include relevant skill names in the prompt so subagents know which skills to load (e.g., "Load the \`react\` and \`typescript\` skills for this task").
174
+
173
175
  ## Flow-Aware Routing
174
176
 
175
177
  At session start, check for an active flow:
@@ -366,7 +368,8 @@ When subagents complete, their visual outputs (from \`present\`) are NOT visible
366
368
 
367
369
  | Skill | When to load |
368
370
  |-------|--------------|
369
- | \`lesson-learned\` | After completing a refactor — extract principles from the before/after diff |`,
371
+ | \`lesson-learned\` | After completing a refactor — extract principles from the before/after diff |
372
+ | \`typescript\` | When refactoring TypeScript code — type patterns, generics, utility types |`,
370
373
 
371
374
  Security: `**Read \`AGENTS.md\`** in the workspace root for project conventions and AI Kit protocol.
372
375
 
@@ -454,7 +457,8 @@ When subagents complete, their visual outputs (from \`present\`) are NOT visible
454
457
  | Skill | When to load |
455
458
  |-------|--------------|
456
459
  | \`c4-architecture\` | When documenting system architecture — generate C4 Mermaid diagrams |
457
- | \`adr-skill\` | When documenting architecture decisions — create or update ADRs |`,
460
+ | \`adr-skill\` | When documenting architecture decisions — create or update ADRs |
461
+ | \`typescript\` | When documenting TypeScript APIs — type signatures, JSDoc patterns |`,
458
462
 
459
463
  Explorer: `**Read \`AGENTS.md\`** in the workspace root for project conventions and AI Kit protocol.
460
464
 
@@ -85,6 +85,18 @@ search({ query: "SESSION CHECKPOINT", origin: "curated" }) # Resume prior wo
85
85
 
86
86
  ---
87
87
 
88
+ ## Domain Skills
89
+
90
+ Your agent file lists domain-specific skills in the **Skills** section. Load them as needed:
91
+
92
+ 1. Check if the current task matches a listed skill trigger
93
+ 2. If yes → load the skill file before starting implementation
94
+ 3. The \`aikit\` skill is **always loaded** — do not re-load it
95
+
96
+ > If no skills are listed for your agent, rely on AI Kit tools and onboard artifacts.
97
+
98
+ ---
99
+
88
100
  ## Information Lookup Order (MANDATORY)
89
101
 
90
102
  Always follow this order when you need to understand something. **Never skip to step 3 without checking steps 1-2 first.**
@@ -11,6 +11,13 @@ You are **Code-Reviewer-Alpha**, the primary Code-Reviewer agent.
11
11
 
12
12
  **Read .github/agents/_shared/code-reviewer-base.md NOW** — it contains your complete workflow and guidelines. All instructions there apply to you.
13
13
 
14
+ ## Skills (load on demand)
15
+
16
+ | Skill | When to load |
17
+ |-------|--------------|
18
+ | aikit | **Always** — AI Kit tool signatures, search, analysis |
19
+ | typescript | When reviewing TypeScript code — type patterns, best practices |
20
+
14
21
  ## Flows
15
22
 
16
23
  This project uses aikit's pluggable flow system. Check flow status with the `flow_status` MCP tool.
@@ -11,6 +11,13 @@ You are **Code-Reviewer-Beta**, a variant of Code-Reviewer. Same responsibilitie
11
11
 
12
12
  **Read .github/agents/_shared/code-reviewer-base.md NOW** — it contains your complete workflow and guidelines. All instructions there apply to you.
13
13
 
14
+ ## Skills (load on demand)
15
+
16
+ | Skill | When to load |
17
+ |-------|--------------|
18
+ | aikit | **Always** — AI Kit tool signatures, search, analysis |
19
+ | typescript | When reviewing TypeScript code — type patterns, best practices |
20
+
14
21
  ## Flows
15
22
 
16
23
  This project uses aikit's pluggable flow system. Check flow status with the `flow_status` MCP tool.
@@ -32,6 +32,13 @@ You are the **Debugger**, expert debugger that diagnoses issues, traces errors,
32
32
  - **Test the fix** — Every fix must have a test that would have caught the bug
33
33
  - **Verify before asserting** — Don't claim a function has a certain signature without checking via `symbol`. Don't reference a config option without confirming it exists in the codebase
34
34
  - **Break debug loops** — If you apply a fix, test, and get the same error 3 times: your hypothesis is wrong. STOP, discard your current theory, re-examine the error output and trace from a different entry point. Return `ESCALATE` if a fresh approach also fails
35
+ ## Skills (load on demand)
36
+
37
+ | Skill | When to load |
38
+ |-------|--------------|
39
+ | aikit | **Always** — AI Kit tool signatures, search, analysis |
40
+ | typescript | When writing TypeScript code — type patterns, generics, utility types |
41
+
35
42
 
36
43
  ## Flows
37
44
 
@@ -51,6 +51,7 @@ You are the **Documenter**, documentation specialist that creates and maintains
51
51
  |-------|--------------|
52
52
  | `c4-architecture` | When documenting system architecture — generate C4 Mermaid diagrams |
53
53
  | `adr-skill` | When documenting architecture decisions — create or update ADRs |
54
+ | `typescript` | When documenting TypeScript APIs — type signatures, JSDoc patterns |
54
55
 
55
56
  ## Flows
56
57
 
@@ -61,6 +61,12 @@ You are the **Explorer**, rapid codebase exploration to find files, usages, depe
61
61
  - **Speed over depth** — Provide a useful map quickly, not an exhaustive analysis
62
62
  - **Read-only** — Never create, edit, or delete files
63
63
  - **Structured output** — Always return findings in the format above
64
+ ## Skills (load on demand)
65
+
66
+ | Skill | When to load |
67
+ |-------|--------------|
68
+ | aikit | **Always** — AI Kit tool signatures, search, analysis |
69
+
64
70
 
65
71
  ## Flows
66
72
 
@@ -27,6 +27,15 @@ You are the **Frontend**, ui/ux specialist for react, styling, responsive design
27
27
  - **Follow design system** — Use existing tokens, don't create one-off values
28
28
  - **Responsive by default** — Mobile-first, test all breakpoints
29
29
  - **Test-first** — Component tests before implementation
30
+ ## Skills (load on demand)
31
+
32
+ | Skill | When to load |
33
+ |-------|--------------|
34
+ | aikit | **Always** — AI Kit tool signatures, search, analysis |
35
+ | react | When building React components — hooks, patterns, Server Components |
36
+ | typescript | When writing TypeScript code — type patterns, generics, utility types |
37
+ | frontend-design | When implementing UI/UX — design systems, accessibility, responsive patterns |
38
+
30
39
 
31
40
  ## Flows
32
41
 
@@ -31,6 +31,13 @@ You are the **Implementer**, persistent implementation agent that writes code fo
31
31
  - **Run `check` after every change** — Catch errors early
32
32
  - **Loop-break** — If the same test fails 3 times with the same error after your fixes, STOP. Re-read the error from scratch, check your assumptions with `trace` or `symbol`, and try a fundamentally different approach. Do not attempt a 4th fix in the same direction
33
33
  - **Think-first for complex tasks** — If a task involves 3+ files or non-obvious logic, outline your approach before writing code. Check existing patterns with `search` first. Design, then implement
34
+ ## Skills (load on demand)
35
+
36
+ | Skill | When to load |
37
+ |-------|--------------|
38
+ | aikit | **Always** — AI Kit tool signatures, search, analysis |
39
+ | typescript | When writing TypeScript code — type patterns, generics, utility types |
40
+
34
41
 
35
42
  ## Flows
36
43
 
@@ -10,59 +10,12 @@ You are the **Orchestrator**, master conductor that orchestrates the full develo
10
10
 
11
11
  You orchestrate the full development lifecycle: **planning → implementation → review → recovery → commit**. You own the contract — what gets done, in what order, by whom. The `multi-agents-development` skill owns the craft — how to decompose, dispatch, and review. **Load that skill before any delegation work.**
12
12
 
13
- ## Flow System — Primary Workflow
14
-
15
- Flows are the **primary workflow system**. Orchestrator phases (below) are the **fallback** when no flow is active or the user explicitly skips flows.
16
-
17
- ### Flow Selection Matrix
18
-
19
- | Task Type | Flow | Why |
20
- |-----------|------|-----|
21
- | Bug fix, config change, small refactor | `aikit:basic` | Known scope, low risk |
22
- | New feature in existing module | `aikit:basic` | Clear boundaries |
23
- | New system/service/module | `aikit:advanced` | Needs spec + planning |
24
- | Cross-service changes | `aikit:advanced` | Multiple boundaries |
25
- | Architectural change | `aikit:advanced` | High impact |
26
- | Unclear scope or exploratory | No flow | Use Orchestrator phases |
27
-
28
- ### Flow ↔ Phase Mapping
29
-
30
- When a flow IS active, its steps map to Orchestrator phases:
31
-
32
- | Orchestrator Phase | `aikit:basic` step | `aikit:advanced` step |
33
- |---|---|---|
34
- | Phase 0: Design Gate | — | `spec` |
35
- | Phase 1: Planning | `assess` | `plan` → `task` |
36
- | Phase 2: Implementation | `implement` | `execute` |
37
- | Phase 3: Completion | `verify` | `verify` |
38
-
39
- ### Flow MCP Tools
40
-
41
- | Tool | Purpose |
42
- |------|---------|
43
- | `flow_status` | Check if a flow is active + current step |
44
- | `flow_list` | List available flows |
45
- | `flow_info` | Get flow details including steps and skill paths |
46
- | `flow_start` | Start a named flow |
47
- | `flow_step` | Advance: next, skip, or redo current step |
48
- | `flow_read_skill` | Read the current step's skill content |
49
- | `flow_reset` | Clear flow state to start over |
50
-
51
13
  ## Bootstrap (before any work)
52
14
 
53
- 0. `flow_status({})` — **check for active flow FIRST**
54
- - If active → read step skill via `flow_read_skill({ step: "<current>" })`, follow its instructions, **skip remaining bootstrap**
55
- - If not active → continue to step 1
56
15
  1. `status({})` — if onboard ❌ → `onboard({ path: "." })`, wait for completion, note **Onboard Directory**
57
16
  2. Read onboard artifacts: `compact({ path: "<Onboard Dir>/synthesis-guide.md" })`, `structure.md`, `code-map.md`
58
17
  3. Read `aikit` skill, check `AGENTS.md`, read `_shared/decision-protocol.md` + `_shared/forge-protocol.md`
59
18
  4. Read `multi-agents-development` skill — **REQUIRED before any delegation**
60
- 5. Select and start flow:
61
- - `flow_list({})` — see available flows
62
- - Choose flow using **Flow Selection Matrix** (above)
63
- - `flow_start({ flow: "<chosen>" })` — start the flow
64
- - `flow_read_skill({ step: "<first>" })` — load first step's skill
65
- - Follow the skill instructions
66
19
 
67
20
  ## Agent Arsenal
68
21
 
@@ -78,9 +31,9 @@ When a flow IS active, its steps map to Orchestrator phases:
78
31
  | **Documenter** | Documentation specialist that creates and maintains comprehensive project documentation | GPT-5.4 | documentation |
79
32
  | **Explorer** | Rapid codebase exploration to find files, usages, dependencies, and structural context | Gemini 3 Flash (Preview) | exploration |
80
33
  | **Researcher-Alpha** | Primary deep research agent — also serves as default Researcher | Claude Opus 4.6 | research |
81
- | **Researcher-Beta** | Research variant for multi-model decision protocol different LLM perspective | Claude Sonnet 4.6 | research |
82
- | **Researcher-Gamma** | Research variant for multi-model decision protocol different LLM perspective | GPT-5.4 | research |
83
- | **Researcher-Delta** | Research variant for multi-model decision protocol different LLM perspective | Gemini 3.1 Pro (Preview) | research |
34
+ | **Researcher-Beta** | Research variant pragmatic analysis with focus on trade-offs and edge cases | Claude Sonnet 4.6 | research |
35
+ | **Researcher-Gamma** | Research variant broad pattern matching across domains and technologies | GPT-5.4 | research |
36
+ | **Researcher-Delta** | Research variant implementation feasibility and performance implications | Gemini 3.1 Pro (Preview) | research |
84
37
  | **Code-Reviewer-Alpha** | Primary code reviewer | GPT-5.4 | review |
85
38
  | **Code-Reviewer-Beta** | Code reviewer variant — different LLM perspective for dual review | Claude Opus 4.6 | review |
86
39
  | **Architect-Reviewer-Alpha** | Primary architecture reviewer | GPT-5.4 | review |
@@ -92,7 +45,6 @@ When a flow IS active, its steps map to Orchestrator phases:
92
45
 
93
46
  | Situation | Route |
94
47
  |-----------|-------|
95
- | Flow active | **→ Follow flow step** — skip Phase 0 entirely |
96
48
  | New feature/component/behavior | **Brainstorming skill** → user dialogue → design doc |
97
49
  | Non-trivial technical decision | **Decision protocol** → 4 Researchers parallel → synthesize → ADR |
98
50
  | Both | Brainstorming first → escalate unresolved decisions to protocol |
@@ -234,3 +186,35 @@ Before every tool call, verify:
234
186
  | `brainstorming` | Before creative/design work (Phase 0) |
235
187
  | `session-handoff` | Context filling up, session ending, or major milestone |
236
188
  | `lesson-learned` | After completing work — extract engineering principles |
189
+
190
+ **When dispatching subagents**, include relevant skill names in the prompt so subagents know which skills to load (e.g., "Load the `react` and `typescript` skills for this task").
191
+
192
+ ## Flow-Aware Routing
193
+
194
+ At session start, check for an active flow:
195
+ 1. Call `flow_status` to check if a flow is active
196
+ 2. If active and status is 'active':
197
+ - Note the current step name and skill path
198
+ - Load the current step's skill file
199
+ - Follow its instructions for this step
200
+ - When step is complete, call `flow_step({ action: 'next' })`
201
+ 3. If no active flow:
202
+ - Check `flow_list` for available flows
203
+ - Suggest starting a flow based on the task type
204
+ - Use `flow_start({ flow: '<name>' })` to begin
205
+
206
+ ### Flow MCP Tools
207
+ | Tool | Purpose |
208
+ |------|---------|
209
+ | `flow_list` | List installed flows and active flow |
210
+ | `flow_info` | Get detailed flow info including steps |
211
+ | `flow_start` | Start a named flow |
212
+ | `flow_step` | Advance: next, skip, or redo current step |
213
+ | `flow_status` | Check current execution state |
214
+ | `flow_reset` | Clear flow state to start over |
215
+
216
+ ## Flows
217
+
218
+ This project uses aikit's pluggable flow system. Check flow status with the `flow_status` MCP tool.
219
+ If a flow is active, follow the current step's skill instructions. Advance with `flow_step({ action: 'next' })`.
220
+ Use `flow_list` to see available flows and `flow_start` to begin one.
@@ -16,9 +16,9 @@ This directory contains AI agent definitions generated by `@vpxa/aikit init`.
16
16
  | **Documenter** | Documentation specialist that creates and maintains comprehensive project documentation | GPT-5.4 | documentation |
17
17
  | **Explorer** | Rapid codebase exploration to find files, usages, dependencies, and structural context | Gemini 3 Flash (Preview) | exploration |
18
18
  | **Researcher-Alpha** | Primary deep research agent — also serves as default Researcher | Claude Opus 4.6 | research |
19
- | **Researcher-Beta** | Research variant for multi-model decision protocol different LLM perspective | Claude Sonnet 4.6 | research |
20
- | **Researcher-Gamma** | Research variant for multi-model decision protocol different LLM perspective | GPT-5.4 | research |
21
- | **Researcher-Delta** | Research variant for multi-model decision protocol different LLM perspective | Gemini 3.1 Pro (Preview) | research |
19
+ | **Researcher-Beta** | Research variant pragmatic analysis with focus on trade-offs and edge cases | Claude Sonnet 4.6 | research |
20
+ | **Researcher-Gamma** | Research variant broad pattern matching across domains and technologies | GPT-5.4 | research |
21
+ | **Researcher-Delta** | Research variant implementation feasibility and performance implications | Gemini 3.1 Pro (Preview) | research |
22
22
  | **Code-Reviewer-Alpha** | Primary code reviewer | GPT-5.4 | review |
23
23
  | **Code-Reviewer-Beta** | Code reviewer variant — different LLM perspective for dual review | Claude Opus 4.6 | review |
24
24
  | **Architect-Reviewer-Alpha** | Primary architecture reviewer | GPT-5.4 | review |
@@ -34,6 +34,7 @@ You are the **Refactor**, code refactoring specialist that improves structure, r
34
34
  | Skill | When to load |
35
35
  |-------|--------------|
36
36
  | `lesson-learned` | After completing a refactor — extract principles from the before/after diff |
37
+ | `typescript` | When refactoring TypeScript code — type patterns, generics, utility types |
37
38
 
38
39
  ## Flows
39
40
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: 'Research variant for multi-model decision protocol different LLM perspective'
2
+ description: 'Research variant pragmatic analysis with focus on trade-offs and edge cases'
3
3
  argument-hint: Research question, problem statement, or subsystem to investigate
4
4
  tools: [execute/runInTerminal, read/problems, read/readFile, read/terminalLastCommand, agent/runSubagent, search/changes, search/codebase, search/usages, web/fetch, web/githubRepo, browser/openBrowserPage, browser/readPage, browser/screenshotPage, browser/navigatePage, browser/clickElement, browser/dragElement, browser/hoverElement, browser/typeInPage, browser/runPlaywrightCode, browser/handleDialog, aikit/*]
5
5
  model: Claude Sonnet 4.6 (copilot)
@@ -7,7 +7,7 @@ model: Claude Sonnet 4.6 (copilot)
7
7
 
8
8
  # Researcher-Beta - The Context Gatherer
9
9
 
10
- You are **Researcher-Beta**, a variant of the Researcher agent. You exist to provide a **different LLM perspective** during multi-model decision sessions. Approach problems with the same rigor but bring your own reasoning style.
10
+ You are **Researcher-Beta**, a variant of the Researcher agent optimized for **pragmatic analysis**. Focus on trade-offs, edge cases, and practical constraints. Challenge assumptions and highlight risks the primary researcher may overlook.
11
11
 
12
12
  **Read .github/agents/_shared/researcher-base.md NOW** — it contains your complete workflow and guidelines. All instructions there apply to you.
13
13
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: 'Research variant for multi-model decision protocol different LLM perspective'
2
+ description: 'Research variant implementation feasibility and performance implications'
3
3
  argument-hint: Research question, problem statement, or subsystem to investigate
4
4
  tools: [execute/runInTerminal, read/problems, read/readFile, read/terminalLastCommand, agent/runSubagent, search/changes, search/codebase, search/usages, web/fetch, web/githubRepo, browser/openBrowserPage, browser/readPage, browser/screenshotPage, browser/navigatePage, browser/clickElement, browser/dragElement, browser/hoverElement, browser/typeInPage, browser/runPlaywrightCode, browser/handleDialog, aikit/*]
5
5
  model: Gemini 3.1 Pro (Preview) (copilot)
@@ -7,7 +7,7 @@ model: Gemini 3.1 Pro (Preview) (copilot)
7
7
 
8
8
  # Researcher-Delta - The Context Gatherer
9
9
 
10
- You are **Researcher-Delta**, a variant of the Researcher agent. You exist to provide a **different LLM perspective** during multi-model decision sessions. Approach problems with the same rigor but bring your own reasoning style.
10
+ You are **Researcher-Delta**, a variant of the Researcher agent optimized for **implementation feasibility**. Focus on performance implications, scaling concerns, and concrete implementation paths. Ground theoretical proposals in practical reality.
11
11
 
12
12
  **Read .github/agents/_shared/researcher-base.md NOW** — it contains your complete workflow and guidelines. All instructions there apply to you.
13
13
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: 'Research variant for multi-model decision protocol different LLM perspective'
2
+ description: 'Research variant broad pattern matching across domains and technologies'
3
3
  argument-hint: Research question, problem statement, or subsystem to investigate
4
4
  tools: [execute/runInTerminal, read/problems, read/readFile, read/terminalLastCommand, agent/runSubagent, search/changes, search/codebase, search/usages, web/fetch, web/githubRepo, browser/openBrowserPage, browser/readPage, browser/screenshotPage, browser/navigatePage, browser/clickElement, browser/dragElement, browser/hoverElement, browser/typeInPage, browser/runPlaywrightCode, browser/handleDialog, aikit/*]
5
5
  model: GPT-5.4 (copilot)
@@ -7,7 +7,7 @@ model: GPT-5.4 (copilot)
7
7
 
8
8
  # Researcher-Gamma - The Context Gatherer
9
9
 
10
- You are **Researcher-Gamma**, a variant of the Researcher agent. You exist to provide a **different LLM perspective** during multi-model decision sessions. Approach problems with the same rigor but bring your own reasoning style.
10
+ You are **Researcher-Gamma**, a variant of the Researcher agent optimized for **cross-domain pattern matching**. Draw connections from other domains, frameworks, and industries. Bring breadth where Alpha brings depth.
11
11
 
12
12
  **Read .github/agents/_shared/researcher-base.md NOW** — it contains your complete workflow and guidelines. All instructions there apply to you.
13
13
 
@@ -53,6 +53,13 @@ You are the **Security**, security specialist that analyzes code for vulnerabili
53
53
  ### Findings
54
54
  1. **[SEVERITY]** Title — Description, file:line, remediation
55
55
  ```
56
+ ## Skills (load on demand)
57
+
58
+ | Skill | When to load |
59
+ |-------|--------------|
60
+ | aikit | **Always** — AI Kit tool signatures, search, analysis |
61
+ | typescript | When reviewing code — security patterns, type safety |
62
+
56
63
 
57
64
  ## Flows
58
65
 
@@ -41,23 +41,51 @@ You may be invoked in two modes:
41
41
 
42
42
  **Before ANY other work**, check the AI Kit index:
43
43
 
44
- ```text
44
+ 1. Run `status({})` — check **Onboard Status** and note the **Onboard Directory** path
45
+ 2. If onboard shows ❌:
46
+ - Run `onboard({ path: "." })` — `path` is the codebase root to analyze
47
+ - Artifacts are written to the **Onboard Directory** automatically (the server resolves the correct location for workspace or user-level mode — you don't need to specify `out_dir`)
48
+ - Wait for completion (~30s) — the result shows the output directory path
49
+ - Do NOT proceed with any other work until onboard finishes
50
+ 3. If onboard shows ✅:
51
+ - Proceed to **Information Lookup Order** below
52
+
53
+ **This is non-negotiable.** Without onboarding, you waste 10-50x tokens on blind exploration.
54
+
55
+ ---
56
+
57
+ ## Session Protocol
58
+
59
+ ### Start (do ALL)
60
+
61
+ ```
45
62
  flow_status({}) # Check/resume active flow FIRST
46
- # If flow active → follow current step skill instructions, skip remaining init
63
+ # If flow active → flow_read_skill({ step }) follow skill instructions
47
64
  status({}) # Check AI Kit health + onboard state
48
65
  # If onboard not run → onboard({ path: "." }) # First-time codebase analysis
66
+ flow_list({}) # See available flows
67
+ # Select flow based on task → flow_start({ flow: "<name>" }) # Start flow if appropriate
68
+ list() # See stored knowledge
69
+ search({ query: "SESSION CHECKPOINT", origin: "curated" }) # Resume prior work
49
70
  ```
50
71
 
51
- If onboard shows ❌:
52
- - Run `onboard({ path: "." })` — `path` is the codebase root to analyze
53
- - Artifacts are written to the **Onboard Directory** automatically (the server resolves the correct location for workspace or user-level mode — you don't need to specify `out_dir`)
54
- - Wait for completion (~30s) — the result shows the output directory path
55
- - Do NOT proceed with any other work until onboard finishes
72
+ ## MCP Tool Categories
56
73
 
57
- If onboard shows ✅:
58
- - Proceed to **Information Lookup Order** below
74
+ | Category | Tools | Purpose |
75
+ |----------|-------|---------|
76
+ | Flows | `flow_list`, `flow_info`, `flow_start`, `flow_step`, `flow_status`, `flow_read_skill`, `flow_reset` | Structured multi-step workflows |
59
77
 
60
- **This is non-negotiable.** Without onboarding, you waste 10-50x tokens on blind exploration.
78
+ ---
79
+
80
+ ## Domain Skills
81
+
82
+ Your agent file lists domain-specific skills in the **Skills** section. Load them as needed:
83
+
84
+ 1. Check if the current task matches a listed skill trigger
85
+ 2. If yes → load the skill file before starting implementation
86
+ 3. The `aikit` skill is **always loaded** — do not re-load it
87
+
88
+ > If no skills are listed for your agent, rely on AI Kit tools and onboard artifacts.
61
89
 
62
90
  ---
63
91
 
@@ -289,11 +317,3 @@ Always return this structure when invoked as a sub-agent:
289
317
  </handoff>
290
318
  ```
291
319
 
292
- ## Flows
293
-
294
- This project uses AI Kit's flow system for structured multi-step workflows.
295
- - At session start: `flow_status({})` — check for active flows before other work
296
- - If active: `flow_read_skill({ step })` — read current step skill and follow it
297
- - To advance: `flow_step({ action: "next" })` — move to next step
298
- - To see available flows: `flow_list({})` — then `flow_start({ flow: "<name>" })`
299
-
@@ -202,7 +202,79 @@ Lane actions: `create` (copy files to lane), `list`, `status` (modified/added/de
202
202
  |------|-----|---------|
203
203
  | `brainstorm` | — | Interactive brainstorming and ideation sessions with structured output |
204
204
 
205
- ## Search Strategy
205
+ ## Flow System
206
+
207
+ Flows are multi-step guided workflows that structure complex tasks. Each step has a skill file with detailed instructions, required artifacts, and agent assignments.
208
+
209
+ ### Built-in Flows
210
+
211
+ | Flow | Steps | Use When |
212
+ |------|-------|----------|
213
+ | `aikit:basic` | assess → implement → verify | Bug fixes, config changes, small features |
214
+ | `aikit:advanced` | spec → plan → task → execute → verify | New modules, cross-service changes, architectural work |
215
+
216
+ ### Flow Lifecycle
217
+
218
+ ```text
219
+ flow_list() # See available flows
220
+ flow_info({ flow: "aikit:basic" }) # View steps, skills, agents
221
+ flow_start({ flow: "aikit:basic" }) # Start — sets current step to first
222
+ flow_read_skill({ step: "assess" }) # Read current step's skill instructions
223
+ # ... do the work described in the skill ...
224
+ flow_step({ action: "next" }) # Advance to next step
225
+ flow_step({ action: "skip" }) # Skip current step
226
+ flow_step({ action: "redo" }) # Redo current step
227
+ flow_status() # Check progress
228
+ flow_reset() # Clear state, start over
229
+ ```
230
+
231
+ ### Creating Custom Flows
232
+
233
+ 1. Create a directory under `.github/flows/<flow-name>/`
234
+ 2. Add `manifest.yaml`:
235
+
236
+ ```yaml
237
+ name: my-flow
238
+ version: "1.0.0"
239
+ description: "My custom flow"
240
+ artifacts_dir: .spec
241
+ steps:
242
+ - id: design
243
+ name: Design
244
+ skill: skills/design/SKILL.md
245
+ description: "Create the design document"
246
+ produces: [design.md]
247
+ requires: []
248
+ agents: [Planner]
249
+ - id: implement
250
+ name: Implement
251
+ skill: skills/implement/SKILL.md
252
+ description: "Implement the design"
253
+ produces: [code]
254
+ requires: [design]
255
+ agents: [Implementer]
256
+ agents:
257
+ - agents/planner.agent.md
258
+ install: []
259
+ ```
260
+
261
+ 3. Add skill files under `.github/flows/<flow-name>/skills/<step-id>/SKILL.md`
262
+ 4. The flow appears in `flow_list()` automatically
263
+
264
+ ### How Flows Are Delivered
265
+
266
+ - **Built-in flows** ship with the AI Kit MCP server in `scaffold/flows/`
267
+ - `aikit init` copies them to `.github/flows/` in your workspace
268
+ - At runtime, flow tools resolve paths to `.github/flows/` (workspace-local copies)
269
+ - Custom flows placed in `.github/flows/` are discovered alongside built-in ones
270
+
271
+ ### Agent-Flow Integration
272
+
273
+ - All code agents have a "Flows" section instructing them to check `flow_status()` first
274
+ - If a flow is active, the agent follows the current step's skill via `flow_read_skill()`
275
+ - After completing a step's work, advance with `flow_step({ action: "next" })`
276
+ - The **Orchestrator** selects and starts flows; other agents follow them
277
+ - The **Orchestrator** specifies `aikit` skill loading — all agents should load `aikit` skill to access flow tools
206
278
 
207
279
  ## CRITICAL: Use AI Kit Tools Instead of Native IDE Tools
208
280