@vpxa/aikit 0.1.76 → 0.1.78
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 +32 -8
- package/package.json +5 -8
- package/packages/cli/dist/index.js +1 -2
- package/packages/flows/dist/index.d.ts +3 -0
- package/packages/flows/dist/index.js +1 -1
- package/packages/server/dist/index.js +1 -1
- package/packages/server/dist/routes-0OCkdgRe.js +5 -0
- package/packages/server/dist/{server-CVhVH5cT.js → server-VgZC6Q43.js} +3 -3
- package/packages/server/dist/settings-static-BosGZSPf.js +1 -0
- package/packages/settings-ui/dist/assets/index-BlJqzH2g.js +10 -0
- package/packages/tools/dist/index.d.ts +52 -2
- package/packages/tools/dist/index.js +46 -46
- package/scaffold/README.md +39 -4
- package/scaffold/dist/adapters/flows.mjs +1 -1
- package/scaffold/dist/adapters/skills.mjs +1 -1
- package/scaffold/dist/definitions/bodies.mjs +1 -0
- package/scaffold/dist/{compiled/flows-data.mjs → definitions/flows.mjs} +5 -1
- package/packages/tui/dist/App-Bkz0lpCn.js +0 -2
- package/packages/tui/dist/App.d.ts +0 -13
- package/packages/tui/dist/App.js +0 -2
- package/packages/tui/dist/CuratedPanel-DGFKz-fJ.js +0 -2
- package/packages/tui/dist/LogPanel-BrBa5xIT.js +0 -17
- package/packages/tui/dist/SearchPanel-CDSGcT7M.js +0 -2
- package/packages/tui/dist/StatusPanel-yRieSRc3.js +0 -2
- package/packages/tui/dist/chunk-DqSKhezp.js +0 -2
- package/packages/tui/dist/devtools-6rm8h8Q1.js +0 -7
- package/packages/tui/dist/hooks/useKBClient.d.ts +0 -9
- package/packages/tui/dist/hooks/useKBClient.js +0 -2
- package/packages/tui/dist/hooks/usePolling.d.ts +0 -8
- package/packages/tui/dist/hooks/usePolling.js +0 -2
- package/packages/tui/dist/index-floZQwfo.d.ts +0 -65
- package/packages/tui/dist/index.d.ts +0 -7
- package/packages/tui/dist/index.js +0 -2
- package/packages/tui/dist/jsx-runtime-CI8Ofr1S.js +0 -294
- package/packages/tui/dist/panels/CuratedPanel.d.ts +0 -7
- package/packages/tui/dist/panels/CuratedPanel.js +0 -2
- package/packages/tui/dist/panels/LogPanel.d.ts +0 -7
- package/packages/tui/dist/panels/LogPanel.js +0 -2
- package/packages/tui/dist/panels/SearchPanel.d.ts +0 -7
- package/packages/tui/dist/panels/SearchPanel.js +0 -2
- package/packages/tui/dist/panels/StatusPanel.d.ts +0 -7
- package/packages/tui/dist/panels/StatusPanel.js +0 -2
- package/packages/tui/dist/react-CKRDn6y3.js +0 -24
- package/packages/tui/dist/useKBClient-BACLDL_U.js +0 -2
- package/packages/tui/dist/usePolling-D-4v1sTA.js +0 -2
- package/scaffold/definitions/agents.mjs +0 -266
- package/scaffold/definitions/bodies.mjs +0 -735
- package/scaffold/definitions/exclusions.mjs +0 -58
- package/scaffold/definitions/hooks.mjs +0 -43
- package/scaffold/definitions/models.mjs +0 -84
- package/scaffold/definitions/plugins.mjs +0 -147
- package/scaffold/definitions/prompts.mjs +0 -365
- package/scaffold/definitions/protocols.mjs +0 -863
- package/scaffold/definitions/tools.mjs +0 -250
- /package/scaffold/dist/{compiled/skills-data.mjs → definitions/skills.mjs} +0 -0
package/README.md
CHANGED
|
@@ -292,14 +292,6 @@ Tools supporting `workspaces` param: `search`, `find`, `symbol`.
|
|
|
292
292
|
| `aikit_flow_remove` | `aikit flow remove` | Remove an installed flow |
|
|
293
293
|
| `aikit_flow_update` | `aikit flow update` | Update flow definition or steps |
|
|
294
294
|
|
|
295
|
-
### TUI Dashboard
|
|
296
|
-
|
|
297
|
-
```bash
|
|
298
|
-
aikit tui # Launch interactive Ink terminal dashboard
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
The TUI is a human monitoring dashboard with 4 panels: Status, Search, Curated, and Activity Log. It shows real-time tool activity via the replay audit trail, letting you observe what an AI agent is doing with the KB.
|
|
302
|
-
|
|
303
295
|
## MCP Integration
|
|
304
296
|
|
|
305
297
|
After `aikit init`, your `.vscode/mcp.json` is configured automatically:
|
|
@@ -389,8 +381,40 @@ aikit reindex [--full]
|
|
|
389
381
|
aikit onboard <path> [--generate] [--out-dir <dir>]
|
|
390
382
|
aikit serve [--transport stdio|http] [--port N]
|
|
391
383
|
aikit init [--user|--workspace] [--force] [--guide]
|
|
384
|
+
aikit dashboard [--port N] [--no-open]
|
|
385
|
+
aikit settings [--port N] [--no-open]
|
|
392
386
|
```
|
|
393
387
|
|
|
388
|
+
## Settings UI
|
|
389
|
+
|
|
390
|
+
`aikit settings` launches a local web UI for managing `aikit.config.json`
|
|
391
|
+
and environment variables (workspace `.env` and global
|
|
392
|
+
`~/.aikit-data/global.env`).
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
aikit settings # opens http://localhost:3210/settings/
|
|
396
|
+
aikit settings --port 4000 # custom port
|
|
397
|
+
aikit settings --no-open # don't auto-open browser
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
The same UI is also mounted at `/settings/` whenever the MCP server is
|
|
401
|
+
running with `--transport http`. Both surfaces share these REST endpoints
|
|
402
|
+
under `/settings/api`:
|
|
403
|
+
|
|
404
|
+
| Method | Path | Purpose |
|
|
405
|
+
|--------|------|---------|
|
|
406
|
+
| GET | `/status` | Mode (workspace/user), config path, env paths, MCP info |
|
|
407
|
+
| GET | `/schema` | Known config keys and env vars with types and descriptions |
|
|
408
|
+
| GET | `/config` | Current `aikit.config.json` content |
|
|
409
|
+
| PATCH | `/config` | Apply set/unset patch ops, atomic write |
|
|
410
|
+
| GET | `/env?reveal=true` | Workspace + global env snapshots (secrets masked unless `reveal`) |
|
|
411
|
+
| PUT | `/env/:key` | Write a value to `{ scope: 'workspace' \| 'global' }` |
|
|
412
|
+
| DELETE | `/env/:key?scope=...` | Remove a key from the chosen scope |
|
|
413
|
+
|
|
414
|
+
The HTTP server binds `127.0.0.1` only (matching the existing
|
|
415
|
+
`/_dashboard/` convention). Restart the MCP server for environment
|
|
416
|
+
changes to take effect.
|
|
417
|
+
|
|
394
418
|
## Configuration
|
|
395
419
|
|
|
396
420
|
`aikit.config.json`:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vpxa/aikit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.78",
|
|
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",
|
|
@@ -29,13 +29,10 @@
|
|
|
29
29
|
"packages/chunker/src/queries/**/*.scm",
|
|
30
30
|
"scaffold/",
|
|
31
31
|
"!scaffold/__tests__/",
|
|
32
|
-
"!scaffold/
|
|
33
|
-
"!scaffold/flows/",
|
|
34
|
-
"!scaffold/compile.mjs",
|
|
32
|
+
"!scaffold/definitions/",
|
|
35
33
|
"!scaffold/_preview/",
|
|
36
34
|
"!scaffold/generate.mjs",
|
|
37
35
|
"!scaffold/adapters/",
|
|
38
|
-
"!scaffold/compiled/",
|
|
39
36
|
"README.md",
|
|
40
37
|
"LICENSE"
|
|
41
38
|
],
|
|
@@ -51,17 +48,17 @@
|
|
|
51
48
|
"aikit": "./bin/aikit.mjs"
|
|
52
49
|
},
|
|
53
50
|
"dependencies": {
|
|
54
|
-
"@huggingface/transformers": "^
|
|
51
|
+
"@huggingface/transformers": "^4.x",
|
|
55
52
|
"@lancedb/lancedb": "^0.x",
|
|
56
53
|
"@mcp-ui/server": "^6.x",
|
|
57
54
|
"@modelcontextprotocol/ext-apps": "^1.x",
|
|
58
55
|
"@modelcontextprotocol/sdk": "^1.x",
|
|
59
|
-
"diff": "^
|
|
56
|
+
"diff": "^9.x",
|
|
60
57
|
"express": "^5.x",
|
|
61
58
|
"gpt-tokenizer": "^3.x",
|
|
62
59
|
"linkedom": "^0.x",
|
|
63
60
|
"lru-cache": "^11.x",
|
|
64
|
-
"marked": "^
|
|
61
|
+
"marked": "^18.x",
|
|
65
62
|
"minimatch": "^10.x",
|
|
66
63
|
"sql.js": "^1.x",
|
|
67
64
|
"tree-sitter-wasms": "~0.1.13",
|
|
@@ -10,7 +10,6 @@ Actions: stats, find-nodes, find-edges, neighbors, traverse, delete, clear`),pro
|
|
|
10
10
|
Nodes:`);for(let e of f.nodes){let t=Object.keys(e.properties).length>0?` ${JSON.stringify(e.properties)}`:``;console.log(` ${e.name} (${e.type}, id: ${e.id})${t}`)}}if(f.edges&&f.edges.length>0){console.log(`
|
|
11
11
|
Edges:`);for(let e of f.edges){let t=e.weight===1?``:` (weight: ${e.weight})`;console.log(` ${e.fromId} --[${e.type}]--> ${e.toId}${t}`)}}f.stats&&(console.log(`\nNode types: ${JSON.stringify(f.stats.nodeTypes)}`),console.log(`Edge types: ${JSON.stringify(f.stats.edgeTypes)}`)),f.deleted!==void 0&&console.log(`Deleted: ${f.deleted}`)}}],Ot=[{name:`remember`,description:`Store curated knowledge`,usage:`aikit remember <title> --category <cat> [--tags tag1,tag2]`,run:async e=>{let t=N(e,`--category`,``).trim(),n=I(N(e,`--tags`,``)),r=e.shift()?.trim()??``,i=await F(),a=i.trim().length>0?i:e.join(` `).trim();(!r||!t||!a.trim())&&(console.error(`Usage: aikit remember <title> --category <cat> [--tags tag1,tag2]`),process.exit(1));let{curated:o}=await Y(),s=await o.remember(r,a,t,n);console.log(`Stored curated entry`),console.log(` Path: ${s.path}`),console.log(` Category: ${t}`),n.length>0&&console.log(` Tags: ${n.join(`, `)}`)}},{name:`forget`,description:`Remove a curated entry`,usage:`aikit forget <path> --reason <reason>`,run:async e=>{let t=N(e,`--reason`,``).trim(),n=e.shift()?.trim()??``;(!n||!t)&&(console.error(`Usage: aikit forget <path> --reason <reason>`),process.exit(1));let{curated:r}=await Y(),i=await r.forget(n,t);console.log(`Removed curated entry: ${i.path}`)}},{name:`read`,description:`Read a curated entry`,usage:`aikit read <path>`,run:async e=>{let t=e.shift()?.trim()??``;t||(console.error(`Usage: aikit read <path>`),process.exit(1));let{curated:n}=await Y(),r=await n.read(t);console.log(r.title),console.log(`─`.repeat(60)),console.log(`Path: ${r.path}`),console.log(`Category: ${r.category}`),console.log(`Version: ${r.version}`),console.log(`Tags: ${r.tags.length>0?r.tags.join(`, `):`None`}`),console.log(``),console.log(r.content)}},{name:`list`,description:`List curated entries`,usage:`aikit list [--category <cat>] [--tag <tag>]`,run:async e=>{let t=N(e,`--category`,``).trim()||void 0,n=N(e,`--tag`,``).trim()||void 0,{curated:r}=await Y(),i=await r.list({category:t,tag:n});if(i.length===0){console.log(`No curated entries found.`);return}console.log(`Curated entries (${i.length})`),console.log(`─`.repeat(60));for(let e of i){console.log(e.path),console.log(` ${e.title}`),console.log(` Category: ${e.category} | Version: ${e.version}`),console.log(` Tags: ${e.tags.length>0?e.tags.join(`, `):`None`}`);let t=e.contentPreview.replace(/\s+/g,` `).trim();t&&console.log(` Preview: ${t}`),console.log(``)}}},{name:`update`,description:`Update a curated entry`,usage:`aikit update <path> --reason <reason>`,run:async e=>{let t=N(e,`--reason`,``).trim(),n=e.shift()?.trim()??``,r=await F();(!n||!t||!r.trim())&&(console.error(`Usage: aikit update <path> --reason <reason>`),process.exit(1));let{curated:i}=await Y(),a=await i.update(n,r,t);console.log(`Updated curated entry`),console.log(` Path: ${a.path}`),console.log(` Version: ${a.version}`)}},{name:`compact`,description:`Compress text for context`,usage:`aikit compact <query> [--path <file>] [--max-chars N] [--segmentation paragraph|sentence|line]`,run:async e=>{let t=M(e,`--max-chars`,3e3),n=N(e,`--path`,``).trim()||void 0,r=N(e,`--segmentation`,`paragraph`),i=e.join(` `).trim(),a=n?void 0:await F();(!i||!n&&!a?.trim())&&(console.error(`Usage: aikit compact <query> --path <file> OR cat file | aikit compact <query>`),process.exit(1));let{embedder:o}=await Y(),s=await ie(o,{text:a,path:n,query:i,maxChars:t,segmentation:r});console.log(`Compressed ${s.originalChars} chars to ${s.compressedChars} chars`),console.log(`Ratio: ${(s.ratio*100).toFixed(1)}% | Segments: ${s.segmentsKept}/${s.segmentsTotal}`),console.log(``),console.log(s.text)}}],kt=[{name:`search`,description:`Search the AI Kit index`,usage:`aikit search <query> [--limit N] [--mode hybrid|semantic|keyword] [--graph-hops 0-3]`,run:async e=>{let t=M(e,`--limit`,5),n=N(e,`--mode`,`hybrid`),r=M(e,`--graph-hops`,0),i=e.join(` `).trim();i||(console.error(`Usage: aikit search <query>`),process.exit(1));let{embedder:a,store:o,graphStore:s}=await Y(),c=await a.embedQuery(i),l;if(n===`keyword`)l=await o.ftsSearch(i,{limit:t});else if(n===`semantic`)l=await o.search(c,{limit:t});else{let[e,n]=await Promise.all([o.search(c,{limit:t*2}),o.ftsSearch(i,{limit:t*2}).catch(()=>[])]);l=U(e,n).slice(0,t)}if(l.length===0){console.log(`No results found.`);return}for(let{record:e,score:t}of l){console.log(`\n${`─`.repeat(60)}`),console.log(`[${(t*100).toFixed(1)}%] ${e.sourcePath}:${e.startLine}-${e.endLine}`),console.log(` Type: ${e.contentType} | Origin: ${e.origin}`),e.tags.length>0&&console.log(` Tags: ${e.tags.join(`, `)}`),console.log(``);let n=e.content.length>500?`${e.content.slice(0,500)}...`:e.content;console.log(n)}if(console.log(`\n${`─`.repeat(60)}`),console.log(`${l.length} result(s) found.`),r>0&&l.length>0)try{let{graphAugmentSearch:e}=await import(`../../tools/dist/index.js`),t=(await e(s,l.map(e=>({recordId:e.record.id,score:e.score,sourcePath:e.record.sourcePath})),{hops:r,maxPerHit:5})).filter(e=>e.graphContext.nodes.length>0);if(t.length>0){console.log(`\nGraph context (${r} hop${r>1?`s`:``}):\n`);for(let e of t){console.log(` ${e.sourcePath}:`);for(let t of e.graphContext.nodes.slice(0,5))console.log(` → ${t.name} (${t.type})`);for(let t of e.graphContext.edges.slice(0,5))console.log(` → ${t.fromId} --[${t.type}]--> ${t.toId}`)}}}catch(e){console.error(`[graph] augmentation failed: ${e.message}`)}}},{name:`find`,description:`Run federated search across indexed content and files`,usage:`aikit find [query] [--glob <pattern>] [--pattern <regex>] [--limit N]`,run:async e=>{let t=M(e,`--limit`,10),n=N(e,`--glob`,``).trim()||void 0,r=N(e,`--pattern`,``).trim()||void 0,i=e.join(` `).trim()||void 0;!i&&!n&&!r&&(console.error(`Usage: aikit find [query] [--glob <pattern>] [--pattern <regex>] [--limit N]`),process.exit(1));let{embedder:a,store:o}=await Y(),s=await g(a,o,{query:i,glob:n,pattern:r,limit:t});if(s.results.length===0){console.log(`No matches found.`);return}console.log(`Strategies: ${s.strategies.join(`, `)}`),console.log(`Results: ${s.results.length} shown (${s.totalFound} total)`);for(let e of s.results){let t=e.lineRange?`:${e.lineRange.start}-${e.lineRange.end}`:``;console.log(`\n[${e.source}] ${e.path}${t}`),console.log(` Score: ${(e.score*100).toFixed(1)}%`),e.preview&&console.log(` ${e.preview.replace(/\s+/g,` `).trim()}`)}}},{name:`scope-map`,description:`Generate a reading plan for a task`,usage:`aikit scope-map <task> [--max-files N]`,run:async e=>{let t=M(e,`--max-files`,15),n=e.join(` `).trim();n||(console.error(`Usage: aikit scope-map <task> [--max-files N]`),process.exit(1));let{embedder:r,store:i}=await Y(),a=await Fe(r,i,{task:n,maxFiles:t});console.log(`Task: ${a.task}`),console.log(`Files: ${a.files.length}`),console.log(`Estimated tokens: ${a.totalEstimatedTokens}`),console.log(``),console.log(`Reading order:`);for(let e of a.readingOrder)console.log(` ${e}`);for(let[e,t]of a.files.entries())console.log(`\n${e+1}. ${t.path}`),console.log(` Relevance: ${(t.relevance*100).toFixed(1)}% | Tokens: ${t.estimatedTokens}`),console.log(` Why: ${t.reason}`),t.focusRanges.length>0&&console.log(` Focus: ${at(t.focusRanges)}`)}},{name:`symbol`,description:`Resolve a symbol definition, imports, and references`,usage:`aikit symbol <name> [--limit N]`,run:async e=>{let t=M(e,`--limit`,20),n=e.join(` `).trim();n||(console.error(`Usage: aikit symbol <name> [--limit N]`),process.exit(1));let{embedder:r,store:i}=await Y();ht(await Ve(r,i,{name:n,limit:t}))}},{name:`trace`,description:`Trace forward/backward flow for a symbol or file location`,usage:`aikit trace <start> [--direction forward|backward|both] [--max-depth N]`,run:async e=>{let t=N(e,`--direction`,`both`).trim()||`both`,n=M(e,`--max-depth`,3),r=e.join(` `).trim();(!r||![`forward`,`backward`,`both`].includes(t))&&(console.error(`Usage: aikit trace <start> [--direction forward|backward|both] [--max-depth N]`),process.exit(1));let{embedder:i,store:a}=await Y();dt(await Ue(i,a,{start:r,direction:t,maxDepth:n}))}},{name:`examples`,description:`Find real code examples of a symbol or pattern`,usage:`aikit examples <query> [--limit N] [--content-type type]`,run:async e=>{let t=M(e,`--limit`,5),n=N(e,`--content-type`,``).trim()||void 0,r=e.join(` `).trim();r||(console.error(`Usage: aikit examples <query> [--limit N] [--content-type type]`),process.exit(1));let{embedder:i,store:a}=await Y();ft(await pe(i,a,{query:r,limit:t,contentType:n}))}},{name:`dead-symbols`,description:`Find exported symbols that appear to be unused`,usage:`aikit dead-symbols [--limit N]`,run:async e=>{let t=M(e,`--limit`,100),{embedder:n,store:r}=await Y();pt(await fe(n,r,{limit:t}))}},{name:`lookup`,description:`Look up indexed content by record ID or source path`,usage:`aikit lookup <id>`,run:async e=>{let t=e.join(` `).trim();t||(console.error(`Usage: aikit lookup <id>`),process.exit(1));let{store:n}=await Y(),r=await n.getById(t);if(r){console.log(r.id),console.log(`─`.repeat(60)),console.log(`Path: ${r.sourcePath}`),console.log(`Chunk: ${r.chunkIndex+1}/${r.totalChunks}`),console.log(`Lines: ${r.startLine}-${r.endLine}`),console.log(`Type: ${r.contentType} | Origin: ${r.origin}`),r.tags.length>0&&console.log(`Tags: ${r.tags.join(`, `)}`),console.log(``),console.log(r.content);return}let i=await n.getBySourcePath(t);if(i.length===0){console.log(`No indexed content found for: ${t}`);return}i.sort((e,t)=>e.chunkIndex-t.chunkIndex),console.log(t),console.log(`─`.repeat(60)),console.log(`Chunks: ${i.length} | Type: ${i[0].contentType}`);for(let e of i){let t=e.startLine?` (lines ${e.startLine}-${e.endLine})`:``;console.log(`\nChunk ${e.chunkIndex+1}/${e.totalChunks}${t}`),console.log(e.content)}}}],X=s(u(import.meta.url));function Z(e){let t=e;for(let e=0;e<10;e++){try{let e=c(t,`package.json`);if(r(e)&&JSON.parse(a(e,`utf8`)).name===`@vpxa/aikit`)return t}catch{}let e=s(t);if(e===t)break;t=e}return l(e,`..`,`..`,`..`)}const At=[{name:`status`,description:`Show AI Kit index status and statistics`,run:async()=>{let{isUserInstalled:e,getGlobalDataDir:t,computePartitionKey:n,listWorkspaces:r}=await import(`../../core/dist/index.js`),{existsSync:i}=await import(`node:fs`),a=process.cwd(),o=e(),s=i(l(a,`.vscode`,`mcp.json`)),c,u;if(o&&s)c=`workspace (overrides user-level for this workspace)`,u=l(a,`.aikit-data`);else if(o){let e=n(a);c=i(l(a,`AGENTS.md`))?`user (workspace scaffolded)`:`user (workspace not scaffolded)`,u=l(t(),e)}else c=`workspace`,u=l(a,`.aikit-data`);if(console.log(`AI Kit Status`),console.log(`─`.repeat(40)),console.log(` Mode: ${c}`),console.log(` Data: ${u}`),o&&!s){let e=r();console.log(` Registry: ${e.length} workspace(s) enrolled`)}try{let{store:e}=await Y(),t=await e.getStats(),n=await e.listSourcePaths();console.log(` Records: ${t.totalRecords}`),console.log(` Files: ${t.totalFiles}`),console.log(` Indexed: ${t.lastIndexedAt??`Never`}`),console.log(` Backend: ${t.storeBackend}`),console.log(` Model: ${t.embeddingModel}`),console.log(``),console.log(`Content Types:`);for(let[e,n]of Object.entries(t.contentTypeBreakdown))console.log(` ${e}: ${n}`);if(n.length>0){console.log(``),console.log(`Files (${n.length} total):`);for(let e of n.slice(0,20))console.log(` ${e}`);n.length>20&&console.log(` ... and ${n.length-20} more`)}}catch{console.log(``),console.log(" Index not available — run `aikit reindex` to index this workspace.")}o&&!s&&!i(l(a,`AGENTS.md`))&&(console.log(``),console.log(" Action: Run `npx @vpxa/aikit init` to add AGENTS.md and copilot-instructions.md"))}},{name:`reindex`,description:`Re-index the AI Kit index from configured sources`,usage:`aikit reindex [--full]`,run:async e=>{let t=e.includes(`--full`),{store:n,indexer:r,curated:i,config:a}=await Y();console.log(`Indexing sources...`);let o=e=>{e.phase===`chunking`&&e.currentFile&&process.stdout.write(`\r [${e.filesProcessed+1}/${e.filesTotal}] ${e.currentFile}`),e.phase===`done`&&process.stdout.write(`
|
|
12
12
|
`)},s;t?(console.log(`Dropping existing index for full reindex...`),s=await r.reindexAll(a,o)):s=await r.index(a,o),console.log(`Done: ${s.filesProcessed} files, ${s.chunksCreated} chunks in ${(s.durationMs/1e3).toFixed(1)}s`),console.log(`Building FTS index...`),await n.createFtsIndex(),console.log(`Re-indexing curated entries...`);let c=await i.reindexAll();console.log(`Curated: ${c.indexed} entries restored`)}},{name:`serve`,description:`Start the MCP server (stdio or HTTP)`,usage:`aikit serve [--transport stdio|http] [--port N]`,run:async e=>{let t=l(Z(X),`packages`,`server`,`dist`,`index.js`),n=N(e,`--transport`,`stdio`),r=N(e,`--port`,`3210`),i=tt(t,[],{stdio:n===`stdio`?[`pipe`,`pipe`,`inherit`,`ipc`]:`inherit`,env:{...process.env,AIKIT_TRANSPORT:n,AIKIT_PORT:r}});n===`stdio`&&i.stdin&&i.stdout&&(process.stdin.pipe(i.stdin),i.stdout.pipe(process.stdout)),i.on(`exit`,e=>process.exit(e??0)),process.on(`SIGINT`,()=>i.kill(`SIGINT`)),process.on(`SIGTERM`,()=>i.kill(`SIGTERM`)),await new Promise(()=>{})}},{name:`init`,description:`Initialize AI Kit in the current directory`,usage:`aikit init [--user|--workspace] [--force] [--guide]`,run:async e=>{let t=e.includes(`--user`),n=e.includes(`--workspace`),r=e.includes(`--guide`),i=e.includes(`--force`);if(t&&n&&(console.error(`Cannot use --user and --workspace together.`),process.exit(1)),r){let{guideProject:e}=await import(`./init-CuRXmyD9.js`);await e();return}if(t){let{initUser:e}=await import(`./user-vbJwa7x2.js`);await e({force:i})}else if(n){let{initProject:e}=await import(`./init-CuRXmyD9.js`);await e({force:i})}else{let{initSmart:e}=await import(`./init-CuRXmyD9.js`);await e({force:i})}}},{name:`check`,description:`Run incremental typecheck and lint`,usage:`aikit check [--cwd <dir>] [--files f1,f2] [--skip-types] [--skip-lint] [--detail summary|errors|full]`,run:async e=>{let t=N(e,`--cwd`,``).trim()||void 0,n=N(e,`--files`,``),r=N(e,`--detail`,`full`)||`full`,i=n.split(`,`).map(e=>e.trim()).filter(Boolean),a=!1;e.includes(`--skip-types`)&&(e.splice(e.indexOf(`--skip-types`),1),a=!0);let o=!1;e.includes(`--skip-lint`)&&(e.splice(e.indexOf(`--skip-lint`),1),o=!0);let s=await m({cwd:t,files:i.length>0?i:void 0,skipTypes:a,skipLint:o,detail:r});st(s),s.passed||(process.exitCode=1)}},{name:`batch`,description:`Execute built-in operations from JSON input`,usage:`aikit batch [--file path] [--concurrency N]`,run:async e=>{let t=N(e,`--file`,``).trim()||void 0,n=(()=>{let t=e.indexOf(`--concurrency`);if(t===-1||t+1>=e.length)return 0;let n=Number.parseInt(e.splice(t,2)[1],10);return Number.isNaN(n)?0:n})(),r=await rt(t);r.trim()||(console.error(`Usage: aikit batch [--file path] [--concurrency N]`),process.exit(1));let i=it(r),a=n>0?n:i.concurrency,o=i.operations.some(e=>e.type!==`check`)?await Y():null,s=await p(i.operations,async e=>vt(e,o),{concurrency:a});console.log(JSON.stringify(s,null,2)),s.some(e=>e.status===`error`)&&(process.exitCode=1)}},{name:`health`,description:`Run project health checks on the current directory`,usage:`aikit health [path]`,run:async e=>{let t=ve(e.shift());console.log(`Project Health: ${t.path}`),console.log(`─`.repeat(50));for(let e of t.checks){let t=e.status===`pass`?`+`:e.status===`warn`?`~`:`X`;console.log(` [${t}] ${e.name}: ${e.message}`)}console.log(`─`.repeat(50)),console.log(`Score: ${t.score}% — ${t.summary}`)}},{name:`audit`,description:`Run a unified project audit (structure, deps, patterns, health, dead symbols, check)`,usage:`aikit audit [path] [--checks structure,dependencies,patterns,health,dead_symbols,check,entry_points] [--detail summary|full]`,run:async e=>{let{store:t,embedder:n}=await Y(),r=N(e,`--detail`,`summary`)||`summary`,i=N(e,`--checks`,``),a=i?i.split(`,`).map(e=>e.trim()):void 0,o=await f(t,n,{path:e.shift()||`.`,checks:a,detail:r});if(o.ok){if(console.log(o.summary),o.next&&o.next.length>0){console.log(`
|
|
13
|
-
Suggested next steps:`);for(let e of o.next)console.log(` → ${e.tool}: ${e.reason}`)}}else console.error(o.error?.message??`Audit failed`),process.exitCode=1}},{name:`guide`,description:`Tool discovery — recommend AI Kit tools for a given goal`,usage:`aikit guide <goal> [--max N]`,run:async e=>{let t=e.indexOf(`--max`),n=5;t!==-1&&t+1<e.length&&(n=Number.parseInt(e.splice(t,2)[1],10)||5);let r=e.join(` `).trim();r||(console.error(`Usage: aikit guide <goal> [--max N]`),console.error(`Example: aikit guide "audit this project"`),process.exit(1));let i=_e(r,n);console.log(`Workflow: ${i.workflow}`),console.log(` ${i.description}\n`),console.log(`Recommended tools:`);for(let e of i.tools){let t=e.suggestedArgs?` ${JSON.stringify(e.suggestedArgs)}`:``;console.log(` ${e.order}. ${e.tool} — ${e.reason}${t}`)}i.alternativeWorkflows.length>0&&console.log(`\nAlternatives: ${i.alternativeWorkflows.join(`, `)}`)}},{name:`replay`,description:`Show recent tool invocation audit trail`,usage:`aikit replay [--last N] [--tool <name>] [--source mcp|cli]`,run:async e=>{let t=Me({last:Number.parseInt(e[e.indexOf(`--last`)+1],10)||20,tool:e.includes(`--tool`)?e[e.indexOf(`--tool`)+1]:void 0,source:e.includes(`--source`)?e[e.indexOf(`--source`)+1]:void 0});if(t.length===0){console.log(`No replay entries. Activity is logged when tools are invoked.`);return}console.log(`Replay Log (${t.length} entries)\n`);for(let e of t){let t=e.ts.split(`T`)[1]?.split(`.`)[0]??e.ts,n=e.status===`ok`?`✓`:`✗`;console.log(`${t} ${n} ${e.tool} (${e.durationMs}ms) [${e.source}]`),console.log(` in: ${e.input}`),console.log(` out: ${e.output}`)}Ne().catch(()=>{})}},{name:`replay-clear`,description:`Clear the replay audit trail`,run:async()=>{je(),console.log(`Replay log cleared.`)}},{name:`tui`,description:`Launch interactive terminal dashboard (human monitoring)`,run:async()=>{try{let{launch:e}=await import(`../../tui/dist/index.js`),{DirectKBClient:t}=await import(`../../aikit-client/dist/index.js`),{store:n,embedder:r,graphStore:i,curated:a}=await Y();e(new t({store:n,embedder:r,graphStore:i,listCurated:async()=>(await a.list()).map(e=>({...e,content:e.contentPreview})),readCurated:e=>a.read(e)}))}catch(e){throw e.code===`ERR_MODULE_NOT_FOUND`&&(console.error(`TUI requires ink and react. Install them with:
|
|
14
|
-
pnpm add -D ink react @types/react`),process.exit(1)),e}}},{name:`dashboard`,description:`Launch web dashboard for knowledge graph visualization`,usage:`aikit dashboard [--port <port>] [--no-open]`,run:async e=>{let t=e.indexOf(`--port`),n=t!==-1&&e[t+1]?Number.parseInt(e[t+1],10):3210,r=Number.isFinite(n)?n:3210,i=e.includes(`--no-open`);console.log(`Starting AI Kit server on port ${r}...`);let{spawn:a}=await import(`node:child_process`),{platform:o}=await import(`node:os`),s=l(Z(X),`packages`,`server`,`dist`,`index.js`),c=a(process.execPath,[s,`--transport`,`http`,`--port`,String(r)],{stdio:[`ignore`,`pipe`,`pipe`],env:{...process.env,AIKIT_TRANSPORT:`http`,AIKIT_PORT:String(r)}}),u=`http://localhost:${r}/_dashboard/`,d=`http://localhost:${r}/health`,f=!1;for(let e=0;e<30;e+=1){try{if((await fetch(d)).ok){f=!0;break}}catch{}await new Promise(e=>setTimeout(e,1e3))}if(f||(console.error(`Server failed to start within 30 seconds.`),c.kill(),process.exit(1)),console.log(`AI Kit Dashboard: ${u}`),console.log(`Press Ctrl+C to stop.`),!i){let e=o();e===`win32`?a(`cmd`,[`/c`,`start`,``,u],{stdio:`ignore`,detached:!0}).unref():a(e===`darwin`?`open`:`xdg-open`,[u],{stdio:`ignore`,detached:!0}).unref()}let p=()=>{c.kill(),process.exit(0)};process.on(`SIGINT`,p),process.on(`SIGTERM`,p),await new Promise(e=>{c.on(`exit`,()=>e())})}}];function jt(e){let t=e;for(let e=0;e<10;e++){try{let e=c(t,`package.json`);if(r(e)&&JSON.parse(a(e,`utf8`)).name===`@vpxa/aikit`)return t}catch{}let e=s(t);if(e===t)break;t=e}return l(e,`..`,`..`,`..`)}const Mt=[{name:`upgrade`,description:`Upgrade AI Kit agents, prompts, and skills to the latest version (user-level and workspace-level)`,usage:`aikit upgrade`,run:async()=>{let{initUser:n}=await import(`./user-vbJwa7x2.js`);await n({force:!0});let i=process.cwd(),o=r(l(i,`.github`,`.aikit-scaffold.json`)),c=r(l(i,`.github`,`agents`)),d=r(l(i,`.github`,`prompts`)),f=r(l(i,`.claude`,`commands`));if(o||c||d||f){let{initScaffoldOnly:e}=await import(`./init-CuRXmyD9.js`);await e({force:!0})}if(r(l(i,`.github`,`skills`))){let{smartCopySkills:n}=await import(`./scaffold-WMQ2uQ48.js`),r=jt(s(u(import.meta.url))),o=JSON.parse(a(l(r,`package.json`),`utf-8`)).version;await n(i,r,[...e],o,!0);let{smartCopyFlows:c}=await import(`./scaffold-WMQ2uQ48.js`);await c(i,r,[...t],o,!0)}}}],Nt=[{name:`workset`,description:`Manage saved file sets`,usage:`aikit workset <action> [name] [--files f1,f2] [--description desc]`,run:async e=>{let t=e.shift()?.trim(),n=I(N(e,`--files`,``)),r=N(e,`--description`,``).trim()||void 0,i=e.shift()?.trim();switch(t||(console.error(`Usage: aikit workset <action> [name] [--files f1,f2] [--description desc]`),console.error(`Actions: save, get, list, delete, add, remove`),process.exit(1)),t){case`save`:{(!i||n.length===0)&&(console.error(`Usage: aikit workset save <name> --files f1,f2 [--description desc]`),process.exit(1));let e=Pe(i,n,{description:r});console.log(`Saved workset: ${e.name}`),B(e);return}case`get`:{i||(console.error(`Usage: aikit workset get <name>`),process.exit(1));let e=me(i);if(!e){console.log(`No workset found: ${i}`);return}B(e);return}case`list`:{let e=Te();if(e.length===0){console.log(`No worksets saved.`);return}console.log(`Worksets (${e.length})`),console.log(`─`.repeat(60));for(let t of e)B(t),console.log(``);return}case`delete`:{i||(console.error(`Usage: aikit workset delete <name>`),process.exit(1));let e=ce(i);console.log(e?`Deleted workset: ${i}`:`No workset found: ${i}`);return}case`add`:{(!i||n.length===0)&&(console.error(`Usage: aikit workset add <name> --files f1,f2`),process.exit(1));let e=d(i,n);console.log(`Updated workset: ${e.name}`),B(e);return}case`remove`:{(!i||n.length===0)&&(console.error(`Usage: aikit workset remove <name> --files f1,f2`),process.exit(1));let e=ke(i,n);if(!e){console.log(`No workset found: ${i}`);return}console.log(`Updated workset: ${e.name}`),B(e);return}default:console.error(`Unknown workset action: ${t}`),console.error(`Actions: save, get, list, delete, add, remove`),process.exit(1)}}},{name:`stash`,description:`Persist and retrieve named intermediate values`,usage:`aikit stash <set|get|list|delete|clear> [key] [value]`,run:async e=>{let t=e.shift()?.trim(),n=e.shift()?.trim();switch(t||(console.error(`Usage: aikit stash <set|get|list|delete|clear> [key] [value]`),process.exit(1)),t){case`set`:{n||(console.error(`Usage: aikit stash set <key> <value>`),process.exit(1));let t=e.join(` `),r=t.trim()?``:await F(),i=Be(n,gt(t||r));console.log(`Stored stash entry: ${i.key}`),console.log(` Type: ${i.type}`),console.log(` Stored: ${i.storedAt}`);return}case`get`:{n||(console.error(`Usage: aikit stash get <key>`),process.exit(1));let e=Re(n);if(!e){console.log(`No stash entry found: ${n}`);return}console.log(JSON.stringify(e,null,2));return}case`list`:{let e=ze();if(e.length===0){console.log(`No stash entries saved.`);return}console.log(`Stash entries (${e.length})`),console.log(`─`.repeat(60));for(let t of e)console.log(`${t.key} (${t.type})`),console.log(` Stored: ${t.storedAt}`);return}case`delete`:{n||(console.error(`Usage: aikit stash delete <key>`),process.exit(1));let e=Le(n);console.log(e?`Deleted stash entry: ${n}`:`No stash entry found: ${n}`);return}case`clear`:{let e=Ie();console.log(`Cleared ${e} stash entr${e===1?`y`:`ies`}.`);return}default:console.error(`Unknown stash action: ${t}`),console.error(`Actions: set, get, list, delete, clear`),process.exit(1)}}},{name:`lane`,description:`Manage verified lanes — isolated file copies for parallel exploration`,usage:`aikit lane <create|list|status|diff|merge|discard> [name] [--files f1,f2]`,run:async e=>{let t=e.shift();if((!t||![`create`,`list`,`status`,`diff`,`merge`,`discard`].includes(t))&&(console.error(`Usage: aikit lane <create|list|status|diff|merge|discard> [name] [--files f1,f2]`),process.exit(1)),t===`list`){let e=Se();if(e.length===0){console.log(`No active lanes.`);return}for(let t of e)console.log(`${t.name} (${t.sourceFiles.length} files, created ${t.createdAt})`);return}let n=e.shift();switch(n||(console.error(`Lane name is required for "${t}".`),process.exit(1)),t){case`create`:{let t=N(e,`--files`,``);t||(console.error(`Usage: aikit lane create <name> --files file1.ts,file2.ts`),process.exit(1));let r=ye(n,t.split(`,`).map(e=>e.trim()));console.log(`Lane "${r.name}" created with ${r.sourceFiles.length} files.`);break}case`status`:{let e=we(n);console.log(`Lane: ${e.name}`),console.log(`Modified: ${e.modified} | Added: ${e.added} | Deleted: ${e.deleted}`);for(let t of e.entries)console.log(` ${t.status.padEnd(10)} ${t.file}`);break}case`diff`:{let e=be(n);console.log(`Lane: ${e.name} — ${e.modified} modified, ${e.added} added, ${e.deleted} deleted`);for(let t of e.entries)t.diff&&(console.log(`\n--- ${t.file} (${t.status})`),console.log(t.diff));break}case`merge`:{let e=Ce(n);console.log(`Merged ${e.filesMerged} files from lane "${e.name}".`);for(let t of e.files)console.log(` ${t}`);break}case`discard`:{let e=xe(n);console.log(e?`Lane "${n}" discarded.`:`Lane "${n}" not found.`);break}}}},{name:`queue`,description:`Manage task queues for sequential agent operations`,usage:`aikit queue <create|push|next|done|fail|get|list|clear|delete> [name] [args]`,run:async e=>{let t=e.shift();if((!t||![`create`,`push`,`next`,`done`,`fail`,`get`,`list`,`clear`,`delete`].includes(t))&&(console.error(`Usage: aikit queue <create|push|next|done|fail|get|list|clear|delete> [name] [args]`),process.exit(1)),t===`list`){let e=Ee();if(e.length===0){console.log(`No queues.`);return}for(let t of e)console.log(`${t.name} pending:${t.pending} done:${t.done} failed:${t.failed} total:${t.total}`);return}let n=e.shift();switch(n||(console.error(`Queue name is required for "${t}".`),process.exit(1)),t){case`create`:{let e=w(n);console.log(`Queue "${e.name}" created.`);break}case`push`:{let t=Oe(n,e.join(` `)||`Untitled task`);console.log(`Pushed "${t.title}" (${t.id}) to queue "${n}".`);break}case`next`:{let e=De(n);console.log(e?`Next: ${e.title} (${e.id})`:`No pending items in queue "${n}".`);break}case`done`:{let t=e.shift();t||(console.error(`Usage: aikit queue done <name> <id>`),process.exit(1));let r=E(n,t);console.log(`Marked "${r.title}" as done.`);break}case`fail`:{let t=e.shift(),r=e.join(` `)||`Unknown error`;t||(console.error(`Usage: aikit queue fail <name> <id> [error message]`),process.exit(1));let i=D(n,t,r);console.log(`Marked "${i.title}" as failed: ${r}`);break}case`get`:{let e=O(n);if(!e){console.log(`Queue "${n}" not found.`);return}console.log(`Queue: ${e.name} (${e.items.length} items)`);for(let t of e.items){let e=t.error?` — ${t.error}`:``;console.log(` ${t.status.padEnd(12)} ${t.id} ${t.title}${e}`)}break}case`clear`:{let e=C(n);console.log(`Cleared ${e} completed/failed items from queue "${n}".`);break}case`delete`:{let e=T(n);console.log(e?`Queue "${n}" deleted.`:`Queue "${n}" not found.`);break}}}}],Q=[...kt,...Ot,...nt,...Dt,...At,...xt,...yt,...Nt,...bt,...Mt,...q];Q.push({name:`help`,description:`Show available commands`,run:async()=>{$()}});async function Pt(e){let t=[...e],n=t.shift();if(!n||n===`--help`||n===`-h`){$();return}if(n===`--version`||n===`-v`){let e=l(s(u(import.meta.url)),`..`,`..`,`..`,`package.json`),t=JSON.parse(a(e,`utf-8`));console.log(t.version);return}let r=Q.find(e=>e.name===n);r||(console.error(`Unknown command: ${n}`),$(),process.exit(1));try{await r.run(t)}finally{let e=Et();e&&await e.store.close()}}function $(){console.log(`@vpxa/aikit — Local-first AI developer toolkit
|
|
13
|
+
Suggested next steps:`);for(let e of o.next)console.log(` → ${e.tool}: ${e.reason}`)}}else console.error(o.error?.message??`Audit failed`),process.exitCode=1}},{name:`guide`,description:`Tool discovery — recommend AI Kit tools for a given goal`,usage:`aikit guide <goal> [--max N]`,run:async e=>{let t=e.indexOf(`--max`),n=5;t!==-1&&t+1<e.length&&(n=Number.parseInt(e.splice(t,2)[1],10)||5);let r=e.join(` `).trim();r||(console.error(`Usage: aikit guide <goal> [--max N]`),console.error(`Example: aikit guide "audit this project"`),process.exit(1));let i=_e(r,n);console.log(`Workflow: ${i.workflow}`),console.log(` ${i.description}\n`),console.log(`Recommended tools:`);for(let e of i.tools){let t=e.suggestedArgs?` ${JSON.stringify(e.suggestedArgs)}`:``;console.log(` ${e.order}. ${e.tool} — ${e.reason}${t}`)}i.alternativeWorkflows.length>0&&console.log(`\nAlternatives: ${i.alternativeWorkflows.join(`, `)}`)}},{name:`replay`,description:`Show recent tool invocation audit trail`,usage:`aikit replay [--last N] [--tool <name>] [--source mcp|cli]`,run:async e=>{let t=Me({last:Number.parseInt(e[e.indexOf(`--last`)+1],10)||20,tool:e.includes(`--tool`)?e[e.indexOf(`--tool`)+1]:void 0,source:e.includes(`--source`)?e[e.indexOf(`--source`)+1]:void 0});if(t.length===0){console.log(`No replay entries. Activity is logged when tools are invoked.`);return}console.log(`Replay Log (${t.length} entries)\n`);for(let e of t){let t=e.ts.split(`T`)[1]?.split(`.`)[0]??e.ts,n=e.status===`ok`?`✓`:`✗`;console.log(`${t} ${n} ${e.tool} (${e.durationMs}ms) [${e.source}]`),console.log(` in: ${e.input}`),console.log(` out: ${e.output}`)}Ne().catch(()=>{})}},{name:`replay-clear`,description:`Clear the replay audit trail`,run:async()=>{je(),console.log(`Replay log cleared.`)}},{name:`dashboard`,description:`Launch web dashboard for knowledge graph visualization`,usage:`aikit dashboard [--port <port>] [--no-open]`,run:async e=>{let t=e.indexOf(`--port`),n=t!==-1&&e[t+1]?Number.parseInt(e[t+1],10):3210,r=Number.isFinite(n)?n:3210,i=e.includes(`--no-open`);console.log(`Starting AI Kit server on port ${r}...`);let{spawn:a}=await import(`node:child_process`),{platform:o}=await import(`node:os`),s=l(Z(X),`packages`,`server`,`dist`,`index.js`),c=a(process.execPath,[s,`--transport`,`http`,`--port`,String(r)],{stdio:[`ignore`,`pipe`,`pipe`],env:{...process.env,AIKIT_TRANSPORT:`http`,AIKIT_PORT:String(r)}}),u=`http://localhost:${r}/_dashboard/`,d=`http://localhost:${r}/health`,f=!1;for(let e=0;e<30;e+=1){try{if((await fetch(d)).ok){f=!0;break}}catch{}await new Promise(e=>setTimeout(e,1e3))}if(f||(console.error(`Server failed to start within 30 seconds.`),c.kill(),process.exit(1)),console.log(`AI Kit Dashboard: ${u}`),console.log(`Press Ctrl+C to stop.`),!i){let e=o();e===`win32`?a(`cmd`,[`/c`,`start`,``,u],{stdio:`ignore`,detached:!0}).unref():a(e===`darwin`?`open`:`xdg-open`,[u],{stdio:`ignore`,detached:!0}).unref()}let p=()=>{c.kill(),process.exit(0)};process.on(`SIGINT`,p),process.on(`SIGTERM`,p),await new Promise(e=>{c.on(`exit`,()=>e())})}},{name:`settings`,description:`Launch web UI to manage AI Kit configuration and environment variables`,usage:`aikit settings [--port <port>] [--no-open]`,run:async e=>{let t=e.indexOf(`--port`),n=t!==-1&&e[t+1]?Number.parseInt(e[t+1],10):3210,r=Number.isFinite(n)?n:3210,i=e.includes(`--no-open`);console.log(`Starting AI Kit server on port ${r}...`);let{spawn:a}=await import(`node:child_process`),{platform:o}=await import(`node:os`),s=l(Z(X),`packages`,`server`,`dist`,`index.js`),c=a(process.execPath,[s,`--transport`,`http`,`--port`,String(r)],{stdio:[`ignore`,`pipe`,`pipe`],env:{...process.env,AIKIT_TRANSPORT:`http`,AIKIT_PORT:String(r)}}),u=`http://localhost:${r}/settings/`,d=`http://localhost:${r}/health`,f=!1;for(let e=0;e<30;e+=1){try{if((await fetch(d)).ok){f=!0;break}}catch{}await new Promise(e=>setTimeout(e,1e3))}if(f||(console.error(`Server failed to start within 30 seconds.`),c.kill(),process.exit(1)),console.log(`AI Kit Settings: ${u}`),console.log(`Press Ctrl+C to stop.`),!i){let e=o();e===`win32`?a(`cmd`,[`/c`,`start`,``,u],{stdio:`ignore`,detached:!0}).unref():a(e===`darwin`?`open`:`xdg-open`,[u],{stdio:`ignore`,detached:!0}).unref()}let p=()=>{c.kill(),process.exit(0)};process.on(`SIGINT`,p),process.on(`SIGTERM`,p),await new Promise(e=>{c.on(`exit`,()=>e())})}}];function jt(e){let t=e;for(let e=0;e<10;e++){try{let e=c(t,`package.json`);if(r(e)&&JSON.parse(a(e,`utf8`)).name===`@vpxa/aikit`)return t}catch{}let e=s(t);if(e===t)break;t=e}return l(e,`..`,`..`,`..`)}const Mt=[{name:`upgrade`,description:`Upgrade AI Kit agents, prompts, and skills to the latest version (user-level and workspace-level)`,usage:`aikit upgrade`,run:async()=>{let{initUser:n}=await import(`./user-vbJwa7x2.js`);await n({force:!0});let i=process.cwd(),o=r(l(i,`.github`,`.aikit-scaffold.json`)),c=r(l(i,`.github`,`agents`)),d=r(l(i,`.github`,`prompts`)),f=r(l(i,`.claude`,`commands`));if(o||c||d||f){let{initScaffoldOnly:e}=await import(`./init-CuRXmyD9.js`);await e({force:!0})}if(r(l(i,`.github`,`skills`))){let{smartCopySkills:n}=await import(`./scaffold-WMQ2uQ48.js`),r=jt(s(u(import.meta.url))),o=JSON.parse(a(l(r,`package.json`),`utf-8`)).version;await n(i,r,[...e],o,!0);let{smartCopyFlows:c}=await import(`./scaffold-WMQ2uQ48.js`);await c(i,r,[...t],o,!0)}}}],Nt=[{name:`workset`,description:`Manage saved file sets`,usage:`aikit workset <action> [name] [--files f1,f2] [--description desc]`,run:async e=>{let t=e.shift()?.trim(),n=I(N(e,`--files`,``)),r=N(e,`--description`,``).trim()||void 0,i=e.shift()?.trim();switch(t||(console.error(`Usage: aikit workset <action> [name] [--files f1,f2] [--description desc]`),console.error(`Actions: save, get, list, delete, add, remove`),process.exit(1)),t){case`save`:{(!i||n.length===0)&&(console.error(`Usage: aikit workset save <name> --files f1,f2 [--description desc]`),process.exit(1));let e=Pe(i,n,{description:r});console.log(`Saved workset: ${e.name}`),B(e);return}case`get`:{i||(console.error(`Usage: aikit workset get <name>`),process.exit(1));let e=me(i);if(!e){console.log(`No workset found: ${i}`);return}B(e);return}case`list`:{let e=Te();if(e.length===0){console.log(`No worksets saved.`);return}console.log(`Worksets (${e.length})`),console.log(`─`.repeat(60));for(let t of e)B(t),console.log(``);return}case`delete`:{i||(console.error(`Usage: aikit workset delete <name>`),process.exit(1));let e=ce(i);console.log(e?`Deleted workset: ${i}`:`No workset found: ${i}`);return}case`add`:{(!i||n.length===0)&&(console.error(`Usage: aikit workset add <name> --files f1,f2`),process.exit(1));let e=d(i,n);console.log(`Updated workset: ${e.name}`),B(e);return}case`remove`:{(!i||n.length===0)&&(console.error(`Usage: aikit workset remove <name> --files f1,f2`),process.exit(1));let e=ke(i,n);if(!e){console.log(`No workset found: ${i}`);return}console.log(`Updated workset: ${e.name}`),B(e);return}default:console.error(`Unknown workset action: ${t}`),console.error(`Actions: save, get, list, delete, add, remove`),process.exit(1)}}},{name:`stash`,description:`Persist and retrieve named intermediate values`,usage:`aikit stash <set|get|list|delete|clear> [key] [value]`,run:async e=>{let t=e.shift()?.trim(),n=e.shift()?.trim();switch(t||(console.error(`Usage: aikit stash <set|get|list|delete|clear> [key] [value]`),process.exit(1)),t){case`set`:{n||(console.error(`Usage: aikit stash set <key> <value>`),process.exit(1));let t=e.join(` `),r=t.trim()?``:await F(),i=Be(n,gt(t||r));console.log(`Stored stash entry: ${i.key}`),console.log(` Type: ${i.type}`),console.log(` Stored: ${i.storedAt}`);return}case`get`:{n||(console.error(`Usage: aikit stash get <key>`),process.exit(1));let e=Re(n);if(!e){console.log(`No stash entry found: ${n}`);return}console.log(JSON.stringify(e,null,2));return}case`list`:{let e=ze();if(e.length===0){console.log(`No stash entries saved.`);return}console.log(`Stash entries (${e.length})`),console.log(`─`.repeat(60));for(let t of e)console.log(`${t.key} (${t.type})`),console.log(` Stored: ${t.storedAt}`);return}case`delete`:{n||(console.error(`Usage: aikit stash delete <key>`),process.exit(1));let e=Le(n);console.log(e?`Deleted stash entry: ${n}`:`No stash entry found: ${n}`);return}case`clear`:{let e=Ie();console.log(`Cleared ${e} stash entr${e===1?`y`:`ies`}.`);return}default:console.error(`Unknown stash action: ${t}`),console.error(`Actions: set, get, list, delete, clear`),process.exit(1)}}},{name:`lane`,description:`Manage verified lanes — isolated file copies for parallel exploration`,usage:`aikit lane <create|list|status|diff|merge|discard> [name] [--files f1,f2]`,run:async e=>{let t=e.shift();if((!t||![`create`,`list`,`status`,`diff`,`merge`,`discard`].includes(t))&&(console.error(`Usage: aikit lane <create|list|status|diff|merge|discard> [name] [--files f1,f2]`),process.exit(1)),t===`list`){let e=Se();if(e.length===0){console.log(`No active lanes.`);return}for(let t of e)console.log(`${t.name} (${t.sourceFiles.length} files, created ${t.createdAt})`);return}let n=e.shift();switch(n||(console.error(`Lane name is required for "${t}".`),process.exit(1)),t){case`create`:{let t=N(e,`--files`,``);t||(console.error(`Usage: aikit lane create <name> --files file1.ts,file2.ts`),process.exit(1));let r=ye(n,t.split(`,`).map(e=>e.trim()));console.log(`Lane "${r.name}" created with ${r.sourceFiles.length} files.`);break}case`status`:{let e=we(n);console.log(`Lane: ${e.name}`),console.log(`Modified: ${e.modified} | Added: ${e.added} | Deleted: ${e.deleted}`);for(let t of e.entries)console.log(` ${t.status.padEnd(10)} ${t.file}`);break}case`diff`:{let e=be(n);console.log(`Lane: ${e.name} — ${e.modified} modified, ${e.added} added, ${e.deleted} deleted`);for(let t of e.entries)t.diff&&(console.log(`\n--- ${t.file} (${t.status})`),console.log(t.diff));break}case`merge`:{let e=Ce(n);console.log(`Merged ${e.filesMerged} files from lane "${e.name}".`);for(let t of e.files)console.log(` ${t}`);break}case`discard`:{let e=xe(n);console.log(e?`Lane "${n}" discarded.`:`Lane "${n}" not found.`);break}}}},{name:`queue`,description:`Manage task queues for sequential agent operations`,usage:`aikit queue <create|push|next|done|fail|get|list|clear|delete> [name] [args]`,run:async e=>{let t=e.shift();if((!t||![`create`,`push`,`next`,`done`,`fail`,`get`,`list`,`clear`,`delete`].includes(t))&&(console.error(`Usage: aikit queue <create|push|next|done|fail|get|list|clear|delete> [name] [args]`),process.exit(1)),t===`list`){let e=Ee();if(e.length===0){console.log(`No queues.`);return}for(let t of e)console.log(`${t.name} pending:${t.pending} done:${t.done} failed:${t.failed} total:${t.total}`);return}let n=e.shift();switch(n||(console.error(`Queue name is required for "${t}".`),process.exit(1)),t){case`create`:{let e=w(n);console.log(`Queue "${e.name}" created.`);break}case`push`:{let t=Oe(n,e.join(` `)||`Untitled task`);console.log(`Pushed "${t.title}" (${t.id}) to queue "${n}".`);break}case`next`:{let e=De(n);console.log(e?`Next: ${e.title} (${e.id})`:`No pending items in queue "${n}".`);break}case`done`:{let t=e.shift();t||(console.error(`Usage: aikit queue done <name> <id>`),process.exit(1));let r=E(n,t);console.log(`Marked "${r.title}" as done.`);break}case`fail`:{let t=e.shift(),r=e.join(` `)||`Unknown error`;t||(console.error(`Usage: aikit queue fail <name> <id> [error message]`),process.exit(1));let i=D(n,t,r);console.log(`Marked "${i.title}" as failed: ${r}`);break}case`get`:{let e=O(n);if(!e){console.log(`Queue "${n}" not found.`);return}console.log(`Queue: ${e.name} (${e.items.length} items)`);for(let t of e.items){let e=t.error?` — ${t.error}`:``;console.log(` ${t.status.padEnd(12)} ${t.id} ${t.title}${e}`)}break}case`clear`:{let e=C(n);console.log(`Cleared ${e} completed/failed items from queue "${n}".`);break}case`delete`:{let e=T(n);console.log(e?`Queue "${n}" deleted.`:`Queue "${n}" not found.`);break}}}}],Q=[...kt,...Ot,...nt,...Dt,...At,...xt,...yt,...Nt,...bt,...Mt,...q];Q.push({name:`help`,description:`Show available commands`,run:async()=>{$()}});async function Pt(e){let t=[...e],n=t.shift();if(!n||n===`--help`||n===`-h`){$();return}if(n===`--version`||n===`-v`){let e=l(s(u(import.meta.url)),`..`,`..`,`..`,`package.json`),t=JSON.parse(a(e,`utf-8`));console.log(t.version);return}let r=Q.find(e=>e.name===n);r||(console.error(`Unknown command: ${n}`),$(),process.exit(1));try{await r.run(t)}finally{let e=Et();e&&await e.store.close()}}function $(){console.log(`@vpxa/aikit — Local-first AI developer toolkit
|
|
15
14
|
`),console.log(`Usage: aikit <command> [options]
|
|
16
15
|
`),console.log(`Commands:`);let e=Math.max(...Q.map(e=>e.name.length));for(let t of Q)console.log(` ${t.name.padEnd(e+2)}${t.description}`);console.log(``),console.log(`Options:`),console.log(` --help, -h Show this help`),console.log(` --version, -v Show version`)}export{Pt as run};
|
|
@@ -310,6 +310,9 @@ interface BuiltinFlow {
|
|
|
310
310
|
/**
|
|
311
311
|
* Returns all built-in flow definitions bundled with @aikit/flows.
|
|
312
312
|
* These flows are always available, even without installation via `flow add`.
|
|
313
|
+
*
|
|
314
|
+
* scaffoldDir points to the generated preview output (scaffold/_preview/flows/).
|
|
315
|
+
* Run `node scaffold/generate.mjs --ide flows` to populate it for dev mode.
|
|
313
316
|
*/
|
|
314
317
|
declare function getBuiltinFlows(): BuiltinFlow[];
|
|
315
318
|
//#endregion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import{copyFileSync as e,cpSync as t,existsSync as n,mkdirSync as r,readFileSync as i,readdirSync as a,rmSync as o,rmdirSync as s,symlinkSync as c,unlinkSync as l,writeFileSync as u}from"node:fs";import{basename as d,dirname as f,join as p,relative as m}from"node:path";import{parse as h}from"yaml";import{execSync as g,spawnSync as _}from"node:child_process";import{tmpdir as v}from"node:os";const y=[`spec`,`design`,`plan`,`task`,`execute`,`verify`];function b(e){let t=e.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);if(!t)return{data:{},body:e};let n=h(t[1]),r={};if(n&&typeof n==`object`&&!Array.isArray(n))for(let[e,t]of Object.entries(n))r[e]=String(t);return{data:r,body:t[2]}}function x(e){return e.split(/[-_]/g).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}function S(e){let t=y.indexOf(e);if(t!==-1)return t;let n=e.lastIndexOf(`.`);if(n!==-1){let t=e.slice(n+1),r=y.indexOf(t);if(r!==-1)return r}return 1/0}var C=class{format=`claude-plugin`;detect(e){return n(p(e,`.claude-plugin`,`plugin.json`))}async parse(e,t){let n=this.readPluginJson(e),r=this.discoverSteps(e);await this.materializeNativeSteps(e,r,t);let i=this.discoverAgents(e),a=r.map(({step:e})=>e);return{name:this.readString(n.name)??d(e),version:this.readString(n.version)??`1.0.0`,description:this.readString(n.description)??``,author:this.readString(n.author),steps:a,agents:i,artifacts_dir:`.spec`,install:[]}}readPluginJson(e){let t=p(e,`.claude-plugin`,`plugin.json`);return JSON.parse(i(t,`utf-8`))}readString(e){return typeof e==`string`?e:void 0}discoverSteps(e){let t=p(e,`skills`);if(!n(t))return[];let r=a(t,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name).map(t=>this.readStep(e,t)).filter(e=>e!==null).sort((e,t)=>{let n=Number(e.metadata.order),r=Number(t.metadata.order),i=Number.isFinite(n),a=Number.isFinite(r);if(i&&a)return n-r;if(i)return-1;if(a)return 1;let o=S(e.step.id),s=S(t.step.id);return o===s?e.step.id.localeCompare(t.step.id):o-s});return r.map((e,t)=>({...e,step:{...e.step,requires:t>0?[r[t-1].step.id]:[]}}))}readStep(e,t){let r=p(e,`skills`,t,`SKILL.md`);if(!n(r))return null;let a=i(r,`utf-8`),{data:o,body:s}=b(a),c=o.name||x(t),l=o.description||`${c} step`;return{step:{id:t,name:c,instruction:`steps/${t}/README.md`,produces:[`${t}.md`],requires:[],agents:[],description:l},metadata:o,content:a,body:s}}syncStepAssets(e,r,i){let a=[`references`,`assets`,`scripts`];for(let s of r)for(let r of a){let a=p(e,`skills`,s.id,r),c=p(e,`steps`,s.id,r);if(n(a)){if(n(c)){if(!i)continue;o(c,{recursive:!0,force:!0})}t(a,c,{recursive:!0})}}}async materializeNativeSteps(e,t,n){for(let i of t){let t=p(e,`steps`,i.step.id);r(t,{recursive:!0});let a=n?.transform?await n.transform({content:i.content,sourceFormat:`claude-plugin`,stepName:i.step.id,metadata:i.metadata}):this.buildStepReadme(i.step.name,i.step.description,i.body);u(p(t,`README.md`),a,`utf-8`)}this.syncStepAssets(e,t.map(({step:e})=>e),n?.forceAssetSync)}buildStepReadme(e,t,n){return[`# ${e}`,``,t,``,`---`,``,n.trim()].join(`
|
|
2
2
|
`).trimEnd().concat(`
|
|
3
|
-
`)}discoverAgents(e){let t=p(e,`agents`);return n(t)?a(t,{withFileTypes:!0}).filter(e=>e.isFile()&&e.name.endsWith(`.md`)).map(e=>`agents/${e.name}`):[]}},w=class{format=`copilot`;detect(e){return n(p(e,`.github`,`agents`))}async parse(e,t){let n=a(p(e,`.github`,`agents`),{withFileTypes:!0}).filter(e=>e.isFile()&&e.name.endsWith(`.md`)).map(e=>`.github/agents/${e.name}`),r=n.map(e=>this.getStepId(e)),i=n.map((e,t)=>{let n=r[t];return{id:n,name:n.charAt(0).toUpperCase()+n.slice(1),instruction:`steps/${n}/README.md`,produces:[`${n}.md`],requires:t>0?[r[t-1]]:[],agents:[e],description:`${n} agent step`}});return await this.materializeSteps(e,i,t),{name:d(e),version:`1.0.0`,description:`Copilot agents flow from ${d(e)}`,steps:i,agents:n,artifacts_dir:`.spec`,install:[]}}getStepId(e){return d(e,`.md`).toLowerCase().replace(/\.agent$/,``)}async materializeSteps(e,t,n){for(let a of t){let t=a.agents[0];if(!t)continue;let o=i(p(e,t),`utf-8`),s=p(e,`steps`,a.id),c=p(s,`README.md`);r(s,{recursive:!0}),u(c,n?.transform?await n.transform({content:o,sourceFormat:`copilot`,stepName:a.id,metadata:{sourcePath:t,displayName:a.name}}):`# ${a.name}\n\n${o}`,`utf-8`)}}},T=class{format=`native`;detect(e){return n(p(e,`flow.json`))}async parse(e){let t=i(p(e,`flow.json`),`utf-8`);return JSON.parse(t)}},E=class{format=`openspec`;detect(e){return!!(n(p(e,`openspec`,`config.yaml`))||n(p(e,`schemas`))&&this.findSchemaYaml(e))}async parse(e,t){let n=this.readMeta(e),r=this.loadSchema(e),i=this.buildStepsFromSchema(r);return await this.materializeSteps(e,i,r,t),{name:n.name,version:n.version,description:r.description??n.description,author:n.author,steps:i,agents:[],artifacts_dir:`openspec`,install:[]}}readMeta(e){let t=p(e,`package.json`);if(n(t))try{let n=JSON.parse(i(t,`utf-8`));return{name:n.name??d(e),version:n.version??`0.1.0`,description:n.description??`OpenSpec flow`,author:n.author}}catch{}return{name:d(e),version:`0.1.0`,description:`OpenSpec flow`}}readConfigSchema(e){let t=p(e,`openspec`,`config.yaml`);if(!n(t))return`spec-driven`;try{let e=h(i(t,`utf-8`));return typeof e?.schema==`string`&&e.schema.trim().length>0?e.schema:`spec-driven`}catch{return`spec-driven`}}resolveSchemaDir(e){let t=this.readConfigSchema(e),r=p(e,`openspec`,`schemas`,t);if(n(p(r,`schema.yaml`)))return r;let i=p(e,`schemas`,t);if(n(p(i,`schema.yaml`)))return i;try{let e=p(g(`npm root -g`,{encoding:`utf-8`,timeout:5e3,stdio:[`ignore`,`pipe`,`ignore`]}).trim(),`@fission-ai`,`openspec`,`schemas`,t);if(n(p(e,`schema.yaml`)))return e}catch{}return null}parseSchemaArtifacts(e){try{let t=h(e);if(!t||!Array.isArray(t.artifacts))return null;let n=t.artifacts.map(e=>this.normalizeArtifact(e)).filter(e=>e!==null);return n.length===0?null:{name:typeof t.name==`string`&&t.name.trim().length>0?t.name:this.readString(t.schema)??`spec-driven`,version:typeof t.version==`number`?t.version:1,description:this.readString(t.description),artifacts:n,apply:this.normalizeApply(t.apply)}}catch{return null}}loadSchema(e){let t=this.resolveSchemaDir(e);if(t){let e=p(t,`schema.yaml`);try{let t=i(e,`utf-8`),n=this.parseSchemaArtifacts(t);if(n)return n}catch{}}return this.discoverSchemaFromDirectory(e)}discoverSchemaFromDirectory(e){let t=[p(e,`openspec`,`schemas`),p(e,`schemas`)];for(let e of t)if(n(e))try{let t=a(e,{withFileTypes:!0}).filter(e=>e.isDirectory());for(let r of t){let t=p(e,r.name,`schema.yaml`);if(n(t))try{let e=this.parseSchemaArtifacts(i(t,`utf-8`));if(e)return e}catch{}}}catch{}let r=[],o=p(e,`openspec`),s=[],c=this.collectMarkdownFiles(o);for(let e of c){let t=m(o,e).replace(/\\/g,`/`),n=this.toStepIdFromMarkdown(t);!n||s.includes(n)||(r.push({id:n,generates:t,description:`${this.humanizeStepName(n)} phase`,template:d(e),requires:s.length>0?[s[s.length-1]]:[]}),s.push(n))}return{name:this.readConfigSchema(e),version:1,artifacts:r}}collectMarkdownFiles(e){if(!n(e))return[];let t=[];try{let n=a(e,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name));for(let r of n){let n=p(e,r.name);if(r.isFile()&&r.name.toLowerCase().endsWith(`.md`)){t.push(n);continue}r.isDirectory()&&t.push(...this.collectMarkdownFiles(n))}}catch{}return t}hasFileRecursive(e,t){if(!n(e))return!1;try{let n=a(e,{withFileTypes:!0});for(let r of n)if(r.isFile()&&r.name===t||r.isDirectory()&&this.hasFileRecursive(p(e,r.name),t))return!0}catch{}return!1}findSchemaYaml(e){let t=p(e,`schemas`);if(!n(t))return!1;try{return a(t,{withFileTypes:!0}).filter(e=>e.isDirectory()).some(e=>n(p(t,e.name,`schema.yaml`)))}catch{return!1}}toStepIdFromMarkdown(e){let t=e.replace(/\\/g,`/`).split(`/`).filter(Boolean);if(t.length===0)return null;let n=(t[t.length-1]??``).replace(/\.md$/i,``);return(n.toLowerCase()===`readme`&&t.length>1?t[t.length-2]:n).toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``)||null}buildStepsFromSchema(e){let t=e.artifacts.map(e=>({id:e.id,name:this.humanizeStepName(e.id),instruction:`steps/${e.id}/README.md`,produces:e.generates?[e.generates]:[],requires:e.requires,agents:[],description:e.description}));return e.apply&&t.push({id:`apply`,name:`Apply`,instruction:`steps/apply/README.md`,produces:[],requires:e.apply.requires,agents:[],description:`Implement the tasks, writing code and tests according to the design`}),t}async materializeSteps(e,t,i,a){let o=this.resolveSchemaDir(e),s=new Map(i.artifacts.map(e=>[e.id,e]));for(let c of t){let t=p(e,`steps`,c.id),l=p(t,`README.md`);r(t,{recursive:!0});let d=this.resolveInstructionContent(o,c.id,s.get(c.id),i.apply);if(!d){n(l)||u(l,`# ${c.name}\n\n${c.description}\n`,`utf-8`);continue}u(l,a?.transform?await a.transform({content:d,sourceFormat:`openspec`,stepName:c.id,metadata:{schemaName:i.name,displayName:c.name,description:c.description,produces:c.produces,requires:c.requires}}):`# ${c.name}\n\n${d}`,`utf-8`)}}resolveInstructionContent(e,t,r,a){if(t===`apply`&&a?.instruction)return a.instruction;if(!r)return null;if(r.instruction)return r.instruction;if(e&&r.template){let t=p(e,`templates`,r.template);if(n(t))try{return i(t,`utf-8`)}catch{}}return r.description||null}normalizeArtifact(e){if(!e||typeof e!=`object`)return null;let t=e,n=this.readString(t.id),r=this.readString(t.generates);return!n||!r?null:{id:n,generates:r,description:this.readString(t.description)??`${this.humanizeStepName(n)} phase`,template:this.readString(t.template)??``,instruction:this.readString(t.instruction),requires:this.readStringArray(t.requires)}}normalizeApply(e){if(!e||typeof e!=`object`)return;let t=e;return{requires:this.readStringArray(t.requires),tracks:this.readString(t.tracks)??null,instruction:this.readString(t.instruction)}}readString(e){return typeof e==`string`&&e.trim().length>0?e:void 0}readStringArray(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`&&e.length>0):[]}humanizeStepName(e){return e.split(/[-_]/g).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}};const D={name:`aikit:basic`,version:`0.1.0`,description:`Quick development flow for bug fixes, small features, and refactoring`,steps:[{id:`design`,name:`Design Gate`,instruction:`steps/design/README.md`,produces:[`design-decisions.md`],requires:[],agents:[`Researcher-Alpha`,`Researcher-Beta`,`Researcher-Gamma`,`Researcher-Delta`],description:`Evaluate task type, run brainstorming for features, FORGE classification. Auto-skips for bug fixes and refactors.`},{id:`assess`,name:`Assessment`,instruction:`steps/assess/README.md`,produces:[`assessment.md`],requires:[`design-decisions.md`],agents:[`Explorer`,`Researcher-Alpha`],description:`Understand scope, analyze codebase, identify approach`},{id:`implement`,name:`Implementation`,instruction:`steps/implement/README.md`,produces:[`progress.md`],requires:[`assessment.md`],agents:[`Implementer`,`Frontend`],description:`Write code following the assessment plan`},{id:`verify`,name:`Verification`,instruction:`steps/verify/README.md`,produces:[`verify-report.md`],requires:[`progress.md`],agents:[`Code-Reviewer-Alpha`,`Security`],description:`Review code, run tests, validate changes`}],agents:[],artifacts_dir:`.spec`,install:[]},O={name:`aikit:advanced`,version:`0.1.0`,description:`Full development flow for new features, API design, and architecture changes`,steps:[{id:`design`,name:`Design Gate`,instruction:`steps/design/README.md`,produces:[`design-decisions.md`],requires:[],agents:[`Researcher-Alpha`,`Researcher-Beta`,`Researcher-Gamma`,`Researcher-Delta`],description:`Full brainstorming, FORGE classification, decision protocol with parallel research. ADR for critical-tier tasks.`},{id:`spec`,name:`Specification`,instruction:`steps/spec/README.md`,produces:[`spec.md`],requires:[`design-decisions.md`],agents:[`Researcher-Alpha`],description:`Elicit requirements, clarify scope, define acceptance criteria`},{id:`plan`,name:`Planning`,instruction:`steps/plan/README.md`,produces:[`plan.md`],requires:[`spec.md`],agents:[`Planner`,`Explorer`],description:`Analyze codebase, design architecture, create implementation plan`},{id:`task`,name:`Task Breakdown`,instruction:`steps/task/README.md`,produces:[`tasks.md`],requires:[`plan.md`],agents:[`Planner`,`Architect-Reviewer-Alpha`],description:`Break plan into ordered implementation tasks with dependencies`},{id:`execute`,name:`Execution`,instruction:`steps/execute/README.md`,produces:[`progress.md`],requires:[`tasks.md`],agents:[`Orchestrator`,`Implementer`,`Frontend`,`Refactor`],description:`Implement all tasks, write code, write tests`},{id:`verify`,name:`Verification`,instruction:`steps/verify/README.md`,produces:[`verify-report.md`],requires:[`progress.md`],agents:[`Code-Reviewer-Alpha`,`Code-Reviewer-Beta`,`Architect-Reviewer-Alpha`,`Architect-Reviewer-Beta`,`Security`],description:`Dual code review, architecture review, security review, test validation`}],agents:[],artifacts_dir:`.spec`,install:[]};function k(){return[{manifest:D,scaffoldDir:`scaffold/flows/aikit-basic`},{manifest:O,scaffoldDir:`scaffold/flows/aikit-advanced`}]}const A=`<!-- aikit foundation context -->`,j=`<!-- end foundation context -->`;function M(e){let t=e.artifacts_dir||`.spec`;return`${A}
|
|
3
|
+
`)}discoverAgents(e){let t=p(e,`agents`);return n(t)?a(t,{withFileTypes:!0}).filter(e=>e.isFile()&&e.name.endsWith(`.md`)).map(e=>`agents/${e.name}`):[]}},w=class{format=`copilot`;detect(e){return n(p(e,`.github`,`agents`))}async parse(e,t){let n=a(p(e,`.github`,`agents`),{withFileTypes:!0}).filter(e=>e.isFile()&&e.name.endsWith(`.md`)).map(e=>`.github/agents/${e.name}`),r=n.map(e=>this.getStepId(e)),i=n.map((e,t)=>{let n=r[t];return{id:n,name:n.charAt(0).toUpperCase()+n.slice(1),instruction:`steps/${n}/README.md`,produces:[`${n}.md`],requires:t>0?[r[t-1]]:[],agents:[e],description:`${n} agent step`}});return await this.materializeSteps(e,i,t),{name:d(e),version:`1.0.0`,description:`Copilot agents flow from ${d(e)}`,steps:i,agents:n,artifacts_dir:`.spec`,install:[]}}getStepId(e){return d(e,`.md`).toLowerCase().replace(/\.agent$/,``)}async materializeSteps(e,t,n){for(let a of t){let t=a.agents[0];if(!t)continue;let o=i(p(e,t),`utf-8`),s=p(e,`steps`,a.id),c=p(s,`README.md`);r(s,{recursive:!0}),u(c,n?.transform?await n.transform({content:o,sourceFormat:`copilot`,stepName:a.id,metadata:{sourcePath:t,displayName:a.name}}):`# ${a.name}\n\n${o}`,`utf-8`)}}},T=class{format=`native`;detect(e){return n(p(e,`flow.json`))}async parse(e){let t=i(p(e,`flow.json`),`utf-8`);return JSON.parse(t)}},E=class{format=`openspec`;detect(e){return!!(n(p(e,`openspec`,`config.yaml`))||n(p(e,`schemas`))&&this.findSchemaYaml(e))}async parse(e,t){let n=this.readMeta(e),r=this.loadSchema(e),i=this.buildStepsFromSchema(r);return await this.materializeSteps(e,i,r,t),{name:n.name,version:n.version,description:r.description??n.description,author:n.author,steps:i,agents:[],artifacts_dir:`openspec`,install:[]}}readMeta(e){let t=p(e,`package.json`);if(n(t))try{let n=JSON.parse(i(t,`utf-8`));return{name:n.name??d(e),version:n.version??`0.1.0`,description:n.description??`OpenSpec flow`,author:n.author}}catch{}return{name:d(e),version:`0.1.0`,description:`OpenSpec flow`}}readConfigSchema(e){let t=p(e,`openspec`,`config.yaml`);if(!n(t))return`spec-driven`;try{let e=h(i(t,`utf-8`));return typeof e?.schema==`string`&&e.schema.trim().length>0?e.schema:`spec-driven`}catch{return`spec-driven`}}resolveSchemaDir(e){let t=this.readConfigSchema(e),r=p(e,`openspec`,`schemas`,t);if(n(p(r,`schema.yaml`)))return r;let i=p(e,`schemas`,t);if(n(p(i,`schema.yaml`)))return i;try{let e=p(g(`npm root -g`,{encoding:`utf-8`,timeout:5e3,stdio:[`ignore`,`pipe`,`ignore`]}).trim(),`@fission-ai`,`openspec`,`schemas`,t);if(n(p(e,`schema.yaml`)))return e}catch{}return null}parseSchemaArtifacts(e){try{let t=h(e);if(!t||!Array.isArray(t.artifacts))return null;let n=t.artifacts.map(e=>this.normalizeArtifact(e)).filter(e=>e!==null);return n.length===0?null:{name:typeof t.name==`string`&&t.name.trim().length>0?t.name:this.readString(t.schema)??`spec-driven`,version:typeof t.version==`number`?t.version:1,description:this.readString(t.description),artifacts:n,apply:this.normalizeApply(t.apply)}}catch{return null}}loadSchema(e){let t=this.resolveSchemaDir(e);if(t){let e=p(t,`schema.yaml`);try{let t=i(e,`utf-8`),n=this.parseSchemaArtifacts(t);if(n)return n}catch{}}return this.discoverSchemaFromDirectory(e)}discoverSchemaFromDirectory(e){let t=[p(e,`openspec`,`schemas`),p(e,`schemas`)];for(let e of t)if(n(e))try{let t=a(e,{withFileTypes:!0}).filter(e=>e.isDirectory());for(let r of t){let t=p(e,r.name,`schema.yaml`);if(n(t))try{let e=this.parseSchemaArtifacts(i(t,`utf-8`));if(e)return e}catch{}}}catch{}let r=[],o=p(e,`openspec`),s=[],c=this.collectMarkdownFiles(o);for(let e of c){let t=m(o,e).replace(/\\/g,`/`),n=this.toStepIdFromMarkdown(t);!n||s.includes(n)||(r.push({id:n,generates:t,description:`${this.humanizeStepName(n)} phase`,template:d(e),requires:s.length>0?[s[s.length-1]]:[]}),s.push(n))}return{name:this.readConfigSchema(e),version:1,artifacts:r}}collectMarkdownFiles(e){if(!n(e))return[];let t=[];try{let n=a(e,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name));for(let r of n){let n=p(e,r.name);if(r.isFile()&&r.name.toLowerCase().endsWith(`.md`)){t.push(n);continue}r.isDirectory()&&t.push(...this.collectMarkdownFiles(n))}}catch{}return t}hasFileRecursive(e,t){if(!n(e))return!1;try{let n=a(e,{withFileTypes:!0});for(let r of n)if(r.isFile()&&r.name===t||r.isDirectory()&&this.hasFileRecursive(p(e,r.name),t))return!0}catch{}return!1}findSchemaYaml(e){let t=p(e,`schemas`);if(!n(t))return!1;try{return a(t,{withFileTypes:!0}).filter(e=>e.isDirectory()).some(e=>n(p(t,e.name,`schema.yaml`)))}catch{return!1}}toStepIdFromMarkdown(e){let t=e.replace(/\\/g,`/`).split(`/`).filter(Boolean);if(t.length===0)return null;let n=(t[t.length-1]??``).replace(/\.md$/i,``);return(n.toLowerCase()===`readme`&&t.length>1?t[t.length-2]:n).toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``)||null}buildStepsFromSchema(e){let t=e.artifacts.map(e=>({id:e.id,name:this.humanizeStepName(e.id),instruction:`steps/${e.id}/README.md`,produces:e.generates?[e.generates]:[],requires:e.requires,agents:[],description:e.description}));return e.apply&&t.push({id:`apply`,name:`Apply`,instruction:`steps/apply/README.md`,produces:[],requires:e.apply.requires,agents:[],description:`Implement the tasks, writing code and tests according to the design`}),t}async materializeSteps(e,t,i,a){let o=this.resolveSchemaDir(e),s=new Map(i.artifacts.map(e=>[e.id,e]));for(let c of t){let t=p(e,`steps`,c.id),l=p(t,`README.md`);r(t,{recursive:!0});let d=this.resolveInstructionContent(o,c.id,s.get(c.id),i.apply);if(!d){n(l)||u(l,`# ${c.name}\n\n${c.description}\n`,`utf-8`);continue}u(l,a?.transform?await a.transform({content:d,sourceFormat:`openspec`,stepName:c.id,metadata:{schemaName:i.name,displayName:c.name,description:c.description,produces:c.produces,requires:c.requires}}):`# ${c.name}\n\n${d}`,`utf-8`)}}resolveInstructionContent(e,t,r,a){if(t===`apply`&&a?.instruction)return a.instruction;if(!r)return null;if(r.instruction)return r.instruction;if(e&&r.template){let t=p(e,`templates`,r.template);if(n(t))try{return i(t,`utf-8`)}catch{}}return r.description||null}normalizeArtifact(e){if(!e||typeof e!=`object`)return null;let t=e,n=this.readString(t.id),r=this.readString(t.generates);return!n||!r?null:{id:n,generates:r,description:this.readString(t.description)??`${this.humanizeStepName(n)} phase`,template:this.readString(t.template)??``,instruction:this.readString(t.instruction),requires:this.readStringArray(t.requires)}}normalizeApply(e){if(!e||typeof e!=`object`)return;let t=e;return{requires:this.readStringArray(t.requires),tracks:this.readString(t.tracks)??null,instruction:this.readString(t.instruction)}}readString(e){return typeof e==`string`&&e.trim().length>0?e:void 0}readStringArray(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`&&e.length>0):[]}humanizeStepName(e){return e.split(/[-_]/g).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}};const D={name:`aikit:basic`,version:`0.1.0`,description:`Quick development flow for bug fixes, small features, and refactoring`,steps:[{id:`design`,name:`Design Gate`,instruction:`steps/design/README.md`,produces:[`design-decisions.md`],requires:[],agents:[`Researcher-Alpha`,`Researcher-Beta`,`Researcher-Gamma`,`Researcher-Delta`],description:`Evaluate task type, run brainstorming for features, FORGE classification. Auto-skips for bug fixes and refactors.`},{id:`assess`,name:`Assessment`,instruction:`steps/assess/README.md`,produces:[`assessment.md`],requires:[`design-decisions.md`],agents:[`Explorer`,`Researcher-Alpha`],description:`Understand scope, analyze codebase, identify approach`},{id:`implement`,name:`Implementation`,instruction:`steps/implement/README.md`,produces:[`progress.md`],requires:[`assessment.md`],agents:[`Implementer`,`Frontend`],description:`Write code following the assessment plan`},{id:`verify`,name:`Verification`,instruction:`steps/verify/README.md`,produces:[`verify-report.md`],requires:[`progress.md`],agents:[`Code-Reviewer-Alpha`,`Security`],description:`Review code, run tests, validate changes`}],agents:[],artifacts_dir:`.spec`,install:[]},O={name:`aikit:advanced`,version:`0.1.0`,description:`Full development flow for new features, API design, and architecture changes`,steps:[{id:`design`,name:`Design Gate`,instruction:`steps/design/README.md`,produces:[`design-decisions.md`],requires:[],agents:[`Researcher-Alpha`,`Researcher-Beta`,`Researcher-Gamma`,`Researcher-Delta`],description:`Full brainstorming, FORGE classification, decision protocol with parallel research. ADR for critical-tier tasks.`},{id:`spec`,name:`Specification`,instruction:`steps/spec/README.md`,produces:[`spec.md`],requires:[`design-decisions.md`],agents:[`Researcher-Alpha`],description:`Elicit requirements, clarify scope, define acceptance criteria`},{id:`plan`,name:`Planning`,instruction:`steps/plan/README.md`,produces:[`plan.md`],requires:[`spec.md`],agents:[`Planner`,`Explorer`],description:`Analyze codebase, design architecture, create implementation plan`},{id:`task`,name:`Task Breakdown`,instruction:`steps/task/README.md`,produces:[`tasks.md`],requires:[`plan.md`],agents:[`Planner`,`Architect-Reviewer-Alpha`],description:`Break plan into ordered implementation tasks with dependencies`},{id:`execute`,name:`Execution`,instruction:`steps/execute/README.md`,produces:[`progress.md`],requires:[`tasks.md`],agents:[`Orchestrator`,`Implementer`,`Frontend`,`Refactor`],description:`Implement all tasks, write code, write tests`},{id:`verify`,name:`Verification`,instruction:`steps/verify/README.md`,produces:[`verify-report.md`],requires:[`progress.md`],agents:[`Code-Reviewer-Alpha`,`Code-Reviewer-Beta`,`Architect-Reviewer-Alpha`,`Architect-Reviewer-Beta`,`Security`],description:`Dual code review, architecture review, security review, test validation`}],agents:[],artifacts_dir:`.spec`,install:[]};function k(){return[{manifest:D,scaffoldDir:`scaffold/_preview/flows/aikit-basic`},{manifest:O,scaffoldDir:`scaffold/_preview/flows/aikit-advanced`}]}const A=`<!-- aikit foundation context -->`,j=`<!-- end foundation context -->`;function M(e){let t=e.artifacts_dir||`.spec`;return`${A}
|
|
4
4
|
You are operating within the @vpxa/aikit framework.
|
|
5
5
|
- Use aikit MCP tools for all search, analysis, and memory operations
|
|
6
6
|
- Follow agents defined in AGENTS.md for delegation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./curated-manager-DX-_oJg0.js";import{readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{fileURLToPath as i}from"node:url";import{parseArgs as
|
|
1
|
+
import{t as e}from"./curated-manager-DX-_oJg0.js";import{readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{fileURLToPath as i,pathToFileURL as a}from"node:url";import{parseArgs as o}from"node:util";import{createLogger as s,serializeError as c}from"../../core/dist/index.js";const l=n(i(import.meta.url)),u=(()=>{try{let e=r(l,`..`,`..`,`..`,`package.json`);return JSON.parse(t(e,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}})(),d=s(`server`),{values:f}=(()=>{let e=process.argv[1];if(!e)return!1;try{return import.meta.url===a(e).href}catch{return!1}})()?o({allowPositionals:!0,options:{transport:{type:`string`,default:process.env.AIKIT_TRANSPORT??`stdio`},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}}):{values:{transport:process.env.AIKIT_TRANSPORT??`stdio`,port:process.env.AIKIT_PORT??`3210`}};async function p(){if(process.on(`unhandledRejection`,e=>{d.error(`Unhandled rejection`,c(e))}),d.info(`Starting MCP AI Kit server`,{version:u}),f.transport===`http`){let[{default:e},{loadConfig:t,resolveIndexMode:n},{registerDashboardRoutes:r,resolveDashboardDir:i},{registerSettingsRoutes:a,resolveSettingsDir:o},{createSettingsRouter:s}]=await Promise.all([import(`express`),import(`./config-C5IU9Lau.js`),import(`./dashboard-static-BfIe0Si1.js`),import(`./settings-static-BosGZSPf.js`),import(`./routes-0OCkdgRe.js`)]),l=t();d.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path});let u=e();u.use(e.json());let p=Number(f.port);u.use((e,t,n)=>{if(t.setHeader(`Access-Control-Allow-Origin`,process.env.AIKIT_CORS_ORIGIN??`http://localhost:${p}`),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, PATCH, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization`),e.method===`OPTIONS`){t.status(204).end();return}n()}),r(u,i(),d);let m=new Date().toISOString();u.use(`/settings/api`,s({log:d,mcpInfo:()=>({transport:`http`,port:p,pid:process.pid,startedAt:m})})),a(u,o(),d),u.get(`/health`,(e,t)=>{t.json({status:`ok`})});let h=!1,g=null,_=null,v=null,y=Promise.resolve();u.post(`/mcp`,async(e,t)=>{if(!h||!_||!v){t.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let n=y,r;y=new Promise(e=>{r=e}),await n;try{let n=new v({sessionIdGenerator:void 0});await _.connect(n),await n.handleRequest(e,t,e.body),n.close()}catch(e){if(d.error(`MCP handler error`,c(e)),!t.headersSent){let n=e instanceof Error?e.message:String(e),r=n.includes(`Not Acceptable`);t.status(r?406:500).json({jsonrpc:`2.0`,error:{code:r?-32e3:-32603,message:r?n:`Internal server error`},id:null})}}finally{r()}}),u.get(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))}),u.delete(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))});let b=u.listen(p,`127.0.0.1`,()=>{d.info(`MCP server listening`,{url:`http://127.0.0.1:${p}/mcp`,port:p}),setTimeout(async()=>{try{let[{createLazyServer:e,ALL_TOOL_NAMES:t},{StreamableHTTPServerTransport:r},{checkForUpdates:i,autoUpgradeScaffold:a}]=await Promise.all([import(`./server-VgZC6Q43.js`),import(`@modelcontextprotocol/sdk/server/streamableHttp.js`),import(`./version-check-D4j0Pykd.js`)]);i(),a();let o=n(l),s=e(l,o);_=s.server,v=r,h=!0,d.info(`MCP server configured (lazy — AI Kit initializing in background)`,{toolCount:t.length,resourceCount:2}),s.startInit(),o===`auto`?s.ready.then(async()=>{try{let e=l.sources.map(e=>e.path).join(`, `);d.info(`Running initial index`,{sourcePaths:e}),await s.runInitialIndex(),d.info(`Initial index complete`)}catch(e){d.error(`Initial index failed; will retry on aikit_reindex`,c(e))}}).catch(e=>d.error(`AI Kit init or indexing failed`,c(e))):o===`smart`?s.ready.then(async()=>{try{if(!s.kb)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`);g=new e(s.kb.indexer,l,s.kb.store),g.start(),s.setSmartScheduler(g),d.info(`Smart index scheduler started (HTTP mode)`)}catch(e){d.error(`Failed to start smart index scheduler`,c(e))}}).catch(e=>d.error(`AI Kit initialization failed`,c(e))):(s.ready.catch(e=>d.error(`AI Kit initialization failed`,c(e))),d.info(`Initial full indexing skipped in HTTP mode`,{indexMode:o}))}catch(e){d.error(`Failed to load server modules`,c(e))}},100)}),x=async e=>{d.info(`Shutdown signal received`,{signal:e}),g?.stop(),b.close(),_&&await _.close(),process.exit(0)};process.on(`SIGINT`,()=>x(`SIGINT`)),process.on(`SIGTERM`,()=>x(`SIGTERM`))}else{let[{loadConfig:e,reconfigureForWorkspace:t,resolveIndexMode:n},{createLazyServer:r},{checkForUpdates:a,autoUpgradeScaffold:o},{RootsListChangedNotificationSchema:s}]=await Promise.all([import(`./config-C5IU9Lau.js`),import(`./server-VgZC6Q43.js`),import(`./version-check-D4j0Pykd.js`),import(`@modelcontextprotocol/sdk/types.js`)]),l=e();d.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path}),a(),o();let u=n(l),f=r(l,u),{server:p,startInit:m,ready:h,runInitialIndex:g}=f,{StdioServerTransport:_}=await import(`@modelcontextprotocol/sdk/server/stdio.js`),v=new _;await p.connect(v),d.info(`MCP server started`,{transport:`stdio`});let y=e=>{if(e.length===0)return!1;let n=e[0].uri,r=n.startsWith(`file://`)?i(n):n;return d.info(`MCP roots resolved`,{rootUri:n,rootPath:r,rootCount:e.length}),t(l,r),!0},b=!1;try{b=y((await p.server.listRoots()).roots),b||d.info(`No MCP roots yet; waiting for roots/list_changed notification`)}catch(e){d.warn(`MCP roots/list not supported by client; using cwd fallback`,{cwd:process.cwd(),...c(e)}),b=!0}b||=await new Promise(e=>{let t=setTimeout(()=>{d.warn(`Timed out waiting for MCP roots/list_changed; using cwd fallback`,{cwd:process.cwd()}),e(!1)},5e3);p.server.setNotificationHandler(s,async()=>{clearTimeout(t);try{e(y((await p.server.listRoots()).roots))}catch(t){d.warn(`roots/list retry failed after notification`,c(t)),e(!1)}})}),m();let x=null,S=()=>{x&&clearTimeout(x),x=setTimeout(()=>{d.info(`Auto-shutdown: no activity for 30 minutes — exiting`),process.exit(0)},18e5),x.unref&&x.unref()};S(),process.stdin.on(`data`,()=>S()),h.catch(e=>{d.error(`Initialization failed — server will continue with limited tools`,c(e))}),u===`auto`?g().catch(e=>d.error(`Initial index failed`,c(e))):u===`smart`?h.then(async()=>{try{if(!f.kb)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(f.kb.indexer,l,f.kb.store);t.start(),f.setSmartScheduler(t),d.info(`Smart index scheduler started (stdio mode)`)}catch(e){d.error(`Failed to start smart index scheduler`,c(e))}}).catch(e=>d.error(`AI Kit init failed for smart scheduler`,c(e))):d.warn(`Initial full indexing skipped; use aikit_reindex to index manually`,{indexMode:u})}}p().catch(e=>{d.error(`Fatal error`,c(e)),process.exit(1)});export{e as CuratedKnowledgeManager};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{existsSync as e,mkdirSync as t,readFileSync as n,renameSync as r,writeFileSync as i}from"node:fs";import{dirname as a,resolve as o}from"node:path";import{getGlobalDataDir as s,isUserInstalled as c}from"../../core/dist/index.js";import{z as l}from"zod";import{Router as u}from"express";const d=[{key:`serverName`,type:`string`,default:`aikit`,description:`MCP server name advertised to clients.`,group:`general`,requiresRestart:!0},{key:`toolPrefix`,type:`string`,default:``,description:`Prefix prepended to every MCP tool name (e.g. "aikit_").`,group:`general`,requiresRestart:!0},{key:`toolProfile`,type:`string`,default:`full`,description:`Active tool profile.`,group:`general`,enum:[`full`,`safe`,`research`,`minimal`,`discovery`],requiresRestart:!0},{key:`autoIndex`,type:`boolean`,default:!1,description:`Deprecated. Prefer indexMode. true → auto, false → manual.`,group:`indexing`},{key:`indexMode`,type:`string`,default:`smart`,description:`Indexing strategy. auto = full on startup, manual = on demand, smart = on-demand + idle.`,group:`indexing`,enum:[`auto`,`manual`,`smart`]},{key:`sources`,type:`array`,description:`Source roots to index. Each entry has { path, excludePatterns }.`,group:`indexing`,requiresRestart:!0},{key:`indexing.chunkSize`,type:`number`,default:1500,description:`Maximum chunk size in characters.`,group:`indexing`},{key:`indexing.chunkOverlap`,type:`number`,default:200,description:`Overlap between adjacent chunks.`,group:`indexing`},{key:`indexing.minChunkSize`,type:`number`,default:100,description:`Minimum chunk size before merging into the next chunk.`,group:`indexing`},{key:`indexing.concurrency`,type:`number`,description:`Max files processed concurrently. Defaults to half of CPU cores.`,group:`indexing`},{key:`embedding.model`,type:`string`,default:`mixedbread-ai/mxbai-embed-large-v1`,description:`Embedding model identifier.`,group:`embedding`,requiresRestart:!0},{key:`embedding.dimensions`,type:`number`,default:1024,description:`Embedding vector dimensions. Must match the model.`,group:`embedding`,requiresRestart:!0},{key:`store.backend`,type:`string`,default:`lancedb`,description:`Vector store backend.`,group:`store`,requiresRestart:!0},{key:`store.path`,type:`string`,description:`Filesystem path for the vector store.`,group:`store`,requiresRestart:!0},{key:`curated.path`,type:`string`,description:`Path to curated knowledge directory.`,group:`store`,requiresRestart:!0},{key:`onboardDir`,type:`string`,description:`Directory for onboard / produce_knowledge output.`,group:`store`,requiresRestart:!0},{key:`stateDir`,type:`string`,description:`Directory for session state (stash, checkpoints, etc.).`,group:`store`,requiresRestart:!0},{key:`er.enabled`,type:`boolean`,default:!1,description:`Enable enterprise RAG bridge integration.`,group:`enterprise-bridge`,requiresRestart:!0},{key:`er.baseUrl`,type:`string`,description:`Base URL of the ER API.`,group:`enterprise-bridge`,requiresRestart:!0},{key:`er.timeoutMs`,type:`number`,default:5e3,description:`ER request timeout in milliseconds.`,group:`enterprise-bridge`},{key:`er.fallbackThreshold`,type:`number`,default:.45,description:`Vector similarity threshold below which ER fallback triggers.`,group:`enterprise-bridge`}],f=[{key:`AIKIT_TRANSPORT`,type:`string`,default:`stdio`,description:`MCP transport mode.`,group:`transport`,enum:[`stdio`,`http`],defaultScope:`workspace`},{key:`AIKIT_PORT`,type:`string`,default:`3210`,description:`HTTP port when transport = http.`,group:`transport`,defaultScope:`workspace`},{key:`AIKIT_CORS_ORIGIN`,type:`string`,description:`CORS Access-Control-Allow-Origin header for HTTP mode.`,group:`transport`,defaultScope:`workspace`},{key:`AIKIT_CONFIG_PATH`,type:`string`,description:`Override path to aikit.config.json.`,group:`paths`,defaultScope:`workspace`},{key:`AIKIT_WORKSPACE_ROOT`,type:`string`,description:`Override workspace root used when no config file is present.`,group:`paths`,defaultScope:`workspace`},{key:`AIKIT_GLOBAL_DATA_DIR`,type:`string`,description:`Override global data directory (default: ~/.aikit-data).`,group:`paths`,defaultScope:`global`},{key:`AIKIT_INDEX_MODE`,type:`string`,description:`Override config indexMode.`,group:`indexing`,enum:[`auto`,`manual`,`smart`],defaultScope:`workspace`},{key:`AIKIT_AUTO_INDEX`,type:`string`,description:`Legacy boolean override. Prefer AIKIT_INDEX_MODE.`,group:`indexing`,enum:[`true`,`false`],defaultScope:`workspace`},{key:`AIKIT_TOOLSET`,type:`string`,description:`Override active tool profile.`,group:`general`,defaultScope:`workspace`},{key:`AIKIT_SEARCH_DEADLINE_MS`,type:`string`,default:`10000`,description:`Multi-provider web search deadline (milliseconds).`,group:`search-providers`,defaultScope:`global`},{key:`SEARXNG_URL`,type:`string`,description:`Optional SearXNG instance URL for the web_search tool.`,group:`search-providers`,defaultScope:`global`},{key:`GOOGLE_API_KEY`,type:`secret`,description:`Google Custom Search API key.`,group:`search-providers`,defaultScope:`global`},{key:`GOOGLE_CSE_ID`,type:`string`,description:`Google Custom Search Engine ID.`,group:`search-providers`,defaultScope:`global`},{key:`BRAVE_API_KEY`,type:`secret`,description:`Brave Search API key.`,group:`search-providers`,defaultScope:`global`},{key:`BING_API_KEY`,type:`secret`,description:`Bing Web Search API key.`,group:`search-providers`,defaultScope:`global`}];function p(e){return f.find(t=>t.key===e)}function m(e){let t=p(e);return t?t.type===`secret`:/(_KEY|_TOKEN|_SECRET|_PASSWORD|_PASS|_PWD)$/i.test(e)}const h=/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=(.*)$/;function g(e){let t=e.replace(/^\s+/,``);if(t.startsWith(`"`)){let e=1,n=``;for(;e<t.length;){let r=t[e];if(r===`\\`&&e+1<t.length){let r=t[e+1];r===`n`?n+=`
|
|
2
|
+
`:r===`r`?n+=`\r`:r===`t`?n+=` `:n+=r,e+=2;continue}if(r===`"`){let r=t.slice(e+1),i=r.indexOf(`#`),a=i===-1?``:r.slice(i);return{value:n,quoted:!0,inlineComment:a}}n+=r,e+=1}return{value:t.slice(1),quoted:!0,inlineComment:``}}let n=t.match(/(\s+#.*)$/);return n&&n.index!==void 0?{value:t.slice(0,n.index).trimEnd(),quoted:!1,inlineComment:n[1].trimStart()}:{value:t.trimEnd(),quoted:!1,inlineComment:``}}function _(e){let t;t=e.quoted||/[\s#"']/.test(e.value)||e.value.includes(`
|
|
3
|
+
`)||e.value.length===0?`"${e.value.replace(/\\/g,`\\\\`).replace(/"/g,`\\"`).replace(/\n/g,`\\n`).replace(/\r/g,`\\r`).replace(/\t/g,`\\t`)}"`:e.value;let n=e.inlineComment?` ${e.inlineComment}`:``;return`${e.key}=${t}${n}`}function v(e){let t=[],n=e.split(/\r?\n/),r=e.endsWith(`
|
|
4
|
+
`)?n.slice(0,-1):n;for(let e of r){let n=e.match(h);if(!n){t.push({kind:`raw`,text:e});continue}let r=n[1],{value:i,quoted:a,inlineComment:o}=g(n[2]);t.push({kind:`assign`,key:r,value:i,quoted:a,inlineComment:o})}return{lines:t}}function y(e){return`${e.lines.map(e=>e.kind===`assign`?_(e):e.text).join(`
|
|
5
|
+
`)}\n`}function b(e){let t={};for(let n of e.lines)n.kind===`assign`&&(t[n.key]=n.value);return t}function x(e,t,n){let r=e.lines.map(e=>e.kind===`assign`&&e.key===t?{...e,value:n}:e);return e.lines.some(e=>e.kind===`assign`&&e.key===t)||r.push({kind:`assign`,key:t,value:n,quoted:!1,inlineComment:``}),{lines:r}}function S(e,t){return{lines:e.lines.filter(e=>!(e.kind===`assign`&&e.key===t))}}function C(e){return o(e,`.env`)}function w(){return o(s(),`global.env`)}function T(e,t){return e===`workspace`?C(t):w()}function E(t){return e(t)?v(n(t,`utf-8`)):{lines:[]}}function D(n,o){let s=a(n);e(s)||t(s,{recursive:!0});let c=`${n}.${process.pid}.${Date.now()}.tmp`;i(c,y(o),{encoding:`utf-8`,mode:384}),r(c,n)}function O(t,n,r={}){let i=T(t,n),a=e(i),o=b(E(i)),s={};for(let[e,t]of Object.entries(o))s[e]=r.reveal||!m(e)?t:k(t);return{scope:t,path:i,exists:a,vars:s}}function k(e){return e.length===0?``:e.length<=4?`•`.repeat(e.length):`${e.slice(0,2)}${`•`.repeat(Math.min(e.length-4,12))}${e.slice(-2)}`}function A(){return process.env.AIKIT_WORKSPACE_ROOT??process.cwd()}function j(){return c()?`user`:`workspace`}function M(){let n=s();return e(n)||t(n,{recursive:!0}),n}var N=class extends Error{details;constructor(e,t){super(e),this.name=`ConfigValidationError`,this.details=t}};function P(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function F(e=A()){let t=process.env.AIKIT_CONFIG_PATH;return t?o(t):o(e,`aikit.config.json`)}function I(t){if(!e(t))return null;let r=n(t,`utf-8`),i=JSON.parse(r);if(!P(i))throw new N(`config-not-object`,[`Config file must contain a JSON object at the root.`]);return i}function L(n,o){let s=a(n);e(s)||t(s,{recursive:!0});let c=`${JSON.stringify(o,null,2)}\n`,l=`${n}.${process.pid}.${Date.now()}.tmp`;i(l,c,{encoding:`utf-8`}),r(l,n)}function R(e){return e.length===0?[]:e.split(`.`)}function z(e,t,n){let r=R(t);if(r.length===0)throw new N(`invalid-path`,[`Patch path must not be empty.`]);let i={...e},a=i;for(let e=0;e<r.length-1;e+=1){let t=r[e],n=r[e+1],i=/^\d+$/.test(n);if(Array.isArray(a)){let n=Number(t);if(!Number.isInteger(n))throw new N(`invalid-path`,[`Path segment "${t}" must be an integer index for array at depth ${e}.`]);let r=a[n];if(i){let e=Array.isArray(r)?[...r]:[];a[n]=e,a=e}else{let e=P(r)?{...r}:{};a[n]=e,a=e}continue}let o=a[t];if(i){let e=Array.isArray(o)?[...o]:[];a[t]=e,a=e}else{let e=P(o)?{...o}:{};a[t]=e,a=e}}let o=r[r.length-1];if(Array.isArray(a)){let e=Number(o);if(!Number.isInteger(e))throw new N(`invalid-path`,[`Path segment "${o}" must be an integer index for array.`]);a[e]=n}else a[o]=n;return i}function B(e,t){let n=R(t);if(n.length===0)throw new N(`invalid-path`,[`Patch path must not be empty.`]);let r={...e},i=r;for(let e=0;e<n.length-1;e+=1){let t=n[e];if(Array.isArray(i)){let e=Number(t);if(!Number.isInteger(e))return r;let n=i[e];if(!P(n)&&!Array.isArray(n))return r;let a=Array.isArray(n)?[...n]:{...n};i[e]=a,i=a;continue}let a=i[t];if(!P(a)&&!Array.isArray(a))return r;let o=Array.isArray(a)?[...a]:{...a};i[t]=o,i=o}let a=n[n.length-1];if(Array.isArray(i)){let e=Number(a);Number.isInteger(e)&&i.splice(e,1)}else delete i[a];return r}function V(e,t){let n=e;for(let e of t)n=e.op===`set`?z(n,e.path,e.value):B(n,e.path);return n}function H(e){let t=[];if(`autoIndex`in e&&e.autoIndex!==void 0&&typeof e.autoIndex!=`boolean`&&t.push(`autoIndex must be a boolean.`),`serverName`in e&&e.serverName!==void 0&&typeof e.serverName!=`string`&&t.push(`serverName must be a string.`),`toolPrefix`in e&&e.toolPrefix!==void 0&&typeof e.toolPrefix!=`string`&&t.push(`toolPrefix must be a string.`),`indexMode`in e&&e.indexMode!==void 0&&![`auto`,`manual`,`smart`].includes(e.indexMode)&&t.push(`indexMode must be one of: auto, manual, smart.`),(!Array.isArray(e.sources)||e.sources.length===0)&&t.push(`sources must be a non-empty array.`),`indexing`in e&&e.indexing!==void 0)if(!P(e.indexing))t.push(`indexing must be an object.`);else for(let n of[`chunkSize`,`chunkOverlap`,`minChunkSize`,`concurrency`]){let r=e.indexing[n];r!==void 0&&(typeof r!=`number`||!Number.isFinite(r)||r<=0)&&t.push(`indexing.${n} must be a positive number.`)}return`store`in e&&e.store!==void 0&&(P(e.store)?(typeof e.store.backend!=`string`&&t.push(`store.backend must be a string.`),typeof e.store.path!=`string`&&t.push(`store.path must be a string.`)):t.push(`store must be an object.`)),t}const U=l.object({ops:l.array(l.object({op:l.enum([`set`,`unset`]),path:l.string().min(1),value:l.unknown().optional()})).min(1)}),W=l.string().min(1).regex(/^[A-Za-z_][A-Za-z0-9_]*$/,`Invalid env key`),G=l.object({value:l.string(),scope:l.enum([`workspace`,`global`])}),K=l.enum([`workspace`,`global`]);function q(e,t,n,r){e.status(t).json({error:n,details:r})}function J(t){let n=u(),r=t.workspaceRoot??A;return n.get(`/status`,(n,i)=>{let a=r(),o=F(a);i.json({mode:j(),cwd:process.cwd(),workspaceRoot:a,configPath:o,configExists:e(o),globalDataDir:M(),envPaths:{workspace:C(a),global:w()},mcp:t.mcpInfo?.()??{transport:`http`,pid:process.pid,startedAt:new Date(0).toISOString()}})}),n.get(`/schema`,(e,t)=>{t.json({config:d,env:f})}),n.get(`/config`,(e,t)=>{let n=F(r());try{let e=I(n);t.json({path:n,exists:e!==null,content:e??{}})}catch(e){if(e instanceof N){q(t,400,e.message,e.details);return}q(t,500,`config-read-failed`,e instanceof Error?e.message:String(e))}}),n.patch(`/config`,(e,n)=>{let i=U.safeParse(e.body);if(!i.success){q(n,400,`invalid-body`,i.error.issues);return}let a=F(r()),o;try{o=I(a)??{}}catch(e){if(e instanceof N){q(n,400,e.message,e.details);return}q(n,500,`config-read-failed`,e instanceof Error?e.message:String(e));return}let s;try{s=V(o,i.data.ops)}catch(e){if(e instanceof N){q(n,400,e.message,e.details);return}q(n,400,`patch-failed`,e instanceof Error?e.message:String(e));return}let c=H(s);if(c.length>0){q(n,400,`invalid-config`,c);return}try{L(a,s)}catch(e){q(n,500,`config-write-failed`,e instanceof Error?e.message:String(e));return}t.log.info(`Settings: config updated`,{path:a,ops:i.data.ops.length}),n.json({path:a,content:s,restartRecommended:!0})}),n.get(`/env`,(e,n)=>{let i=e.query.reveal===`true`||e.query.reveal===`1`;i&&t.log.warn(`Settings: env values revealed`,{ip:e.ip??`unknown`});let a=r();n.json({workspace:O(`workspace`,a,{reveal:i}),global:O(`global`,a,{reveal:i}),processOverrides:Object.keys(process.env).filter(e=>e.startsWith(`AIKIT_`)||/^(SEARXNG_URL|GOOGLE_|BRAVE_|BING_)/.test(e)).sort()})}),n.put(`/env/:key`,(e,n)=>{let i=W.safeParse(e.params.key);if(!i.success){q(n,400,`invalid-key`,i.error.issues);return}let a=G.safeParse(e.body);if(!a.success){q(n,400,`invalid-body`,a.error.issues);return}let o=a.data.scope,s=T(o,r());try{D(s,x(E(s),i.data,a.data.value)),t.log.info(`Settings: env set`,{key:i.data,scope:o,path:s}),n.json({ok:!0,scope:o,path:s,restartRecommended:!0})}catch(e){q(n,500,`env-write-failed`,e instanceof Error?e.message:String(e))}}),n.delete(`/env/:key`,(e,n)=>{let i=W.safeParse(e.params.key);if(!i.success){q(n,400,`invalid-key`,i.error.issues);return}let a=K.safeParse(e.query.scope);if(!a.success){q(n,400,`invalid-scope`,a.error.issues);return}let o=a.data,s=T(o,r());try{D(s,S(E(s),i.data)),t.log.info(`Settings: env unset`,{key:i.data,scope:o,path:s}),n.json({ok:!0,scope:o,path:s,restartRecommended:!0})}catch(e){q(n,500,`env-write-failed`,e instanceof Error?e.message:String(e))}}),n}export{J as createSettingsRouter};
|
|
@@ -1260,10 +1260,10 @@ Use \`status({})\` to check smart indexing queue status.`}]};let l=oa(c).createT
|
|
|
1260
1260
|
|
|
1261
1261
|
`),j=(c===`hybrid`?`hybrid (vector + keyword RRF)`:c===`keyword`?`keyword (FTS)`:`semantic (vector)`)+E,M=el(b,e),te=M.length>0?`\n_Distinctive terms: ${M.map(e=>`\`${e}\``).join(`, `)}_`:``,ne=await nl(n,b),N=[];if(b.length===0)N.push("`reindex` — no results found, index may be stale"),N.push("`find` — try federated search with glob/regex");else{let e=b[0]?.record.sourcePath;e&&N.push(`\`lookup\` — see all chunks from \`${e}\``),N.push("`symbol` — resolve a specific symbol from the results"),N.push("`compact` — compress a result file for focused reading")}let re=[O?`${O}\n\n`:``,ne?`${ne}\n\n`:``,ee,`\n\n---\n_Search mode: ${j} | ${b.length} results_${te}`,`\n_Next: ${N.join(` | `)}_`],ie=C+re.join(``);g&&(ie=Xt(ie,g));let ae=new Set,oe=[];for(let e of b){if(e.record.origin!==`curated`||e.record.sourcePath.startsWith(`[`))continue;let t=qo(e.record.sourcePath);if(!t)continue;let n=Go(t,e.record.headingPath??t);n&&!ae.has(n.uri)&&(ae.add(n.uri),oe.push(n))}return{content:[{type:`text`,text:ie},...oe],structuredContent:{results:b.map(e=>({sourcePath:e.record.sourcePath,contentType:e.record.contentType,score:e.score,...e.record.headingPath?{headingPath:e.record.headingPath}:{},...e.record.startLine?{startLine:e.record.startLine}:{},...e.record.endLine?{endLine:e.record.endLine}:{},...e.record.origin===`indexed`?{}:{origin:e.record.origin},...e.record.category?{category:e.record.category}:{},...e.record.tags?.length?{tags:e.record.tags}:{}})),totalResults:b.length,searchMode:c,query:e}}}catch(e){return Yc.error(`Search failed`,A(e)),{content:[{type:`text`,text:`Search failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}const il=E(`tools`);function al(e,t){let n=L(`session_digest`);e.registerTool(`session_digest`,{title:n.title,description:`Compress the current session's tool trajectory into a focused digest. Aggregates replay log, stash state, and checkpoints. Supports deterministic and LLM-assisted (sampling) modes with configurable token budget.`,inputSchema:{scope:F.enum([`tools`,`stash`,`all`]).default(`all`).describe(`What to include: tools (replay only), stash (stash + checkpoints only), or all`),since:F.string().optional().describe(`ISO timestamp — only include activity after this time`),last:F.number().min(1).max(500).optional().describe(`Max replay entries to consider (default: 50)`),focus:F.string().optional().describe(`Focus query — prioritize entries matching this topic`),mode:F.enum([`deterministic`,`sampling`]).default(`deterministic`).describe(`Summary mode: deterministic (fast, template-based) or sampling (LLM-assisted, richer)`),token_budget:F.number().min(100).max(8e3).default(2e3).describe(`Target token budget for the digest output`),persist:F.boolean().default(!0).describe(`Auto-save digest to stash for crash recovery`)},annotations:n.annotations},async({scope:e,since:n,last:r,focus:i,mode:a,token_budget:o,persist:s})=>{try{let c={scope:e,since:n,last:r,focus:i,mode:a,tokenBudget:o,persist:s};return{content:[{type:`text`,text:(a===`sampling`&&t?.available?await Lt(c,async(e,n,r)=>(await t.createMessage({prompt:e,systemPrompt:n,maxTokens:r})).text):It(c)).digest}]}}catch(e){return il.error(`Session digest failed`,A(e)),{content:[{type:`text`,text:`Session digest failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}const ol=E(`tools`);function sl(e,t,n,r=15e3){let i,a=new Promise(e=>{i=setTimeout(()=>{ol.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),ol.warn(`Status sub-operation "${n}" failed: ${e instanceof Error?e.message:String(e)}`),{value:t,timedOut:!1})),a])}const cl=5*6e4;let ll=null,ul=null;function dl(e,t,n,r){let i=Math.min(e/2e4,1),a=Math.min((t+n)/5e4,1),o=Math.min(r/200,1);return Math.round(i*40+a*35+o*25)}function fl(){let e=Date.now();if(ll&&e-ll.ts<cl)return ll.value;try{let t=_(N(),`.copilot`,`.aikit-scaffold.json`);if(!a(t))return ll={value:null,ts:e},null;let n=JSON.parse(s(t,`utf-8`)).version??null;return ll={value:n,ts:e},n}catch{return ll={value:null,ts:e},null}}function pl(){let e=Date.now();if(ul&&e-ul.ts<cl)return ul.value;try{let t=_(process.cwd(),`.github`,`.aikit-scaffold.json`);if(!a(t))return ul={value:null,ts:e},null;let n=JSON.parse(s(t,`utf-8`)).version??null;return ul={value:n,ts:e},n}catch{return ul={value:null,ts:e},null}}function ml(e){let t=L(`status`);e.registerTool(`status`,{title:t.title,description:`Get the current status and statistics of the AI Kit index.`,outputSchema:gi,annotations:t.annotations},async()=>{let e=r(),t=fl(),a=pl(),o=t!=null&&t!==e,s=a!=null&&a!==e,c=[`## AI Kit Status`,``,`⏳ **AI Kit is initializing** — index stats will be available shortly.`,``,`### Runtime`,`- **Tree-sitter (WASM)**: ${re.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`,``,`### Version`,`- **Server**: ${e}`,`- **Scaffold (user)**: ${t??`not installed`}`,`- **Scaffold (workspace)**: ${a??`not installed`}`];if(o||s){let r=i(),l=[];o&&l.push(`user scaffold v${t}`),s&&l.push(`workspace scaffold v${a}`);let u=l.join(`, `);r.state===`success`?c.push(``,`### ✅ Upgrade Applied`,`- Server v${e} — ${u} auto-upgraded successfully.`,`- _Restart the MCP server to use the updated version._`):r.state===`pending`?c.push(``,`### ⏳ Upgrade In Progress`,`- Server v${e} ≠ ${u}`,`- Auto-upgrade is running in the background…`):r.state===`failed`?(n(),c.push(``,`### ⬆ Upgrade Available (auto-upgrade failed, retrying)`,`- Server v${e} ≠ ${u}`,`- Error: ${r.error??`unknown`}`)):(n(),c.push(``,`### ⬆ Upgrade Available`,`- Server v${e} ≠ ${u}`,`- Auto-upgrade triggered — check again shortly.`))}let l={totalRecords:0,totalFiles:0,lastIndexedAt:null,onboarded:!1,onboardDir:``,contentTypes:{},wasmAvailable:!!re.get(),graphStats:null,curatedCount:0,serverVersion:e,scaffoldVersion:t??null,workspaceScaffoldVersion:a??null,upgradeAvailable:o||s,contextPressure:0};return{content:[{type:`text`,text:c.join(`
|
|
1262
1262
|
`)}],structuredContent:l}})}function hl(e,t,o,s,c,l,u,f){let p=L(`status`);e.registerTool(`status`,{title:p.title,description:`Get the current status and statistics of the AI Kit index.`,outputSchema:gi,annotations:p.annotations},async()=>{let e=[];try{let[p,m]=await Promise.all([sl(t.getStats(),{totalRecords:0,totalFiles:0,lastIndexedAt:null,contentTypeBreakdown:{}},`store.getStats`),sl(t.listSourcePaths(),[],`store.listSourcePaths`)]),h=p.value;p.timedOut&&e.push(`⚠ Index stats timed out — values may be incomplete`);let g=m.value;m.timedOut&&e.push(`⚠ File listing timed out`);let v=null,b=0,x=[`## AI Kit Status`,``,`- **Total Records**: ${h.totalRecords}`,`- **Total Files**: ${h.totalFiles}`,`- **Last Indexed**: ${h.lastIndexedAt??`Never`}`,``,`### Content Types`,...Object.entries(h.contentTypeBreakdown).map(([e,t])=>`- ${e}: ${t}`),``,`### Indexed Files`,...g.slice(0,50).map(e=>`- ${e}`),g.length>50?`\n... and ${g.length-50} more files`:``];if(o)try{let t=await sl(o.getStats(),{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}},`graphStore.getStats`);if(t.timedOut)e.push(`⚠ Graph stats timed out`),x.push(``,`### Knowledge Graph`,`- Graph stats timed out`);else{let e=t.value;v={nodes:e.nodeCount,edges:e.edgeCount},x.push(``,`### Knowledge Graph`,`- **Nodes**: ${e.nodeCount}`,`- **Edges**: ${e.edgeCount}`,...Object.entries(e.nodeTypes).map(([e,t])=>` - ${e}: ${t}`));try{let e=await sl(o.validate(),{valid:!0,danglingEdges:[],orphanNodes:[],stats:{nodeCount:0,edgeCount:0,nodeTypes:{},edgeTypes:{}}},`graphStore.validate`);if(!e.timedOut){let t=e.value;t.valid||x.push(`- **⚠ Integrity Issues**: ${t.danglingEdges.length} dangling edges`),t.orphanNodes.length>0&&x.push(`- **Orphan nodes**: ${t.orphanNodes.length}`)}}catch{}}}catch{x.push(``,`### Knowledge Graph`,`- Graph store unavailable`)}let S=l?.onboardDir??_(process.cwd(),y.aiContext),C=a(S),w=c?.onboardComplete||C;if(x.push(``,`### Onboard Status`,w?`- ✅ Complete${c?.onboardTimestamp?` (last: ${c.onboardTimestamp})`:``}`:'- ❌ Not run — call `onboard({ path: "." })` to analyze the codebase',`- **Onboard Directory**: \`${S}\``),s)try{let t=await sl(s.list(),[],`curated.list`);if(t.timedOut)e.push(`⚠ Curated knowledge listing timed out`),x.push(``,`### Curated Knowledge`,`- Listing timed out`);else{let e=t.value;b=e.length,x.push(``,`### Curated Knowledge`,e.length>0?`- ${e.length} entries`:"- Empty — use `remember()` to persist decisions")}}catch{x.push(``,`### Curated Knowledge`,`- Unable to read curated entries`)}let T=dl(h.totalRecords,v?.nodes??0,v?.edges??0,b);x.push(``),x.push(`## 📊 Context Pressure: ${T}/100`),T>=80?x.push(`⚠️ High pressure — consider pruning stale entries or compacting context.`):T>=50?x.push(`ℹ️ Moderate pressure — knowledge base is well-populated.`):x.push(`✅ Low pressure — plenty of headroom for more content.`);let E=0;if(h.lastIndexedAt){E=new Date(h.lastIndexedAt).getTime();let e=(Date.now()-E)/(1e3*60*60);x.push(``,`### Index Freshness`,e>24?u===`smart`?`- ⚠ Last indexed ${Math.floor(e)}h ago — smart indexing will refresh automatically`:`- ⚠ Last indexed ${Math.floor(e)}h ago — may be stale. Run \`reindex({})\``:`- ✅ Last indexed ${e<1?`less than 1h`:`${Math.floor(e)}h`} ago`)}if(u===`smart`)if(x.push(``,`### Smart Indexing`),f){let e=f();e?x.push(`- **Mode**: Smart (trickle)`,`- **Status**: ${e.running?`✅ Running`:`⏸ Stopped`}`,`- **Queue**: ${e.queueSize} files pending`,`- **Changed files**: ${e.changedFilesSize} detected`,`- **Interval**: ${Math.round(e.intervalMs/1e3)}s per batch of ${e.batchSize}`):x.push(`- **Mode**: Smart (trickle)`,`- **Status**: scheduler state unavailable (init may have failed)`)}else x.push(`- **Mode**: Smart (trickle) — scheduler state unavailable`);{try{let e=_(process.cwd(),y.data,`stash`);if(a(e)){let t=d(e).mtimeMs;t>E&&(E=t)}}catch{}let e=[];if(s)try{let t=b>0?await s.list():[];for(let e of t){let t=new Date(e.updated||e.created).getTime();t>E&&(E=t)}e.push(...t.sort((e,t)=>new Date(t.updated).getTime()-new Date(e.updated).getTime()).slice(0,5))}catch{}let t=E>0?Date.now()-E:0;if(t>=144e5){let n=Math.floor(t/36e5);if(x.push(``,`### 🌅 Session Briefing`,`_${n}+ hours since last activity — here's what to pick up:_`,``),e.length>0){x.push(`**Recent decisions/notes:**`);for(let t of e)x.push(`- **${t.title}** (${t.category??`note`}) — ${(t.contentPreview??``).slice(0,80)}…`)}x.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")}}x.push(``,`### Runtime`,`- **Tree-sitter (WASM)**: ${re.get()?`✅ Available (AST analysis)`:`⚠ Unavailable (regex fallback)`}`);let D=fl(),O=pl(),k=r(),ee=D!=null&&D!==k,A=O!=null&&O!==k;if(ee||A){let e=i(),t=[];ee&&t.push(`user scaffold v${D}`),A&&t.push(`workspace scaffold v${O}`);let r=t.join(`, `);e.state===`success`?x.push(``,`### ✅ Upgrade Applied`,`- Server v${k} — ${r} auto-upgraded successfully.`,`- _Restart the MCP server to use the updated version._`):e.state===`pending`?x.push(``,`### ⏳ Upgrade In Progress`,`- Server v${k} ≠ ${r}`,`- Auto-upgrade is running in the background…`):e.state===`failed`?(n(),x.push(``,`### ⬆ Upgrade Available (auto-upgrade failed, retrying)`,`- Server v${k} ≠ ${r}`,`- Error: ${e.error??`unknown`}`)):(n(),x.push(``,`### ⬆ Upgrade Available`,`- Server v${k} ≠ ${r}`,`- Auto-upgrade triggered — check again shortly.`))}e.length>0&&x.push(``,`### ⚠ Warnings`,...e.map(e=>`- ${e}`));let j=Br();if(j.length>0){let e=j.sort((e,t)=>t.callCount-e.callCount);x.push(``,`### Tool Usage This Session`,``),x.push(`| Tool | Calls | Tokens In | Tokens Out | Errors | Avg Latency |`),x.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);x.push(`| ${t.tool} | ${t.callCount} | ${e.toLocaleString()} | ${n.toLocaleString()} | ${t.errorCount} | ${r}ms |`)}}let M=Nr();if(M.bufferSize>=10){let e=M.state===`healthy`?`🟢`:M.state===`degraded`?`🔴`:`🟡`;x.push(``,`### Auto-GC: ${e} ${M.state}`),x.push(`- p95 latency: ${M.p95}ms | buffer: ${M.bufferSize} samples`),M.gcCount>0&&x.push(`- GC cycles triggered: ${M.gcCount}`)}let te=x.join(`
|
|
1263
|
-
`),ne={totalRecords:h.totalRecords,totalFiles:h.totalFiles,lastIndexedAt:h.lastIndexedAt??null,onboarded:w,onboardDir:S,contentTypes:h.contentTypeBreakdown,wasmAvailable:!!re.get(),graphStats:v,curatedCount:b,serverVersion:k,scaffoldVersion:D??null,workspaceScaffoldVersion:O??null,upgradeAvailable:ee||A,contextPressure:T};return{content:[{type:`text`,text:te+(u===`smart`?"\n\n---\n_Next: Use `search` to query indexed content or `graph({action:'find_nodes', name_pattern:'<top-level-module>'})` → then `graph({action:'neighbors', node_id})` for relationships. Smart indexing handles updates automatically._":"\n\n---\n_Next: Use `search` to query indexed content, `graph({action:'find_nodes', name_pattern:'<top-level-module>'})` → then `graph({action:'neighbors', node_id})` for relationships, or `reindex` to refresh the index._")}],structuredContent:ne}}catch(e){return ol.error(`Status failed`,A(e)),{content:[{type:`text`,text:`Status check failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}const gl=E(`tools`);function _l(e,t,n){let r=L(`update`);e.registerTool(`update`,{title:r.title,description:`Update an existing curated knowledge entry. Increments version and records the reason in the changelog.`,inputSchema:{path:F.string().describe(`Relative path within .ai/curated/ (e.g., "decisions/use-lancedb.md")`),content:F.string().min(10).max(1e5).describe(`New markdown content to replace existing content`),reason:F.string().min(3).max(1e3).describe(`Why this update is being made (recorded in changelog)`)},annotations:r.annotations},async({path:e,content:r,reason:i})=>{try{let a=await t.update(e,r,i);return n&&n.notifyAfterCuratedWrite(e).catch(()=>{}),{content:[{type:`text`,text:`Updated: \`.ai/curated/${a.path}\` → version ${a.version}\n\nReason: ${i}\n\n---\n_Next: Use \`read\` to verify the updated content, or \`search\` to test searchability._`}]}}catch(e){return gl.error(`Update failed`,A(e)),{content:[{type:`text`,text:`Update failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}const Z=E(`tools`);function vl(e){let t=L(`web_search`);e.registerTool(`web_search`,{title:t.title,description:`PREFERRED web search —
|
|
1264
|
-
`)};if(
|
|
1263
|
+
`),ne={totalRecords:h.totalRecords,totalFiles:h.totalFiles,lastIndexedAt:h.lastIndexedAt??null,onboarded:w,onboardDir:S,contentTypes:h.contentTypeBreakdown,wasmAvailable:!!re.get(),graphStats:v,curatedCount:b,serverVersion:k,scaffoldVersion:D??null,workspaceScaffoldVersion:O??null,upgradeAvailable:ee||A,contextPressure:T};return{content:[{type:`text`,text:te+(u===`smart`?"\n\n---\n_Next: Use `search` to query indexed content or `graph({action:'find_nodes', name_pattern:'<top-level-module>'})` → then `graph({action:'neighbors', node_id})` for relationships. Smart indexing handles updates automatically._":"\n\n---\n_Next: Use `search` to query indexed content, `graph({action:'find_nodes', name_pattern:'<top-level-module>'})` → then `graph({action:'neighbors', node_id})` for relationships, or `reindex` to refresh the index._")}],structuredContent:ne}}catch(e){return ol.error(`Status failed`,A(e)),{content:[{type:`text`,text:`Status check failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}const gl=E(`tools`);function _l(e,t,n){let r=L(`update`);e.registerTool(`update`,{title:r.title,description:`Update an existing curated knowledge entry. Increments version and records the reason in the changelog.`,inputSchema:{path:F.string().describe(`Relative path within .ai/curated/ (e.g., "decisions/use-lancedb.md")`),content:F.string().min(10).max(1e5).describe(`New markdown content to replace existing content`),reason:F.string().min(3).max(1e3).describe(`Why this update is being made (recorded in changelog)`)},annotations:r.annotations},async({path:e,content:r,reason:i})=>{try{let a=await t.update(e,r,i);return n&&n.notifyAfterCuratedWrite(e).catch(()=>{}),{content:[{type:`text`,text:`Updated: \`.ai/curated/${a.path}\` → version ${a.version}\n\nReason: ${i}\n\n---\n_Next: Use \`read\` to verify the updated content, or \`search\` to test searchability._`}]}}catch(e){return gl.error(`Update failed`,A(e)),{content:[{type:`text`,text:`Update failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}const Z=E(`tools`);function vl(e){let t=L(`web_search`);e.registerTool(`web_search`,{title:t.title,description:`PREFERRED web search — fans out to multiple keyless providers (DuckDuckGo + Bing-HTML + Mojeek) by default, returning a deduplicated, consensus-ranked union within a 10s deadline. Optional providers (SearXNG, Google, Brave, Bing API) join the fan-out automatically when their env vars are set. Pass one query or multiple for parallel searching.`,inputSchema:{queries:F.array(F.string().max(2e3)).min(1).max(5).describe('Search queries (1–5). Single: `["react hooks"]`. Multiple searched in parallel.'),limit:F.number().min(1).max(20).default(5).describe(`Max results per query`),site:F.string().optional().describe(`Restrict to domain (e.g., "docs.aws.amazon.com")`),provider:F.enum([`multi`,`duckduckgo`,`bing-html`,`mojeek`,`searxng`,`google`,`brave`,`bing`]).optional().describe("Search provider. Defaults to env AIKIT_SEARCH_PROVIDER, then `multi` (fan-out). Single keyless: `duckduckgo`, `bing-html`, `mojeek`. Self-hosted: `searxng` (requires SEARXNG_URL). Keyed APIs: `google` (GOOGLE_API_KEY+GOOGLE_CSE_ID), `brave` (BRAVE_API_KEY), `bing` (BING_API_KEY). Missing keys auto-fall back to duckduckgo.")},annotations:t.annotations},async({queries:e,limit:t,site:n,provider:r})=>{let i=e,a=async e=>{let i=await tn({query:e,limit:t,site:n,provider:r}),a=[`## Search: ${i.query} _(via ${i.provider})_`,``];if(i.results.length===0)a.push(`No results found.`);else for(let e of i.results)a.push(`### [${e.title}](${e.url})`,e.snippet,``);return a.join(`
|
|
1264
|
+
`)};if(i.length===1)try{return{content:[{type:`text`,text:`${await a(i[0])}\n---\n_Next: Use \`web_fetch\` to read any of these pages in full._`}]}}catch(e){return Z.error(`Web search failed`,A(e)),{content:[{type:`text`,text:`Web search failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}let o=await Promise.allSettled(i.map(e=>a(e))),s=[],c=0;for(let e=0;e<o.length;e++){let t=o[e];if(t.status===`fulfilled`)s.push(t.value);else{c++;let n=t.reason instanceof Error?t.reason.message:String(t.reason);Z.error(`Web search failed`,{query:i[e],error:n}),s.push(`## ❌ Search failed: ${i[e]}\n\n${n}`)}}let l=`_Searched ${o.length-c}/${o.length} queries successfully._`;return s.push(``,`---`,l,"_Next: Use `web_fetch` to read any of these pages in full._"),{content:[{type:`text`,text:s.join(`
|
|
1265
1265
|
|
|
1266
|
-
`)}],...
|
|
1266
|
+
`)}],...c===o.length?{isError:!0}:{}}})}function yl(e){let t=L(`http`);e.registerTool(`http`,{title:t.title,description:`Make HTTP requests (GET/POST/PUT/PATCH/DELETE/HEAD) for API testing. Returns status, headers, and formatted body with timing info.`,inputSchema:{url:F.string().url().describe(`Request URL (http/https only)`),method:F.enum([`GET`,`POST`,`PUT`,`PATCH`,`DELETE`,`HEAD`]).default(`GET`).describe(`HTTP method`),headers:F.record(F.string(),F.string()).optional().describe(`Request headers as key-value pairs`),body:F.string().optional().describe(`Request body (for POST/PUT/PATCH)`),timeout:F.number().min(1e3).max(6e4).default(15e3).describe(`Timeout in milliseconds`)},annotations:t.annotations},async({url:e,method:t,headers:n,body:r,timeout:i})=>{try{let a=await $e({url:e,method:t,headers:n,body:r,timeout:i}),o=[`## ${t} ${e}`,``,`**Status:** ${a.status} ${a.statusText}`,`**Time:** ${a.durationMs}ms`,`**Size:** ${a.sizeBytes} bytes`,`**Content-Type:** ${a.contentType}`,``,`### Headers`,"```json",JSON.stringify(a.headers),"```",``,`### Body`,a.contentType.includes(`json`)?"```json":"```",a.body,"```"];return a.truncated&&o.push(``,`_Response truncated — total size: ${a.sizeBytes} bytes_`),{content:[{type:`text`,text:o.join(`
|
|
1267
1267
|
`)}]}}catch(e){return Z.error(`HTTP request failed`,A(e)),{content:[{type:`text`,text:`HTTP request failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function bl(e){let t=L(`regex_test`);e.registerTool(`regex_test`,{title:t.title,description:`Test a regex pattern against sample strings. Supports match, replace, and split modes.`,inputSchema:{pattern:F.string().max(500).describe(`Regex pattern (without delimiters)`),flags:F.string().max(10).regex(/^[gimsuy]*$/).default(``).describe(`Regex flags (g, i, m, s, etc.)`),test_strings:F.array(F.string().max(1e4)).max(50).describe(`Strings to test the pattern against`),mode:F.enum([`match`,`replace`,`split`]).default(`match`).describe(`Test mode`),replacement:F.string().optional().describe(`Replacement string (for replace mode)`)},annotations:t.annotations},async({pattern:e,flags:t,test_strings:n,mode:r,replacement:i})=>{let a=Tt({pattern:e,flags:t,testStrings:n,mode:r,replacement:i});if(!a.valid)return{content:[{type:`text`,text:`Invalid regex: ${a.error}`}],isError:!0};let o=[`## Regex: \`/${a.pattern}/${a.flags}\``,``,`Mode: ${r}`,``];for(let e of a.results){if(o.push(`**Input:** \`${e.input}\``),o.push(`**Matched:** ${e.matched}`),e.matches)for(let t of e.matches){let e=t.groups.length>0?` groups: [${t.groups.join(`, `)}]`:``;o.push(` - "${t.full}" at index ${t.index}${e}`)}e.replaced!==void 0&&o.push(`**Result:** \`${e.replaced}\``),e.split&&o.push(`**Split:** ${JSON.stringify(e.split)}`),o.push(``)}return{content:[{type:`text`,text:o.join(`
|
|
1268
1268
|
`)}]}})}function xl(e){let t=L(`encode`);e.registerTool(`encode`,{title:t.title,description:`Encode, decode, or hash text. Supports base64, URL encoding, SHA-256, MD5, JWT decode, hex.`,inputSchema:{operation:F.enum([`base64_encode`,`base64_decode`,`url_encode`,`url_decode`,`sha256`,`md5`,`jwt_decode`,`hex_encode`,`hex_decode`]).describe(`Operation to perform`),input:F.string().max(1e6).describe(`Input text`)},annotations:t.annotations},async({operation:e,input:t})=>{try{let n=Le({operation:e,input:t});return{content:[{type:`text`,text:`## ${e}\n\n**Input:** \`${t.length>100?`${t.slice(0,100)}...`:t}\`\n**Output:**\n\`\`\`\n${n.output}\n\`\`\``}]}}catch(e){return Z.error(`Encode failed`,A(e)),{content:[{type:`text`,text:`Encode failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function Sl(e){let t=L(`measure`);e.registerTool(`measure`,{title:t.title,description:`Measure code complexity, line counts, and function counts for a file or directory. Returns per-file metrics sorted by complexity.`,outputSchema:yi,inputSchema:{path:F.string().describe(`File or directory path to measure`),extensions:F.array(F.string()).optional().describe(`File extensions to include (default: .ts,.tsx,.js,.jsx)`)},annotations:t.annotations},async({path:e,extensions:t})=>{try{let n=await ct({path:e,extensions:t}),r=[`## Code Metrics`,``,`**Files:** ${n.summary.totalFiles}`,`**Total lines:** ${n.summary.totalLines} (${n.summary.totalCodeLines} code)`,`**Functions:** ${n.summary.totalFunctions}`,`**Avg complexity:** ${n.summary.avgComplexity}`,`**Max complexity:** ${n.summary.maxComplexity.value} (${n.summary.maxComplexity.file})`,``,`### Top files by complexity`,``,`| File | Lines | Code | Complexity | Cognitive | Functions | Imports |`,`|------|-------|------|------------|-----------|-----------|---------|`];for(let e of n.files.slice(0,20)){let t=e.cognitiveComplexity===void 0?`—`:String(e.cognitiveComplexity);r.push(`| ${e.path} | ${e.lines.total} | ${e.lines.code} | ${e.complexity} | ${t} | ${e.functions} | ${e.imports} |`)}n.files.length>20&&r.push(``,`_...and ${n.files.length-20} more files_`);let i={summary:{totalFiles:n.summary.totalFiles,totalLines:n.summary.totalLines,totalCodeLines:n.summary.totalCodeLines,totalFunctions:n.summary.totalFunctions,avgComplexity:n.summary.avgComplexity,maxComplexity:{value:n.summary.maxComplexity.value,file:n.summary.maxComplexity.file}},files:n.files.map(e=>({path:e.path,lines:e.lines.total,code:e.lines.code,complexity:e.complexity,functions:e.functions}))};return{content:[{type:`text`,text:r.join(`
|
|
1269
1269
|
`)}],structuredContent:i}}catch(e){return Z.error(`Measure failed`,A(e)),{content:[{type:`text`,text:`Measure failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function Cl(e){let t=L(`changelog`);e.registerTool(`changelog`,{title:t.title,description:`Generate a changelog from git history between two refs. Groups by conventional commit type.`,inputSchema:{from:F.string().max(200).describe(`Start ref (tag, SHA, HEAD~N)`),to:F.string().max(200).default(`HEAD`).describe(`End ref (default: HEAD)`),format:F.enum([`grouped`,`chronological`,`per-scope`]).default(`grouped`).describe(`Output format`),include_breaking:F.boolean().default(!0).describe(`Highlight breaking changes`),cwd:F.string().optional().describe(`Repository root or working directory`)},annotations:t.annotations},async({from:e,to:t,format:n,include_breaking:r,cwd:i})=>{try{let a=xe({from:e,to:t,format:n,includeBreaking:r,cwd:i}),o=`${a.stats.total} commits (${Object.entries(a.stats.types).map(([e,t])=>`${t} ${e}`).join(`, `)})`;return{content:[{type:`text`,text:`${a.markdown}\n---\n_${o}_`}]}}catch(e){return Z.error(`Changelog failed`,A(e)),{content:[{type:`text`,text:`Changelog failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}})}function wl(e){let t=L(`schema_validate`);e.registerTool(`schema_validate`,{title:t.title,description:`Validate JSON data against a JSON Schema. Supports type, required, properties, items, enum, pattern, min/max.`,inputSchema:{data:F.string().max(5e5).describe(`JSON data to validate (as string)`),schema:F.string().max(5e5).describe(`JSON Schema to validate against (as string)`)},annotations:t.annotations},async({data:e,schema:t})=>{try{let n=Pt({data:JSON.parse(e),schema:JSON.parse(t)});if(n.valid)return{content:[{type:`text`,text:`## Validation: PASSED
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createReadStream as e,existsSync as t,statSync as n}from"node:fs";import{dirname as r,extname as i,join as a,resolve as o,sep as s}from"node:path";import{fileURLToPath as c}from"node:url";const l=import.meta.dirname??r(c(import.meta.url)),u={".html":`text/html`,".js":`application/javascript`,".css":`text/css`,".json":`application/json`,".png":`image/png`,".svg":`image/svg+xml`,".ico":`image/x-icon`,".woff":`font/woff`,".woff2":`font/woff2`};function d(e=l){return a(e,`..`,`..`,`settings-ui`,`dist`)}function f(e,r){let c=r.replace(/^\/settings\/?/,``)||`index.html`;if(c.startsWith(`api/`)||c===`api`)return{kind:`not-found`};try{c=decodeURIComponent(c)}catch{}let l=o(e,c);if(!(l===e||l.startsWith(`${e}${s}`)))return{kind:`forbidden`};try{if(n(l).isFile())return{kind:`file`,path:l,contentType:u[i(l)]??`application/octet-stream`}}catch{}let d=a(e,`index.html`);return t(d)?{kind:`spa`,path:d,contentType:`text/html`}:{kind:`not-found`}}function p(n,r,i){return t(r)?(n.get(`/settings{/*path}`,(t,n)=>{let i=f(r,t.path);if(i.kind===`forbidden`){n.status(403).end(`Forbidden`);return}if(i.kind===`not-found`){n.status(404).end(`Not found`);return}n.setHeader(`Content-Type`,i.contentType),i.kind===`file`&&/\.[a-f0-9]{8,}\.(js|css)$/i.test(i.path)?n.setHeader(`Cache-Control`,`public, max-age=31536000, immutable`):n.setHeader(`Cache-Control`,`no-cache`),e(i.path).pipe(n)}),i.info(`Settings UI available`,{url:`/settings/`,dir:r}),!0):!1}export{p as registerSettingsRoutes,d as resolveSettingsDir,f as resolveSettingsRequest};
|