@vpxa/aikit 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/package.json +1 -1
- package/packages/aikit-client/dist/types.d.ts +3 -3
- package/packages/cli/dist/aikit-init.d.ts +1 -1
- package/packages/cli/dist/aikit-init.js +1 -1
- package/packages/cli/dist/commands/context-cmds.js +1 -1
- package/packages/cli/dist/commands/environment.js +1 -1
- package/packages/cli/dist/commands/init/config.d.ts +1 -1
- package/packages/cli/dist/commands/init/config.js +2 -2
- package/packages/cli/dist/commands/init/constants.d.ts +3 -3
- package/packages/cli/dist/commands/init/index.d.ts +4 -4
- package/packages/cli/dist/commands/init/index.js +4 -4
- package/packages/cli/dist/commands/init/templates.js +12 -12
- package/packages/cli/dist/commands/init/user.d.ts +3 -3
- package/packages/cli/dist/commands/init/user.js +2 -2
- package/packages/cli/dist/commands/search.js +1 -1
- package/packages/cli/dist/commands/system.js +4 -4
- package/packages/cli/dist/commands/upgrade.js +1 -1
- package/packages/cli/dist/commands/workspace.js +1 -1
- package/packages/cli/dist/helpers.js +1 -1
- package/packages/cli/dist/index.d.ts +1 -1
- package/packages/core/dist/constants.d.ts +3 -3
- package/packages/core/dist/global-registry.d.ts +7 -1
- package/packages/core/dist/global-registry.js +1 -1
- package/packages/core/dist/index.d.ts +2 -2
- package/packages/core/dist/index.js +1 -1
- package/packages/core/dist/types.d.ts +6 -2
- package/packages/dashboard/dist/assets/{index-BjA4YODs.js → index-CO2S9BKY.js} +2 -2
- package/packages/dashboard/dist/assets/index-CO2S9BKY.js.map +1 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/enterprise-bridge/dist/er-client.d.ts +1 -1
- package/packages/flows/dist/git.js +1 -1
- package/packages/flows/dist/registry.d.ts +3 -3
- package/packages/flows/dist/registry.js +1 -1
- package/packages/flows/dist/symlinks.js +1 -1
- package/packages/indexer/dist/filesystem-crawler.js +1 -1
- package/packages/indexer/dist/hash-cache.js +1 -1
- package/packages/indexer/dist/incremental-indexer.js +1 -1
- package/packages/kb-client/dist/direct-client.d.ts +37 -0
- package/packages/kb-client/dist/direct-client.js +1 -0
- package/packages/kb-client/dist/index.d.ts +5 -0
- package/packages/kb-client/dist/index.js +1 -0
- package/packages/kb-client/dist/mcp-client.d.ts +19 -0
- package/packages/kb-client/dist/mcp-client.js +4 -0
- package/packages/kb-client/dist/parsers.d.ts +35 -0
- package/packages/kb-client/dist/parsers.js +2 -0
- package/packages/kb-client/dist/types.d.ts +62 -0
- package/packages/kb-client/dist/types.js +1 -0
- package/packages/present/dist/index.html +28 -28
- package/packages/server/dist/background-task.d.ts +47 -0
- package/packages/server/dist/background-task.js +1 -0
- package/packages/server/dist/config.js +1 -1
- package/packages/server/dist/idle-timer.d.ts +33 -0
- package/packages/server/dist/idle-timer.js +1 -0
- package/packages/server/dist/index.js +1 -1
- package/packages/server/dist/memory-monitor.d.ts +37 -0
- package/packages/server/dist/memory-monitor.js +1 -0
- package/packages/server/dist/prompts.js +5 -5
- package/packages/server/dist/resource-links.d.ts +1 -1
- package/packages/server/dist/resource-links.js +1 -1
- package/packages/server/dist/resources/curated-resources.d.ts +2 -2
- package/packages/server/dist/resources/curated-resources.js +2 -2
- package/packages/server/dist/resources/resource-notifier.d.ts +1 -1
- package/packages/server/dist/resources/resource-notifier.js +1 -1
- package/packages/server/dist/resources/resources.js +1 -1
- package/packages/server/dist/server.d.ts +4 -2
- package/packages/server/dist/server.js +3 -3
- package/packages/server/dist/tool-metadata.d.ts +1 -1
- package/packages/server/dist/tool-metadata.js +1 -1
- package/packages/server/dist/tool-timeout.d.ts +27 -0
- package/packages/server/dist/tool-timeout.js +1 -0
- package/packages/server/dist/tools/bridge.tools.d.ts +1 -1
- package/packages/server/dist/tools/bridge.tools.js +3 -3
- package/packages/server/dist/tools/config.tool.d.ts +8 -0
- package/packages/server/dist/tools/config.tool.js +12 -0
- package/packages/server/dist/tools/evolution.tools.js +1 -1
- package/packages/server/dist/tools/flow.tools.js +1 -1
- package/packages/server/dist/tools/infra.tools.js +1 -1
- package/packages/server/dist/tools/onboard.tool.js +1 -1
- package/packages/server/dist/tools/present/browser.js +9 -9
- package/packages/server/dist/tools/present/tool.js +4 -4
- package/packages/server/dist/tools/reindex.tool.js +1 -1
- package/packages/server/dist/tools/search.tool.js +4 -4
- package/packages/server/dist/tools/status.tool.d.ts +1 -1
- package/packages/server/dist/tools/status.tool.js +3 -3
- package/packages/store/dist/sqlite-graph-store.d.ts +3 -0
- package/packages/store/dist/sqlite-graph-store.js +3 -3
- package/packages/tools/dist/checkpoint.js +1 -1
- package/packages/tools/dist/config-extractor.js +1 -1
- package/packages/tools/dist/evidence-map.js +1 -1
- package/packages/tools/dist/find.d.ts +1 -1
- package/packages/tools/dist/forge-ground.d.ts +1 -1
- package/packages/tools/dist/guide.js +1 -1
- package/packages/tools/dist/lane.js +1 -1
- package/packages/tools/dist/onboard.d.ts +2 -2
- package/packages/tools/dist/onboard.js +2 -2
- package/packages/tools/dist/queue.js +1 -1
- package/packages/tools/dist/replay.js +1 -1
- package/packages/tools/dist/response-envelope.d.ts +1 -1
- package/packages/tools/dist/restore-points.js +1 -1
- package/packages/tools/dist/schema-validate.js +1 -1
- package/packages/tools/dist/snippet.js +1 -1
- package/packages/tools/dist/stash.js +1 -1
- package/packages/tools/dist/synthesis-engine.js +2 -2
- package/packages/tools/dist/workset.js +1 -1
- package/packages/tui/dist/{App-DU2KEylW.js → App-DpjN3iS-.js} +1 -1
- package/packages/tui/dist/App.d.ts +1 -1
- package/packages/tui/dist/App.js +1 -1
- package/packages/tui/dist/LogPanel-Db-SeZhR.js +3 -0
- package/packages/tui/dist/hooks/useKBClient.d.ts +1 -1
- package/packages/tui/dist/{index-BXafekwr.d.ts → index-MXJeXmCf.d.ts} +3 -3
- package/packages/tui/dist/index.d.ts +1 -1
- package/packages/tui/dist/index.js +1 -1
- package/packages/tui/dist/panels/LogPanel.js +1 -1
- package/scaffold/README.md +192 -192
- package/scaffold/definitions/bodies.mjs +16 -16
- package/scaffold/definitions/plugins.mjs +1 -1
- package/scaffold/definitions/prompts.mjs +6 -6
- package/scaffold/definitions/protocols.mjs +12 -12
- package/scaffold/definitions/tools.mjs +1 -1
- package/scaffold/flows/aikit-advanced/skills/execute/SKILL.md +124 -124
- package/scaffold/flows/aikit-advanced/skills/plan/SKILL.md +100 -100
- package/scaffold/flows/aikit-advanced/skills/spec/SKILL.md +100 -100
- package/scaffold/flows/aikit-advanced/skills/task/SKILL.md +99 -99
- package/scaffold/flows/aikit-advanced/skills/verify/SKILL.md +122 -122
- package/scaffold/flows/aikit-basic/skills/assess/SKILL.md +82 -82
- package/scaffold/flows/aikit-basic/skills/implement/SKILL.md +105 -105
- package/scaffold/flows/aikit-basic/skills/verify/SKILL.md +96 -96
- package/scaffold/general/agents/Debugger.agent.md +2 -2
- package/scaffold/general/agents/Documenter.agent.md +2 -2
- package/scaffold/general/agents/Explorer.agent.md +2 -2
- package/scaffold/general/agents/Frontend.agent.md +1 -1
- package/scaffold/general/agents/Implementer.agent.md +2 -2
- package/scaffold/general/agents/Orchestrator.agent.md +1 -1
- package/scaffold/general/agents/Planner.agent.md +2 -2
- package/scaffold/general/agents/Refactor.agent.md +2 -2
- package/scaffold/general/agents/Security.agent.md +2 -2
- package/scaffold/general/agents/_shared/architect-reviewer-base.md +1 -1
- package/scaffold/general/agents/_shared/code-agent-base.md +6 -6
- package/scaffold/general/agents/_shared/code-reviewer-base.md +1 -1
- package/scaffold/general/agents/_shared/forge-protocol.md +1 -1
- package/scaffold/general/agents/_shared/researcher-base.md +3 -3
- package/scaffold/general/prompts/ask.prompt.md +4 -4
- package/scaffold/general/prompts/debug.prompt.md +1 -1
- package/scaffold/general/prompts/plan.prompt.md +1 -1
- package/scaffold/general/skills/aikit/SKILL.md +5 -5
- package/scaffold/general/skills/multi-agents-development/SKILL.md +435 -435
- package/scaffold/general/skills/present/SKILL.md +424 -424
- package/packages/dashboard/dist/assets/index-BjA4YODs.js.map +0 -1
- package/packages/tui/dist/LogPanel-Bo8a8QXB.js +0 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{createLogger as n,serializeError as r}from"../../../core/dist/index.js";const i=n(`tools`);function a(n,a){let o=e(`er_evolve_review`);n.registerTool(`er_evolve_review`,{title:o.title,description:`Review evolution metrics for the
|
|
1
|
+
import{getToolMeta as e}from"../tool-metadata.js";import{z as t}from"zod";import{createLogger as n,serializeError as r}from"../../../core/dist/index.js";const i=n(`tools`);function a(n,a){let o=e(`er_evolve_review`);n.registerTool(`er_evolve_review`,{title:o.title,description:`Review evolution metrics for the AI Kit ↔ ER bridge. Shows local miss rates, push acceptance, rule effectiveness, and top missed queries. Use this to reason about improving classification rules and knowledge flow.`,inputSchema:{include_details:t.boolean().default(!0).describe(`Include detailed breakdowns (top missed queries, rule stats)`),reset_after:t.boolean().default(!1).describe(`Reset collected metrics after review`)},annotations:o.annotations},async({include_details:e,reset_after:t})=>{try{let n=a.getMetrics(),r=[`## ER Evolution Review
|
|
2
2
|
`,`**Period**: ${n.period.startedAt} → ${n.period.queriedAt}`,`**Total events**: ${n.period.totalEvents}\n`,`### Search`,`- Total searches: ${n.search.totalSearches}`,`- ER fallback triggered: ${n.search.erFallbackCount} (${(n.search.erFallbackRate*100).toFixed(1)}%)`,`- ER cache hits: ${n.search.erCacheHitCount} (${(n.search.erCacheHitRate*100).toFixed(1)}% of fallbacks)`];if(e&&n.search.topMissedQueries.length>0){r.push(`
|
|
3
3
|
**Top missed queries** (triggered ER fallback):`);for(let e of n.search.topMissedQueries.slice(0,10)){let t=e.query.length>60?`${e.query.slice(0,57)}...`:e.query;r.push(` - "${t}" (${e.count}x)`)}}if(r.push(``,`### Push`,`- Total pushes: ${n.push.totalPushes} (${n.push.successCount} ok, ${n.push.failCount} failed)`,`- Classification match rate: ${(n.push.classificationMatchRate*100).toFixed(1)}%`,`- Push acceptance rate: ${(n.push.pushAcceptanceRate*100).toFixed(1)}%`),r.push(``,`### Rule Effectiveness`),Object.keys(n.rules.matchCounts).length>0)for(let[e,t]of Object.entries(n.rules.matchCounts)){let i=n.rules.pushCounts[e]??0,a=t>0?(i/t*100).toFixed(0):`0`;r.push(`- **${e}**: ${t} matches → ${i} pushes (${a}% conversion)`)}else r.push(`- _No rule activity recorded yet_`);if(e&&n.rules.lowConversionRules.length>0){r.push(``,`### ⚠️ Low Conversion Rules (potential false positives)`);for(let e of n.rules.lowConversionRules)r.push(`- **${e.ruleId}**: ${e.matchCount} matches, ${e.pushCount} pushes (${(e.conversionRate*100).toFixed(0)}% conversion) — consider tightening patterns`)}return r.push(``,`---`,"_Next: Use `er_update_policy` to refine rules based on these metrics, or `er_push` to share high-value knowledge._"),t&&(i.info(`Evolution metrics reset requested`,{requestedAt:new Date().toISOString(),clearedEvents:n.period.totalEvents}),a.reset(),r.push(`
|
|
4
4
|
_Metrics have been reset._`)),{content:[{type:`text`,text:r.join(`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getToolMeta as e}from"../tool-metadata.js";import{join as t}from"node:path";import{z as n}from"zod";import{createLogger as r,serializeError as i}from"../../../core/dist/index.js";const a=r(`flow-tools`);function o(e){return{content:[{type:`text`,text:e}]}}function s(e){return e instanceof Error?e.message:String(e)}function c(r,c){let l=t(c.sources[0].path,`.aikit-state
|
|
1
|
+
import{getToolMeta as e}from"../tool-metadata.js";import{join as t}from"node:path";import{z as n}from"zod";import{createLogger as r,serializeError as i}from"../../../core/dist/index.js";const a=r(`flow-tools`);function o(e){return{content:[{type:`text`,text:e}]}}function s(e){return e instanceof Error?e.message:String(e)}function c(r,c){let l=t(c.stateDir??t(c.sources[0].path,`.aikit-state`),`flows`),u=t(l,`registry.json`),d=t(l,`state.json`);async function f(){let{FlowRegistryManager:e,FlowStateMachine:t}=await import(`../../../flows/dist/index.js`);return{registry:new e(u),stateMachine:new t(d)}}let p=e(`flow_list`);r.registerTool(`flow_list`,{title:p.title,description:`List all installed flows and their steps`,annotations:p.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await f(),n=e.list(),r=t.getStatus(),i={flows:n.map(e=>({name:e.name,version:e.version,source:e.source,sourceType:e.sourceType,format:e.format,steps:e.manifest.steps.map(e=>e.id)})),activeFlow:r.success&&r.data?{flow:r.data.flow,status:r.data.status,currentStep:r.data.currentStep}:null};return o(JSON.stringify(i,null,2))}catch(e){return a.error(`flow_list failed`,i(e)),o(`Error: ${s(e)}`)}});let m=e(`flow_info`);r.registerTool(`flow_info`,{title:m.title,description:`Show detailed information about a specific flow`,annotations:m.annotations,inputSchema:{name:n.string().describe(`Flow name to get info for`)}},async({name:e})=>{try{let{registry:t}=await f(),n=t.get(e);if(!n)return o(`Flow "${e}" not found. Use flow_list to see available flows.`);let r={name:n.name,version:n.version,description:n.manifest.description,source:n.source,sourceType:n.sourceType,format:n.format,installPath:n.installPath,registeredAt:n.registeredAt,updatedAt:n.updatedAt,steps:n.manifest.steps.map(e=>({id:e.id,name:e.name,skill:e.skill,produces:e.produces,requires:e.requires,description:e.description})),agents:n.manifest.agents,artifactsDir:n.manifest.artifacts_dir,install:n.manifest.install};return o(JSON.stringify(r,null,2))}catch(e){return a.error(`flow_info failed`,i(e)),o(`Error: ${s(e)}`)}});let h=e(`flow_start`);r.registerTool(`flow_start`,{title:h.title,description:`Start a flow. Sets the active flow and positions at the first step.`,annotations:h.annotations,inputSchema:{flow:n.string().describe(`Flow name to start (use flow_list to see options)`)}},async({flow:e})=>{try{let{registry:t,stateMachine:n}=await f(),r=t.get(e);if(!r)return o(`Flow "${e}" not found. Use flow_list to see available flows.`);let i=n.start(r.name,r.manifest);if(!i.success||!i.data)return o(`Cannot start: ${i.error}`);let a=i.data,s=r.manifest.steps.find(e=>e.id===a.currentStep),c={started:!0,flow:a.flow,currentStep:a.currentStep,currentStepSkill:s?.skill??null,currentStepDescription:s?.description??null,totalSteps:r.manifest.steps.length,stepSequence:r.manifest.steps.map(e=>e.id),artifactsDir:r.manifest.artifacts_dir};return o(JSON.stringify(c,null,2))}catch(e){return a.error(`flow_start failed`,i(e)),o(`Error: ${s(e)}`)}});let g=e(`flow_step`);r.registerTool(`flow_step`,{title:g.title,description:`Advance the active flow: complete current step and move to next, skip current step, or redo current step.`,annotations:g.annotations,inputSchema:{action:n.enum([`next`,`skip`,`redo`]).describe(`next: mark current step done and advance. skip: skip current step. redo: repeat current step.`)}},async({action:e})=>{try{let{registry:t,stateMachine:n}=await f(),r=n.load();if(!r)return o(`No active flow. Use flow_start first.`);let i=t.get(r.flow);if(!i)return o(`Flow "${r.flow}" not found in registry.`);let a=n.step(e,i.manifest);if(!a.success||!a.data)return o(`Cannot ${e}: ${a.error}`);let s=a.data,c=s.currentStep?i.manifest.steps.find(e=>e.id===s.currentStep):null,l={flow:s.flow,status:s.status,action:e,currentStep:s.currentStep,currentStepSkill:c?.skill??null,currentStepDescription:c?.description??null,completedSteps:s.completedSteps,skippedSteps:s.skippedSteps,totalSteps:i.manifest.steps.length,remaining:i.manifest.steps.filter(e=>!s.completedSteps.includes(e.id)&&!s.skippedSteps.includes(e.id)&&e.id!==s.currentStep).map(e=>e.id)};return o(JSON.stringify(l,null,2))}catch(e){return a.error(`flow_step failed`,i(e)),o(`Error: ${s(e)}`)}});let _=e(`flow_status`);r.registerTool(`flow_status`,{title:_.title,description:`Show the current flow execution state — which flow is active, current step, completed steps, and artifacts.`,annotations:_.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await f(),n=t.getStatus();if(!n.success||!n.data)return o(`No active flow. Use flow_start to begin one, or flow_list to see available flows.`);let r=n.data,i=e.get(r.flow),a=i?.manifest.steps.find(e=>e.id===r.currentStep),s={flow:r.flow,status:r.status,currentStep:r.currentStep,currentStepSkill:a?.skill??null,currentStepDescription:a?.description??null,completedSteps:r.completedSteps,skippedSteps:r.skippedSteps,artifacts:r.artifacts,startedAt:r.startedAt,updatedAt:r.updatedAt,totalSteps:i?.manifest.steps.length??0,progress:i?`${r.completedSteps.length+r.skippedSteps.length}/${i.manifest.steps.length}`:`unknown`};return o(JSON.stringify(s,null,2))}catch(e){return a.error(`flow_status failed`,i(e)),o(`Error: ${s(e)}`)}});let v=e(`flow_reset`);r.registerTool(`flow_reset`,{title:v.title,description:`Reset the active flow, clearing all state. Use to start over or switch to a different flow.`,annotations:v.annotations,inputSchema:{}},async()=>{try{let{stateMachine:e}=await f(),t=e.reset();return t.success?o(`Flow state reset. Use flow_start to begin a new flow.`):o(`Reset failed: ${t.error}`)}catch(e){return a.error(`flow_reset failed`,i(e)),o(`Error: ${s(e)}`)}})}export{c as registerFlowTools};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{getToolMeta as e}from"../tool-metadata.js";import{HealthOutputSchema as t}from"../output-schemas.js";import{z as n}from"zod";import{createLogger as r,serializeError as i}from"../../../core/dist/index.js";import{guide as a,health as o,processList as s,processLogs as c,processStart as l,processStatus as u,processStop as d,watchList as f,watchStart as p,watchStop as m,webFetch as h}from"../../../tools/dist/index.js";const g=r(`tools:infra`);function _(t){let r=e(`process`);t.registerTool(`process`,{title:r.title,description:`Start, stop, inspect, list, and tail logs for in-memory managed child processes.`,inputSchema:{action:n.enum([`start`,`stop`,`status`,`list`,`logs`]).describe(`Process action to perform`),id:n.string().optional().describe(`Managed process ID`),command:n.string().optional().describe(`Executable to start`),args:n.array(n.string()).optional().describe(`Arguments for start actions`),tail:n.number().min(1).max(500).optional().describe(`Log lines to return for logs actions`)},annotations:r.annotations},async({action:e,id:t,command:n,args:r,tail:a})=>{try{switch(e){case`start`:if(!t||!n)throw Error(`id and command are required for start`);return{content:[{type:`text`,text:JSON.stringify(l(t,n,r??[]))}]};case`stop`:if(!t)throw Error(`id is required for stop`);return{content:[{type:`text`,text:JSON.stringify(d(t)??null)}]};case`status`:if(!t)throw Error(`id is required for status`);return{content:[{type:`text`,text:JSON.stringify(u(t)??null)}]};case`list`:return{content:[{type:`text`,text:JSON.stringify(s())}]};case`logs`:if(!t)throw Error(`id is required for logs`);return{content:[{type:`text`,text:JSON.stringify(c(t,a))}]}}}catch(e){return g.error(`Process action failed`,i(e)),{content:[{type:`text`,text:`Process action failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function v(t){let r=e(`watch`);t.registerTool(`watch`,{title:r.title,description:`Watch a directory for file changes (create/modify/delete). Actions: start (begin watching), stop (by ID), list (show active watchers). Events are emitted as structured JSON with path, event type, and timestamp.`,inputSchema:{action:n.enum([`start`,`stop`,`list`]).describe(`Watch action to perform`),path:n.string().optional().describe(`Directory path to watch for start actions`),id:n.string().optional().describe(`Watcher ID for stop actions`)},annotations:r.annotations},async({action:e,path:t,id:n})=>{try{switch(e){case`start`:if(!t)throw Error(`path is required for start`);return{content:[{type:`text`,text:JSON.stringify(p({path:t}))}]};case`stop`:if(!n)throw Error(`id is required for stop`);return{content:[{type:`text`,text:JSON.stringify({stopped:m(n)})}]};case`list`:return{content:[{type:`text`,text:JSON.stringify(f())}]}}}catch(e){return g.error(`Watch action failed`,i(e)),{content:[{type:`text`,text:`Watch action failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function y(r){let a=e(`health`);r.registerTool(`health`,{title:a.title,description:`Run project health checks — verifies package.json, tsconfig, scripts, lockfile, README, LICENSE, .gitignore.`,outputSchema:t,inputSchema:{path:n.string().optional().describe(`Root directory to check (defaults to cwd)`)},annotations:a.annotations},async({path:e})=>{try{let t=o(e),n={ok:t.checks.every(e=>e.status!==`fail`),checks:t.checks.map(e=>({name:e.name,ok:e.status===`pass`,message:e.message}))};return{content:[{type:`text`,text:JSON.stringify(t)}],structuredContent:n}}catch(e){return g.error(`Health check failed`,i(e)),{content:[{type:`text`,text:`Health check failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function b(t){let r=e(`web_fetch`);t.registerTool(`web_fetch`,{title:r.title,description:`PREFERRED web fetcher — fetch one or many URLs and convert to LLM-optimized markdown. Pass one URL or multiple for parallel fetching. Supports CSS selectors, 4 output modes (markdown/raw/links/outline), smart paragraph-boundary truncation. Strips scripts/styles/nav automatically.`,inputSchema:{urls:n.array(n.string().url()).min(1).max(10).describe('URLs to fetch (1–10). Single URL: `["https://..."]`. Multiple fetched in parallel.'),mode:n.enum([`markdown`,`raw`,`links`,`outline`]).default(`markdown`).describe(`Output mode: markdown (clean content), raw (HTML), links (extracted URLs), outline (heading hierarchy)`),selector:n.string().optional().describe(`CSS selector to extract a specific element instead of auto-detecting main content`),max_length:n.number().min(500).max(1e5).default(15e3).describe(`Max characters in output — truncates at paragraph boundaries`),include_metadata:n.boolean().default(!0).describe(`Include page title, description, and URL as a header`),include_links:n.boolean().default(!1).describe(`Append extracted links list at the end`),include_images:n.boolean().default(!1).describe(`Include image alt texts inline`),timeout:n.number().min(1e3).max(6e4).default(15e3).describe(`Request timeout in milliseconds`)},annotations:r.annotations},async({urls:e,mode:t,selector:n,max_length:r,include_metadata:a,include_links:o,include_images:s,timeout:c})=>{let l=e,u=async(e,i)=>{let l=await h({url:e,mode:t,selector:n,maxLength:r,includeMetadata:a,includeLinks:o,includeImages:s,timeout:c}),u=[i?`## ${i} ${l.title||`Web Page`}\n> Source: ${e}`:`## ${l.title||`Web Page`}`,``,l.content];return l.truncated&&u.push(``,`_Original length: ${l.originalLength.toLocaleString()} chars_`),u.join(`
|
|
2
2
|
`)};if(l.length===1)try{return{content:[{type:`text`,text:await u(l[0])+"\n\n---\n_Next: Use `remember` to save key findings, or `web_fetch` with a `selector` to extract a specific section._"}]}}catch(e){let t=e instanceof Error?e.message:String(e);return/HTTP [45]\d{2}/.test(t)?g.warn(`Web fetch failed`,{error:t}):g.error(`Web fetch failed`,i(e)),{content:[{type:`text`,text:`Web fetch failed: ${t}`}],isError:!0}}let d=l.length,f=await Promise.allSettled(l.map((e,t)=>u(e,`[${t+1}/${d}]`))),p=[],m=0;for(let e=0;e<f.length;e++){let t=f[e];if(t.status===`fulfilled`)p.push(t.value);else{m++;let n=t.reason instanceof Error?t.reason.message:String(t.reason);/HTTP [45]\d{2}/.test(n)?g.warn(`Web fetch failed`,{url:l[e],error:n}):g.error(`Web fetch failed`,{url:l[e],...i(t.reason)}),p.push(`## ❌ Failed: ${l[e]}\n\n${n}`)}}let _=`_Fetched ${f.length-m}/${f.length} URLs successfully._`;return p.push(``,`---`,_,"_Next: Use `remember` to save key findings, or `web_fetch` with a `selector` to extract a specific section._"),{content:[{type:`text`,text:p.join(`
|
|
3
3
|
|
|
4
|
-
`)}],...m===f.length?{isError:!0}:{}}})}function x(t){let r=e(`guide`);t.registerTool(`guide`,{title:r.title,description:`Tool discovery — given a goal description, recommends which
|
|
4
|
+
`)}],...m===f.length?{isError:!0}:{}}})}function x(t){let r=e(`guide`);t.registerTool(`guide`,{title:r.title,description:`Tool discovery — given a goal description, recommends which AI Kit tools to use and in what order. Matches against 10 predefined workflows: onboard, audit, bugfix, implement, refactor, search, context, memory, validate, analyze.`,inputSchema:{goal:n.string().describe(`What you want to accomplish (e.g., "audit this monorepo", "fix a failing test")`),max_recommendations:n.number().min(1).max(10).default(5).describe(`Maximum number of tool recommendations`)},annotations:r.annotations},async({goal:e,max_recommendations:t})=>{try{let n=a(e,t),r=[`## Recommended Workflow: **${n.workflow}**`,n.description,``,`### Tools`,...n.tools.map(e=>{let t=e.suggestedArgs?` — \`${JSON.stringify(e.suggestedArgs)}\``:``;return`${e.order}. **${e.tool}** — ${e.reason}${t}`})];return n.alternativeWorkflows.length>0&&r.push(``,`_Alternative workflows: ${n.alternativeWorkflows.join(`, `)}_`),r.push(``,`---`,"_Next: Run the first recommended tool, or use `guide` again with a more specific goal._"),{content:[{type:`text`,text:r.join(`
|
|
5
5
|
`)}]}}catch(e){return g.error(`Guide failed`,i(e)),{content:[{type:`text`,text:`Guide failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{x as registerGuideTool,y as registerHealthTool,_ as registerProcessTool,v as registerWatchTool,b as registerWebFetchTool};
|
|
@@ -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
|
|
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(`
|
|
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};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{escHtml as e}from"../present-utils.js";import{buildTemplateHtml as t}from"./templates.js";import{FONT_LINK as n,getDesignSystemCSS as r}from"../present-theme.js";import{contentToHtml as i}from"./html.js";function a(a,o,s,c){let l=c&&c!==`auto`?t(c,o):i(a,o);return`<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
6
|
-
<title>${
|
|
7
|
-
${
|
|
8
|
-
<style>${
|
|
6
|
+
<title>${e(a??`AI Kit Dashboard`)}</title>
|
|
7
|
+
${n}
|
|
8
|
+
<style>${r()}</style>
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div class="dashboard">
|
|
12
12
|
<div class="header">
|
|
13
|
-
<h1>${
|
|
14
|
-
<div class="subtitle">
|
|
13
|
+
<h1>${e(a??`AI Kit Dashboard`)}</h1>
|
|
14
|
+
<div class="subtitle">AI Kit</div>
|
|
15
15
|
</div>
|
|
16
16
|
${l}
|
|
17
|
-
${(()=>{let
|
|
17
|
+
${(()=>{let t=Array.isArray(s)?s:[];return t.length===0?``:`
|
|
18
18
|
<div class="actions-bar">
|
|
19
19
|
<h2>Actions</h2>
|
|
20
|
-
<div class="actions-grid">${
|
|
20
|
+
<div class="actions-grid">${t.map(t=>{let n=String(t.id??``);if(t.type===`select`&&Array.isArray(t.options)){let r=t.options.map(t=>{let n=typeof t==`string`?t:t.label;return`<option value="${e(typeof t==`string`?t:t.value)}">${e(n)}</option>`}).join(``);return`<div class="action-group"><label>${e(String(t.label??``))}</label><select data-action-id="${e(n)}" onchange="sendCallback(${e(JSON.stringify(n))},this.value)">${r}</select></div>`}return`<button class="action-btn action-${String(t.variant??`default`)}" onclick="sendCallback(${e(JSON.stringify(n))},'clicked')">${e(String(t.label??``))}</button>`}).join(`
|
|
21
21
|
`)}</div>
|
|
22
22
|
<div id="action-feedback" class="action-feedback"></div>
|
|
23
23
|
</div>
|
|
@@ -42,7 +42,7 @@ ${e}
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
<\/script>`})()}
|
|
45
|
-
<div class="footer">
|
|
45
|
+
<div class="footer">AI Kit MCP Server · Generated ${new Date().toLocaleString()}</div>
|
|
46
46
|
</div>
|
|
47
47
|
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"><\/script>
|
|
48
48
|
<script>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{getToolMeta as e}from"../../tool-metadata.js";import{buildBrowserHtml as t}from"./browser.js";import{buildMarkdown as n}from"./markdown.js";import{readFileSync as r}from"node:fs";import{dirname as i,join as a}from"node:path";import{fileURLToPath as o}from"node:url";import{z as s}from"zod";import{
|
|
1
|
+
import{getToolMeta as e}from"../../tool-metadata.js";import{buildBrowserHtml as t}from"./browser.js";import{buildMarkdown as n}from"./markdown.js";import{readFileSync as r}from"node:fs";import{dirname as i,join as a}from"node:path";import{fileURLToPath as o}from"node:url";import{z as s}from"zod";import{RESOURCE_MIME_TYPE as c,registerAppResource as l,registerAppTool as u}from"@modelcontextprotocol/ext-apps/server";import{exec as d}from"node:child_process";import{createServer as f}from"node:http";import{createUIResource as p}from"@mcp-ui/server";const m=import.meta.dirname??i(o(import.meta.url)),h=`ui://kb/present.html`,g=s.object({type:s.enum([`button`,`select`]).describe(`Action type`),id:s.string().describe(`Unique action identifier`),label:s.string().describe(`Display label`),variant:s.enum([`primary`,`danger`,`default`]).optional().describe(`Button style variant`),options:s.array(s.union([s.string(),s.object({label:s.string(),value:s.string()})])).optional().describe(`Select options (for type=select)`)}),_={format:s.enum([`html`,`browser`]).default(`html`).describe(`Output format.
|
|
2
2
|
- "html" (default): Rich markdown in chat + embedded UIResource for MCP-UI hosts. Actions shown as numbered choices.
|
|
3
3
|
- "browser": Rich markdown in chat + opens beautiful themed dashboard in the browser. When actions are provided, the browser shows interactive buttons and the tool blocks until user clicks, returning their selection.`),title:s.string().optional().describe(`Optional heading`),content:s.any().describe(`Content to present. Accepts: markdown string, array of objects (→ table), { nodes, edges } (→ mermaid graph), typed blocks [{ type, value }], or any JSON (→ tree).`),actions:s.array(g).optional().describe(`Interactive actions (buttons/selects). In html mode, shown as numbered choices. In browser mode, rendered as clickable buttons and the tool blocks until user clicks.`),template:s.enum([`auto`,`list-sort`,`data-table`,`picker`,`flame-graph`,`form`,`timeline`,`kanban`,`tree`,`diff-view`,`dashboard`]).optional().describe(`UI template for interactive display in MCP Apps hosts.
|
|
4
4
|
- auto (default): detect from content shape
|
|
@@ -11,9 +11,9 @@ import{getToolMeta as e}from"../../tool-metadata.js";import{buildBrowserHtml as
|
|
|
11
11
|
- kanban: drag-drop board — content: { columns: [{id, label, color?}], cards: [{id, title, column, tags?[], priority?}] }
|
|
12
12
|
- tree: collapsible tree view — content: { root: {label, children?:[...]} | [...] }
|
|
13
13
|
- diff-view: side-by-side diff — content: { files: [{path, status, additions, deletions, hunks:[{header, changes:[{type, content}]}]}] }
|
|
14
|
-
- dashboard: metric cards grid — content: { metrics: [{label, value, trend?, status?, type?}] }`)};let v,y=!1,b=null;process.on(`exit`,()=>{if(b){try{b.close()}catch{}b=null}});function x(){return a(m,`..`,`..`,`..`,`..`,`present`,`dist`,`index.html`)}function S(){if(!v)try{v=r(x(),`utf-8`)}catch{v=``}return v}function C(t,n){let r=e(`present`);y||=(
|
|
14
|
+
- dashboard: metric cards grid — content: { metrics: [{label, value, trend?, status?, type?}] }`)};let v,y=!1,b=null;process.on(`exit`,()=>{if(b){try{b.close()}catch{}b=null}});function x(){return a(m,`..`,`..`,`..`,`..`,`present`,`dist`,`index.html`)}function S(){if(!v)try{v=r(x(),`utf-8`)}catch{v=``}return v}function C(t,n){let r=e(`present`);y||=(l(t,`AI Kit Present App`,h,{description:`Rich interactive content viewer for AI Kit tools`},async()=>({contents:[{uri:h,mimeType:c,text:S()}]})),!0),u(t,`present`,{title:r.title,description:`Present content to the user in the best format. Two modes:
|
|
15
15
|
- "html" (default): Rich markdown in chat + embedded UIResource. Use for display-only content (tables, charts, reports, status boards) where no user interaction is needed.
|
|
16
16
|
- "browser": Serves a themed dashboard on a local URL. Use ONLY when you need user interaction back (confirmations, selections, form input). The tool blocks until user clicks an action button, then returns their selection.
|
|
17
17
|
FORMAT RULE: If no user interaction is needed → use "html". If you need user input back → use "browser".
|
|
18
|
-
BROWSER WORKFLOW: After calling present with format "browser", you MUST extract the URL from the response and call openBrowserPage({ url }) to open it in VS Code Simple Browser. A system browser fallback also opens automatically, but always call openBrowserPage yourself.`,annotations:r.annotations,inputSchema:_,_meta:{ui:{resourceUri:h}}},async({format:e,title:t,content:r,actions:i,template:a})=>(e??`html`)===`browser`?await w(t,r,i,n,a):T(t,r,i,a))}async function w(e,r,i,a,o){let s=n(e,r),
|
|
19
|
-
`)}`}let c=
|
|
18
|
+
BROWSER WORKFLOW: After calling present with format "browser", you MUST extract the URL from the response and call openBrowserPage({ url }) to open it in VS Code Simple Browser. A system browser fallback also opens automatically, but always call openBrowserPage yourself.`,annotations:r.annotations,inputSchema:_,_meta:{ui:{resourceUri:h}}},async({format:e,title:t,content:r,actions:i,template:a})=>(e??`html`)===`browser`?await w(t,r,i,n,a):T(t,r,i,a))}async function w(e,r,i,a,o){let s=n(e,r),c=t(e,r,i,o),l=p({uri:`ui://kb/present-browser.html`,content:{type:`rawHtml`,htmlString:c},encoding:`text`,adapters:{mcpApps:{enabled:!0}}}),u,m,h=Array.isArray(i)?i:[],g=``,_;try{b&&=(b.close(),null),h.length>0&&(u=new Promise(e=>{m=e}));let e=!1;g=await new Promise((t,n)=>{let r=f((t,n)=>{if(e||(e=!0,_&&clearTimeout(_)),t.method===`POST`&&t.url===`/callback`){let e=``;t.on(`data`,t=>{e+=t.toString()}),t.on(`end`,()=>{n.writeHead(200,{"Content-Type":`application/json`,"Access-Control-Allow-Origin":`*`}),n.end(`{"ok":true}`);try{let t=JSON.parse(e);m?.(t)}catch{}});return}if(t.method===`OPTIONS`){n.writeHead(204,{"Access-Control-Allow-Origin":`*`,"Access-Control-Allow-Methods":`POST`,"Access-Control-Allow-Headers":`Content-Type`}),n.end();return}n.writeHead(200,{"Content-Type":`text/html; charset=utf-8`}),n.end(c)});r.listen(0,`127.0.0.1`,()=>{let i=r.address();if(typeof i==`object`&&i){b=r;let n=`http://127.0.0.1:${i.port}`;_=setTimeout(()=>{if(!e)try{d(process.platform===`win32`?`start "" "${n}"`:process.platform===`darwin`?`open "${n}"`:`xdg-open "${n}"`)}catch{}},8e3),_.unref(),t(n)}else n(Error(`Failed to start present server`))}),setTimeout(()=>{r.close(),b===r&&(b=null)},300*1e3).unref()})}catch{}let v=g?`${s}\n\n---\n🌐 **Dashboard opened in browser:** ${g}\n\n**IMPORTANT:** You MUST now open this URL using the \`openBrowserPage\` tool (Simple Browser). If that tool is unavailable, open the URL in the system browser as a fallback. If neither works, ask the user to open the URL manually.`:s;if(h.length>0&&a?.available&&u)try{let e=await Promise.race([u,new Promise((e,t)=>setTimeout(()=>t(Error(`timeout`)),300*1e3))]);return{content:[{type:`text`,text:`${v}\n\n✅ **Selected:** ${e.actionId} = \`${e.value}\``},l]}}catch{return{content:[{type:`text`,text:`${v}\n\n⚠️ *No selection received (timed out).*`},l]}}return{content:[{type:`text`,text:v},l]}}function T(e,r,i,a){let o=Array.isArray(i)?i:[],s=n(e,r);if(o.length>0){let e=[``];for(let t=0;t<o.length;t++){let n=o[t],r=typeof n.label==`string`?n.label:`Action ${t+1}`;if(n.type===`select`&&Array.isArray(n.options)){let i=n.options.map(e=>typeof e==`string`?e:e.label).join(`, `);e.push(`${t+1}. **${r}** — choose: ${i}`)}else e.push(`${t+1}. **${r}**`)}s+=`\n${e.join(`
|
|
19
|
+
`)}`}let c=p({uri:`ui://kb/present-static.html`,content:{type:`rawHtml`,htmlString:t(e,r,i,a)},encoding:`text`,adapters:{mcpApps:{enabled:!0}}});return{content:[{type:`text`,text:s},c],structuredContent:{title:e,content:r,actions:o}}}export{w as formatAsBrowser,T as formatAsHtml,S as getPresentHtml,C as registerPresentTool,x as resolvePresentHtml};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{getToolMeta as e}from"../tool-metadata.js";import{createTaskRunner as t}from"../task-manager.js";import{z as n}from"zod";import{createLogger as r,serializeError as i}from"../../../core/dist/index.js";const a=r(`tools`);function o(r,o,s,c,l,u){let d=e(`reindex`);r.registerTool(`reindex`,{title:d.title,description:`Trigger re-indexing of the
|
|
1
|
+
import{getToolMeta as e}from"../tool-metadata.js";import{createTaskRunner as t}from"../task-manager.js";import{z as n}from"zod";import{createLogger as r,serializeError as i}from"../../../core/dist/index.js";const a=r(`tools`);function o(r,o,s,c,l,u){let d=e(`reindex`);r.registerTool(`reindex`,{title:d.title,description:`Trigger re-indexing of the AI Kit index. Can do incremental (only changed files) or full re-index.`,inputSchema:{full:n.boolean().default(!1).describe(`If true, force full re-index ignoring file hashes`)},annotations:d.annotations},async({full:e},n)=>{try{if(o.isIndexing)return{content:[{type:`text`,text:`## Reindex Already in Progress
|
|
2
2
|
|
|
3
3
|
A reindex operation is currently running. Search and other tools continue to work with existing data. Use \`status({})\` to check when it completes.`}]};let r=t(n).createTask(`Reindex`,1);r.progress(0,`Starting ${e?`full`:`incremental`} reindex`),a.info(`Starting background re-index`,{mode:e?`full`:`incremental`});let d=e=>t=>{t.phase===`chunking`&&t.currentFile&&a.debug(`Re-index progress`,{prefix:e,current:t.filesProcessed+1,total:t.filesTotal,file:t.currentFile})};return(e?o.reindexAll(s,d(`Reindex`)):o.index(s,d(`Index`))).then(async e=>{if(a.info(`Background re-index complete`,{filesProcessed:e.filesProcessed,chunksCreated:e.chunksCreated,durationMs:e.durationMs}),r.complete(`Reindex complete: ${e.filesProcessed} files, ${e.chunksCreated} chunks in ${e.durationMs}ms`),l)try{await l.createFtsIndex(),a.info(`FTS index rebuilt after reindex`)}catch(e){a.warn(`FTS index rebuild failed`,i(e))}try{let e=await c.reindexAll();a.info(`Curated re-index complete`,{indexed:e.indexed})}catch(e){a.warn(`Curated re-index failed`,i(e))}if(u)try{await u.notifyAfterReindex()}catch(e){a.warn(`Post-reindex resource notification failed`,i(e))}}).catch(e=>{r.fail(`Reindex failed: ${e instanceof Error?e.message:String(e)}`),a.error(`Background reindex failed`,i(e))}),{content:[{type:`text`,text:`## Reindex Started (Background)\n\n- **Mode**: ${e?`Full`:`Incremental`}\n- Search and other tools continue to work with existing data during reindex.\n- Completion will be logged. Use \`status({})\` to check index stats afterward.\n\n---\n_Next: Continue working — the reindex runs in the background._`}]}}catch(e){return a.error(`Reindex failed`,i(e)),{content:[{type:`text`,text:`Reindex failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{o as registerReindexTool};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import{getToolMeta as e}from"../tool-metadata.js";import{SearchOutputSchema as t}from"../output-schemas.js";import{fanOutFtsSearch as n,fanOutSearch as r,openWorkspaceStores as i,resolveWorkspaces as a}from"../cross-workspace.js";import{curatedResourceLink as o,extractCuratedPath as s}from"../resource-links.js";import{basename as c}from"node:path";import{stat as l}from"node:fs/promises";import{z as u}from"zod";import{CONTENT_TYPES as d,KNOWLEDGE_ORIGINS as f,SOURCE_TYPES as p,computePartitionKey as m,createLogger as h,serializeError as g}from"../../../core/dist/index.js";import{bookendReorder as _,graphAugmentSearch as v,stashGet as y,truncateToTokenBudget as
|
|
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`,
|
|
1
|
+
import{getToolMeta as e}from"../tool-metadata.js";import{SearchOutputSchema as t}from"../output-schemas.js";import{fanOutFtsSearch as n,fanOutSearch as r,openWorkspaceStores as i,resolveWorkspaces as a}from"../cross-workspace.js";import{curatedResourceLink as o,extractCuratedPath as s}from"../resource-links.js";import{basename as c}from"node:path";import{stat as l}from"node:fs/promises";import{z as u}from"zod";import{CONTENT_TYPES as d,KNOWLEDGE_ORIGINS as f,SOURCE_TYPES as p,computePartitionKey as m,createLogger as h,serializeError as g}from"../../../core/dist/index.js";import{bookendReorder as _,graphAugmentSearch as v,stashGet as y,truncateToTokenBudget as b}from"../../../tools/dist/index.js";import{mergeResults as x}from"../../../enterprise-bridge/dist/index.js";const S=h(`tools`);function ee(e){let t=[],n=c(process.cwd());n&&t.push(`[project: ${n}]`);let r=y(`__context_boost`);return r&&t.push(`[focus: ${r.value}]`),t.length===0?e:`${t.join(` `)} ${e}`}async function C(e,t,n,r,i){if(!e||t>=e.config.fallbackThreshold&&n.length>0)return{results:n,triggered:!1,cacheHit:!1};let a=!1;try{let t=e.cache.get(r);return t?a=!0:(t=await e.client.search(r,i),t.length>0&&e.cache.set(r,t)),t.length>0?{results:x(n,t,i).map(e=>({record:{id:`er:${e.sourcePath}`,content:e.content,sourcePath:e.source===`er`?`[ER] ${e.sourcePath}`:e.sourcePath,startLine:e.startLine??0,endLine:e.endLine??0,contentType:e.contentType??`documentation`,headingPath:e.headingPath,origin:e.source===`er`?`curated`:e.origin??`indexed`,category:e.category,tags:e.tags??[],chunkIndex:0,totalChunks:1,fileHash:``,indexedAt:new Date().toISOString(),version:1},score:e.score})),triggered:!0,cacheHit:a}:{results:n,triggered:!0,cacheHit:a}}catch(e){return S.warn(`ER fallback failed`,g(e)),{results:n,triggered:!0,cacheHit:a}}}function te(e,t,n=60){let r=new Map;for(let t=0;t<e.length;t++){let i=e[t];r.set(i.record.id,{record:i.record,score:1/(n+t+1)})}for(let e=0;e<t.length;e++){let i=t[e],a=r.get(i.record.id);a?a.score+=1/(n+e+1):r.set(i.record.id,{record:i.record,score:1/(n+e+1)})}return[...r.values()].sort((e,t)=>t.score-e.score).map(({record:e,score:t})=>({record:e,score:t}))}function w(e,t){let n=t.toLowerCase().split(/\s+/).filter(e=>e.length>=2);return n.length<2?e:e.map(e=>{let t=e.record.content.toLowerCase();if(t.length>5e3)return e;let r=n.map(e=>{let n=[],r=t.indexOf(e);for(;r!==-1&&n.length<10;)n.push(r),r=t.indexOf(e,r+1);return n});if(r.some(e=>e.length===0))return e;let i=t.length;for(let e of r[0]){let t=e,a=e+n[0].length;for(let i=1;i<r.length;i++){let o=r[i][0],s=Math.abs(o-e);for(let t=1;t<r[i].length;t++){let n=Math.abs(r[i][t]-e);n<s&&(s=n,o=r[i][t])}t=Math.min(t,o),a=Math.max(a,o+n[i].length)}i=Math.min(i,a-t)}let a=1+.25/(1+i/200);return{record:e.record,score:e.score*a}}).sort((e,t)=>t.score-e.score)}function T(e,t,n=8){let r=new Set(t.toLowerCase().split(/\s+/).filter(e=>e.length>=2)),i=new Map,a=e.length;for(let t of e){let e=t.record.content.split(/[^a-zA-Z0-9_]+/).filter(e=>e.length>=3&&!E.has(e.toLowerCase())),n=new Set;for(let t of e){let e=t.toLowerCase();/[_A-Z]/.test(t)&&i.set(`__id__${e}`,1),n.has(e)||(n.add(e),i.set(e,(i.get(e)??0)+1))}}let o=[];for(let[e,t]of i){if(e.startsWith(`__id__`)||r.has(e)||t>a*.8)continue;let n=Math.log(a/t),s=i.has(`__id__${e}`)?1:0,c=e.length>8?.5:0;o.push({term:e,score:n+s+c})}return o.sort((e,t)=>t.score-e.score).slice(0,n).map(e=>e.term)}const E=new Set(`the.and.for.are.but.not.you.all.can.had.her.was.one.our.out.has.have.from.this.that.with.they.been.said.each.which.their.will.other.about.many.then.them.these.some.would.make.like.into.could.time.very.when.come.just.know.take.people.also.back.after.only.more.than.over.such.import.export.const.function.return.true.false.null.undefined.string.number.boolean.void.type.interface`.split(`.`));async function D(e,t){try{let n=await e.getStats();if(!n.lastIndexedAt)return;let r=new Date(n.lastIndexedAt).getTime(),i=Date.now(),a=[...new Set(t.map(e=>e.record.sourcePath))].filter(e=>!e.startsWith(`[ER]`)).slice(0,5);if(a.length===0)return;let o=0;for(let e of a)try{(await l(e)).mtimeMs>r&&o++}catch{o++}if(o>0){let e=i-r,t=Math.floor(e/6e4),n=t<1?`<1 min`:`${t} min`;return`> ⚠️ **Index may be stale** — ${o} file(s) modified since last index (${n} ago). Use \`reindex\` to refresh.`}}catch{}}function O(c,l,h,y,x,E,O){let k=e(`search`);c.registerTool(`search`,{title:k.title,description:`Search AI Kit for code, docs, and prior decisions. Default choice for discovery. Modes: hybrid (default), semantic, keyword. For multi-strategy precision queries use find; for a known file path use lookup.`,outputSchema:t,inputSchema:{query:u.string().max(5e3).describe(`Natural language search query`),limit:u.number().min(1).max(20).default(5).describe(`Maximum results to return`),search_mode:u.enum([`hybrid`,`semantic`,`keyword`]).default(`hybrid`).describe(`Search strategy: hybrid (vector + FTS + RRF fusion, default), semantic (vector only), keyword (FTS only)`),content_type:u.enum(d).optional().describe(`Filter by content type`),source_type:u.enum(p).optional().describe(`Coarse filter: "source" (code only), "documentation" (md, curated), "test", "config". Overrides content_type if both set.`),origin:u.enum(f).optional().describe(`Filter by knowledge origin`),category:u.string().optional().describe(`Filter by category (e.g., decisions, patterns, conventions)`),tags:u.array(u.string()).optional().describe(`Filter by tags (returns results matching ANY of the specified tags)`),min_score:u.number().min(0).max(1).default(.25).describe(`Minimum similarity score`),graph_hops:u.number().min(0).max(3).default(1).describe(`Number of graph hops to augment results with connected entities (0 = disabled, 1 = direct connections, 2-3 = deeper traversal). Default 1 provides module/symbol context automatically.`),max_tokens:u.number().min(100).max(5e4).optional().describe(`Maximum token budget for the response. When set, output is truncated to fit.`),dedup:u.enum([`file`,`chunk`]).default(`chunk`).describe(`Deduplication mode: "chunk" (default, show all matching chunks) or "file" (collapse chunks from same file into single result with merged line ranges)`),workspaces:u.array(u.string()).optional().describe(`Cross-workspace search: partition names or folder basenames to include. Use ["*"] for all registered workspaces. Only works in user-level install mode.`)},annotations:k.annotations},async({query:e,limit:t,search_mode:c,content_type:u,source_type:d,origin:f,category:p,tags:k,min_score:ne,graph_hops:A,max_tokens:j,dedup:M,workspaces:N})=>{try{let P={limit:t,minScore:ne,contentType:u,sourceType:d,origin:f,category:p,tags:k},F,I=!1,L=!1,R=``,z=ee(e);if(c===`keyword`)F=await h.ftsSearch(e,P),F=F.slice(0,t);else if(c===`semantic`){let n=await l.embedQuery(z);F=await h.search(n,P);let r=await C(x,F[0]?.score??0,F,e,t);F=r.results,I=r.triggered,L=r.cacheHit}else{let n=await l.embedQuery(z),[r,i]=await Promise.all([h.search(n,{...P,limit:t*2}),h.ftsSearch(e,{...P,limit:t*2}).catch(()=>[])]);F=te(r,i).slice(0,t);let a=await C(x,r[0]?.score??0,F,e,t);F=a.results,I=a.triggered,L=a.cacheHit}E&&E.recordSearch(e,I,L),F.length>1&&(F=w(F,e));let B=``;if(N&&N.length>0){let o=a(N,m(process.cwd()));if(o.length>0){let{stores:a,closeAll:s}=await i(o);try{let i;i=c===`keyword`?await n(a,e,{...P,limit:t}):await r(a,await l.embedQuery(e),{...P,limit:t});for(let e of i)F.push({record:{...e.record,sourcePath:`[${e.workspace}] ${e.record.sourcePath}`},score:e.score});F=F.sort((e,t)=>t.score-e.score).slice(0,t),B=` + ${o.length} workspace(s)`}finally{await s()}}}if(M===`file`&&F.length>1){let e=new Map;for(let t of F){let n=t.record.sourcePath,r=e.get(n);r?(t.score>r.best.score&&(r.best=t),r.ranges.push({start:t.record.startLine,end:t.record.endLine})):e.set(n,{best:t,ranges:[{start:t.record.startLine,end:t.record.endLine}]})}F=[...e.values()].sort((e,t)=>t.best.score-e.best.score).map(({best:e,ranges:t})=>({record:{...e.record,content:t.length>1?`${e.record.content}\n\n_Matched ${t.length} sections: ${t.sort((e,t)=>e.start-t.start).map(e=>`L${e.start}-${e.end}`).join(`, `)}_`:e.record.content},score:e.score}))}if(F.length===0){if(O?.available)try{let t=(await O.createMessage({prompt:`The search query "${e}" returned 0 results in AI Kit code search. Suggest ONE alternative search query that might find relevant results. Reply with ONLY the alternative query, nothing else.`,systemPrompt:`You are a search query optimizer for AI Kit code search. Generate a single alternative query.`,maxTokens:100})).text.trim().split(`
|
|
2
|
+
`)[0].slice(0,500);if(t&&t!==e){let n=await l.embedQuery(t),r=await h.search(n,P);r.length>0&&(F=r,R=`> _Original query "${e}" returned 0 results. Auto-reformulated to "${t}"._\n\n`,S.info(`Smart search fallback succeeded`,{originalQuery:e,altQuery:t,resultCount:r.length}))}}catch(e){S.debug(`Smart search fallback failed`,{error:String(e)})}if(F.length===0)return{content:[{type:`text`,text:`No results found for the given query.`}],structuredContent:{results:[],totalResults:0,searchMode:c,query:e}}}let V,H;if(A>0&&!y&&(H="> **Note:** `graph_hops` was set but no graph store is available. Graph augmentation skipped."),A>0&&y)try{let e=await v(y,F.map(e=>({recordId:e.record.id,score:e.score,sourcePath:e.record.sourcePath})),{hops:A,maxPerHit:5});V=new Map;for(let t of e)if(t.graphContext.nodes.length>0){let e=t.graphContext.nodes.slice(0,5).map(e=>` - **${e.name}** (${e.type})`).join(`
|
|
3
3
|
`),n=t.graphContext.edges.slice(0,5).map(e=>` - ${e.fromId} —[${e.type}]→ ${e.toId}`).join(`
|
|
4
4
|
`),r=[`- **Graph Context** (${A} hop${A>1?`s`:``}):`];e&&r.push(` Entities:\n${e}`),n&&r.push(` Relationships:\n${n}`),V.set(t.recordId,r.join(`
|
|
5
|
-
`))}}catch(e){
|
|
5
|
+
`))}}catch(e){S.warn(`Graph augmentation failed`,g(e)),H=`> **Note:** Graph augmentation failed. Results shown without graph context.`}let U=Date.now();for(let e of F)if(e.record.origin===`curated`&&e.record.indexedAt){let t=U-new Date(e.record.indexedAt).getTime(),n=Math.max(0,t/864e5);e.score*=.95**n}F.sort((e,t)=>t.score-e.score),F=_(F);let W=F.map((e,t)=>{let n=e.record;return`${`### Result ${t+1} (score: ${e.score.toFixed(3)})`}\n${[`- **Source**: ${n.sourcePath}`,n.headingPath?`- **Section**: ${n.headingPath}`:null,`- **Type**: ${n.contentType}`,n.startLine?`- **Lines**: ${n.startLine}-${n.endLine}`:null,n.origin===`indexed`?null:`- **Origin**: ${n.origin}`,n.category?`- **Category**: ${n.category}`:null,n.tags?.length?`- **Tags**: ${n.tags.join(`, `)}`:null,V?.get(n.id)??null].filter(Boolean).join(`
|
|
6
6
|
`)}\n\n${n.content}`}).join(`
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
`),G=(c===`hybrid`?`hybrid (vector + keyword RRF)`:c===`keyword`?`keyword (FTS)`:`semantic (vector)`)+B,K=T(F,e),q=K.length>0?`\n_Distinctive terms: ${K.map(e=>`\`${e}\``).join(`, `)}_`:``,J=await D(h,F),Y=[];if(F.length===0)Y.push("`reindex` — no results found, index may be stale"),Y.push("`find` — try federated search with glob/regex");else{let e=F[0]?.record.sourcePath;e&&Y.push(`\`lookup\` — see all chunks from \`${e}\``),Y.push("`symbol` — resolve a specific symbol from the results"),Y.push("`compact` — compress a result file for focused reading")}let X=[H?`${H}\n\n`:``,J?`${J}\n\n`:``,W,`\n\n---\n_Search mode: ${G} | ${F.length} results_${q}`,`\n_Next: ${Y.join(` | `)}_`],Z=R+X.join(``);j&&(Z=
|
|
10
|
+
`),G=(c===`hybrid`?`hybrid (vector + keyword RRF)`:c===`keyword`?`keyword (FTS)`:`semantic (vector)`)+B,K=T(F,e),q=K.length>0?`\n_Distinctive terms: ${K.map(e=>`\`${e}\``).join(`, `)}_`:``,J=await D(h,F),Y=[];if(F.length===0)Y.push("`reindex` — no results found, index may be stale"),Y.push("`find` — try federated search with glob/regex");else{let e=F[0]?.record.sourcePath;e&&Y.push(`\`lookup\` — see all chunks from \`${e}\``),Y.push("`symbol` — resolve a specific symbol from the results"),Y.push("`compact` — compress a result file for focused reading")}let X=[H?`${H}\n\n`:``,J?`${J}\n\n`:``,W,`\n\n---\n_Search mode: ${G} | ${F.length} results_${q}`,`\n_Next: ${Y.join(` | `)}_`],Z=R+X.join(``);j&&(Z=b(Z,j));let Q=new Set,$=[];for(let e of F){if(e.record.origin!==`curated`||e.record.sourcePath.startsWith(`[`))continue;let t=s(e.record.sourcePath);if(!t)continue;let n=o(t,e.record.headingPath??t);n&&!Q.has(n.uri)&&(Q.add(n.uri),$.push(n))}return{content:[{type:`text`,text:Z},...$],structuredContent:{results:F.map(e=>({sourcePath:e.record.sourcePath,contentType:e.record.contentType,score:e.score,...e.record.headingPath?{headingPath:e.record.headingPath}:{},...e.record.startLine?{startLine:e.record.startLine}:{},...e.record.endLine?{endLine:e.record.endLine}:{},...e.record.origin===`indexed`?{}:{origin:e.record.origin},...e.record.category?{category:e.record.category}:{},...e.record.tags?.length?{tags:e.record.tags}:{}})),totalResults:F.length,searchMode:c,query:e}}}catch(e){return S.error(`Search failed`,g(e)),{content:[{type:`text`,text:`Search failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{O as registerSearchTool};
|
|
@@ -12,7 +12,7 @@ declare function getScaffoldVersion(): string | null;
|
|
|
12
12
|
declare function getWorkspaceScaffoldVersion(): string | null;
|
|
13
13
|
/**
|
|
14
14
|
* Lightweight status tool registered during init — returns version info
|
|
15
|
-
* without needing the
|
|
15
|
+
* without needing the AI Kit store, graph, or curated manager.
|
|
16
16
|
*/
|
|
17
17
|
declare function registerEarlyStatusTool(server: McpServer): void;
|
|
18
18
|
declare function registerStatusTool(server: McpServer, store: IKnowledgeStore, graphStore?: IGraphStore, curated?: CuratedKnowledgeManager, onboardState?: OnboardState, config?: KBConfig): void;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{getGcStatus as e}from"../auto-gc.js";import{getToolTelemetry as t}from"../replay-interceptor.js";import{getToolMeta as n}from"../tool-metadata.js";import{StatusOutputSchema as r}from"../output-schemas.js";import{autoUpgradeScaffold as i,getCurrentVersion as a,getUpgradeState as o}from"../version-check.js";import{existsSync as s,readFileSync as c,statSync as l}from"node:fs";import{resolve as u}from"node:path";import{AIKIT_PATHS as d,createLogger as f,serializeError as p}from"../../../core/dist/index.js";import{WasmRuntime as m}from"../../../chunker/dist/index.js";import{homedir as h}from"node:os";const g=f(`tools`);function _(e,t,n,r=
|
|
2
|
-
`)}],structuredContent:l}})}function
|
|
3
|
-
`),R={totalRecords:
|
|
1
|
+
import{getGcStatus as e}from"../auto-gc.js";import{getToolTelemetry as t}from"../replay-interceptor.js";import{getToolMeta as n}from"../tool-metadata.js";import{StatusOutputSchema as r}from"../output-schemas.js";import{autoUpgradeScaffold as i,getCurrentVersion as a,getUpgradeState as o}from"../version-check.js";import{existsSync as s,readFileSync as c,statSync as l}from"node:fs";import{resolve as u}from"node:path";import{AIKIT_PATHS as d,createLogger as f,serializeError as p}from"../../../core/dist/index.js";import{WasmRuntime as m}from"../../../chunker/dist/index.js";import{homedir as h}from"node:os";const g=f(`tools`);function _(e,t,n,r=15e3){let i,a=new Promise(e=>{i=setTimeout(()=>{g.warn(`Status sub-operation "${n}" timed out after ${r}ms`),e({value:t,timedOut:!0})},r)});return Promise.race([e.then(e=>(clearTimeout(i),{value:e,timedOut:!1}),e=>(clearTimeout(i),g.warn(`Status sub-operation "${n}" failed: ${e instanceof Error?e.message:String(e)}`),{value:t,timedOut:!1})),a])}const v=5*6e4;let y=null,b=null;function x(){let e=Date.now();if(y&&e-y.ts<v)return y.value;try{let t=u(h(),`.copilot`,`.aikit-scaffold.json`);if(!s(t))return y={value:null,ts:e},null;let n=JSON.parse(c(t,`utf-8`)).version??null;return y={value:n,ts:e},n}catch{return y={value:null,ts:e},null}}function S(){let e=Date.now();if(b&&e-b.ts<v)return b.value;try{let t=u(process.cwd(),`.github`,`.aikit-scaffold.json`);if(!s(t))return b={value:null,ts:e},null;let n=JSON.parse(c(t,`utf-8`)).version??null;return b={value:n,ts:e},n}catch{return b={value:null,ts:e},null}}function C(e){let t=n(`status`);e.registerTool(`status`,{title:t.title,description:`Get the current status and statistics of the AI Kit index.`,outputSchema:r,annotations:t.annotations},async()=>{let e=a(),t=x(),n=S(),r=t!=null&&t!==e,s=n!=null&&n!==e,c=[`## AI Kit Status`,``,`⏳ **AI Kit is initializing** — index stats will be available shortly.`,``,`### Runtime`,`- **Tree-sitter (WASM)**: ${m.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`,``,`### Version`,`- **Server**: ${e}`,`- **Scaffold (user)**: ${t??`not installed`}`,`- **Scaffold (workspace)**: ${n??`not installed`}`];if(r||s){let a=o(),l=[];r&&l.push(`user scaffold v${t}`),s&&l.push(`workspace scaffold v${n}`);let u=l.join(`, `);a.state===`success`?c.push(``,`### ✅ Upgrade Applied`,`- Server v${e} — ${u} auto-upgraded successfully.`,`- _Restart the MCP server to use the updated version._`):a.state===`pending`?c.push(``,`### ⏳ Upgrade In Progress`,`- Server v${e} ≠ ${u}`,`- Auto-upgrade is running in the background…`):a.state===`failed`?(i(),c.push(``,`### ⬆ Upgrade Available (auto-upgrade failed, retrying)`,`- Server v${e} ≠ ${u}`,`- Error: ${a.error??`unknown`}`)):(i(),c.push(``,`### ⬆ Upgrade Available`,`- Server v${e} ≠ ${u}`,`- Auto-upgrade triggered — check again shortly.`))}let l={totalRecords:0,totalFiles:0,lastIndexedAt:null,onboarded:!1,onboardDir:``,contentTypes:{},wasmAvailable:!!m.get(),graphStats:null,curatedCount:0,serverVersion:e,scaffoldVersion:t??null,workspaceScaffoldVersion:n??null,upgradeAvailable:r||s};return{content:[{type:`text`,text:c.join(`
|
|
2
|
+
`)}],structuredContent:l}})}function w(c,f,h,v,y,b){let C=n(`status`);c.registerTool(`status`,{title:C.title,description:`Get the current status and statistics of the AI Kit index.`,outputSchema:r,annotations:C.annotations},async()=>{let n=[];try{let[r,c]=await Promise.all([_(f.getStats(),{totalRecords:0,totalFiles:0,lastIndexedAt:null,contentTypeBreakdown:{}},`store.getStats`),_(f.listSourcePaths(),[],`store.listSourcePaths`)]),p=r.value;r.timedOut&&n.push(`⚠ Index stats timed out — values may be incomplete`);let g=c.value;c.timedOut&&n.push(`⚠ File listing timed out`);let C=null,w=0,T=[`## AI Kit Status`,``,`- **Total Records**: ${p.totalRecords}`,`- **Total Files**: ${p.totalFiles}`,`- **Last Indexed**: ${p.lastIndexedAt??`Never`}`,``,`### Content Types`,...Object.entries(p.contentTypeBreakdown).map(([e,t])=>`- ${e}: ${t}`),``,`### Indexed Files`,...g.slice(0,50).map(e=>`- ${e}`),g.length>50?`\n... and ${g.length-50} more files`:``];if(h)try{let e=await _(h.getStats(),{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}},`graphStore.getStats`);if(e.timedOut)n.push(`⚠ Graph stats timed out`),T.push(``,`### Knowledge Graph`,`- Graph stats timed out`);else{let t=e.value;C={nodes:t.nodeCount,edges:t.edgeCount},T.push(``,`### Knowledge Graph`,`- **Nodes**: ${t.nodeCount}`,`- **Edges**: ${t.edgeCount}`,...Object.entries(t.nodeTypes).map(([e,t])=>` - ${e}: ${t}`));try{let e=await _(h.validate(),{valid:!0,danglingEdges:[],orphanNodes:[],stats:{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}}},`graphStore.validate`);if(!e.timedOut){let t=e.value;t.valid||T.push(`- **⚠ Integrity Issues**: ${t.danglingEdges.length} dangling edges`),t.orphanNodes.length>0&&T.push(`- **Orphan nodes**: ${t.orphanNodes.length}`)}}catch{}}}catch{T.push(``,`### Knowledge Graph`,`- Graph store unavailable`)}let E=b?.onboardDir??u(process.cwd(),d.aiKb),D=s(E),O=y?.onboardComplete??D;if(T.push(``,`### Onboard Status`,O?`- ✅ Complete${y?.onboardTimestamp?` (last: ${y.onboardTimestamp})`:``}`:'- ❌ Not run — call `onboard({ path: "." })` to analyze the codebase',`- **Onboard Directory**: \`${E}\``),v)try{let e=await _(v.list(),[],`curated.list`);if(e.timedOut)n.push(`⚠ Curated knowledge listing timed out`),T.push(``,`### Curated Knowledge`,`- Listing timed out`);else{let t=e.value;w=t.length,T.push(``,`### Curated Knowledge`,t.length>0?`- ${t.length} entries`:"- Empty — use `remember()` to persist decisions")}}catch{T.push(``,`### Curated Knowledge`,`- Unable to read curated entries`)}let k=0;if(p.lastIndexedAt){k=new Date(p.lastIndexedAt).getTime();let e=(Date.now()-k)/(1e3*60*60);T.push(``,`### Index Freshness`,e>24?`- ⚠ Last indexed ${Math.floor(e)}h ago — may be stale. Run \`reindex({})\``:`- ✅ Last indexed ${e<1?`less than 1h`:`${Math.floor(e)}h`} ago`)}{try{let e=u(process.cwd(),d.data,`stash`);if(s(e)){let t=l(e).mtimeMs;t>k&&(k=t)}}catch{}let e=[];if(v)try{let t=w>0?await v.list():[];for(let e of t){let t=new Date(e.updated||e.created).getTime();t>k&&(k=t)}e.push(...t.sort((e,t)=>new Date(t.updated).getTime()-new Date(e.updated).getTime()).slice(0,5))}catch{}let t=k>0?Date.now()-k:0;if(t>=144e5){let n=Math.floor(t/36e5);if(T.push(``,`### 🌅 Session Briefing`,`_${n}+ hours since last activity — here's what to pick up:_`,``),e.length>0){T.push(`**Recent decisions/notes:**`);for(let t of e)T.push(`- **${t.title}** (${t.category??`note`}) — ${(t.contentPreview??``).slice(0,80)}…`)}T.push(``,`**Suggested next steps:**`,'- `search({ query: "SESSION CHECKPOINT", origin: "curated" })` — find your last checkpoint',"- `restore({})` — resume from a saved checkpoint","- `list()` — browse all stored knowledge")}}T.push(``,`### Runtime`,`- **Tree-sitter (WASM)**: ${m.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`);let A=x(),j=S(),M=a(),N=A!=null&&A!==M,P=j!=null&&j!==M;if(N||P){let e=o(),t=[];N&&t.push(`user scaffold v${A}`),P&&t.push(`workspace scaffold v${j}`);let n=t.join(`, `);e.state===`success`?T.push(``,`### ✅ Upgrade Applied`,`- Server v${M} — ${n} auto-upgraded successfully.`,`- _Restart the MCP server to use the updated version._`):e.state===`pending`?T.push(``,`### ⏳ Upgrade In Progress`,`- Server v${M} ≠ ${n}`,`- Auto-upgrade is running in the background…`):e.state===`failed`?(i(),T.push(``,`### ⬆ Upgrade Available (auto-upgrade failed, retrying)`,`- Server v${M} ≠ ${n}`,`- Error: ${e.error??`unknown`}`)):(i(),T.push(``,`### ⬆ Upgrade Available`,`- Server v${M} ≠ ${n}`,`- Auto-upgrade triggered — check again shortly.`))}n.length>0&&T.push(``,`### ⚠ Warnings`,...n.map(e=>`- ${e}`));let F=t();if(F.length>0){let e=F.sort((e,t)=>t.callCount-e.callCount);T.push(``,`### Tool Usage This Session`,``),T.push(`| Tool | Calls | Tokens In | Tokens Out | Errors | Avg Latency |`),T.push(`|------|-------|-----------|------------|--------|-------------|`);for(let t of e.slice(0,15)){let e=Math.round(t.totalInputChars/4),n=Math.round(t.totalOutputChars/4),r=Math.round(t.totalDurationMs/t.callCount);T.push(`| ${t.tool} | ${t.callCount} | ${e.toLocaleString()} | ${n.toLocaleString()} | ${t.errorCount} | ${r}ms |`)}}let I=e();if(I.bufferSize>=10){let e=I.state===`healthy`?`🟢`:I.state===`degraded`?`🔴`:`🟡`;T.push(``,`### Auto-GC: ${e} ${I.state}`),T.push(`- p95 latency: ${I.p95}ms | buffer: ${I.bufferSize} samples`),I.gcCount>0&&T.push(`- GC cycles triggered: ${I.gcCount}`)}let L=T.join(`
|
|
3
|
+
`),R={totalRecords:p.totalRecords,totalFiles:p.totalFiles,lastIndexedAt:p.lastIndexedAt??null,onboarded:O,onboardDir:E,contentTypes:p.contentTypeBreakdown,wasmAvailable:!!m.get(),graphStats:C,curatedCount:w,serverVersion:M,scaffoldVersion:A??null,workspaceScaffoldVersion:j??null,upgradeAvailable:N||P};return{content:[{type:`text`,text:L+"\n\n---\n_Next: Use `search` to query indexed content, `graph(stats)` to explore the knowledge graph, or `reindex` to refresh the index._"}],structuredContent:R}}catch(e){return g.error(`Status failed`,p(e)),{content:[{type:`text`,text:`Status check failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}export{x as getScaffoldVersion,S as getWorkspaceScaffoldVersion,C as registerEarlyStatusTool,w as registerStatusTool};
|
|
@@ -4,11 +4,14 @@ import { GraphEdge, GraphNode, GraphStats, GraphTraversalOptions, GraphTraversal
|
|
|
4
4
|
declare class SqliteGraphStore implements IGraphStore {
|
|
5
5
|
private db;
|
|
6
6
|
private readonly dbPath;
|
|
7
|
+
private sqlFactory;
|
|
7
8
|
private dirty;
|
|
8
9
|
constructor(options?: {
|
|
9
10
|
path?: string;
|
|
10
11
|
});
|
|
11
12
|
initialize(): Promise<void>;
|
|
13
|
+
private configureDb;
|
|
14
|
+
private createTables;
|
|
12
15
|
private ensureDb;
|
|
13
16
|
private persist;
|
|
14
17
|
private markDirty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{AIKIT_PATHS as e}from"../../core/dist/index.js";import{existsSync as t,mkdirSync as n,readFileSync as r,writeFileSync as i}from"node:fs";import{dirname as a,join as o}from"node:path";var s=class{db=null;dbPath;dirty=!1;constructor(t){this.dbPath=o(t?.path??e.data,`graph.db`)}async initialize(){let e=a(this.dbPath);t(e)||n(e,{recursive:!0});let i=(await import(`sql.js`)).default,o=await i();if(t(this.dbPath)){let e=r(this.dbPath);this.db=new o.Database(e)}else this.db=new o.Database;this.db.run(`PRAGMA journal_mode = WAL`),
|
|
1
|
+
import{AIKIT_PATHS as e}from"../../core/dist/index.js";import{existsSync as t,mkdirSync as n,readFileSync as r,writeFileSync as i}from"node:fs";import{dirname as a,join as o}from"node:path";var s=class{db=null;dbPath;sqlFactory=null;dirty=!1;constructor(t){this.dbPath=o(t?.path??e.data,`graph.db`)}async initialize(){let e=a(this.dbPath);t(e)||n(e,{recursive:!0});let i=(await import(`sql.js`)).default,o=await i();if(this.sqlFactory=o,t(this.dbPath)){let e=r(this.dbPath);this.db=new o.Database(e)}else this.db=new o.Database;this.configureDb(this.db),this.createTables(this.db),this.persist()}configureDb(e){e.run(`PRAGMA journal_mode = WAL`),e.exec(`PRAGMA foreign_keys = ON;`)}createTables(e){e.run(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS nodes (
|
|
3
3
|
id TEXT PRIMARY KEY,
|
|
4
4
|
type TEXT NOT NULL,
|
|
@@ -8,7 +8,7 @@ import{AIKIT_PATHS as e}from"../../core/dist/index.js";import{existsSync as t,mk
|
|
|
8
8
|
source_path TEXT,
|
|
9
9
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
10
10
|
)
|
|
11
|
-
`),
|
|
11
|
+
`),e.run(`
|
|
12
12
|
CREATE TABLE IF NOT EXISTS edges (
|
|
13
13
|
id TEXT PRIMARY KEY,
|
|
14
14
|
from_id TEXT NOT NULL,
|
|
@@ -19,7 +19,7 @@ import{AIKIT_PATHS as e}from"../../core/dist/index.js";import{existsSync as t,mk
|
|
|
19
19
|
FOREIGN KEY (from_id) REFERENCES nodes(id) ON DELETE CASCADE,
|
|
20
20
|
FOREIGN KEY (to_id) REFERENCES nodes(id) ON DELETE CASCADE
|
|
21
21
|
)
|
|
22
|
-
`),
|
|
22
|
+
`),e.run(`CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type)`),e.run(`CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name)`),e.run(`CREATE INDEX IF NOT EXISTS idx_nodes_source_path ON nodes(source_path)`),e.run(`CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id)`),e.run(`CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id)`),e.run(`CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type)`)}ensureDb(){if(!this.db){if(!this.sqlFactory)throw Error(`Graph store not initialized — call initialize() first`);this.db=t(this.dbPath)?new this.sqlFactory.Database(r(this.dbPath)):new this.sqlFactory.Database,this.configureDb(this.db),this.createTables(this.db)}return this.db}persist(){if(!this.db)return;let e=this.db.export();try{i(this.dbPath,Buffer.from(e))}finally{this.db.exec(`PRAGMA foreign_keys = ON;`)}this.dirty=!1}markDirty(){this.dirty=!0}flushIfDirty(){this.dirty&&this.persist()}query(e,t=[]){let n=this.ensureDb().prepare(e);n.bind(t);let r=[];try{for(;n.step();)r.push(n.getAsObject())}finally{n.free()}return r}run(e,t=[]){this.ensureDb().run(e,t)}async upsertNode(e){this.run(`INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at)
|
|
23
23
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
24
24
|
ON CONFLICT(id) DO UPDATE SET
|
|
25
25
|
type = excluded.type, name = excluded.name, properties = excluded.properties,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{resolve as e}from"node:path";import{existsSync as t,mkdirSync as n,readFileSync as r,readdirSync as i,writeFileSync as
|
|
1
|
+
import{resolve as e}from"node:path";import{existsSync as t,mkdirSync as n,readFileSync as r,readdirSync as i,renameSync as a,writeFileSync as o}from"node:fs";import{resolveStateDir as s}from"../../core/dist/index.js";function c(r){let i=e(s(r??process.cwd()),`checkpoints`);return t(i)||n(i,{recursive:!0}),i}function l(t,n,r){let i=t.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-|-$/g,``)||`checkpoint`,s={id:`${Date.now()}-${i}`,label:t,createdAt:new Date().toISOString(),data:n,files:r?.files,notes:r?.notes},l=e(c(r?.cwd),`${s.id}.json`),u=`${l}.tmp`;return o(u,`${JSON.stringify(s,null,2)}\n`,`utf-8`),a(u,l),s}function u(n,i){let a=c(i),o=e(a,`${n}.json`);if(o.startsWith(e(a))&&t(o))try{return JSON.parse(r(o,`utf-8`))}catch(e){if(e?.code===`ENOENT`)return;console.warn(`Corrupt state file ${o}: ${e instanceof Error?e.message:String(e)}`);return}}function d(t){let n=c(t);return i(n).filter(e=>e.endsWith(`.json`)).flatMap(t=>{let i=e(n,t);try{return[JSON.parse(r(i,`utf-8`))]}catch(e){return e?.code===`ENOENT`||console.warn(`Corrupt state file ${i}: ${e instanceof Error?e.message:String(e)}`),[]}}).sort((e,t)=>t.createdAt.localeCompare(e.createdAt))}function f(e){return d(e)[0]}export{f as checkpointLatest,d as checkpointList,u as checkpointLoad,l as checkpointSave};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{readFile as e,readdir as t}from"node:fs/promises";import{basename as n,join as r,relative as i}from"node:path";const a=new Set([`node_modules`,`.git`,`dist`,`build`,`coverage`,`.turbo`,`.cache`,`cdk.out`,`__pycache__`,`.venv`,`target`,`obj`,`.gradle`]),o=[{glob:/\.env(?:\.\w+)?$/,type:`env`},{glob:/\.env\.example$/,type:`env`},{glob:/package\.json$/,type:`package-json`},{glob:/^(?:app|config|settings|default)\.(?:json|ya?ml|toml)$/i,type:`config`},{glob:/docker-compose\.ya?ml$/,type:`docker`},{glob:/cdk\.json$/,type:`cdk`},{glob:/turbo\.json$/,type:`tooling`},{glob:/application\.(?:properties|ya?ml)$/i,type:`spring`},{glob:/settings\.py$/,type:`django`},{glob:/\.flaskenv$/,type:`env`},{glob:/appsettings\.(?:\w+\.)?json$/i,type:`dotnet`}];async function s(t,n){let r=[],a=await c(t),o=/
|
|
1
|
+
import{readFile as e,readdir as t}from"node:fs/promises";import{basename as n,join as r,relative as i}from"node:path";const a=new Set([`node_modules`,`.git`,`dist`,`build`,`coverage`,`.turbo`,`.cache`,`cdk.out`,`__pycache__`,`.venv`,`target`,`obj`,`.gradle`]),o=[{glob:/\.env(?:\.\w+)?$/,type:`env`},{glob:/\.env\.example$/,type:`env`},{glob:/package\.json$/,type:`package-json`},{glob:/^(?:app|config|settings|default)\.(?:json|ya?ml|toml)$/i,type:`config`},{glob:/docker-compose\.ya?ml$/,type:`docker`},{glob:/cdk\.json$/,type:`cdk`},{glob:/turbo\.json$/,type:`tooling`},{glob:/application\.(?:properties|ya?ml)$/i,type:`spring`},{glob:/settings\.py$/,type:`django`},{glob:/\.flaskenv$/,type:`env`},{glob:/appsettings\.(?:\w+\.)?json$/i,type:`dotnet`}];async function s(t,n){let r=[],a=await c(t),o=/aikit\.config\.json$/;for(let n of a)try{let a=i(t,n).replace(/\\/g,`/`);if(o.test(a))continue;let s=await e(n,`utf-8`),c=l(n);if(a.split(`/`).length-1>1&&c===`tooling`)continue;let u=d(s,c);u.length>0&&r.push({file:a,type:c,values:u})}catch{}return p(r,n)}async function c(e){let n=[],i=async(e,s)=>{if(!(s>3))try{let c=await t(e,{withFileTypes:!0});for(let t of c){if(a.has(t.name))continue;let c=r(e,t.name);t.isDirectory()&&!t.name.startsWith(`.`)?await i(c,s+1):t.isFile()&&o.some(e=>e.glob.test(t.name))&&n.push(c)}}catch{}};return await i(e,0),n}function l(e){let t=n(e);for(let e of o)if(e.glob.test(t))return e.type;return`unknown`}const u=/(?:secret|password|token|key|api.?key|auth|credential|private)/i;function d(e,t){let n=[];if(t===`env`)for(let t of e.split(`
|
|
2
2
|
`)){let e=t.trim();if(!e||e.startsWith(`#`))continue;let r=e.indexOf(`=`);if(r===-1)continue;let i=e.slice(0,r).trim(),a=e.slice(r+1).trim(),o=u.test(i);n.push({key:i,value:o?`***`:a,sensitive:o})}else if(t===`package-json`)try{let t=JSON.parse(e);if(t.scripts)for(let[e,r]of Object.entries(t.scripts))n.push({key:`scripts.${e}`,value:String(r),sensitive:!1});if(t.engines)for(let[e,r]of Object.entries(t.engines))n.push({key:`engines.${e}`,value:String(r),sensitive:!1})}catch{}else if(t===`spring`)for(let t of e.split(`
|
|
3
3
|
`)){let e=t.trim();if(!e||e.startsWith(`#`)||e.startsWith(`---`))continue;let r=e.match(/^([\w.[\]-]+)\s*[=:]\s*(.*)$/);if(r){let e=r[1],t=r[2].trim(),i=u.test(e);n.push({key:e,value:i?`***`:t,sensitive:i})}}else if(t===`json`||t===`config`||t===`cdk`||t===`tooling`||t===`dotnet`)try{f(JSON.parse(e),``,n,0)}catch{}else if(t===`django`)for(let t of e.split(`
|
|
4
4
|
`)){let e=t.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.+)$/);if(e){let t=e[1],r=e[2].trim(),i=u.test(t);n.push({key:t,value:i?`***`:r.slice(0,100),sensitive:i})}}return n}function f(e,t,n,r){if(!(r>3)&&typeof e==`object`&&e&&!Array.isArray(e))for(let[i,a]of Object.entries(e)){let e=t?`${t}.${i}`:i;if(typeof a==`object`&&a&&!Array.isArray(a))f(a,e,n,r+1);else{let t=u.test(i),r=Array.isArray(a)?`[${a.length} items]`:String(a);n.push({key:e,value:t?`***`:r.slice(0,120),sensitive:t})}}}function p(e,t){let n=[];if(n.push(`## Configuration Values: ${t}\n`),e.length===0)return n.push(`No configuration files detected.`),n.join(`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{dirname as e,resolve as t}from"node:path";import{existsSync as n,mkdirSync as r,readFileSync as i,writeFileSync as
|
|
1
|
+
import{dirname as e,resolve as t}from"node:path";import{existsSync as n,mkdirSync as r,readFileSync as i,renameSync as a,writeFileSync as o}from"node:fs";import{resolveStateDir as s}from"../../core/dist/index.js";function c(e){return t(s(e??process.cwd()),`evidence-maps.json`)}function l(e){let t=c(e);if(!n(t))return{};try{let e=i(t,`utf-8`);return JSON.parse(e)}catch(e){return e?.code===`ENOENT`||console.warn(`Corrupt state file ${t}: ${e instanceof Error?e.message:String(e)}`),{}}}function u(t,i){let s=c(i),l=e(s);n(l)||r(l,{recursive:!0});let u=`${s}.tmp`;o(u,`${JSON.stringify(t,null,2)}\n`,`utf-8`),a(u,s)}function d(e,t){let n=l(t),r=n[e];if(!r)throw Error(`Evidence map not found: ${e}`);return{maps:n,state:r}}function f(e){return e.reduce((e,t)=>Math.max(e,t.id),0)+1}function p(e){let t=e.trim();if(!t)throw Error(`Claim is required`);if(/\r?\n/.test(t))throw Error(`Claim must be a single line`);return t}function m(e){return(e??``).replace(/\r?\n/g,` `).replace(/\|/g,`\\|`)}function h(e){let t=[`| # | Claim | Status | Receipt | Critical | Type | Safety |`,`|---|-------|--------|---------|----------|------|--------|`];for(let n of e.entries)t.push(`| ${n.id} | ${m(n.claim)} | ${n.status} | ${m(n.receipt)} | ${n.criticalPath?`yes`:`no`} | ${m(n.unknownType)} | ${m(n.safetyGate)} |`);return t.join(`
|
|
2
2
|
`)}function g(e){return{total:e.length,verified:e.filter(e=>e.status===`V`).length,assumed:e.filter(e=>e.status===`A`).length,unresolved:e.filter(e=>e.status===`U`).length}}function _(e){let t=[];for(let n of e.entries)n.status===`V`&&n.receipt.trim()===``&&t.push(`V entry without receipt`),n.status===`A`&&e.tier===`critical`&&n.unknownType===`contract`&&t.push(`Assumed contract at Critical tier — should be Verified`);return t}function v(e){return`FORCED DELIVERY annotation: unresolved entries remain -> ${e.filter(e=>e.status===`U`).map(e=>`#${e.id} ${e.claim}`).join(`; `)}`}function y(e){let t=[],n=e.entries.filter(e=>e.status===`V`&&!e.receipt.trim());n.length>0&&t.push(`Provenance: ${n.length} verified claim(s) lack receipts`);let r=e.entries.filter(e=>e.safetyGate===`commitment`&&e.status!==`V`);r.length>0&&t.push(`Commitment: ${r.length} commitment(s) not verified`);let i=e.entries.some(e=>e.safetyGate===`coverage`&&e.status===`U`);return i&&t.push(`Coverage: unresolved coverage entries remain`),{provenance:n.length>0?`fail`:`pass`,commitment:r.length>0?`fail`:`pass`,coverage:i?`fail`:`pass`,failures:t}}function b(e,t=0){let n=e.entries.filter(e=>e.criticalPath&&e.status===`U`),r=_(e),i=g(e.entries);return n.find(e=>e.unknownType===`contract`)?{decision:`HARD_BLOCK`,reason:`Unresolved contract unknown on critical path`,unresolvedCritical:n,warnings:r,stats:i}:n.length>0&&t===0?{decision:`HOLD`,reason:`Unresolved critical-path unknown — retry available`,unresolvedCritical:n,warnings:r,stats:i}:n.length>0&&t>=1?{decision:`FORCED_DELIVERY`,reason:`Unresolved critical-path unknown after retry`,unresolvedCritical:n,warnings:r,stats:i,annotation:v(e.entries)}:{decision:`YIELD`,reason:`All critical-path claims satisfy gate rules`,unresolvedCritical:[],warnings:r,stats:i,...x(e,r,i)}}function x(e,t,n){if(!e.entries.some(e=>e.safetyGate)||e.tier===`floor`)return{};let r=y(e);return r.failures.length>0?{safetyGates:r,decision:`HOLD`,reason:`Safety gate failure: ${r.failures.join(`; `)}`,warnings:[...t,...r.failures]}:{safetyGates:r}}function S(e,t){switch(e.action){case`create`:{let n=l(t),r=new Date().toISOString(),i={taskId:e.taskId,tier:e.tier,entries:[],createdAt:r,updatedAt:r};return n[e.taskId]=i,u(n,t),{state:i,formattedMap:h(i)}}case`add`:{let{maps:n,state:r}=d(e.taskId,t),i={id:f(r.entries),claim:p(e.claim),status:e.status,receipt:e.receipt,criticalPath:e.criticalPath??!1,unknownType:e.unknownType,safetyGate:e.safetyGate};return r.entries.push(i),r.updatedAt=new Date().toISOString(),n[e.taskId]=r,u(n,t),{state:r,entry:i,formattedMap:h(r)}}case`update`:{let{maps:n,state:r}=d(e.taskId,t),i=r.entries.find(t=>t.id===e.id);if(!i)throw Error(`Evidence entry not found: ${e.id}`);return i.status=e.status,i.receipt=e.receipt,r.updatedAt=new Date().toISOString(),n[e.taskId]=r,u(n,t),{state:r,entry:i,formattedMap:h(r)}}case`get`:{let{state:n}=d(e.taskId,t);return{state:n,formattedMap:h(n)}}case`gate`:{let{state:n}=d(e.taskId,t);return{state:n,gate:b(n,e.retryCount??0),formattedMap:h(n)}}case`list`:return{states:Object.values(l(t)).sort((e,t)=>e.createdAt.localeCompare(t.createdAt))};case`delete`:{let n=l(t);return e.taskId in n?(delete n[e.taskId],u(n,t),{deleted:!0}):{deleted:!1}}}}function C(e,t,n){let r=[];for(let i of t){let t=S({action:`add`,taskId:e,claim:`Test failure: ${i}`,status:`U`,receipt:``,criticalPath:!0},n);t.entry&&r.push(t.entry)}return r}export{C as autoClaimTestFailures,S as evidenceMap};
|
|
@@ -24,7 +24,7 @@ interface FindResult {
|
|
|
24
24
|
source: 'vector' | 'keyword' | 'glob' | 'pattern';
|
|
25
25
|
/** Relevance score (0-1 for vector/keyword, 1 for glob/pattern matches) */
|
|
26
26
|
score: number;
|
|
27
|
-
/** Line range if from
|
|
27
|
+
/** Line range if from AI Kit search */
|
|
28
28
|
lineRange?: {
|
|
29
29
|
start: number;
|
|
30
30
|
end: number;
|
|
@@ -33,7 +33,7 @@ interface ForgeGroundResult {
|
|
|
33
33
|
scopeMap: ScopeMapResult | null;
|
|
34
34
|
/** Typed Unknown Queue seeds */
|
|
35
35
|
typedUnknownSeeds: TypedUnknownSeed[];
|
|
36
|
-
/** Constraint seed — relevant
|
|
36
|
+
/** Constraint seed — relevant AI Kit entries from decisions/patterns */
|
|
37
37
|
constraints: ConstraintRef[];
|
|
38
38
|
/** File summaries for target files */
|
|
39
39
|
fileSummaries: Array<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=[{name:`onboard`,description:`First-time codebase exploration and understanding`,keywords:[`onboard`,`new project`,`understand`,`explore`,`first time`,`getting started`,`learn`,`overview`],tools:[{tool:`status`,reason:`Check index health and record count`,order:1},{tool:`onboard`,reason:`Run all analysis tools in one command`,order:2,suggestedArgs:{path:`.`}},{tool:`search`,reason:`Find specific topics of interest`,order:3},{tool:`graph`,reason:`Explore module relationships`,order:4,suggestedArgs:{action:`stats`}}]},{name:`audit`,description:`Assess project health, quality, and structure`,keywords:[`audit`,`health`,`quality`,`assess`,`review project`,`check quality`,`code quality`,`tech debt`],tools:[{tool:`status`,reason:`Check index freshness`,order:1},{tool:`audit`,reason:`Unified audit report with score and recommendations`,order:2,suggestedArgs:{detail:`summary`}},{tool:`check`,reason:`Typecheck + lint validation`,order:3},{tool:`health`,reason:`Detailed health checks on package.json, tsconfig, etc.`,order:4}]},{name:`bugfix`,description:`Diagnose and fix a bug or failing test`,keywords:[`bug`,`fix`,`debug`,`error`,`failing`,`broken`,`crash`,`wrong`,`issue`,`problem`,`not working`],tools:[{tool:`parse_output`,reason:`Parse error output from build tools (tsc, vitest, biome)`,order:1},{tool:`symbol`,reason:`Find definition and all references of the failing symbol`,order:2},{tool:`trace`,reason:`Trace call chain backward from the failure point`,order:3,suggestedArgs:{direction:`backward`}},{tool:`search`,reason:`Search for related patterns or similar fixes`,order:4},{tool:`test_run`,reason:`Re-run tests after fix`,order:5}]},{name:`implement`,description:`Add a new feature or implement a change`,keywords:[`implement`,`add feature`,`new feature`,`build`,`create`,`add`,`develop`,`write code`],tools:[{tool:`scope_map`,reason:`Generate a reading plan for affected files`,order:1},{tool:`search`,reason:`Find related patterns and prior art`,order:2},{tool:`find`,reason:`Find usage examples of similar patterns`,order:3,suggestedArgs:{mode:`examples`}},{tool:`check`,reason:`Validate after implementation`,order:4},{tool:`test_run`,reason:`Run tests to verify`,order:5},{tool:`blast_radius`,reason:`Check impact of changes`,order:6}]},{name:`refactor`,description:`Restructure or clean up existing code`,keywords:[`refactor`,`restructure`,`clean up`,`reorganize`,`rename`,`move`,`extract`,`DRY`,`dead code`],tools:[{tool:`dead_symbols`,reason:`Find unused exports to remove`,order:1},{tool:`symbol`,reason:`Find all references before renaming`,order:2},{tool:`blast_radius`,reason:`Assess impact before making changes`,order:3},{tool:`rename`,reason:`Safe cross-file rename`,order:4},{tool:`check`,reason:`Validate after refactoring`,order:5},{tool:`test_run`,reason:`Ensure no regressions`,order:6}]},{name:`search`,description:`Find specific code, patterns, or information`,keywords:[`find`,`search`,`where`,`locate`,`look for`,`grep`,`which file`,`how does`],tools:[{tool:`search`,reason:`Hybrid semantic + keyword search`,order:1},{tool:`find`,reason:`Federated search with glob and regex`,order:2},{tool:`symbol`,reason:`Resolve a specific symbol definition and references`,order:3},{tool:`graph`,reason:`Explore entity relationships`,order:4,suggestedArgs:{action:`neighbors`}}]},{name:`context`,description:`Compress or manage context for efficient LLM interaction`,keywords:[`context`,`compress`,`summarize`,`too long`,`token`,`budget`,`reduce`,`compact`],tools:[{tool:`file_summary`,reason:`Quick structural overview without reading full file`,order:1},{tool:`compact`,reason:`Compress file to relevant sections`,order:2,suggestedArgs:{segmentation:`paragraph`}},{tool:`digest`,reason:`Compress multiple sources into budgeted summary`,order:3},{tool:`stratum_card`,reason:`Generate reusable context cards`,order:4}]},{name:`memory`,description:`Manage persistent knowledge across sessions`,keywords:[`memory`,`remember`,`persist`,`save`,`recall`,`decision`,`convention`,`session`,`checkpoint`],tools:[{tool:`list`,reason:`See all stored knowledge entries`,order:1},{tool:`search`,reason:`Search curated knowledge`,order:2,suggestedArgs:{origin:`curated`}},{tool:`remember`,reason:`Store a new decision or pattern`,order:3},{tool:`checkpoint`,reason:`Save/restore session progress`,order:4},{tool:`stash`,reason:`Temporary key-value storage within session`,order:5}]},{name:`validate`,description:`Run checks, tests, and validation`,keywords:[`validate`,`check`,`test`,`lint`,`typecheck`,`verify`,`CI`,`pass`,`run tests`],tools:[{tool:`check`,reason:`Typecheck + lint in one call`,order:1,suggestedArgs:{detail:`errors`}},{tool:`test_run`,reason:`Run tests with structured output`,order:2},{tool:`health`,reason:`Project health assessment`,order:3}]},{name:`analyze`,description:`Deep analysis of codebase structure, dependencies, or patterns`,keywords:[`analyze`,`dependency`,`structure`,`pattern`,`architecture`,`diagram`,`entry point`,`import`],tools:[{tool:`analyze_structure`,reason:`Project structure overview`,order:1},{tool:`analyze_dependencies`,reason:`Dependency graph and analysis`,order:2},{tool:`analyze_patterns`,reason:`Detect code patterns and conventions`,order:3},{tool:`analyze_entry_points`,reason:`Find handlers, exports, and entry points`,order:4},{tool:`analyze_diagram`,reason:`Generate Mermaid diagrams`,order:5}]},{name:`upgrade`,description:`Update
|
|
1
|
+
const e=[{name:`onboard`,description:`First-time codebase exploration and understanding`,keywords:[`onboard`,`new project`,`understand`,`explore`,`first time`,`getting started`,`learn`,`overview`],tools:[{tool:`status`,reason:`Check index health and record count`,order:1},{tool:`onboard`,reason:`Run all analysis tools in one command`,order:2,suggestedArgs:{path:`.`}},{tool:`search`,reason:`Find specific topics of interest`,order:3},{tool:`graph`,reason:`Explore module relationships`,order:4,suggestedArgs:{action:`stats`}}]},{name:`audit`,description:`Assess project health, quality, and structure`,keywords:[`audit`,`health`,`quality`,`assess`,`review project`,`check quality`,`code quality`,`tech debt`],tools:[{tool:`status`,reason:`Check index freshness`,order:1},{tool:`audit`,reason:`Unified audit report with score and recommendations`,order:2,suggestedArgs:{detail:`summary`}},{tool:`check`,reason:`Typecheck + lint validation`,order:3},{tool:`health`,reason:`Detailed health checks on package.json, tsconfig, etc.`,order:4}]},{name:`bugfix`,description:`Diagnose and fix a bug or failing test`,keywords:[`bug`,`fix`,`debug`,`error`,`failing`,`broken`,`crash`,`wrong`,`issue`,`problem`,`not working`],tools:[{tool:`parse_output`,reason:`Parse error output from build tools (tsc, vitest, biome)`,order:1},{tool:`symbol`,reason:`Find definition and all references of the failing symbol`,order:2},{tool:`trace`,reason:`Trace call chain backward from the failure point`,order:3,suggestedArgs:{direction:`backward`}},{tool:`search`,reason:`Search for related patterns or similar fixes`,order:4},{tool:`test_run`,reason:`Re-run tests after fix`,order:5}]},{name:`implement`,description:`Add a new feature or implement a change`,keywords:[`implement`,`add feature`,`new feature`,`build`,`create`,`add`,`develop`,`write code`],tools:[{tool:`scope_map`,reason:`Generate a reading plan for affected files`,order:1},{tool:`search`,reason:`Find related patterns and prior art`,order:2},{tool:`find`,reason:`Find usage examples of similar patterns`,order:3,suggestedArgs:{mode:`examples`}},{tool:`check`,reason:`Validate after implementation`,order:4},{tool:`test_run`,reason:`Run tests to verify`,order:5},{tool:`blast_radius`,reason:`Check impact of changes`,order:6}]},{name:`refactor`,description:`Restructure or clean up existing code`,keywords:[`refactor`,`restructure`,`clean up`,`reorganize`,`rename`,`move`,`extract`,`DRY`,`dead code`],tools:[{tool:`dead_symbols`,reason:`Find unused exports to remove`,order:1},{tool:`symbol`,reason:`Find all references before renaming`,order:2},{tool:`blast_radius`,reason:`Assess impact before making changes`,order:3},{tool:`rename`,reason:`Safe cross-file rename`,order:4},{tool:`check`,reason:`Validate after refactoring`,order:5},{tool:`test_run`,reason:`Ensure no regressions`,order:6}]},{name:`search`,description:`Find specific code, patterns, or information`,keywords:[`find`,`search`,`where`,`locate`,`look for`,`grep`,`which file`,`how does`],tools:[{tool:`search`,reason:`Hybrid semantic + keyword search`,order:1},{tool:`find`,reason:`Federated search with glob and regex`,order:2},{tool:`symbol`,reason:`Resolve a specific symbol definition and references`,order:3},{tool:`graph`,reason:`Explore entity relationships`,order:4,suggestedArgs:{action:`neighbors`}}]},{name:`context`,description:`Compress or manage context for efficient LLM interaction`,keywords:[`context`,`compress`,`summarize`,`too long`,`token`,`budget`,`reduce`,`compact`],tools:[{tool:`file_summary`,reason:`Quick structural overview without reading full file`,order:1},{tool:`compact`,reason:`Compress file to relevant sections`,order:2,suggestedArgs:{segmentation:`paragraph`}},{tool:`digest`,reason:`Compress multiple sources into budgeted summary`,order:3},{tool:`stratum_card`,reason:`Generate reusable context cards`,order:4}]},{name:`memory`,description:`Manage persistent knowledge across sessions`,keywords:[`memory`,`remember`,`persist`,`save`,`recall`,`decision`,`convention`,`session`,`checkpoint`],tools:[{tool:`list`,reason:`See all stored knowledge entries`,order:1},{tool:`search`,reason:`Search curated knowledge`,order:2,suggestedArgs:{origin:`curated`}},{tool:`remember`,reason:`Store a new decision or pattern`,order:3},{tool:`checkpoint`,reason:`Save/restore session progress`,order:4},{tool:`stash`,reason:`Temporary key-value storage within session`,order:5}]},{name:`validate`,description:`Run checks, tests, and validation`,keywords:[`validate`,`check`,`test`,`lint`,`typecheck`,`verify`,`CI`,`pass`,`run tests`],tools:[{tool:`check`,reason:`Typecheck + lint in one call`,order:1,suggestedArgs:{detail:`errors`}},{tool:`test_run`,reason:`Run tests with structured output`,order:2},{tool:`health`,reason:`Project health assessment`,order:3}]},{name:`analyze`,description:`Deep analysis of codebase structure, dependencies, or patterns`,keywords:[`analyze`,`dependency`,`structure`,`pattern`,`architecture`,`diagram`,`entry point`,`import`],tools:[{tool:`analyze_structure`,reason:`Project structure overview`,order:1},{tool:`analyze_dependencies`,reason:`Dependency graph and analysis`,order:2},{tool:`analyze_patterns`,reason:`Detect code patterns and conventions`,order:3},{tool:`analyze_entry_points`,reason:`Find handlers, exports, and entry points`,order:4},{tool:`analyze_diagram`,reason:`Generate Mermaid diagrams`,order:5}]},{name:`upgrade`,description:`Update AI Kit agents, prompts, skills, and scaffold to the latest version (user-level and workspace-level)`,keywords:[`upgrade`,`update`,`version`,`scaffold`,`outdated`,`mismatch`,`deploy`,`install`,`refresh`],tools:[{tool:`status`,reason:`Check current versions and detect mismatches — auto-triggers upgrade when a version mismatch is found`,order:1},{tool:`reindex`,reason:`Refresh the index after the upgrade completes`,order:2},{tool:`produce_knowledge`,reason:`Regenerate codebase analysis with updated tooling`,order:3,suggestedArgs:{path:`.`}}]}];function t(t,n=5){let r=t.toLowerCase(),i=e.map(e=>{let t=0;for(let n of e.keywords)r.includes(n)&&(t+=n.includes(` `)?2:1);return{workflow:e,score:t}}).filter(e=>e.score>0).sort((e,t)=>t.score-e.score),a=e.find(e=>e.name===`search`)??e[0],o=i[0]?.workflow??a,s=i.slice(1,4).map(e=>e.workflow.name).filter(e=>e!==o.name);return{workflow:o.name,description:o.description,tools:o.tools.slice(0,n),alternativeWorkflows:s}}export{t as guide};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{join as e,relative as t,resolve as n}from"node:path";import{cpSync as r,existsSync as i,mkdirSync as a,readFileSync as o,readdirSync as s,rmSync as c,statSync as l,writeFileSync as u}from"node:fs";import{
|
|
1
|
+
import{join as e,relative as t,resolve as n}from"node:path";import{cpSync as r,existsSync as i,mkdirSync as a,readFileSync as o,readdirSync as s,rmSync as c,statSync as l,writeFileSync as u}from"node:fs";import{resolveStateDir as d}from"../../core/dist/index.js";function f(e){return n(d(e??process.cwd()),`lanes`)}const p=`.lane-meta.json`;function m(e){return f(e)}function h(e,t){let r=m(t),i=n(r,e);if(!i.startsWith(n(r)))throw Error(`Invalid lane name: "${e}"`);return i}function g(t,n){let r=e(h(t,n),p);if(!i(r))throw Error(`Lane "${t}" does not exist`);try{return JSON.parse(o(r,`utf-8`))}catch{throw Error(`Lane "${t}" has corrupted metadata`)}}function _(o,s,c){let l=c??process.cwd(),d=h(o,c);if(i(d))throw Error(`Lane "${o}" already exists`);a(d,{recursive:!0});let f=[];for(let o of s){let s=n(l,o);if(!i(s))throw Error(`Source file does not exist: ${o}`);let c=t(l,s).replace(/\\/g,`/`),u=e(d,c);a(e(u,`..`),{recursive:!0}),r(s,u),f.push(c)}let m={name:o,createdAt:new Date().toISOString(),sourceFiles:f,rootPath:l};return u(e(d,p),`${JSON.stringify(m,null,2)}\n`,`utf-8`),m}function v(t){let n=m(t);if(!i(n))return[];let r=s(n),a=[];for(let t of r){let r=e(n,t,p);if(i(r))try{a.push(JSON.parse(o(r,`utf-8`)))}catch{}}return a}function y(t,r){let a=g(t,r),s=h(t,r),c=a.rootPath,l=[];for(let t of a.sourceFiles){let r=n(c,t),a=e(s,t);if(!i(a)){l.push({file:t,status:`deleted`});continue}if(!i(r)){l.push({file:t,status:`added`});continue}o(r,`utf-8`)===o(a,`utf-8`)?l.push({file:t,status:`unchanged`}):l.push({file:t,status:`modified`})}let u=C(s);for(let e of u)a.sourceFiles.includes(e)||l.push({file:e,status:`added`});return{name:t,entries:l,modified:l.filter(e=>e.status===`modified`).length,added:l.filter(e=>e.status===`added`).length,deleted:l.filter(e=>e.status===`deleted`).length}}function b(t,r){let a=g(t,r),s=h(t,r),c=a.rootPath,l=[],u=new Set(a.sourceFiles);for(let e of C(s))u.add(e);for(let t of u){let r=n(c,t),a=e(s,t),u=i(r),d=i(a);if(!d&&u){l.push({file:t,status:`deleted`});continue}if(d&&!u){let e=o(a,`utf-8`);l.push({file:t,status:`added`,diff:e.split(`
|
|
2
2
|
`).map(e=>`+${e}`).join(`
|
|
3
3
|
`)});continue}if(!d||!u)continue;let f=o(r,`utf-8`),p=o(a,`utf-8`);f===p?l.push({file:t,status:`unchanged`}):l.push({file:t,status:`modified`,diff:w(f,p)})}return{name:t,entries:l,modified:l.filter(e=>e.status===`modified`).length,added:l.filter(e=>e.status===`added`).length,deleted:l.filter(e=>e.status===`deleted`).length}}function x(t,o){let s=g(t,o),l=h(t,o),u=s.rootPath,d=[],f=new Set(s.sourceFiles);for(let e of C(l))f.add(e);for(let t of f){let o=e(l,t);if(!i(o))continue;let s=n(u,t);a(e(s,`..`),{recursive:!0}),r(o,s),d.push(t)}return c(l,{recursive:!0,force:!0}),{name:t,filesMerged:d.length,files:d}}function S(e,t){let n=h(e,t);return i(n)?(c(n,{recursive:!0,force:!0}),!0):!1}function C(n){let r=[];function a(i){for(let o of s(i)){if(o===p)continue;let s=e(i,o);l(s).isDirectory()?a(s):r.push(t(n,s).replace(/\\/g,`/`))}}return i(n)&&a(n),r.sort()}function w(e,t){let n=e.split(`
|
|
4
4
|
`),r=t.split(`
|
|
@@ -11,7 +11,7 @@ type OnboardMode = 'memory' | 'generate';
|
|
|
11
11
|
interface OnboardOptions {
|
|
12
12
|
/** Root path to analyze */
|
|
13
13
|
path: string;
|
|
14
|
-
/** Output mode: 'memory' (
|
|
14
|
+
/** Output mode: 'memory' (AI Kit only) or 'generate' (write to .ai/kb/) */
|
|
15
15
|
mode?: OnboardMode;
|
|
16
16
|
/** Output directory for generate mode (default: '<path>/.ai/kb') */
|
|
17
17
|
outDir?: string;
|
|
@@ -34,7 +34,7 @@ interface OnboardResult {
|
|
|
34
34
|
outDir?: string;
|
|
35
35
|
/** Total duration in ms */
|
|
36
36
|
totalDurationMs: number;
|
|
37
|
-
/** Auto-generated
|
|
37
|
+
/** Auto-generated AI Kit entries for curated store persistence */
|
|
38
38
|
autoRemember?: Array<{
|
|
39
39
|
title: string;
|
|
40
40
|
content: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{extractConfigValues as e}from"./config-extractor.js";import{buildDiagrams as t}from"./diagram-builder.js";import{buildCodeMap as n,buildSynthesisGuide as r}from"./synthesis-engine.js";import{DependencyAnalyzer as i,DiagramGenerator as a,EntryPointAnalyzer as o,PatternAnalyzer as ee,StructureAnalyzer as s,SymbolAnalyzer as c,extractRegexCallGraph as l,extractTsCallGraph as u}from"../../analyzers/dist/index.js";import{
|
|
1
|
+
import{extractConfigValues as e}from"./config-extractor.js";import{buildDiagrams as t}from"./diagram-builder.js";import{buildCodeMap as n,buildSynthesisGuide as r}from"./synthesis-engine.js";import{DependencyAnalyzer as i,DiagramGenerator as a,EntryPointAnalyzer as o,PatternAnalyzer as ee,StructureAnalyzer as s,SymbolAnalyzer as c,extractRegexCallGraph as l,extractTsCallGraph as u}from"../../analyzers/dist/index.js";import{mkdir as d,readdir as f,rm as p,writeFile as m}from"node:fs/promises";import{basename as h,join as g,resolve as _}from"node:path";import{existsSync as v}from"node:fs";import{AIKIT_PATHS as y}from"../../core/dist/index.js";const b={structure:`Project Structure`,dependencies:`Dependencies`,"entry-points":`Entry Points`,symbols:`Symbols`,patterns:`Patterns`,diagram:`C4 Container Diagram`,"code-map":`Code Map (Module Graph)`,"config-values":`Configuration Values`,"synthesis-guide":`Synthesis Guide`,"api-surface":`API Surface`,"type-inventory":`Type Inventory`};function x(e){let t=e.get(`symbols`);if(!t?.symbols?.length)return`# API Surface
|
|
2
2
|
|
|
3
3
|
*No symbol data available.*
|
|
4
4
|
`;let n=t.symbols.filter(e=>e.exported);if(n.length===0)return`# API Surface
|
|
@@ -14,5 +14,5 @@ import{extractConfigValues as e}from"./config-extractor.js";import{buildDiagrams
|
|
|
14
14
|
*No exported types/interfaces found.*
|
|
15
15
|
`;let r=new Map;for(let e of n){let t=r.get(e.filePath)??[];t.push(e),r.set(e.filePath,t)}let i=[`# Type Inventory
|
|
16
16
|
`];for(let[e,t]of[...r.entries()].sort(([e],[t])=>e.localeCompare(t))){i.push(`## ${e}\n`);for(let e of t){let t=e.typeBody??`*body not available*`;e.jsdoc&&i.push(`> ${e.jsdoc}`),i.push(`### ${e.kind} \`${e.name}\``),i.push("```"),i.push(t),i.push("```\n")}}let a=i.join(`
|
|
17
|
-
`);return a.length>1e5?`${a.slice(0,1e5)}\n\n*[truncated]*`:a}async function C(C){let w=Date.now(),T=
|
|
17
|
+
`);return a.length>1e5?`${a.slice(0,1e5)}\n\n*[truncated]*`:a}async function C(C){let w=Date.now(),T=_(C.path),E=h(T),D=C.mode??`generate`,O=C.outDir??g(T,y.aiKb),k=new s,A=new i,j=new c,M=new ee,N=new o,P=new a,F=[{name:`structure`,fn:()=>k.analyze(T,{format:`markdown`,maxDepth:3,sourceOnly:!0})},{name:`dependencies`,fn:()=>A.analyze(T,{format:`markdown`})},{name:`entry-points`,fn:()=>N.analyze(T)},{name:`symbols`,fn:()=>j.analyze(T,{format:`markdown`})},{name:`patterns`,fn:()=>M.analyze(T)},{name:`diagram`,fn:()=>P.analyze(T,{diagramType:`architecture`})}],I=await Promise.allSettled(F.map(async e=>{let t=Date.now(),n=await e.fn();return{name:e.name,result:n,durationMs:Date.now()-t}})),L=[],R=new Map,z=new Map;for(let e of I)if(e.status===`fulfilled`){let{name:t,result:n,durationMs:r}=e.value,i=n;L.push({name:t,status:`success`,output:i.output,durationMs:r}),R.set(t,i.output),z.set(t,i.data)}else{let t=e.reason,n=F[I.indexOf(e)].name;L.push({name:n,status:`failed`,output:``,durationMs:0,error:t.message})}let B=Date.now(),V=null;try{let e=await u(T);if((!e||e.edges.length===0)&&(e=await l(T)),e&&e.edges.length>0){V=new Map;for(let t of e.edges){let e=V.get(t.from);e||(e=new Map,V.set(t.from,e));let n=e.get(t.to);if(n)for(let e of t.symbols)n.includes(e)||n.push(e);else e.set(t.to,[...t.symbols])}}}catch{}let H=Date.now()-B,U=Date.now(),W=n(z,E,V),G=Date.now()-U+H;if(L.push({name:`code-map`,status:`success`,output:W,durationMs:G}),R.set(`code-map`,W),V&&V.size>0){let e=t(V,z,E),n=L.find(e=>e.name===`diagram`);n&&(n.output=e,R.set(`diagram`,e))}let K=Date.now(),q=await e(T,E),J=Date.now()-K;L.push({name:`config-values`,status:`success`,output:q,durationMs:J}),R.set(`config-values`,q);let Y=r(L,D,E,z);L.push({name:`synthesis-guide`,status:`success`,output:Y,durationMs:0}),R.set(`synthesis-guide`,Y);let X=x(z);L.push({name:`api-surface`,status:`success`,output:X,durationMs:0}),R.set(`api-surface`,X);let Z=S(z);if(L.push({name:`type-inventory`,status:`success`,output:Z,durationMs:0}),R.set(`type-inventory`,Z),D===`generate`){if(v(O))for(let e of await f(O))(e.endsWith(`.md`)||e.endsWith(`.json`))&&await p(g(O,e),{force:!0});await d(O,{recursive:!0});let e=new Date().toISOString();for(let[t,n]of R){let r=g(O,`${t}.md`),i=n.replaceAll(T,E);await m(r,`<!-- Generated: ${e} -->\n<!-- Project: ${E} -->\n<!-- Source: ${T} -->\n\n`+i,`utf-8`)}let t=[`<!-- Generated: ${e} -->`,`<!-- Project: ${E} -->`,`<!-- Source: ${T} -->`,``,`# ${E} — Codebase Knowledge`,``,`## Contents`,``];for(let e of L){let n=`${e.name}.md`,r=b[e.name]??e.name,i=e.status===`success`?`✓`:`✗`,a=e.durationMs>0?` (${e.durationMs}ms)`:``;t.push(`- ${i} [${r}](./${n})${a}`)}t.push(``),await m(g(O,`README.md`),t.join(`
|
|
18
18
|
`),`utf-8`)}let Q=[];Q.push({title:`Onboard: ${E} project overview`,content:Y.slice(0,2e3),category:`conventions`,tags:[`onboard`,`project-overview`,E]});let $=L.find(e=>e.name===`patterns`);return $?.status===`success`&&$.output&&Q.push({title:`Onboard: ${E} detected patterns`,content:$.output.slice(0,1500),category:`patterns`,tags:[`onboard`,`patterns`,E]}),q&&Q.push({title:`Onboard: ${E} config and commands`,content:q.slice(0,1500),category:`conventions`,tags:[`onboard`,`config`,`commands`,E]}),{path:T,mode:D,steps:L,outDir:D===`generate`?O:void 0,totalDurationMs:Date.now()-w,autoRemember:Q}}export{C as onboard};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dirname as e,resolve as t}from"node:path";import{existsSync as n,mkdirSync as r,readFileSync as i,writeFileSync as
|
|
1
|
+
import{dirname as e,resolve as t}from"node:path";import{existsSync as n,mkdirSync as r,readFileSync as i,renameSync as a,writeFileSync as o}from"node:fs";import{resolveStateDir as s}from"../../core/dist/index.js";function c(e){return t(s(e??process.cwd()),`queue.json`)}function l(e){let t=c(e);if(!n(t))return{};try{return JSON.parse(i(t,`utf-8`))}catch(e){return e?.code===`ENOENT`||console.warn(`Corrupt state file ${t}: ${e instanceof Error?e.message:String(e)}`),{}}}function u(t,i){let s=c(i),l=e(s);n(l)||r(l,{recursive:!0});let u=`${s}.tmp`;o(u,`${JSON.stringify(t,null,2)}\n`,`utf-8`),a(u,s)}function d(){return`q_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,6)}`}function f(e,t){let n=l(t);if(n[e])throw Error(`Queue "${e}" already exists`);let r={name:e,items:[]};return n[e]=r,u(n,t),r}function p(e,t,n,r){let i=l(r);i[e]||(i[e]={name:e,items:[]});let a=new Date().toISOString(),o={id:d(),title:t,status:`pending`,data:n,createdAt:a,updatedAt:a};if(i[e].items.length>=500)throw Error(`Queue "${e}" has reached the maximum of 500 items. Clear completed items with queue({ action: "clear" }) before adding more.`);return i[e].items.push(o),u(i,r),o}function m(e,t){let n=l(t),r=n[e];if(!r)throw Error(`Queue "${e}" does not exist`);let i=r.items.find(e=>e.status===`pending`);return i?(i.status=`in-progress`,i.updatedAt=new Date().toISOString(),u(n,t),i):null}function h(e,t,n){let r=l(n),i=r[e];if(!i)throw Error(`Queue "${e}" does not exist`);let a=i.items.find(e=>e.id===t);if(!a)throw Error(`Item "${t}" not found in queue "${e}"`);return a.status=`done`,a.updatedAt=new Date().toISOString(),u(r,n),a}function g(e,t,n,r){let i=l(r),a=i[e];if(!a)throw Error(`Queue "${e}" does not exist`);let o=a.items.find(e=>e.id===t);if(!o)throw Error(`Item "${t}" not found in queue "${e}"`);return o.status=`failed`,o.error=n,o.updatedAt=new Date().toISOString(),u(i,r),o}function _(e,t){return l(t)[e]??null}function v(e){let t=l(e);return Object.values(t).map(e=>({name:e.name,pending:e.items.filter(e=>e.status===`pending`).length,done:e.items.filter(e=>e.status===`done`).length,failed:e.items.filter(e=>e.status===`failed`).length,total:e.items.length}))}function y(e,t){let n=l(t),r=n[e];if(!r)throw Error(`Queue "${e}" does not exist`);let i=r.items.length;r.items=r.items.filter(e=>e.status===`pending`||e.status===`in-progress`);let a=i-r.items.length;return u(n,t),a}function b(e,t){let n=l(t);return n[e]?(delete n[e],u(n,t),!0):!1}export{y as queueClear,f as queueCreate,b as queueDelete,h as queueDone,g as queueFail,_ as queueGet,v as queueList,m as queueNext,p as queuePush};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{readFile as e,writeFile as t}from"node:fs/promises";import{dirname as n,resolve as r}from"node:path";import{appendFileSync as i,mkdirSync as a,readFileSync as o,writeFileSync as s}from"node:fs";import{
|
|
1
|
+
import{readFile as e,writeFile as t}from"node:fs/promises";import{dirname as n,resolve as r}from"node:path";import{appendFileSync as i,mkdirSync as a,readFileSync as o,writeFileSync as s}from"node:fs";import{resolveStateDir as c}from"../../core/dist/index.js";const l=5e3;let u=0;function d(){return r(c(process.cwd()),`replay.jsonl`)}function f(e,t){return e.length<=t?e:`${e.slice(0,t-1)}…`}function p(e){let t=d();a(n(t),{recursive:!0});let r={...e,input:f(e.input,200),output:f(e.output,200)};i(t,`${JSON.stringify(r)}\n`,`utf-8`),u++,u>=100&&(u=0,h().catch(()=>{}))}function m(e={}){let t=d(),n;try{n=o(t,`utf-8`)}catch{return[]}let r=n.trim().split(`
|
|
2
2
|
`).filter(Boolean),i=[];for(let e of r)try{i.push(JSON.parse(e))}catch{}if(e.tool&&(i=i.filter(t=>t.tool===e.tool)),e.source&&(i=i.filter(t=>t.source===e.source)),e.since){let t=e.since;i=i.filter(e=>e.ts>=t)}let a=e.last??20;return i.slice(-a)}async function h(){let n=d(),r;try{r=await e(n,`utf-8`)}catch{return 0}let i=r.trim().split(`
|
|
3
3
|
`).filter(Boolean);if(i.length<=l)return 0;let a=i.length-l;return await t(n,`${i.slice(-l).join(`
|
|
4
4
|
`)}\n`,`utf-8`),a}function g(){let e=d();try{s(e,``,`utf-8`)}catch{}}function _(e,t,n,r){let i=Date.now();return r().then(r=>(p({ts:new Date().toISOString(),source:e,tool:t,input:typeof n==`string`?n:JSON.stringify(n),durationMs:Date.now()-i,status:`ok`,output:typeof r==`string`?r:JSON.stringify(r??``)}),r)).catch(r=>{throw p({ts:new Date().toISOString(),source:e,tool:t,input:typeof n==`string`?n:JSON.stringify(n),durationMs:Date.now()-i,status:`error`,output:r instanceof Error?r.message:String(r)}),r})}export{p as replayAppend,_ as replayCapture,g as replayClear,m as replayList,h as replayTrim};
|