@vpxa/aikit 0.1.24 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vpxa/aikit",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "type": "module",
5
5
  "description": "Local-first AI developer toolkit — knowledge base, code analysis, context management, and developer tools for LLM agents",
6
6
  "license": "MIT",
@@ -46,9 +46,14 @@ interface KBContext {
46
46
  indexer: IncrementalIndexer;
47
47
  curated: ICuratedManager;
48
48
  }
49
+ /**
50
+ * Load config from aikit.config.json in cwd or AIKIT_CONFIG_PATH env.
51
+ * Falls back to sensible defaults when no config file exists (user-level install).
52
+ */
53
+ declare function loadConfig(): KBConfig;
49
54
  /**
50
55
  * Initialize all AI Kit components for CLI use.
51
56
  */
52
57
  declare function initKB(): Promise<KBContext>;
53
58
  //#endregion
54
- export { KBContext, initKB };
59
+ export { KBContext, initKB, loadConfig };
@@ -1 +1 @@
1
- import{existsSync as e,readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{initializeWasm as i}from"../../chunker/dist/index.js";import{AIKIT_PATHS as a,getPartitionDir as o,isUserInstalled as s,registerWorkspace as c}from"../../core/dist/index.js";import{OnnxEmbedder as l}from"../../embeddings/dist/index.js";import{IncrementalIndexer as u}from"../../indexer/dist/index.js";import{SqliteGraphStore as d,createStore as f}from"../../store/dist/index.js";function p(){let i=process.env.AIKIT_CONFIG_PATH??(e(r(process.cwd(),`aikit.config.json`))?r(process.cwd(),`aikit.config.json`):null);if(!i)return m();let a=t(i,`utf-8`),o;try{o=JSON.parse(a)}catch{console.error(`Failed to parse ${i} as JSON. Ensure the file contains valid JSON.`),process.exit(1)}let s=n(i);return o.sources=o.sources.map(e=>({...e,path:r(s,e.path)})),o.store.path=r(s,o.store.path),o.curated=o.curated??{path:`curated`},o.curated.path=r(s,o.curated.path),h(o,s),o}function m(){let e=process.env.AIKIT_WORKSPACE_ROOT??process.cwd(),t={sources:[{path:e,excludePatterns:[`node_modules/**`,`dist/**`,`.git/**`,`coverage/**`,`*.lock`,`pnpm-lock.yaml`]}],serverName:`aikit`,indexing:{chunkSize:1500,chunkOverlap:200,minChunkSize:100},embedding:{model:`mixedbread-ai/mxbai-embed-large-v1`,dimensions:1024},store:{backend:`lancedb`,path:r(e,a.data)},curated:{path:r(e,a.aiCurated)},stateDir:r(e,a.state)};return h(t,e),t}function h(e,t){if(!s())return;let n=c(t);e.store.path=r(o(n.partition)),e.stateDir=r(o(n.partition),`state`),e.curated||={path:r(t,a.aiCurated)}}async function g(){let e=p(),t=new l({model:e.embedding.model,dimensions:e.embedding.dimensions});await t.initialize();let n=await f({backend:e.store.backend,path:e.store.path});await n.initialize();let r=new u(t,n),{CuratedKnowledgeManager:a}=await import(`../../server/dist/curated-manager.js`),o=new a(e.curated.path,n,t),s;try{let t=new d({path:e.store.path});await t.initialize(),s=t,r.setGraphStore(s)}catch(e){console.error(`[aikit] Graph store init failed (non-fatal): ${e.message}`),s={initialize:async()=>{},upsertNode:async()=>{},upsertEdge:async()=>{},upsertNodes:async()=>{},upsertEdges:async()=>{},getNode:async()=>null,getNeighbors:async()=>({nodes:[],edges:[]}),traverse:async()=>({nodes:[],edges:[]}),findNodes:async()=>[],findEdges:async()=>[],deleteNode:async()=>{},deleteBySourcePath:async()=>0,clear:async()=>{},getStats:async()=>({nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}}),validate:async()=>({valid:!0,orphanNodes:[],danglingEdges:[],stats:{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}}}),setNodeCommunity:async()=>{},detectCommunities:async()=>({}),traceProcess:async()=>({id:``,entryNodeId:``,label:``,properties:{},steps:[]}),getProcesses:async()=>[],deleteProcess:async()=>{},depthGroupedTraversal:async()=>({}),getCohesionScore:async()=>0,getSymbol360:async()=>({node:{id:``,type:``,name:``,properties:{}},incoming:[],outgoing:[],community:null,processes:[]}),close:async()=>{}}}return await i().catch(()=>{}),{config:e,embedder:t,store:n,graphStore:s,indexer:r,curated:o}}export{g as initKB};
1
+ import{existsSync as e,readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{initializeWasm as i}from"../../chunker/dist/index.js";import{AIKIT_PATHS as a,getPartitionDir as o,isUserInstalled as s,registerWorkspace as c}from"../../core/dist/index.js";import{OnnxEmbedder as l}from"../../embeddings/dist/index.js";import{IncrementalIndexer as u}from"../../indexer/dist/index.js";import{SqliteGraphStore as d,createStore as f}from"../../store/dist/index.js";function p(){let i=process.env.AIKIT_CONFIG_PATH??(e(r(process.cwd(),`aikit.config.json`))?r(process.cwd(),`aikit.config.json`):null);if(!i)return m();let a=t(i,`utf-8`),o;try{o=JSON.parse(a)}catch{console.error(`Failed to parse ${i} as JSON. Ensure the file contains valid JSON.`),process.exit(1)}let s=n(i);return o.sources=o.sources.map(e=>({...e,path:r(s,e.path)})),o.store.path=r(s,o.store.path),o.curated=o.curated??{path:`curated`},o.curated.path=r(s,o.curated.path),h(o,s),o}function m(){let e=process.env.AIKIT_WORKSPACE_ROOT??process.cwd(),t={sources:[{path:e,excludePatterns:[`node_modules/**`,`dist/**`,`.git/**`,`coverage/**`,`*.lock`,`pnpm-lock.yaml`]}],serverName:`aikit`,indexing:{chunkSize:1500,chunkOverlap:200,minChunkSize:100},embedding:{model:`mixedbread-ai/mxbai-embed-large-v1`,dimensions:1024},store:{backend:`lancedb`,path:r(e,a.data)},curated:{path:r(e,a.aiCurated)},stateDir:r(e,a.state)};return h(t,e),t}function h(e,t){if(!s())return;let n=c(t);e.store.path=r(o(n.partition)),e.stateDir=r(o(n.partition),`state`),e.curated||={path:r(t,a.aiCurated)}}async function g(){let e=p(),t=new l({model:e.embedding.model,dimensions:e.embedding.dimensions});await t.initialize();let n=await f({backend:e.store.backend,path:e.store.path});await n.initialize();let r=new u(t,n),{CuratedKnowledgeManager:a}=await import(`../../server/dist/curated-manager.js`),o=new a(e.curated.path,n,t),s;try{let t=new d({path:e.store.path});await t.initialize(),s=t,r.setGraphStore(s)}catch(e){console.error(`[aikit] Graph store init failed (non-fatal): ${e.message}`),s={initialize:async()=>{},upsertNode:async()=>{},upsertEdge:async()=>{},upsertNodes:async()=>{},upsertEdges:async()=>{},getNode:async()=>null,getNeighbors:async()=>({nodes:[],edges:[]}),traverse:async()=>({nodes:[],edges:[]}),findNodes:async()=>[],findEdges:async()=>[],deleteNode:async()=>{},deleteBySourcePath:async()=>0,clear:async()=>{},getStats:async()=>({nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}}),validate:async()=>({valid:!0,orphanNodes:[],danglingEdges:[],stats:{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}}}),setNodeCommunity:async()=>{},detectCommunities:async()=>({}),traceProcess:async()=>({id:``,entryNodeId:``,label:``,properties:{},steps:[]}),getProcesses:async()=>[],deleteProcess:async()=>{},depthGroupedTraversal:async()=>({}),getCohesionScore:async()=>0,getSymbol360:async()=>({node:{id:``,type:``,name:``,properties:{}},incoming:[],outgoing:[],community:null,processes:[]}),close:async()=>{}}}return await i().catch(()=>{}),{config:e,embedder:t,store:n,graphStore:s,indexer:r,curated:o}}export{g as initKB,p as loadConfig};
@@ -1 +1 @@
1
- import{existsSync as e,mkdirSync as t}from"node:fs";import{basename as n,join as r,resolve as i}from"node:path";const a=r(`.aikit-state`,`flows`),o=r(a,`registry.json`),s=r(a,`state.json`);async function c(){let n=await import(`../../../flows/dist/index.js`),{FlowLoader:i,FlowRegistryManager:c,FlowStateMachine:l,GitInstaller:u,FoundationIntegration:d,SymlinkManager:f}=n,p=typeof n.getBuiltinFlows==`function`?n.getBuiltinFlows:void 0,m=process.cwd(),h=r(m,a),g=r(m,o),_=r(m,s);return e(h)||t(h,{recursive:!0}),{loader:new i,registry:new c(g),stateMachine:new l(_),git:new u(r(h,`installed`)),foundation:new d,symlinks:new f,getBuiltinFlows:p,cwd:m}}const l=[{name:`flow`,description:`Manage pluggable development flows`,usage:`flow <add|remove|list|info|use|update|status|start|reset> [args]`,run:async t=>{let a=t[0];if(!a){console.log(`Usage: aikit flow <add|remove|list|info|use|update|status|start|reset>`),console.log(``),console.log(`Commands:`),console.log(` add <source> Install a flow from git URL or local path`),console.log(` remove <name> Remove an installed flow`),console.log(` list List all installed flows`),console.log(` info <name> Show details of a flow`),console.log(` use <name> Set active flow (start it)`),console.log(` update <name> Update a flow from its source`),console.log(` status Show current flow execution status`),console.log(` start [name] Start a flow (or resume)`),console.log(` reset Reset the active flow`);return}let o=await c();switch(a){case`add`:{let a=t[1];if(!a){console.error(`Usage: aikit flow add <source>`),console.error(` source: git URL (https://...) or local path`);return}let s=a.startsWith(`http`)||a.startsWith(`git@`)||a.endsWith(`.git`),c=i(a),l=e(c);if(!s&&!l){console.error(`Source not found: ${a}`),console.error(`Provide a git URL or existing local path.`);return}let u,d;if(s){console.log(`Cloning ${a}...`);let e=o.git.clone(a);if(!e.success||!e.data){console.error(e.error??`Failed to clone flow`);return}u=e.data,d=`git`}else{let e=t[2]||n(c);console.log(`Copying local flow from ${a}...`);let r=o.git.copyLocal(c,e);if(!r.success||!r.data){console.error(r.error??`Failed to copy local flow`);return}u=r.data,d=`local`}let f=await o.loader.load(u);if(!f.success||!f.data){console.error(f.error??`Failed to load flow`),o.git.remove(u);return}let{manifest:p,format:m}=f.data;if(p.install.length>0){console.log(`Installing ${p.install.length} dependencies...`);let e=o.git.runInstallDeps(p.install);if(!e.success){console.error(`Dependency install failed: ${e.error}`),o.git.remove(u);return}}let h=new Date().toISOString(),g=o.registry.register({name:p.name,version:p.version,source:a,sourceType:d,installPath:u,format:m,registeredAt:h,updatedAt:h,manifest:p});if(!g.success){console.error(g.error??`Failed to register flow`),o.git.remove(u);return}o.foundation.injectPreamble(r(o.cwd,`AGENTS.md`),p),o.symlinks.createSymlinks(o.cwd,p.name,u,p),console.log(`✓ Flow "${p.name}" v${p.version} installed (${m} format)`),console.log(` Steps: ${p.steps.map(e=>e.id).join(` → `)}`);break}case`remove`:{let e=t[1];if(!e){console.error(`Usage: aikit flow remove <name>`);return}let n=o.registry.get(e);if(!n){console.error(`Flow "${e}" not found`);return}o.symlinks.removeSymlinks(o.cwd,e),o.foundation.removePreamble(r(o.cwd,`AGENTS.md`));let i=o.git.remove(n.installPath);if(!i.success){console.error(i.error??`Failed to remove flow files`);return}let a=o.registry.unregister(e);if(!a.success){console.error(a.error??`Failed to unregister flow`);return}console.log(`✓ Flow "${e}" removed`);break}case`list`:{let e=o.registry.list();if(e.length===0){console.log("No flows installed. Use `aikit flow add <source>` to install one.");return}console.log(`Installed Flows:`),console.log(`─`.repeat(60));for(let t of e){let e=t.manifest.steps.map(e=>e.id).join(` → `);console.log(` ${t.name} v${t.version} (${t.sourceType}, ${t.format})`),console.log(` Steps: ${e}`)}let t=o.stateMachine.getStatus();t.success&&t.data&&(console.log(``),console.log(`Active: ${t.data.flow} (${t.data.status}, step: ${t.data.currentStep??`done`})`));break}case`info`:{let e=t[1];if(!e){console.error(`Usage: aikit flow info <name>`);return}let n=o.registry.get(e);if(!n){console.error(`Flow "${e}" not found`);return}console.log(`Flow: ${n.name}`),console.log(`Version: ${n.version}`),console.log(`Source: ${n.source} (${n.sourceType})`),console.log(`Format: ${n.format}`),console.log(`Path: ${n.installPath}`),console.log(`Registered: ${n.registeredAt}`),console.log(`Updated: ${n.updatedAt}`),console.log(``),console.log(`Steps:`);for(let e of n.manifest.steps){let t=e.requires.length?` (requires: ${e.requires.join(`, `)})`:``;console.log(` ${e.id}: ${e.name}${t}`),console.log(` Skill: ${e.skill}`),console.log(` Produces: ${e.produces.join(`, `)}`)}if(n.manifest.install.length>0){console.log(``),console.log(`Dependencies:`);for(let e of n.manifest.install)console.log(` ${e}`)}break}case`use`:case`start`:{let e=t[1],n=e?o.registry.get(e):null;if(a===`use`&&!e){console.error(`Usage: aikit flow use <name>`);return}if(a===`start`&&!e){let e=o.stateMachine.getStatus();if(e.success&&e.data&&e.data.status===`active`){console.log(`Resuming flow: ${e.data.flow}`),console.log(`Current step: ${e.data.currentStep}`),console.log(`Completed: ${e.data.completedSteps.join(`, `)||`none`}`);return}console.error("No active flow. Use `aikit flow start <name>` to begin one.");return}if(!n){console.error(`Flow "${e}" not found. Use \`aikit flow list\` to see installed flows.`);return}let r=o.stateMachine.start(n.name,n.manifest);if(!r.success||!r.data){console.error(r.error??`Failed to start flow`);return}let i=r.data;console.log(`✓ Flow "${n.name}" started`),console.log(` Current step: ${i.currentStep}`),console.log(` Steps: ${n.manifest.steps.map(e=>e.id).join(` → `)}`);break}case`update`:{let e=t[1];if(!e){console.error(`Usage: aikit flow update <name>`);return}let n=o.registry.get(e);if(!n){console.error(`Flow "${e}" not found`);return}if(n.sourceType!==`git`){console.error(`Flow "${e}" is ${n.sourceType}, not updatable via git`);return}console.log(`Updating ${e}...`);let r=o.git.update(n.installPath);if(!r.success){console.error(r.error??`Failed to update flow`);return}let i=await o.loader.load(n.installPath);if(i.success&&i.data){let e=new Date().toISOString(),t=o.registry.register({...n,version:i.data.manifest.version,format:i.data.format,manifest:i.data.manifest,updatedAt:e});if(!t.success){console.error(t.error??`Failed to refresh flow registry entry`);return}}console.log(`✓ Flow "${e}" updated`);break}case`status`:{let e=o.stateMachine.getStatus();if(!e.success||!e.data){console.log(`No active flow.`);return}let t=e.data;if(console.log(`Flow: ${t.flow}`),console.log(`Status: ${t.status}`),console.log(`Current Step: ${t.currentStep??`(completed)`}`),console.log(`Completed: ${t.completedSteps.join(`, `)||`none`}`),t.skippedSteps.length>0&&console.log(`Skipped: ${t.skippedSteps.join(`, `)}`),console.log(`Started: ${t.startedAt}`),console.log(`Updated: ${t.updatedAt}`),Object.keys(t.artifacts).length>0){console.log(`Artifacts:`);for(let[e,n]of Object.entries(t.artifacts))console.log(` ${e}: ${n}`)}break}case`reset`:{let e=o.stateMachine.reset();if(!e.success){console.error(e.error??`Failed to reset flow state`);return}console.log(`✓ Flow state reset`);break}default:console.error(`Unknown flow command: ${a}`),console.log("Use `aikit flow` for help.")}}}];export{l as flowCommands};
1
+ import{loadConfig as e}from"../aikit-init.js";import{existsSync as t,mkdirSync as n}from"node:fs";import{basename as r,join as i,resolve as a}from"node:path";async function o(){let r=await import(`../../../flows/dist/index.js`),{FlowLoader:a,FlowRegistryManager:o,FlowStateMachine:s,GitInstaller:c,FoundationIntegration:l,SymlinkManager:u}=r,d=typeof r.getBuiltinFlows==`function`?r.getBuiltinFlows:void 0,f=e(),p=i(f.stateDir??i(f.sources[0].path,`.aikit-state`),`flows`),m=i(p,`registry.json`),h=i(p,`state.json`);t(p)||n(p,{recursive:!0});let g=f.sources[0].path;return{loader:new a,registry:new o(m),stateMachine:new s(h),git:new c(i(p,`installed`)),foundation:new l,symlinks:new u,getBuiltinFlows:d,cwd:g}}const s=[{name:`flow`,description:`Manage pluggable development flows`,usage:`flow <add|remove|list|info|use|update|status|start|reset> [args]`,run:async e=>{let n=e[0];if(!n){console.log(`Usage: aikit flow <add|remove|list|info|use|update|status|start|reset>`),console.log(``),console.log(`Commands:`),console.log(` add <source> Install a flow from git URL or local path`),console.log(` remove <name> Remove an installed flow`),console.log(` list List all installed flows`),console.log(` info <name> Show details of a flow`),console.log(` use <name> Set active flow (start it)`),console.log(` update <name> Update a flow from its source`),console.log(` status Show current flow execution status`),console.log(` start [name] Start a flow (or resume)`),console.log(` reset Reset the active flow`);return}let s=await o();switch(n){case`add`:{let n=e[1];if(!n){console.error(`Usage: aikit flow add <source>`),console.error(` source: git URL (https://...) or local path`);return}let o=n.startsWith(`http`)||n.startsWith(`git@`)||n.endsWith(`.git`),c=a(n),l=t(c);if(!o&&!l){console.error(`Source not found: ${n}`),console.error(`Provide a git URL or existing local path.`);return}let u,d;if(o){console.log(`Cloning ${n}...`);let e=s.git.clone(n);if(!e.success||!e.data){console.error(e.error??`Failed to clone flow`);return}u=e.data,d=`git`}else{let t=e[2]||r(c);console.log(`Copying local flow from ${n}...`);let i=s.git.copyLocal(c,t);if(!i.success||!i.data){console.error(i.error??`Failed to copy local flow`);return}u=i.data,d=`local`}let f=await s.loader.load(u);if(!f.success||!f.data){console.error(f.error??`Failed to load flow`),s.git.remove(u);return}let{manifest:p,format:m}=f.data;if(p.install.length>0){console.log(`Installing ${p.install.length} dependencies...`);let e=s.git.runInstallDeps(p.install);if(!e.success){console.error(`Dependency install failed: ${e.error}`),s.git.remove(u);return}}let h=new Date().toISOString(),g=s.registry.register({name:p.name,version:p.version,source:n,sourceType:d,installPath:u,format:m,registeredAt:h,updatedAt:h,manifest:p});if(!g.success){console.error(g.error??`Failed to register flow`),s.git.remove(u);return}s.foundation.injectPreamble(i(s.cwd,`AGENTS.md`),p),s.symlinks.createSymlinks(s.cwd,p.name,u,p),console.log(`✓ Flow "${p.name}" v${p.version} installed (${m} format)`),console.log(` Steps: ${p.steps.map(e=>e.id).join(` → `)}`);break}case`remove`:{let t=e[1];if(!t){console.error(`Usage: aikit flow remove <name>`);return}let n=s.registry.get(t);if(!n){console.error(`Flow "${t}" not found`);return}s.symlinks.removeSymlinks(s.cwd,t),s.foundation.removePreamble(i(s.cwd,`AGENTS.md`));let r=s.git.remove(n.installPath);if(!r.success){console.error(r.error??`Failed to remove flow files`);return}let a=s.registry.unregister(t);if(!a.success){console.error(a.error??`Failed to unregister flow`);return}console.log(`✓ Flow "${t}" removed`);break}case`list`:{let e=s.registry.list();if(e.length===0){console.log("No flows installed. Use `aikit flow add <source>` to install one.");return}console.log(`Installed Flows:`),console.log(`─`.repeat(60));for(let t of e){let e=t.manifest.steps.map(e=>e.id).join(` → `);console.log(` ${t.name} v${t.version} (${t.sourceType}, ${t.format})`),console.log(` Steps: ${e}`)}let t=s.stateMachine.getStatus();t.success&&t.data&&(console.log(``),console.log(`Active: ${t.data.flow} (${t.data.status}, step: ${t.data.currentStep??`done`})`));break}case`info`:{let t=e[1];if(!t){console.error(`Usage: aikit flow info <name>`);return}let n=s.registry.get(t);if(!n){console.error(`Flow "${t}" not found`);return}console.log(`Flow: ${n.name}`),console.log(`Version: ${n.version}`),console.log(`Source: ${n.source} (${n.sourceType})`),console.log(`Format: ${n.format}`),console.log(`Path: ${n.installPath}`),console.log(`Registered: ${n.registeredAt}`),console.log(`Updated: ${n.updatedAt}`),console.log(``),console.log(`Steps:`);for(let e of n.manifest.steps){let t=e.requires.length?` (requires: ${e.requires.join(`, `)})`:``;console.log(` ${e.id}: ${e.name}${t}`),console.log(` Skill: ${e.skill}`),console.log(` Produces: ${e.produces.join(`, `)}`)}if(n.manifest.install.length>0){console.log(``),console.log(`Dependencies:`);for(let e of n.manifest.install)console.log(` ${e}`)}break}case`use`:case`start`:{let t=e[1],r=t?s.registry.get(t):null;if(n===`use`&&!t){console.error(`Usage: aikit flow use <name>`);return}if(n===`start`&&!t){let e=s.stateMachine.getStatus();if(e.success&&e.data&&e.data.status===`active`){console.log(`Resuming flow: ${e.data.flow}`),console.log(`Current step: ${e.data.currentStep}`),console.log(`Completed: ${e.data.completedSteps.join(`, `)||`none`}`);return}console.error("No active flow. Use `aikit flow start <name>` to begin one.");return}if(!r){console.error(`Flow "${t}" not found. Use \`aikit flow list\` to see installed flows.`);return}let i=s.stateMachine.start(r.name,r.manifest);if(!i.success||!i.data){console.error(i.error??`Failed to start flow`);return}let a=i.data;console.log(`✓ Flow "${r.name}" started`),console.log(` Current step: ${a.currentStep}`),console.log(` Steps: ${r.manifest.steps.map(e=>e.id).join(` → `)}`);break}case`update`:{let t=e[1];if(!t){console.error(`Usage: aikit flow update <name>`);return}let n=s.registry.get(t);if(!n){console.error(`Flow "${t}" not found`);return}if(n.sourceType!==`git`){console.error(`Flow "${t}" is ${n.sourceType}, not updatable via git`);return}console.log(`Updating ${t}...`);let r=s.git.update(n.installPath);if(!r.success){console.error(r.error??`Failed to update flow`);return}let i=await s.loader.load(n.installPath);if(i.success&&i.data){let e=new Date().toISOString(),t=s.registry.register({...n,version:i.data.manifest.version,format:i.data.format,manifest:i.data.manifest,updatedAt:e});if(!t.success){console.error(t.error??`Failed to refresh flow registry entry`);return}}console.log(`✓ Flow "${t}" updated`);break}case`status`:{let e=s.stateMachine.getStatus();if(!e.success||!e.data){console.log(`No active flow.`);return}let t=e.data;if(console.log(`Flow: ${t.flow}`),console.log(`Status: ${t.status}`),console.log(`Current Step: ${t.currentStep??`(completed)`}`),console.log(`Completed: ${t.completedSteps.join(`, `)||`none`}`),t.skippedSteps.length>0&&console.log(`Skipped: ${t.skippedSteps.join(`, `)}`),console.log(`Started: ${t.startedAt}`),console.log(`Updated: ${t.updatedAt}`),Object.keys(t.artifacts).length>0){console.log(`Artifacts:`);for(let[e,n]of Object.entries(t.artifacts))console.log(` ${e}: ${n}`)}break}case`reset`:{let e=s.stateMachine.reset();if(!e.success){console.error(e.error??`Failed to reset flow state`);return}console.log(`✓ Flow state reset`);break}default:console.error(`Unknown flow command: ${n}`),console.log("Use `aikit flow` for help.")}}}];export{s as flowCommands};
@@ -71,6 +71,31 @@ This project has specialized agents in \`.github/agents/\`. Use them instead of
71
71
  | Documentation | **Documenter** | Comprehensive project docs |
72
72
 
73
73
  Check \`.github/agents/\` for the full list of available agents.
74
+
75
+ ## Persistent Memory
76
+
77
+ AI Kit provides cross-session persistent memory. **Use it actively** — decisions, patterns, and context that survive between conversations.
78
+
79
+ | Action | Tool | Example |
80
+ |--------|------|---------|
81
+ | Store | \`remember\` | \`remember({ title: "Auth uses JWT RS256", content: "...", category: "decisions" })\` |
82
+ | Search | \`search\` | \`search({ query: "authentication", origin: "curated" })\` |
83
+ | Browse | \`list\` | \`list()\` or \`list({ category: "decisions" })\` |
84
+ | Read | \`read\` | \`read({ id: "<entry-id>" })\` |
85
+ | Update | \`update\` | \`update({ id: "<entry-id>", content: "Updated info" })\` |
86
+ | Remove | \`forget\` | \`forget({ id: "<entry-id>" })\` |
87
+
88
+ **Categories:** \`conventions\`, \`decisions\`, \`patterns\`, \`context\`, \`session\`
89
+
90
+ **Session checkpoint** (do at end of every session):
91
+ \`\`\`
92
+ remember({ title: "Session checkpoint: <topic>", content: "Done: ... / Decisions: ... / Next: ... / Blockers: ...", category: "session" })
93
+ \`\`\`
94
+
95
+ **Session resume** (do at start of every session):
96
+ \`\`\`
97
+ search({ query: "SESSION CHECKPOINT", origin: "curated" })
98
+ \`\`\`
74
99
  `}function t(e,t){return`# ${e} — Agent Instructions
75
100
 
76
101
  ## AI Kit MCP Server (\`${t}\`)
@@ -168,6 +193,31 @@ For long sessions or context approaching capacity, use the \`session-handoff\` s
168
193
 
169
194
  ---
170
195
 
196
+ ## Persistent Memory (Long-Term Knowledge)
197
+
198
+ AI Kit provides cross-session persistent memory via curated knowledge. **Use it actively** to remember decisions, patterns, and context across conversations.
199
+
200
+ ### Writing
201
+ | Tool | Purpose | Example |
202
+ |------|---------|---------|
203
+ | \`remember\` | Store new entry | \`remember({ title: "Auth uses JWT RS256", content: "All API auth uses RS256...", category: "decisions" })\` |
204
+ | \`update\` | Modify existing | \`update({ id: "<id>", content: "Updated info" })\` |
205
+ | \`produce_knowledge\` | Auto-generate from code | \`produce_knowledge({ path: "src/" })\` |
206
+
207
+ ### Reading
208
+ | Tool | Purpose | Example |
209
+ |------|---------|---------|
210
+ | \`list\` | Browse entries | \`list()\` or \`list({ category: "decisions" })\` |
211
+ | \`read\` | Read by ID | \`read({ id: "<id>" })\` |
212
+ | \`search\` | Find by content | \`search({ query: "auth", origin: "curated" })\` |
213
+ | \`forget\` | Remove outdated | \`forget({ id: "<id>" })\` |
214
+
215
+ **Categories:** \`conventions\` · \`decisions\` · \`patterns\` · \`context\` · \`session\`
216
+
217
+ **Best practices:** Remember *why* not *what*. Search before remembering (avoid duplicates). Checkpoint at milestones. Clean up outdated entries.
218
+
219
+ ---
220
+
171
221
  ## Search Modes
172
222
 
173
223
  | Mode | When | Example |
@@ -1,4 +1,4 @@
1
- import{FLOW_DIRS as e,MCP_SERVER_ENTRY as t,SERVER_NAME as n,SKILL_NAMES as r,VSCODE_SETTINGS as i}from"./constants.js";import{buildAgentsMd as a,buildCopilotInstructions as o}from"./templates.js";import{smartCopySubdir as s}from"./scaffold.js";import{existsSync as c,mkdirSync as l,readFileSync as u,rmSync as d,unlinkSync as f,writeFileSync as p}from"node:fs";import{dirname as m,resolve as h}from"node:path";import{fileURLToPath as g}from"node:url";import{getGlobalDataDir as _,saveRegistry as v}from"../../../../core/dist/index.js";import{homedir as y}from"node:os";function b(){let e=y(),t=process.platform,n=[],r=h(e,`.copilot`),i=h(r,`instructions`),a=h(e,`.claude`),o=h(e,`.cursor`),s=h(e,`.windsurf`);if(t===`win32`){let t=process.env.APPDATA??h(e,`AppData`,`Roaming`);n.push({ide:`VS Code`,configDir:h(t,`Code`,`User`),mcpConfigPath:h(t,`Code`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VS Code Insiders`,configDir:h(t,`Code - Insiders`,`User`),mcpConfigPath:h(t,`Code - Insiders`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VSCodium`,configDir:h(t,`VSCodium`,`User`),mcpConfigPath:h(t,`VSCodium`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`Cursor`,configDir:h(t,`Cursor`,`User`),mcpConfigPath:h(t,`Cursor`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Cursor Nightly`,configDir:h(t,`Cursor Nightly`,`User`),mcpConfigPath:h(t,`Cursor Nightly`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Windsurf`,configDir:h(t,`Windsurf`,`User`),mcpConfigPath:h(t,`Windsurf`,`User`,`mcp.json`),globalScaffoldRoot:s,instructionsRoot:null})}else if(t===`darwin`){let t=h(e,`Library`,`Application Support`);n.push({ide:`VS Code`,configDir:h(t,`Code`,`User`),mcpConfigPath:h(t,`Code`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VS Code Insiders`,configDir:h(t,`Code - Insiders`,`User`),mcpConfigPath:h(t,`Code - Insiders`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VSCodium`,configDir:h(t,`VSCodium`,`User`),mcpConfigPath:h(t,`VSCodium`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`Cursor`,configDir:h(t,`Cursor`,`User`),mcpConfigPath:h(t,`Cursor`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Cursor Nightly`,configDir:h(t,`Cursor Nightly`,`User`),mcpConfigPath:h(t,`Cursor Nightly`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Windsurf`,configDir:h(t,`Windsurf`,`User`),mcpConfigPath:h(t,`Windsurf`,`User`,`mcp.json`),globalScaffoldRoot:s,instructionsRoot:null})}else{let t=process.env.XDG_CONFIG_HOME??h(e,`.config`);n.push({ide:`VS Code`,configDir:h(t,`Code`,`User`),mcpConfigPath:h(t,`Code`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VS Code Insiders`,configDir:h(t,`Code - Insiders`,`User`),mcpConfigPath:h(t,`Code - Insiders`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VSCodium`,configDir:h(t,`VSCodium`,`User`),mcpConfigPath:h(t,`VSCodium`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`Cursor`,configDir:h(t,`Cursor`,`User`),mcpConfigPath:h(t,`Cursor`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Cursor Nightly`,configDir:h(t,`Cursor Nightly`,`User`),mcpConfigPath:h(t,`Cursor Nightly`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Windsurf`,configDir:h(t,`Windsurf`,`User`),mcpConfigPath:h(t,`Windsurf`,`User`,`mcp.json`),globalScaffoldRoot:s,instructionsRoot:null})}return n.push({ide:`Claude Code`,configDir:h(e,`.claude`),mcpConfigPath:h(e,`.claude`,`mcp.json`),globalScaffoldRoot:a,instructionsRoot:null}),n.push({ide:`Copilot CLI`,configDir:r,mcpConfigPath:h(r,`mcp-config.json`),globalScaffoldRoot:null,instructionsRoot:null}),n.filter(e=>c(e.configDir))}function x(e,n,r=!1){let{mcpConfigPath:i,configDir:a}=e,o={...t},s={};if(c(i)){try{let e=u(i,`utf-8`);s=JSON.parse(e)}catch{let e=`${i}.bak`;p(e,u(i,`utf-8`),`utf-8`),console.log(` Backed up invalid ${i} to ${e}`),s={}}if((s.servers??s.mcpServers??{})[n]&&!r){console.log(` ${e.ide}: ${n} already configured (use --force to update)`);return}}let d=new Set([`VS Code`,`VS Code Insiders`,`VSCodium`,`Windsurf`]).has(e.ide)?`servers`:`mcpServers`,f=s[d]??{};e.ide===`Copilot CLI`?f[n]={...o,tools:[`*`]}:f[n]=o,s[d]=f,l(a,{recursive:!0}),p(i,`${JSON.stringify(s,null,2)}\n`,`utf-8`),console.log(` ${e.ide}: configured ${n} in ${i}`)}const S=new Set([`VS Code`,`VS Code Insiders`,`VSCodium`]);function C(e,t=!1){if(!S.has(e.ide))return;let n=h(e.configDir,`settings.json`),r={};if(c(n))try{let e=u(n,`utf-8`);r=JSON.parse(e)}catch{console.log(` ${e.ide}: skipped settings.json (invalid JSON)`);return}let a=!1;for(let[e,n]of Object.entries(i))if(typeof n==`object`&&n){let t=typeof r[e]==`object`&&r[e]!==null?r[e]:{},i={...t,...n};JSON.stringify(i)!==JSON.stringify(t)&&(r[e]=i,a=!0)}else (t||!(e in r))&&(r[e]=n,a=!0);a&&(p(n,`${JSON.stringify(r,null,2)}\n`,`utf-8`),console.log(` ${e.ide}: updated settings.json`))}function w(t,n,i,u,f=!1){let m=new Set;for(let e of n)e.globalScaffoldRoot&&m.add(e.globalScaffoldRoot);if(m.size===0){console.log(` No IDEs with global scaffold support detected.`);return}let g=h(t,`scaffold`,`general`);for(let n of m){s(g,n,`agents`,u,f),s(g,n,`prompts`,u,f);let i=0;for(let e of r)c(h(g,`skills`,e))&&(s(g,n,`skills/${e}`,u,f),i++);for(let r of e){let e=h(t,`scaffold`,`flows`,r);if(!c(h(e,`steps`)))continue;let i=h(n,`flows`,r);l(i,{recursive:!0});let a=h(i,`skills`);c(a)&&(d(a,{recursive:!0,force:!0}),console.log(` ${n}: migrated ${r} flow to steps/ layout`)),s(e,i,`steps`,u,f)}console.log(` ${n}: scaffold updated (${i} skills)`)}let _=new Set,v=o(`aikit`,i),y=a(`aikit`,i);for(let e of n){if(!e.globalScaffoldRoot)continue;let t=e.globalScaffoldRoot;if(e.ide===`Claude Code`){let e=h(t,`CLAUDE.md`);p(e,`${v}\n---\n\n${y}`,`utf-8`),_.add(e)}else if(e.ide===`VS Code`||e.ide===`VS Code Insiders`||e.ide===`VSCodium`){let n=e.instructionsRoot??t;l(n,{recursive:!0});let r=h(n,`copilot-instructions.md`);_.has(r)||(p(r,`---\napplyTo: "**"\n---\n\n${v}\n---\n\n${y}`,`utf-8`),_.add(r))}else if(e.ide===`Cursor`||e.ide===`Cursor Nightly`){let e=h(t,`rules`);l(e,{recursive:!0});let n=h(e,`aikit.mdc`);_.has(n)||(p(n,`${v}\n---\n\n${y}`,`utf-8`),_.add(n))}else if(e.ide===`Windsurf`){let e=h(t,`rules`);l(e,{recursive:!0});let n=h(e,`aikit.md`);_.has(n)||(p(n,`${v}\n---\n\n${y}`,`utf-8`),_.add(n))}}_.size>0&&console.log(` Instruction files: ${[..._].join(`, `)}`)}function T(e){let t=[];for(let n of e){if(!n.globalScaffoldRoot)continue;let e=n.globalScaffoldRoot;if(n.ide===`VS Code`||n.ide===`VS Code Insiders`||n.ide===`VSCodium`){let r=n.instructionsRoot??e;t.push(h(r,`kb.instructions.md`)),t.push(h(r,`aikit.instructions.md`))}else n.ide===`Cursor`||n.ide===`Cursor Nightly`?t.push(h(e,`rules`,`kb.mdc`)):n.ide===`Windsurf`&&t.push(h(e,`rules`,`kb.md`))}for(let e of t)c(e)&&(f(e),console.log(` Removed legacy file: ${e}`))}async function E(e){let t=n,r=h(m(g(import.meta.url)),`..`,`..`,`..`,`..`,`..`,`package.json`),i=JSON.parse(u(r,`utf-8`)).version;console.log(`Initializing @vpxa/aikit v${i}...\n`);let a=_();l(a,{recursive:!0}),console.log(` Global data store: ${a}`),v({version:1,workspaces:{}}),console.log(` Created registry.json`);let o=b();if(o.length===0)console.log(`
1
+ import{FLOW_DIRS as e,MCP_SERVER_ENTRY as t,SERVER_NAME as n,SKILL_NAMES as r,VSCODE_SETTINGS as i}from"./constants.js";import{buildAgentsMd as a,buildCopilotInstructions as o}from"./templates.js";import{smartCopySubdir as s}from"./scaffold.js";import{existsSync as c,mkdirSync as l,readFileSync as u,rmSync as d,unlinkSync as f,writeFileSync as p}from"node:fs";import{dirname as m,resolve as h}from"node:path";import{fileURLToPath as g}from"node:url";import{getGlobalDataDir as _,saveRegistry as v}from"../../../../core/dist/index.js";import{homedir as y}from"node:os";function b(){let e=y(),t=process.platform,n=[],r=h(e,`.copilot`),i=h(r,`instructions`),a=h(e,`.claude`),o=h(e,`.cursor`),s=h(e,`.windsurf`);if(t===`win32`){let t=process.env.APPDATA??h(e,`AppData`,`Roaming`);n.push({ide:`VS Code`,configDir:h(t,`Code`,`User`),mcpConfigPath:h(t,`Code`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VS Code Insiders`,configDir:h(t,`Code - Insiders`,`User`),mcpConfigPath:h(t,`Code - Insiders`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VSCodium`,configDir:h(t,`VSCodium`,`User`),mcpConfigPath:h(t,`VSCodium`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`Cursor`,configDir:h(t,`Cursor`,`User`),mcpConfigPath:h(t,`Cursor`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Cursor Nightly`,configDir:h(t,`Cursor Nightly`,`User`),mcpConfigPath:h(t,`Cursor Nightly`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Windsurf`,configDir:h(t,`Windsurf`,`User`),mcpConfigPath:h(t,`Windsurf`,`User`,`mcp.json`),globalScaffoldRoot:s,instructionsRoot:null})}else if(t===`darwin`){let t=h(e,`Library`,`Application Support`);n.push({ide:`VS Code`,configDir:h(t,`Code`,`User`),mcpConfigPath:h(t,`Code`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VS Code Insiders`,configDir:h(t,`Code - Insiders`,`User`),mcpConfigPath:h(t,`Code - Insiders`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VSCodium`,configDir:h(t,`VSCodium`,`User`),mcpConfigPath:h(t,`VSCodium`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`Cursor`,configDir:h(t,`Cursor`,`User`),mcpConfigPath:h(t,`Cursor`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Cursor Nightly`,configDir:h(t,`Cursor Nightly`,`User`),mcpConfigPath:h(t,`Cursor Nightly`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Windsurf`,configDir:h(t,`Windsurf`,`User`),mcpConfigPath:h(t,`Windsurf`,`User`,`mcp.json`),globalScaffoldRoot:s,instructionsRoot:null})}else{let t=process.env.XDG_CONFIG_HOME??h(e,`.config`);n.push({ide:`VS Code`,configDir:h(t,`Code`,`User`),mcpConfigPath:h(t,`Code`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VS Code Insiders`,configDir:h(t,`Code - Insiders`,`User`),mcpConfigPath:h(t,`Code - Insiders`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`VSCodium`,configDir:h(t,`VSCodium`,`User`),mcpConfigPath:h(t,`VSCodium`,`User`,`mcp.json`),globalScaffoldRoot:r,instructionsRoot:i},{ide:`Cursor`,configDir:h(t,`Cursor`,`User`),mcpConfigPath:h(t,`Cursor`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Cursor Nightly`,configDir:h(t,`Cursor Nightly`,`User`),mcpConfigPath:h(t,`Cursor Nightly`,`User`,`mcp.json`),globalScaffoldRoot:o,instructionsRoot:null},{ide:`Windsurf`,configDir:h(t,`Windsurf`,`User`),mcpConfigPath:h(t,`Windsurf`,`User`,`mcp.json`),globalScaffoldRoot:s,instructionsRoot:null})}return n.push({ide:`Claude Code`,configDir:h(e,`.claude`),mcpConfigPath:h(e,`.claude`,`mcp.json`),globalScaffoldRoot:a,instructionsRoot:null}),n.push({ide:`Copilot CLI`,configDir:r,mcpConfigPath:h(r,`mcp-config.json`),globalScaffoldRoot:null,instructionsRoot:null}),n.filter(e=>c(e.configDir))}function x(e,n,r=!1){let{mcpConfigPath:i,configDir:a}=e,o={...t},s={};if(c(i)){try{let e=u(i,`utf-8`);s=JSON.parse(e)}catch{let e=`${i}.bak`;p(e,u(i,`utf-8`),`utf-8`),console.log(` Backed up invalid ${i} to ${e}`),s={}}if((s.servers??s.mcpServers??{})[n]&&!r){console.log(` ${e.ide}: ${n} already configured (use --force to update)`);return}}let d=new Set([`VS Code`,`VS Code Insiders`,`VSCodium`,`Windsurf`]).has(e.ide)?`servers`:`mcpServers`,f=s[d]??{};e.ide===`Copilot CLI`?f[n]={...o,tools:[`*`]}:f[n]=o,s[d]=f,l(a,{recursive:!0}),p(i,`${JSON.stringify(s,null,2)}\n`,`utf-8`),console.log(` ${e.ide}: configured ${n} in ${i}`)}const S=new Set([`VS Code`,`VS Code Insiders`,`VSCodium`]);function C(e,t=!1){if(!S.has(e.ide))return;let n=h(e.configDir,`settings.json`),r={};if(c(n))try{let e=u(n,`utf-8`);r=JSON.parse(e)}catch{console.log(` ${e.ide}: skipped settings.json (invalid JSON)`);return}let a=!1;for(let[e,n]of Object.entries(i))if(typeof n==`object`&&n){let t=typeof r[e]==`object`&&r[e]!==null?r[e]:{},i={...t,...n};JSON.stringify(i)!==JSON.stringify(t)&&(r[e]=i,a=!0)}else (t||!(e in r))&&(r[e]=n,a=!0);a&&(p(n,`${JSON.stringify(r,null,2)}\n`,`utf-8`),console.log(` ${e.ide}: updated settings.json`))}function w(t,n,i,u,f=!1){let m=new Set;for(let e of n)e.globalScaffoldRoot&&m.add(e.globalScaffoldRoot);if(m.size===0){console.log(` No IDEs with global scaffold support detected.`);return}let g=h(t,`scaffold`,`general`);for(let n of m){s(g,n,`agents`,u,f),s(g,n,`prompts`,u,f);let i=0;for(let e of r)c(h(g,`skills`,e))&&(s(g,n,`skills/${e}`,u,f),i++);for(let r of e){let e=h(t,`scaffold`,`flows`,r);if(!c(h(e,`steps`)))continue;let i=h(n,`flows`,r);l(i,{recursive:!0});let a=h(i,`skills`);c(a)&&(d(a,{recursive:!0,force:!0}),console.log(` ${n}: migrated ${r} flow to steps/ layout`)),s(e,i,`steps`,u,f)}console.log(` ${n}: scaffold updated (${i} skills)`)}let _=new Set,v=o(`aikit`,i),b=a(`aikit`,i);for(let e of n){if(!e.globalScaffoldRoot)continue;let t=e.globalScaffoldRoot;if(e.ide===`Claude Code`){let e=h(t,`CLAUDE.md`);p(e,`${v}\n---\n\n${b}`,`utf-8`),_.add(e)}else if(e.ide===`VS Code`||e.ide===`VS Code Insiders`||e.ide===`VSCodium`){let n=e.instructionsRoot??t;l(n,{recursive:!0});let r=h(n,`copilot-instructions.md`);_.has(r)||(p(r,`---\napplyTo: "**"\n---\n\n${v}\n---\n\n${b}`,`utf-8`),_.add(r));let i=h(y(),`.github`),a=h(i,`copilot-instructions.md`);_.has(a)||(l(i,{recursive:!0}),p(a,`${v}\n---\n\n${b}`,`utf-8`),_.add(a))}else if(e.ide===`Cursor`||e.ide===`Cursor Nightly`){let e=h(t,`rules`);l(e,{recursive:!0});let n=h(e,`aikit.mdc`);_.has(n)||(p(n,`${v}\n---\n\n${b}`,`utf-8`),_.add(n))}else if(e.ide===`Windsurf`){let e=h(t,`rules`);l(e,{recursive:!0});let n=h(e,`aikit.md`);_.has(n)||(p(n,`${v}\n---\n\n${b}`,`utf-8`),_.add(n))}}_.size>0&&console.log(` Instruction files: ${[..._].join(`, `)}`)}function T(e){let t=[];for(let n of e){if(!n.globalScaffoldRoot)continue;let e=n.globalScaffoldRoot;if(n.ide===`VS Code`||n.ide===`VS Code Insiders`||n.ide===`VSCodium`){let r=n.instructionsRoot??e;t.push(h(r,`kb.instructions.md`)),t.push(h(r,`aikit.instructions.md`))}else n.ide===`Cursor`||n.ide===`Cursor Nightly`?t.push(h(e,`rules`,`kb.mdc`)):n.ide===`Windsurf`&&t.push(h(e,`rules`,`kb.md`))}for(let e of t)c(e)&&(f(e),console.log(` Removed legacy file: ${e}`))}async function E(e){let t=n,r=h(m(g(import.meta.url)),`..`,`..`,`..`,`..`,`..`,`package.json`),i=JSON.parse(u(r,`utf-8`)).version;console.log(`Initializing @vpxa/aikit v${i}...\n`);let a=_();l(a,{recursive:!0}),console.log(` Global data store: ${a}`),v({version:1,workspaces:{}}),console.log(` Created registry.json`);let o=b();if(o.length===0)console.log(`
2
2
  No supported IDEs detected. You can manually add the MCP server config.`);else{console.log(`\n Detected ${o.length} IDE(s):`);for(let n of o)x(n,t,e.force),C(n,e.force)}let s=h(m(g(import.meta.url)),`..`,`..`,`..`,`..`,`..`);console.log(`
3
3
  Installing scaffold files:`),w(s,o,t,i,e.force),T(o),console.log(`
4
4
  User-level AI Kit installation complete!`),console.log(`
@@ -1 +1,2 @@
1
- import{cpSync as e,existsSync as t,mkdirSync as n,rmSync as r}from"node:fs";import{basename as i,join as a}from"node:path";import{execSync as o}from"node:child_process";var s=class{constructor(e){this.flowsDir=e}clone(e){let n=this.repoNameFromUrl(e),i=a(this.flowsDir,n);if(t(i))if(!t(a(i,`.git`)))r(i,{recursive:!0,force:!0});else return{success:!1,error:`Flow "${n}" already installed at ${i}. Use update instead.`};try{return this.ensureFlowsDir(),o(`git clone --depth 1 ${e} ${i}`,{stdio:`pipe`,timeout:6e4}),{success:!0,data:i}}catch(e){return{success:!1,error:`Git clone failed: ${e instanceof Error?e.message:String(e)}`}}}update(e){if(!t(e))return{success:!1,error:`Install path not found: ${e}`};try{return o(`git pull --ff-only`,{cwd:e,stdio:`pipe`,timeout:6e4}),{success:!0}}catch(e){return{success:!1,error:`Git pull failed: ${e instanceof Error?e.message:String(e)}`}}}copyLocal(n,r){let i=a(this.flowsDir,r);if(t(i))return{success:!1,error:`Flow "${r}" already installed at ${i}`};try{return this.ensureFlowsDir(),e(n,i,{recursive:!0}),{success:!0,data:i}}catch(e){return{success:!1,error:`Copy failed: ${e instanceof Error?e.message:String(e)}`}}}remove(e){if(!t(e))return{success:!0};try{return r(e,{recursive:!0,force:!0}),{success:!0}}catch(e){return{success:!1,error:`Remove failed: ${e instanceof Error?e.message:String(e)}`}}}runInstallDeps(e){for(let t of e)try{if(t.startsWith(`npm:`)){o(`npx skills add ${t.slice(4)} -g`,{stdio:`pipe`,timeout:12e4});continue}if(t.endsWith(`.git`)||t.includes(`github.com`)){o(`npx skills add ${t} -g`,{stdio:`pipe`,timeout:12e4});continue}return{success:!1,error:`Unknown install entry format: ${t}`}}catch(e){return{success:!1,error:`Install dependency failed for "${t}": ${e instanceof Error?e.message:String(e)}`}}return{success:!0}}repoNameFromUrl(e){return i(e).replace(/\.git$/,``)}ensureFlowsDir(){t(this.flowsDir)||n(this.flowsDir,{recursive:!0})}};export{s as GitInstaller};
1
+ import{cpSync as e,existsSync as t,mkdirSync as n,rmSync as r}from"node:fs";import{basename as i,join as a}from"node:path";import{execSync as o}from"node:child_process";function s(e){if(!e||typeof e!=`object`||!(`stderr`in e))return``;let t=e.stderr;return Buffer.isBuffer(t)?t.toString().trim():typeof t==`string`?t.trim():``}function c(e){try{return new URL(e).hostname}catch{}return e.match(/^[^@]+@([^:]+):/)?.[1]??`<host>`}function l(e,t,n){let r=[`Git operation failed for: ${e}`],i=c(e),a=t.includes(`ETIMEDOUT`)||t.includes(`SIGTERM`)||t.toLowerCase().includes(`timed out`),o=n.includes(`Authentication failed`)||n.includes(`could not read Username`)||n.includes(`terminal prompts disabled`)||n.includes(`401`)||n.includes(`403`)||n.includes(`Permission denied`),s=n.includes(`SSL certificate`)||n.includes(`unable to access`)&&n.includes(`SSL`),l=n.includes(`Could not resolve host`)||n.includes(`Name or service not known`),u=n.includes(`SAML`)||n.includes(`single sign-on`);return o||u?(r.push(``),r.push(`Cause: Authentication required or credentials not configured.`),r.push(``),r.push(`To fix this, ensure git can access this repository:`),r.push(``),r.push(` Option 1 - SSH key:`),r.push(` 1. Generate an SSH key: ssh-keygen -t ed25519`),r.push(` 2. Add the public key to your Git hosting account`),r.push(` 3. Use the SSH URL instead: git@<host>:<org>/<repo>.git`),r.push(``),r.push(` Option 2 - Personal Access Token (PAT):`),r.push(` 1. Create a PAT in your Git hosting Settings > Developer settings > Tokens`),r.push(` 2. For GitHub Enterprise with SAML SSO, authorize the token for your org`),r.push(` 3. Configure git credentials:`),r.push(` git config --global credential.helper store`),r.push(` git clone ${e} (enter PAT as password)`),r.push(``),r.push(` Option 3 - Git Credential Manager:`),r.push(` 1. Install: https://github.com/git-ecosystem/git-credential-manager`),r.push(` 2. Run: git clone ${e}`),r.push(` 3. Follow the browser-based auth prompt`),r.push(``),r.push(`After configuring credentials, retry: aikit flow add ${e}`)):a?(r.push(``),r.push(`Cause: Connection timed out - the server did not respond within 60 seconds.`),r.push(``),r.push(`Possible reasons:`),r.push(` - The repository requires VPN access. Ensure your VPN is connected`),r.push(` - The host is behind a firewall or corporate proxy`),r.push(` - The URL may be incorrect`),r.push(``),r.push(`Diagnostics:`),r.push(` 1. Verify the URL is correct: ${e}`),r.push(` 2. Test connectivity: git ls-remote ${e}`),r.push(` 3. If behind a proxy, configure git:`),r.push(` git config --global http.proxy http://proxy:port`),r.push(``),r.push(`If this is a corporate/internal host, you may need to:`),r.push(` - Connect to the corporate VPN`),r.push(` - Add the host to your SSH config or git config`),r.push(` - Ask your IT team to allowlist your machine`),r.push(``),r.push(`After resolving, retry: aikit flow add ${e}`)):s?(r.push(``),r.push(`Cause: SSL/TLS certificate verification failed.`),r.push(``),r.push(`This often happens with corporate proxies or self-signed certificates.`),r.push(``),r.push(`To fix:`),r.push(` 1. If your company uses a custom CA, add it:`),r.push(` git config --global http.sslCAInfo /path/to/ca-bundle.crt`),r.push(` 2. As a last resort (not recommended for production):`),r.push(` git config --global http.sslVerify false`),r.push(``),r.push(`After resolving, retry: aikit flow add ${e}`)):l?(r.push(``),r.push(`Cause: Cannot resolve hostname.`),r.push(``),r.push(`Check:`),r.push(` 1. Is the URL correct? ${e}`),r.push(` 2. Are you connected to the internet/VPN?`),r.push(` 3. Can you resolve the host? ping ${i}`),r.push(``),r.push(`After resolving, retry: aikit flow add ${e}`)):(r.push(``),r.push(`Error: ${t}`),n&&r.push(`Details: ${n}`),r.push(``),r.push(`Troubleshooting:`),r.push(` 1. Verify the URL is a valid git repository: git ls-remote ${e}`),r.push(` 2. Check your git credentials and network connectivity`),r.push(` 3. If the repo requires auth, configure credentials first (PAT or SSH key)`),r.push(``),r.push(`After resolving, retry: aikit flow add ${e}`)),r.join(`
2
+ `)}var u=class{constructor(e){this.flowsDir=e}clone(e){let n=this.repoNameFromUrl(e),i=a(this.flowsDir,n);if(t(i))if(!t(a(i,`.git`)))r(i,{recursive:!0,force:!0});else return{success:!1,error:`Flow "${n}" already installed at ${i}. Use update instead.`};try{return this.ensureFlowsDir(),o(`git clone --depth 1 ${e} ${i}`,{stdio:`pipe`,timeout:6e4,env:{...process.env,GIT_TERMINAL_PROMPT:`0`,GIT_ASKPASS:``}}),{success:!0,data:i}}catch(n){t(i)&&r(i,{recursive:!0,force:!0});let a=s(n);return{success:!1,error:l(e,n instanceof Error?n.message:String(n),a)}}}update(e){if(!t(e))return{success:!1,error:`Install path not found: ${e}`};try{return o(`git pull --ff-only`,{cwd:e,stdio:`pipe`,timeout:6e4,env:{...process.env,GIT_TERMINAL_PROMPT:`0`,GIT_ASKPASS:``}}),{success:!0}}catch(t){let n=e;try{n=o(`git remote get-url origin`,{cwd:e,stdio:`pipe`,timeout:1e4}).toString().trim()}catch{}let r=s(t),i=t instanceof Error?t.message:String(t);return{success:!1,error:l(n,i,r)}}}copyLocal(n,r){let i=a(this.flowsDir,r);if(t(i))return{success:!1,error:`Flow "${r}" already installed at ${i}`};try{return this.ensureFlowsDir(),e(n,i,{recursive:!0}),{success:!0,data:i}}catch(e){return{success:!1,error:`Copy failed: ${e instanceof Error?e.message:String(e)}`}}}remove(e){if(!t(e))return{success:!0};try{return r(e,{recursive:!0,force:!0}),{success:!0}}catch(e){return{success:!1,error:`Remove failed: ${e instanceof Error?e.message:String(e)}`}}}runInstallDeps(e){for(let t of e)try{if(t.startsWith(`npm:`)){o(`npx skills add ${t.slice(4)} -g`,{stdio:`pipe`,timeout:12e4});continue}if(t.endsWith(`.git`)||t.includes(`github.com`)){o(`npx skills add ${t} -g`,{stdio:`pipe`,timeout:12e4});continue}return{success:!1,error:`Unknown install entry format: ${t}`}}catch(e){return{success:!1,error:`Install dependency failed for "${t}": ${e instanceof Error?e.message:String(e)}`}}return{success:!0}}repoNameFromUrl(e){return i(e).replace(/\.git$/,``)}ensureFlowsDir(){t(this.flowsDir)||n(this.flowsDir,{recursive:!0})}};export{u as GitInstaller};
@@ -414,6 +414,73 @@ git_context({ diff: true })
414
414
  → check({}) → test_run({})
415
415
  ```
416
416
 
417
+ ---
418
+
419
+ ## Persistent Memory (Long-Term Knowledge)
420
+
421
+ AI Kit provides cross-session persistent memory via a curated knowledge store. Use it to remember decisions, patterns, conventions, and context that should survive beyond the current conversation.
422
+
423
+ ### Writing to Memory
424
+
425
+ | Tool | Purpose | Example |
426
+ |------|---------|---------|
427
+ | `remember` | Store a new knowledge entry | `remember({ title: "Auth uses JWT RS256", content: "All API auth uses RS256 JWT tokens issued by /auth/token. Refresh via httpOnly cookie.", category: "decisions" })` |
428
+ | `update` | Modify an existing entry | `update({ id: "<entry-id>", content: "Updated: now also supports Ed25519" })` |
429
+ | `produce_knowledge` | Auto-generate analysis entries from code | `produce_knowledge({ path: "src/" })` |
430
+
431
+ **Categories** — use these to organize entries:
432
+ - `conventions` — coding standards, naming rules, file organization
433
+ - `decisions` — architecture decisions, technology choices, trade-offs made
434
+ - `patterns` — recurring code patterns, design patterns in use
435
+ - `context` — project context, domain knowledge, business rules
436
+ - `session` — session checkpoints for resuming work
437
+
438
+ ### Reading from Memory
439
+
440
+ | Tool | Purpose | Example |
441
+ |------|---------|---------|
442
+ | `list` | Browse all stored entries | `list()` or `list({ category: "decisions" })` |
443
+ | `read` | Read a specific entry by ID | `read({ id: "<entry-id>" })` |
444
+ | `search` | Find entries by content/query | `search({ query: "authentication", origin: "curated" })` |
445
+ | `forget` | Remove an outdated entry | `forget({ id: "<entry-id>" })` |
446
+
447
+ ### When to Remember
448
+
449
+ | Situation | What to store | Category |
450
+ |-----------|--------------|----------|
451
+ | Architecture decision made | Decision + rationale + alternatives considered | `decisions` |
452
+ | Pattern discovered in codebase | Pattern description + example locations | `patterns` |
453
+ | Convention established | Rule + enforcement approach | `conventions` |
454
+ | Session ending | Checkpoint: what was done, what's next, blockers | `session` |
455
+ | Bug root cause found | Root cause + fix approach + prevention strategy | `context` |
456
+ | External API behavior learned | Behavior quirks, rate limits, gotchas | `context` |
457
+
458
+ ### Session Checkpoint Pattern
459
+
460
+ At the END of every meaningful work session:
461
+ ```
462
+ remember({
463
+ title: "Session checkpoint: <topic>",
464
+ content: "## Done\n- <completed items>\n\n## Decisions\n- <key decisions made>\n\n## Next\n- <pending work>\n\n## Blockers\n- <issues encountered>",
465
+ category: "session"
466
+ })
467
+ ```
468
+
469
+ At the START of the next session:
470
+ ```
471
+ search({ query: "SESSION CHECKPOINT", origin: "curated" }) # Find last checkpoint
472
+ list({ category: "session" }) # Browse all checkpoints
473
+ ```
474
+
475
+ ### Memory Best Practices
476
+
477
+ 1. **Remember decisions, not code** — store *why*, not *what*. Code changes; rationale persists.
478
+ 2. **Search before remembering** — avoid duplicates: `search({ query: "..." })` first.
479
+ 3. **Use categories** — structured categories enable filtered `list()` queries.
480
+ 4. **Checkpoint regularly** — don't wait for session end. Checkpoint at milestones.
481
+ 5. **Clean up** — `forget()` outdated entries. Memory is only valuable when accurate.
482
+ 6. **Cross-reference** — mention related entry titles in content for discoverability.
483
+
417
484
  ## CLI Quick Reference
418
485
 
419
486
  ```bash