@vpxa/kb 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/package.json +1 -1
- package/packages/cli/dist/commands/init.d.ts +2 -1
- package/packages/cli/dist/commands/init.js +246 -6
- package/packages/cli/dist/index.js +2 -2
- package/packages/tools/dist/onboard.js +21 -21
- package/packages/tui/dist/App.js +48 -48
- package/packages/tui/dist/index.js +13 -13
package/README.md
CHANGED
|
@@ -34,18 +34,20 @@ The KB auto-indexes configured source directories on startup, stores embeddings
|
|
|
34
34
|
pnpm add -D @vpxa/kb
|
|
35
35
|
|
|
36
36
|
# Initialize in your project
|
|
37
|
-
npx kb init
|
|
37
|
+
npx @vpxa/kb init
|
|
38
38
|
|
|
39
39
|
# Index your codebase
|
|
40
|
-
npx kb reindex
|
|
40
|
+
npx @vpxa/kb reindex
|
|
41
41
|
|
|
42
42
|
# Search
|
|
43
|
-
npx kb search "authentication middleware"
|
|
43
|
+
npx @vpxa/kb search "authentication middleware"
|
|
44
44
|
|
|
45
45
|
# Start MCP server for AI agents
|
|
46
|
-
npx kb serve
|
|
46
|
+
npx @vpxa/kb serve
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
> **Note:** Once `@vpxa/kb` is installed locally, you can use the short `kb` command (e.g. `kb search`, `kb serve`) since the local binary takes precedence.
|
|
50
|
+
|
|
49
51
|
## Tools by Category
|
|
50
52
|
|
|
51
53
|
### Search & Discovery
|
|
@@ -181,8 +183,9 @@ After `kb init`, your `.vscode/mcp.json` is configured automatically:
|
|
|
181
183
|
{
|
|
182
184
|
"servers": {
|
|
183
185
|
"knowledge-base": {
|
|
186
|
+
"type": "stdio",
|
|
184
187
|
"command": "npx",
|
|
185
|
-
"args": ["kb", "serve"]
|
|
188
|
+
"args": ["@vpxa/kb", "serve"]
|
|
186
189
|
}
|
|
187
190
|
}
|
|
188
191
|
}
|
|
@@ -256,7 +259,7 @@ kb graph traverse <startId> [--direction forward|backward] [--depth N]
|
|
|
256
259
|
# System
|
|
257
260
|
kb status
|
|
258
261
|
kb reindex [--full]
|
|
259
|
-
kb onboard <path> [--
|
|
262
|
+
kb onboard <path> [--generate] [--out-dir <dir>]
|
|
260
263
|
kb serve [--transport stdio|http] [--port N]
|
|
261
264
|
kb init [--force]
|
|
262
265
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `kb init` — scaffold a knowledge base in the current directory.
|
|
3
|
-
* Creates kb.config.json, .gitignore entry,
|
|
3
|
+
* Creates kb.config.json, .gitignore entry, optional IDE config,
|
|
4
|
+
* and agent instruction files (.github/copilot-instructions.md, AGENTS.md).
|
|
4
5
|
*/
|
|
5
6
|
export declare function initProject(options: {
|
|
6
7
|
force: boolean;
|
|
@@ -1,9 +1,249 @@
|
|
|
1
|
-
import{appendFileSync as
|
|
2
|
-
|
|
1
|
+
import{appendFileSync as p,existsSync as s,mkdirSync as u,readFileSync as m,writeFileSync as a}from"node:fs";import{basename as g,resolve as e}from"node:path";const h={sources:[{path:".",excludePatterns:["**/node_modules/**","**/dist/**","**/build/**","**/.git/**","**/.kb-data/**","**/coverage/**","**/*.min.js","**/package-lock.json","**/pnpm-lock.yaml"]}],indexing:{chunkSize:1500,chunkOverlap:200,minChunkSize:100},embedding:{model:"mixedbread-ai/mxbai-embed-large-v1",dimensions:1024},store:{backend:"lancedb",path:".kb-data/lance"},curated:{path:"curated"}},f={servers:{"knowledge-base":{type:"stdio",command:"npx",args:["@vpxa/kb","serve"]}}};function y(o){return`# ${o} \u2014 Copilot Instructions
|
|
2
|
+
|
|
3
|
+
This project uses **@vpxa/kb** as an MCP knowledge base server. Use the KB tools to search, analyze, and understand the codebase before making changes.
|
|
4
|
+
|
|
5
|
+
## KB Tools
|
|
6
|
+
|
|
7
|
+
Before starting any task on **${o}**, use these MCP tools:
|
|
8
|
+
|
|
9
|
+
| Action | Tool | Example |
|
|
10
|
+
|--------|------|---------|
|
|
11
|
+
| Search code & decisions | \`kb_search\` | \`kb_search({ query: "..." })\` |
|
|
12
|
+
| Find symbol definition | \`kb_symbol\` | \`kb_symbol({ name: "ClassName" })\` |
|
|
13
|
+
| Plan what to read | \`kb_scope_map\` | \`kb_scope_map({ task: "..." })\` |
|
|
14
|
+
| Trace call chains | \`kb_trace\` | \`kb_trace({ symbol: "fn", file: "path" })\` |
|
|
15
|
+
| Impact of a change | \`kb_blast_radius\` | \`kb_blast_radius({ changed_files: ["..."] })\` |
|
|
16
|
+
| Persist what you learn | \`kb_remember\` | \`kb_remember({ title: "...", category: "decisions" })\` |
|
|
17
|
+
| Typecheck + lint | \`kb_check\` | \`kb_check({})\` |
|
|
18
|
+
| Run tests | \`kb_test_run\` | \`kb_test_run({})\` |
|
|
19
|
+
|
|
20
|
+
## Workflow
|
|
21
|
+
|
|
22
|
+
\`\`\`
|
|
23
|
+
kb_search({ query: "your task keywords" }) # Recall prior decisions
|
|
24
|
+
kb_scope_map({ task: "what you are doing" }) # Get a reading plan
|
|
25
|
+
# ... do the work ...
|
|
26
|
+
kb_check({}) # Typecheck + lint
|
|
27
|
+
kb_test_run({}) # Run tests
|
|
28
|
+
kb_remember({ title: "What I learned", category: "decisions" }) # Persist
|
|
29
|
+
\`\`\`
|
|
30
|
+
|
|
31
|
+
## KB MCP Tools \u2014 Complete Reference
|
|
32
|
+
|
|
33
|
+
### Search & Discovery
|
|
34
|
+
| Tool | Purpose |
|
|
35
|
+
|------|---------|
|
|
36
|
+
| \`kb_search\` | Hybrid vector + keyword search. Modes: \`hybrid\` (default), \`semantic\`, \`keyword\`. Filters: \`origin\`, \`category\`, \`content_type\`, \`tags\`. |
|
|
37
|
+
| \`kb_find\` | Federated search: vector + FTS + glob + regex in one call. |
|
|
38
|
+
| \`kb_symbol\` | Resolve symbol definition, imports, and all references across files. |
|
|
39
|
+
| \`kb_lookup\` | Full-file retrieval by path or record ID. |
|
|
40
|
+
| \`kb_scope_map\` | Task-scoped reading plan with file list and token estimates. |
|
|
41
|
+
| \`kb_trace\` | Forward/backward flow tracing through call chains. |
|
|
42
|
+
| \`kb_find_examples\` | Find real usage examples of a symbol or pattern. |
|
|
43
|
+
| \`kb_dead_symbols\` | Find exported symbols that are never imported anywhere. |
|
|
44
|
+
| \`kb_file_summary\` | Structural overview of a file (exports, imports, functions). |
|
|
45
|
+
|
|
46
|
+
### Code Analysis
|
|
47
|
+
| Tool | Purpose |
|
|
48
|
+
|------|---------|
|
|
49
|
+
| \`kb_analyze_structure\` | Project structure overview with file tree and stats. |
|
|
50
|
+
| \`kb_analyze_dependencies\` | Dependency graph with confidence scoring. |
|
|
51
|
+
| \`kb_analyze_symbols\` | Symbol extraction and cross-references. |
|
|
52
|
+
| \`kb_analyze_patterns\` | Design pattern detection (Singleton, Factory, etc.). |
|
|
53
|
+
| \`kb_analyze_entry_points\` | Discover entry points (Lambda handlers, CLI, HTTP routes). |
|
|
54
|
+
| \`kb_analyze_diagram\` | Generate Mermaid architecture diagrams. |
|
|
55
|
+
| \`kb_blast_radius\` | Change impact analysis \u2014 what breaks if you modify a file. |
|
|
56
|
+
|
|
57
|
+
### Knowledge Management
|
|
58
|
+
| Tool | Purpose |
|
|
59
|
+
|------|---------|
|
|
60
|
+
| \`kb_remember\` | Store a curated knowledge entry (decisions, patterns, conventions). |
|
|
61
|
+
| \`kb_read\` | Read a curated entry by path. |
|
|
62
|
+
| \`kb_update\` | Update an existing curated entry. |
|
|
63
|
+
| \`kb_forget\` | Delete a curated entry (requires reason). |
|
|
64
|
+
| \`kb_list\` | List curated entries, filterable by category and tags. |
|
|
65
|
+
| \`kb_produce_knowledge\` | Auto-generate knowledge from codebase analysis. |
|
|
66
|
+
|
|
67
|
+
### Execution & Validation
|
|
68
|
+
| Tool | Purpose |
|
|
69
|
+
|------|---------|
|
|
70
|
+
| \`kb_check\` | Incremental typecheck + lint in one call (tsc + biome). |
|
|
71
|
+
| \`kb_test_run\` | Run tests with structured pass/fail results. |
|
|
72
|
+
| \`kb_eval\` | Sandboxed JavaScript/TypeScript execution. |
|
|
73
|
+
| \`kb_batch\` | Execute multiple operations in parallel. |
|
|
74
|
+
|
|
75
|
+
### Code Manipulation
|
|
76
|
+
| Tool | Purpose |
|
|
77
|
+
|------|---------|
|
|
78
|
+
| \`kb_rename\` | Smart whole-word symbol rename across files (dry-run supported). |
|
|
79
|
+
| \`kb_codemod\` | Regex-based code transformations with rule files (dry-run supported). |
|
|
80
|
+
| \`kb_diff_parse\` | Parse unified diff into structured file changes. |
|
|
81
|
+
| \`kb_data_transform\` | JQ-like JSON transformations. |
|
|
82
|
+
|
|
83
|
+
### Context Management
|
|
84
|
+
| Tool | Purpose |
|
|
85
|
+
|------|---------|
|
|
86
|
+
| \`kb_compact\` | Compress text to relevant sections using embeddings (no LLM). |
|
|
87
|
+
| \`kb_workset\` | Named file set management (save/load/add/remove working sets). |
|
|
88
|
+
| \`kb_stash\` | Named key-value store for session data. |
|
|
89
|
+
| \`kb_checkpoint\` | Save/restore lightweight session checkpoints. |
|
|
90
|
+
| \`kb_parse_output\` | Parse build tool output (tsc, vitest, biome, git) into structured JSON. |
|
|
91
|
+
|
|
92
|
+
### FORGE & Context Compression
|
|
93
|
+
| Tool | Purpose |
|
|
94
|
+
|------|---------|
|
|
95
|
+
| \`kb_forge_ground\` | Full FORGE Ground phase (classify + scope + constraints + evidence). |
|
|
96
|
+
| \`kb_forge_classify\` | Quick FORGE tier classification (Floor/Standard/Critical). |
|
|
97
|
+
| \`kb_evidence_map\` | Track critical-path claims as Verified/Assumed/Unknown with receipts. |
|
|
98
|
+
| \`kb_digest\` | Compress multiple text blocks into token-budgeted digest. |
|
|
99
|
+
| \`kb_stratum_card\` | Generate T1/T2 context cards (10-100x token reduction). |
|
|
100
|
+
|
|
101
|
+
### Web & Network
|
|
102
|
+
| Tool | Purpose |
|
|
103
|
+
|------|---------|
|
|
104
|
+
| \`kb_web_fetch\` | Fetch web page \u2192 LLM-optimized markdown. CSS selectors, 4 modes, smart truncation. |
|
|
105
|
+
| \`kb_web_search\` | Search the web via DuckDuckGo (no API key needed). |
|
|
106
|
+
| \`kb_http\` | HTTP requests (GET/POST/PUT/PATCH/DELETE) for API testing with timing. |
|
|
107
|
+
|
|
108
|
+
### Verified Lanes
|
|
109
|
+
| Tool | Purpose |
|
|
110
|
+
|------|---------|
|
|
111
|
+
| \`kb_lane\` | Manage isolated file copies for parallel exploration. Actions: \`create\`, \`list\`, \`status\`, \`diff\`, \`merge\`, \`discard\`. |
|
|
112
|
+
|
|
113
|
+
### Git & Environment
|
|
114
|
+
| Tool | Purpose |
|
|
115
|
+
|------|---------|
|
|
116
|
+
| \`kb_git_context\` | Branch, status, recent commits, optional diff stats. |
|
|
117
|
+
| \`kb_process\` | Process supervisor (start/stop/logs). |
|
|
118
|
+
| \`kb_watch\` | Filesystem watcher for auto-triggered workflows. |
|
|
119
|
+
| \`kb_delegate\` | Delegate subtask to a local Ollama model. |
|
|
120
|
+
|
|
121
|
+
### Developer Utilities
|
|
122
|
+
| Tool | Purpose |
|
|
123
|
+
|------|---------|
|
|
124
|
+
| \`kb_regex_test\` | Test regex patterns with match/replace/split modes. |
|
|
125
|
+
| \`kb_encode\` | Base64, URL, SHA-256, MD5, hex encode/decode, JWT decode. |
|
|
126
|
+
| \`kb_measure\` | Code complexity metrics (cyclomatic complexity, line counts). |
|
|
127
|
+
| \`kb_changelog\` | Generate changelog from git history (conventional commits). |
|
|
128
|
+
| \`kb_schema_validate\` | Validate JSON data against JSON Schema. |
|
|
129
|
+
| \`kb_snippet\` | Save/get/search/delete persistent code snippets. |
|
|
130
|
+
| \`kb_env\` | System and runtime environment info (sensitive values redacted). |
|
|
131
|
+
| \`kb_time\` | Date parsing, timezone conversion, duration math. |
|
|
132
|
+
|
|
133
|
+
### System
|
|
134
|
+
| Tool | Purpose |
|
|
135
|
+
|------|---------|
|
|
136
|
+
| \`kb_status\` | Index statistics (record count, file count, content types). |
|
|
137
|
+
| \`kb_reindex\` | Rebuild the vector index from configured sources. |
|
|
138
|
+
| \`kb_health\` | Project health checks (package.json, tsconfig, lockfile, etc.). |
|
|
139
|
+
| \`kb_onboard\` | First-time codebase onboarding \u2014 runs all analyses, auto-persists results. |
|
|
140
|
+
| \`kb_graph\` | Knowledge graph queries (find_nodes, find_edges, neighbors, traverse, stats). |
|
|
141
|
+
| \`kb_queue\` | Task queue for sequential agent operations. |
|
|
142
|
+
| \`kb_replay_list\` | View audit trail of tool invocations. |
|
|
143
|
+
| \`kb_replay_clear\` | Clear the replay audit trail. |
|
|
144
|
+
`}function w(o){return`# ${o} \u2014 Agent Instructions
|
|
145
|
+
|
|
146
|
+
## KB Knowledge Base
|
|
147
|
+
|
|
148
|
+
This project has a **@vpxa/kb** MCP server providing search, analysis, memory, and developer tools.
|
|
149
|
+
|
|
150
|
+
### Skills Reference
|
|
151
|
+
|
|
152
|
+
| Context | Skill | Details |
|
|
153
|
+
|---------|-------|---------|
|
|
154
|
+
| KB search, analysis, memory | \`kb\` | See [skills/knowledge-base/SKILL.md](skills/knowledge-base/SKILL.md) or run \`kb_status({})\` |
|
|
155
|
+
|
|
156
|
+
### Available Tool Categories
|
|
157
|
+
|
|
158
|
+
| Category | Tools | Purpose |
|
|
159
|
+
|----------|-------|---------|
|
|
160
|
+
| Search & Discovery | \`kb_search\`, \`kb_find\`, \`kb_symbol\`, \`kb_trace\`, \`kb_scope_map\`, \`kb_lookup\`, \`kb_find_examples\`, \`kb_dead_symbols\`, \`kb_file_summary\` | Find code, symbols, data flow, reading plans |
|
|
161
|
+
| Code Analysis | \`kb_analyze_structure\`, \`kb_analyze_dependencies\`, \`kb_analyze_symbols\`, \`kb_analyze_patterns\`, \`kb_analyze_entry_points\`, \`kb_analyze_diagram\`, \`kb_blast_radius\` | Structure, deps, patterns, impact, diagrams |
|
|
162
|
+
| Knowledge | \`kb_remember\`, \`kb_read\`, \`kb_update\`, \`kb_forget\`, \`kb_list\`, \`kb_produce_knowledge\` | Persistent cross-session memory |
|
|
163
|
+
| Execution | \`kb_check\`, \`kb_test_run\`, \`kb_eval\`, \`kb_batch\` | Typecheck, lint, test, run code |
|
|
164
|
+
| Code Manipulation | \`kb_rename\`, \`kb_codemod\`, \`kb_diff_parse\`, \`kb_data_transform\` | Safe renames, transforms, diff parsing |
|
|
165
|
+
| Context | \`kb_compact\`, \`kb_workset\`, \`kb_stash\`, \`kb_checkpoint\`, \`kb_parse_output\` | Manage working sets, save progress |
|
|
166
|
+
| FORGE | \`kb_forge_ground\`, \`kb_forge_classify\`, \`kb_evidence_map\`, \`kb_digest\`, \`kb_stratum_card\` | Quality gates, context compression |
|
|
167
|
+
| Web & API | \`kb_web_fetch\`, \`kb_web_search\`, \`kb_http\` | Fetch pages, search web, test APIs |
|
|
168
|
+
| Lanes | \`kb_lane\` | Isolated file copies for parallel exploration (create/list/status/diff/merge/discard) |
|
|
169
|
+
| Git & Environment | \`kb_git_context\`, \`kb_process\`, \`kb_watch\`, \`kb_delegate\` | Git info, process management |
|
|
170
|
+
| Utilities | \`kb_regex_test\`, \`kb_encode\`, \`kb_measure\`, \`kb_changelog\`, \`kb_schema_validate\`, \`kb_snippet\`, \`kb_env\`, \`kb_time\` | Regex, encoding, metrics, validation |
|
|
171
|
+
| System | \`kb_status\`, \`kb_reindex\`, \`kb_health\`, \`kb_onboard\`, \`kb_graph\`, \`kb_queue\`, \`kb_replay_list\`, \`kb_replay_clear\` | Index management, health checks, knowledge graph |
|
|
172
|
+
|
|
173
|
+
### Search Modes
|
|
174
|
+
|
|
175
|
+
The \`kb_search\` tool supports three search strategies via the \`search_mode\` parameter:
|
|
176
|
+
|
|
177
|
+
- **\`hybrid\`** (default) \u2014 Vector similarity + full-text keyword search merged via Reciprocal Rank Fusion. Best for most queries.
|
|
178
|
+
- **\`semantic\`** \u2014 Pure vector cosine similarity. Best for conceptual/meaning-based queries.
|
|
179
|
+
- **\`keyword\`** \u2014 Full-text search only. Best for exact identifiers, function names, specific strings.
|
|
180
|
+
|
|
181
|
+
Additional filters: \`origin\` (\`indexed\`/\`curated\`/\`produced\`), \`category\`, \`content_type\`, \`tags\`, \`min_score\`.
|
|
182
|
+
|
|
183
|
+
### Session Protocol
|
|
184
|
+
|
|
185
|
+
**Start of session:**
|
|
186
|
+
\`\`\`
|
|
187
|
+
kb_status({})
|
|
188
|
+
kb_search({ query: "SESSION CHECKPOINT", origin: "curated" })
|
|
189
|
+
\`\`\`
|
|
190
|
+
|
|
191
|
+
**During session:**
|
|
192
|
+
\`\`\`
|
|
193
|
+
kb_search \u2192 kb_scope_map \u2192 kb_symbol \u2192 kb_trace # Orient
|
|
194
|
+
kb_check \u2192 kb_test_run # Validate changes
|
|
195
|
+
kb_remember # Capture insights
|
|
196
|
+
\`\`\`
|
|
197
|
+
|
|
198
|
+
**End of session:**
|
|
199
|
+
\`\`\`
|
|
200
|
+
kb_remember({ title: "Session checkpoint: <topic>", content: "<summary>", category: "conventions" })
|
|
201
|
+
\`\`\`
|
|
202
|
+
|
|
203
|
+
### Workflow Chains
|
|
204
|
+
|
|
205
|
+
**Codebase onboarding:**
|
|
206
|
+
\`\`\`
|
|
207
|
+
kb_onboard({ path: "." }) \u2192 kb_produce_knowledge({ path: "src/" }) \u2192 kb_remember(...)
|
|
208
|
+
\`\`\`
|
|
209
|
+
|
|
210
|
+
**Planning a task:**
|
|
211
|
+
\`\`\`
|
|
212
|
+
kb_search({ query: "task keywords" }) \u2192 kb_scope_map({ task: "description" }) \u2192 kb_workset({ action: "save", name: "task", files: [...] })
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
**Bug investigation:**
|
|
216
|
+
\`\`\`
|
|
217
|
+
kb_parse_output({ output: "<error>" }) \u2192 kb_symbol({ name: "failingFn" }) \u2192 kb_trace({ symbol: "failingFn", direction: "backward" }) \u2192 kb_blast_radius({ changed_files: ["suspect.ts"] })
|
|
218
|
+
\`\`\`
|
|
219
|
+
|
|
220
|
+
**Safe refactor with lanes:**
|
|
221
|
+
\`\`\`
|
|
222
|
+
kb_lane({ action: "create", name: "refactor", files: [...] }) \u2192 [make changes] \u2192 kb_lane({ action: "diff", name: "refactor" }) \u2192 kb_check({}) \u2192 kb_lane({ action: "merge", name: "refactor" })
|
|
223
|
+
\`\`\`
|
|
224
|
+
|
|
225
|
+
**After making changes:**
|
|
226
|
+
\`\`\`
|
|
227
|
+
kb_blast_radius({ changed_files: ["src/file.ts"] }) \u2192 kb_check({}) \u2192 kb_test_run({}) \u2192 kb_reindex({}) \u2192 kb_remember(...)
|
|
228
|
+
\`\`\`
|
|
229
|
+
|
|
230
|
+
### Knowledge Categories
|
|
231
|
+
|
|
232
|
+
\`decisions\` | \`patterns\` | \`conventions\` | \`troubleshooting\`
|
|
233
|
+
|
|
234
|
+
### Core Rules
|
|
235
|
+
|
|
236
|
+
- Search KB for prior decisions before proposing new ones
|
|
237
|
+
- Follow \`_Next:\` hints in tool responses for guided workflows
|
|
238
|
+
- Use \`kb_check\` and \`kb_test_run\` to validate before committing
|
|
239
|
+
- Use \`kb_remember\` to persist architecture decisions and lessons learned
|
|
240
|
+
- Analysis results are auto-persisted as \`origin: "produced"\` entries
|
|
241
|
+
`}async function P(o){const t=process.cwd(),n=e(t,"kb.config.json");if(s(n)&&!o.force){console.log("kb.config.json already exists. Use --force to overwrite.");return}a(n,`${JSON.stringify(h,null,2)}
|
|
242
|
+
`,"utf-8"),console.log(" Created kb.config.json");const i=e(t,"curated");s(i)||(u(i,{recursive:!0}),console.log(" Created curated/"));const r=e(t,".gitignore");s(r)?m(r,"utf-8").includes(".kb-data")||(p(r,`
|
|
3
243
|
# Knowledge base vector store
|
|
4
244
|
.kb-data/
|
|
5
|
-
`,"utf-8"),console.log(" Added .kb-data/ to .gitignore")):(
|
|
245
|
+
`,"utf-8"),console.log(" Added .kb-data/ to .gitignore")):(a(r,`# Knowledge base vector store
|
|
6
246
|
.kb-data/
|
|
7
|
-
`,"utf-8"),console.log(" Created .gitignore with .kb-data/"));const
|
|
8
|
-
`,"utf-8"),console.log(" Created .vscode/mcp.json")),console.log(`
|
|
9
|
-
Knowledge base initialized! Next steps:`),console.log(" kb reindex Index your codebase"),console.log(" kb search Search indexed content"),console.log(" kb serve Start MCP server for IDE integration")}export{
|
|
247
|
+
`,"utf-8"),console.log(" Created .gitignore with .kb-data/"));const c=e(t,".vscode"),l=e(c,"mcp.json");s(c)&&!s(l)&&(a(l,`${JSON.stringify(f,null,2)}
|
|
248
|
+
`,"utf-8"),console.log(" Created .vscode/mcp.json"));const d=g(t),b=e(t,".github"),k=e(b,"copilot-instructions.md");s(k)||(u(b,{recursive:!0}),a(k,y(d),"utf-8"),console.log(" Created .github/copilot-instructions.md"));const _=e(t,"AGENTS.md");s(_)||(a(_,w(d),"utf-8"),console.log(" Created AGENTS.md")),console.log(`
|
|
249
|
+
Knowledge base initialized! Next steps:`),console.log(" kb reindex Index your codebase"),console.log(" kb search Search indexed content"),console.log(" kb serve Start MCP server for IDE integration")}export{P as initProject};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{analyzeCommands as
|
|
1
|
+
import{readFileSync as i}from"node:fs";import{dirname as c,resolve as p}from"node:path";import{fileURLToPath as l}from"node:url";import{analyzeCommands as d}from"./commands/analyze.js";import{contextCommands as f}from"./commands/context-cmds.js";import{environmentCommands as g}from"./commands/environment.js";import{executionCommands as h}from"./commands/execution.js";import{graphCommands as C}from"./commands/graph.js";import{knowledgeCommands as v}from"./commands/knowledge.js";import{searchCommands as u}from"./commands/search.js";import{systemCommands as k}from"./commands/system.js";import{workspaceCommands as x}from"./commands/workspace.js";import{getCtx as y}from"./context.js";const e=[...u,...v,...d,...C,...k,...h,...f,...x,...g];e.push({name:"help",description:"Show available commands",run:async()=>{s()}});async function F(r){const o=[...r],n=o.shift();if(!n||n==="--help"||n==="-h"){s();return}if(n==="--version"||n==="-v"){const m=p(c(l(import.meta.url)),"..","..","..","package.json"),a=JSON.parse(i(m,"utf-8"));console.log(a.version);return}const t=e.find(m=>m.name===n);t||(console.error(`Unknown command: ${n}`),s(),process.exit(1));try{await t.run(o)}finally{const m=y();m&&await m.store.close()}}function s(){console.log(`@vpxa/kb \u2014 Local-first AI developer toolkit
|
|
2
2
|
`),console.log(`Usage: kb <command> [options]
|
|
3
|
-
`),console.log("Commands:");const
|
|
3
|
+
`),console.log("Commands:");const r=Math.max(...e.map(o=>o.name.length));for(const o of e)console.log(` ${o.name.padEnd(r+2)}${o.description}`);console.log(""),console.log("Options:"),console.log(" --help, -h Show this help"),console.log(" --version, -v Show version")}export{F as run};
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`);const v=g.filter(m=>m.status==="success"),
|
|
1
|
+
import{existsSync as F,mkdirSync as V,readdirSync as q,rmSync as U,writeFileSync as B}from"node:fs";import{readdir as J,readFile as Z}from"node:fs/promises";import{basename as N,join as O,relative as H,resolve as Q}from"node:path";import{DependencyAnalyzer as X,DiagramGenerator as Y,EntryPointAnalyzer as ee,extractRegexCallGraph as te,extractTsCallGraph as se,PatternAnalyzer as ne,StructureAnalyzer as oe,SymbolAnalyzer as re}from"../../analyzers/dist/index.js";const L={structure:"Project Structure",dependencies:"Dependencies","entry-points":"Entry Points",symbols:"Symbols",patterns:"Patterns",diagram:"C4 Container Diagram","code-map":"Code Map (Module Graph)","config-values":"Configuration Values","synthesis-guide":"Synthesis Guide"};function ie(g,u,t,p){const n=[`Analysis baselines for **${t}** have been generated.`];u==="generate"?n.push("Individual results are in the sibling `.md` and `.json` files in this directory.",""):n.push("Results are stored in the KB vector store.","");const a=p.get("symbols"),i=p.get("dependencies"),d=p.get("patterns"),y=p.get("entry-points"),$=a?.totalCount??0,b=a?.exportedCount??0,M=i?.totalImports??0,C=y?.total??0,r=(d?.patterns??[]).map(m=>m.pattern),w=r.some(m=>m.startsWith("Spring")),_=r.includes("AWS CDK")||r.includes("CDK IaC"),P=r.includes("Maven"),T=r.includes("Serverless")||C>3,k=i?.external?Object.keys(i.external):[],f=k.some(m=>["express","fastify","next","react","vitest","jest"].includes(m))||M>0,x=k.some(m=>["turbo","lerna","nx"].includes(m))||r.includes("Monorepo");if(n.push("### Project Profile",""),n.push(`- **${$} symbols** (${b} exported), **${M} imports**, **${C} entry ${C===1?"point":"points"}**`),r.length>0&&n.push(`- **Detected**: ${r.slice(0,8).join(", ")}`),n.push(""),$===0&&M===0&&C===0)return n.push("> **Note:** This project appears to be empty or contains no analyzable source code.","> Run onboard again after adding source files."),n.join(`
|
|
2
|
+
`);const v=g.filter(m=>m.status==="success"),j=g.filter(m=>m.status==="failed");n.push("### Completed Analyses","");for(const m of v){const S=L[m.name]??m.name,e=m.output.length>1e3?`${Math.round(m.output.length/1024)}KB`:`${m.output.length}B`;u==="generate"?n.push(`- \u2713 [${S}](./${m.name}.md) (${e})`):n.push(`- \u2713 ${S} (${e})`)}if(j.length>0){n.push("","### Failed Analyses","");for(const m of j)n.push(`- \u2717 ${m.name}: ${m.error}`)}n.push("","### Recommended Reading Order","","1. **Start with** `synthesis-guide.md` (this file) \u2192 `entry-points.md` \u2192 `patterns.md`","2. **Module graph** via `code-map.md` \u2014 cross-package call edges with function names","3. **Architecture** via `diagram.md` (C4 Container) \u2192 `dependencies.md`","4. **Browse structure** via `structure.md` for file layout","5. **API surface** via `symbols.md` \u2014 file paths + exported symbols (capped at 80KB)","6. **Reference**: `config-values.md` (config reference)","","> **Size guidance:** Total output is ~");const D=v.reduce((m,S)=>m+S.output.length,0)/1024;return n[n.length-1]+=`${Math.round(D)}KB. Focus on code-map.md + entry-points.md + diagram.md (~${Math.round((v.find(m=>m.name==="code-map")?.output.length??0)/1024+(v.find(m=>m.name==="entry-points")?.output.length??0)/1024+(v.find(m=>m.name==="diagram")?.output.length??0)/1024)}KB) for maximum signal-to-token ratio.`,n.push("","### Synthesize Knowledge","","Produce the following `kb_remember` entries:",""),n.push("1. **Architecture Summary** (category: `architecture`)"),x?(n.push(" - Package boundaries, dependency graph between packages"),n.push(" - Shared vs service-specific code")):T?(n.push(" - Lambda functions, triggers, event flow"),n.push(" - Infrastructure patterns (queues, tables, APIs)")):w?(n.push(" - Controller \u2192 Service \u2192 Repository layers"),n.push(" - Spring configuration and profiles")):(n.push(" - Layer structure, dependency flow"),n.push(" - Key design decisions")),n.push(""),n.push("2. **Domain Model** (category: `architecture`)"),n.push(" - Key entities/types and their relationships"),n.push(" - Data flow from entry points through processing"),n.push(""),n.push("3. **Conventions** (category: `conventions`)"),n.push(" - Naming patterns, file organization, testing approach"),_&&n.push(" - CDK construct patterns and stack organization"),f&&n.push(" - Build tooling, package manager, module system"),P&&n.push(" - Maven module structure, dependency management"),n.push("","### Using KB Tools","","This project has a KB MCP server with tools for search, analysis, memory, and more.","`kb init` has already created `.github/copilot-instructions.md` and `AGENTS.md` with the complete tool reference.","If not, run `npx @vpxa/kb init` to generate them.","","**Workflow pattern \u2014 use on every task:**","","```",'kb_search({ query: "your task keywords" }) # Recall prior decisions','kb_scope_map({ task: "what you are doing" }) # Get a reading plan',"# ... do the work ...","kb_check({}) # Typecheck + lint","kb_test_run({}) # Run tests",'kb_remember({ title: "What I learned", category: "decisions" }) # Persist',"```"),n.join(`
|
|
3
3
|
`)}const ae=new Set(["test","tests","__tests__","spec","specs","__mocks__","__fixtures__","fixtures","test-utils"]);function R(g){return g.replace(/\\/g,"/").split("/").some(t=>ae.has(t))||/\.(test|spec)\.[jt]sx?$/.test(g)||/Test\.java$/.test(g)}function ce(g,u,t){const p=g.get("dependencies"),n=g.get("symbols"),a=g.get("entry-points"),i=[`## Code Map: ${u}
|
|
4
4
|
`];if(!p&&!n)return i.push("No dependency or symbol data available."),i.join(`
|
|
5
|
-
`);const d=p?.reverseGraph??{},y=n?.symbols??[]
|
|
5
|
+
`);const d=p?.reverseGraph??{},y=n?.symbols??[],$=a?.entryPoints??[],b=new Map;for(const f of y){if(!f.exported)continue;const x=f.filePath.replace(/\\/g,"/");if(R(x))continue;const v=b.get(x);v?v.push({name:f.name,kind:f.kind}):b.set(x,[{name:f.name,kind:f.kind}])}const M=new Map;for(const[f,x]of Object.entries(d)){const v=f.replace(/\\/g,"/"),j=ue(v,b),D=x.map(S=>S.replace(/\\/g,"/")).filter(S=>!R(S));if(D.length===0)continue;const m=M.get(j);if(m)for(const S of D)m.add(S);else M.set(j,new Set(D))}const C=new Map;for(const f of $)C.set(f.filePath.replace(/\\/g,"/"),{name:f.name,trigger:f.trigger});const l=new Map,r=new Map;if(t)for(const[f,x]of t){if(R(f))continue;const v=z(f);for(const[j,D]of x){if(R(j))continue;const m=z(j);if(v===m)continue;let S=l.get(f);S||(S=new Map,l.set(f,S)),S.set(j,D);const e=r.get(j),o={file:f,symbols:D};e?e.push(o):r.set(j,[o])}}const w=new Set;for(const f of C.keys())w.add(f);for(const f of l.keys())w.add(f);for(const f of r.keys())w.add(f);if(!t)for(const f of b.keys()){const x=M.get(f);x&&x.size>=3&&w.add(f)}const _=new Map;for(const f of w){const x=z(f),v=_.get(x);v?v.push(f):_.set(x,[f])}const P=[..._.entries()].sort((f,x)=>f[0].localeCompare(x[0])),T=t?"AST call graph":"import analysis",k=t?`, ${l.size} cross-package callers`:"";i.push(`**${w.size} key modules** (${T}${k})
|
|
6
6
|
`),i.push(`**Legend:** \u26A1 Entry point | \u{1F4E4} Exports | \u2192 Calls (outgoing) | \u2190 Called by (incoming) | \u27A1 Used by (import)
|
|
7
|
-
`);for(const[f,
|
|
8
|
-
`);for(const v of
|
|
7
|
+
`);for(const[f,x]of P){x.sort(),i.push(`### ${f}/
|
|
8
|
+
`);for(const v of x){const j=b.get(v),D=C.get(v),m=l.get(v),S=r.get(v),e=M.get(v),o=v.startsWith(`${f}/`)?v.slice(f.length+1):v;if(i.push(`**${o}**`),D&&i.push(` \u26A1 Entry: \`${D.name}\`${D.trigger?` (${D.trigger})`:""}`),j&&j.length>0){const s=j.slice(0,8).map(h=>`${h.name}`).join(", "),c=j.length>8?` (+${j.length-8})`:"";i.push(` \u{1F4E4} ${s}${c}`)}if(m&&m.size>0){const s=[...m.entries()].sort((c,h)=>h[1].length-c[1].length);for(const[c,h]of s.slice(0,4)){const A=c.startsWith(`${f}/`)?c.slice(f.length+1):c;i.push(` \u2192 ${A}: ${h.slice(0,5).join(", ")}${h.length>5?"\u2026":""}`)}s.length>4&&i.push(` \u2192 +${s.length-4} more targets`)}if(S&&S.length>0){for(const s of S.slice(0,4)){const c=s.file.startsWith(`${f}/`)?s.file.slice(f.length+1):s.file;i.push(` \u2190 ${c}: ${s.symbols.slice(0,4).join(", ")}${s.symbols.length>4?"\u2026":""}`)}S.length>4&&i.push(` \u2190 +${S.length-4} more callers`)}else if(!t&&e&&e.size>0){const s=[...e].filter(c=>!R(c));s.length<=3?i.push(` \u27A1 Used by: ${s.join(", ")}`):i.push(` \u27A1 Used by: ${s.slice(0,3).join(", ")} (+${s.length-3} more)`)}i.push("")}}return i.join(`
|
|
9
9
|
`)}function z(g){const u=g.split("/");if(u.length>=2&&["packages","services","providers","apps","libs"].includes(u[0]))return`${u[0]}/${u[1]}`;const t=u.indexOf("java"),p=u.indexOf("kotlin"),n=t>=0?t:p;if(n>=0&&n+2<u.length){const a=u.slice(n+1);return["com","org","net","io","dev"].includes(a[0])&&a.length>=3?a.slice(0,3).join("/"):a.slice(0,2).join("/")}return u[0]==="src"&&u.length>=3?`${u[0]}/${u[1]}`:u[0]}function le(g,u,t){const p=u.get("symbols"),n=u.get("entry-points"),a=u.get("dependencies"),i=new Map;for(const[e,o]of g)if(!R(e))for(const[s,c]of o){if(R(s))continue;const h=z(e),A=z(s);if(h===A)continue;const E=`${h}|${A}`;i.set(E,(i.get(E)??0)+c.length)}if(i.size===0)return`## Architecture Diagram
|
|
10
10
|
|
|
11
|
-
No cross-package dependencies detected.`;const d=new Set;for(const e of i.keys()){const[o,s]=e.split("|");d.add(o),d.add(s)}const y=new Map;if(p?.symbols)for(const e of p.symbols){if(!e.exported)continue;const o=e.filePath.replace(/\\/g,"/");if(R(o))continue;const s=z(o);y.set(s,(y.get(s)??0)+1)}const
|
|
11
|
+
No cross-package dependencies detected.`;const d=new Set;for(const e of i.keys()){const[o,s]=e.split("|");d.add(o),d.add(s)}const y=new Map;if(p?.symbols)for(const e of p.symbols){if(!e.exported)continue;const o=e.filePath.replace(/\\/g,"/");if(R(o))continue;const s=z(o);y.set(s,(y.get(s)??0)+1)}const $=new Map;if(n?.entryPoints)for(const e of n.entryPoints){const o=e.filePath.replace(/\\/g,"/"),s=z(o),c=$.get(s);c?(c.count++,e.trigger&&c.triggers.add(e.trigger)):$.set(s,{count:1,triggers:new Set(e.trigger?[e.trigger]:[])})}const b=[];if(a?.external){const e=a.external,o={"client-dynamodb":{id:"dynamodb",name:"DynamoDB"},"lib-dynamodb":{id:"dynamodb",name:"DynamoDB"},"client-sqs":{id:"sqs",name:"SQS"},"client-ses":{id:"ses",name:"SES"},"client-sesv2":{id:"ses",name:"SES"},"client-s3":{id:"s3",name:"S3"},"client-eventbridge":{id:"eventbridge",name:"EventBridge"},"client-sns":{id:"sns",name:"SNS"},"client-secrets-manager":{id:"secrets",name:"Secrets Manager"},"client-scheduler":{id:"scheduler",name:"EventBridge Scheduler"},"client-apigatewaymanagementapi":{id:"apigw",name:"API Gateway"},"client-cloudwatch":{id:"cloudwatch",name:"CloudWatch"}},s=new Set;for(const c of Object.keys(e))for(const[h,A]of Object.entries(o))c.includes(h)&&!s.has(A.id)&&(s.add(A.id),b.push(A));b.sort((c,h)=>c.name.localeCompare(h.name))}const M=new Map;for(const e of[...d].sort()){const o=e.split("/")[0],s=M.get(o);s?s.push(e):M.set(o,[e])}const C=new Map;if(p?.symbols){const e=new Map;for(const s of p.symbols){const c=s.filePath.replace(/\\/g,"/"),h=z(c),A=c.match(/\.[^./]+$/)?.[0]||"";e.has(h)||e.set(h,new Map);const E=e.get(h);E.set(A,(E.get(A)??0)+1)}const o={".ts":"TypeScript",".tsx":"TypeScript",".js":"JavaScript",".jsx":"JavaScript",".java":"Java",".kt":"Kotlin",".scala":"Scala",".py":"Python",".go":"Go",".rs":"Rust",".cs":"C#",".rb":"Ruby",".php":"PHP",".swift":"Swift"};for(const[s,c]of e){let h="",A=0;for(const[E,I]of c)I>A&&(A=I,h=E);C.set(s,o[h]||"TypeScript")}}const l=e=>e.replace(/[^a-zA-Z0-9]/g,"_"),r=[];r.push("```mermaid"),r.push("C4Container"),r.push(` title C4 Container: ${t}`),r.push("");const w=e=>{const o=[],s=$.get(e);s&&(o.push(`${s.count} handlers`),s.triggers.size>0&&o.push([...s.triggers].join(", ")));const c=y.get(e);return c&&o.push(`${c} exports`),o.join(" \xB7 ")||""},_=e=>{const o=C.get(e)||"TypeScript";if(e.startsWith("infra"))return`CDK/${o}`;if($.has(e)){const s=$.get(e);if(s?.triggers.has("SQS")||s?.triggers.has("SNS")||s?.triggers.has("API Gateway"))return`Lambda/${o}`;if(s?.triggers.has("HTTP Server")||s?.triggers.has("HTTP Endpoint"))return`Spring Boot/${o}`}return o};for(const[e,o]of[...M.entries()].sort()){const c=new Set(["com","org","net","io","dev","src"]).has(e)?t.charAt(0).toUpperCase()+t.slice(1):e.charAt(0).toUpperCase()+e.slice(1);if(o.length===1&&o[0]===e){const h=o[0];r.push(` Container(${l(h)}, "${h}", "${_(h)}", "${w(h)}")`)}else{r.push(` System_Boundary(${l(e)}_boundary, "${c}") {`);for(const h of o){const A=h.split("/").slice(1).join("/")||h;r.push(` Container(${l(h)}, "${A}", "${_(h)}", "${w(h)}")`)}r.push(" }")}r.push("")}if(b.length>0){for(const e of b)r.push(` System_Ext(ext_${e.id}, "${e.name}", "AWS")`);r.push("")}const P=[...i.entries()].sort((e,o)=>o[1]-e[1]);for(const[e,o]of P.slice(0,30)){const[s,c]=e.split("|");r.push(` Rel(${l(s)}, ${l(c)}, "Uses", "${o} calls")`)}r.push("```");const T=`## C4 Container Diagram
|
|
12
12
|
|
|
13
13
|
${r.join(`
|
|
14
|
-
`)}
|
|
14
|
+
`)}`,k=[];k.push("```mermaid"),k.push("graph TB");const f=new Set;for(const[,e]of $)for(const o of e.triggers)f.add(o);if(f.size>0){k.push(' subgraph Triggers["External Triggers"]');for(const e of[...f].sort()){const o=`trigger_${e.replace(/[^a-zA-Z0-9]/g,"_")}`;k.push(` ${o}(("${e}"))`)}k.push(" end"),k.push("")}const x=[...d].filter(e=>$.has(e)).sort(),v=[...d].filter(e=>!$.has(e)).sort();if(x.length>0){k.push(' subgraph Services["Service Layer"]');for(const e of x){const o=`flow_${l(e)}`,s=e.includes("/")?e.split("/").pop()??e:e,c=$.get(e);k.push(` ${o}["${s} (${c?.count??0} handlers)"]`)}k.push(" end"),k.push("")}if(v.length>0){k.push(' subgraph Libraries["Shared Libraries"]');for(const e of v){const o=`flow_${l(e)}`,s=e.includes("/")?e.split("/").pop()??e:e;k.push(` ${o}["${s}"]`)}k.push(" end"),k.push("")}if(b.length>0){k.push(' subgraph External["AWS Services"]');for(const e of b)k.push(` flow_ext_${e.id}[("${e.name}")]`);k.push(" end"),k.push("")}for(const e of x){const o=$.get(e);if(!o)continue;const s=`flow_${l(e)}`;for(const c of o.triggers){const h=`trigger_${c.replace(/[^a-zA-Z0-9]/g,"_")}`;k.push(` ${h} --> ${s}`)}}const j=P.filter(([e])=>{const[o,s]=e.split("|");return $.has(o)&&!$.has(s)});for(const[e,o]of j.slice(0,15)){const[s,c]=e.split("|");k.push(` flow_${l(s)} -->|${o}| flow_${l(c)}`)}const D=P.filter(([e])=>{const[o,s]=e.split("|");return!$.has(o)&&!$.has(s)});for(const[e,o]of D.slice(0,10)){const[s,c]=e.split("|");k.push(` flow_${l(s)} -->|${o}| flow_${l(c)}`)}k.push("```");const m=`## Architectural Flow
|
|
15
15
|
|
|
16
|
-
${
|
|
16
|
+
${k.join(`
|
|
17
17
|
`)}`,S=[`# Architecture Diagrams: ${t}
|
|
18
18
|
`];return S.push(T),S.push(m),S.join(`
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
`)}function ue(g,u){if(u.has(g))return g;for(const t of[".ts",".tsx",".js",".jsx"])if(u.has(`${g}${t}`))return`${g}${t}`;return u.has(`${g}/index.ts`)?`${g}/index.ts`:g}const ge=new Set(["node_modules",".git","dist","build","coverage",".turbo",".cache","cdk.out","__pycache__",".venv","target","obj",".gradle"]),G=[{glob:/\.env(?:\.\w+)?$/,type:"env"},{glob:/\.env\.example$/,type:"env"},{glob:/package\.json$/,type:"package-json"},{glob:/^(?:app|config|settings|default)\.(?:json|ya?ml|toml)$/i,type:"config"},{glob:/docker-compose\.ya?ml$/,type:"docker"},{glob:/cdk\.json$/,type:"cdk"},{glob:/turbo\.json$/,type:"tooling"},{glob:/application\.(?:properties|ya?ml)$/i,type:"spring"},{glob:/settings\.py$/,type:"django"},{glob:/\.flaskenv$/,type:"env"},{glob:/appsettings\.(?:\w+\.)?json$/i,type:"dotnet"}];async function pe(g,u){const t=[],p=await fe(g),n=/kb\.config\.json$/;for(const a of p)try{const i=H(g,a).replace(/\\/g,"/");if(n.test(i))continue;const d=await Z(a,"utf-8"),y=de(a);if(i.split("/").length-1>1&&y==="tooling")continue;const
|
|
23
|
-
`)){const n=p.trim();if(!n||n.startsWith("#"))continue;const a=n.indexOf("=");if(a===-1)continue;const i=n.slice(0,a).trim(),d=n.slice(a+1).trim(),y=
|
|
24
|
-
`)){const n=p.trim();if(!n||n.startsWith("#")||n.startsWith("---"))continue;const a=n.match(/^([\w.[\]-]+)\s*[=:]\s*(.*)$/);if(a){const i=a[1],d=a[2].trim(),y=
|
|
25
|
-
`)){const n=p.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.+)$/);if(n){const a=n[1],i=n[2].trim(),d=
|
|
22
|
+
`)}function ue(g,u){if(u.has(g))return g;for(const t of[".ts",".tsx",".js",".jsx"])if(u.has(`${g}${t}`))return`${g}${t}`;return u.has(`${g}/index.ts`)?`${g}/index.ts`:g}const ge=new Set(["node_modules",".git","dist","build","coverage",".turbo",".cache","cdk.out","__pycache__",".venv","target","obj",".gradle"]),G=[{glob:/\.env(?:\.\w+)?$/,type:"env"},{glob:/\.env\.example$/,type:"env"},{glob:/package\.json$/,type:"package-json"},{glob:/^(?:app|config|settings|default)\.(?:json|ya?ml|toml)$/i,type:"config"},{glob:/docker-compose\.ya?ml$/,type:"docker"},{glob:/cdk\.json$/,type:"cdk"},{glob:/turbo\.json$/,type:"tooling"},{glob:/application\.(?:properties|ya?ml)$/i,type:"spring"},{glob:/settings\.py$/,type:"django"},{glob:/\.flaskenv$/,type:"env"},{glob:/appsettings\.(?:\w+\.)?json$/i,type:"dotnet"}];async function pe(g,u){const t=[],p=await fe(g),n=/kb\.config\.json$/;for(const a of p)try{const i=H(g,a).replace(/\\/g,"/");if(n.test(i))continue;const d=await Z(a,"utf-8"),y=de(a);if(i.split("/").length-1>1&&y==="tooling")continue;const b=he(d,y);b.length>0&&t.push({file:i,type:y,values:b})}catch{}return me(t,u)}async function fe(g){const u=[],t=async(p,n)=>{if(!(n>3))try{const a=await J(p,{withFileTypes:!0});for(const i of a){if(ge.has(i.name))continue;const d=O(p,i.name);i.isDirectory()&&!i.name.startsWith(".")?await t(d,n+1):i.isFile()&&G.some(y=>y.glob.test(i.name))&&u.push(d)}}catch{}};return await t(g,0),u}function de(g){const u=N(g);for(const t of G)if(t.glob.test(u))return t.type;return"unknown"}const K=/(?:secret|password|token|key|api.?key|auth|credential|private)/i;function he(g,u){const t=[];if(u==="env")for(const p of g.split(`
|
|
23
|
+
`)){const n=p.trim();if(!n||n.startsWith("#"))continue;const a=n.indexOf("=");if(a===-1)continue;const i=n.slice(0,a).trim(),d=n.slice(a+1).trim(),y=K.test(i);t.push({key:i,value:y?"***":d,sensitive:y})}else if(u==="package-json")try{const p=JSON.parse(g);if(p.scripts)for(const[n,a]of Object.entries(p.scripts))t.push({key:`scripts.${n}`,value:String(a),sensitive:!1});if(p.engines)for(const[n,a]of Object.entries(p.engines))t.push({key:`engines.${n}`,value:String(a),sensitive:!1})}catch{}else if(u==="spring")for(const p of g.split(`
|
|
24
|
+
`)){const n=p.trim();if(!n||n.startsWith("#")||n.startsWith("---"))continue;const a=n.match(/^([\w.[\]-]+)\s*[=:]\s*(.*)$/);if(a){const i=a[1],d=a[2].trim(),y=K.test(i);t.push({key:i,value:y?"***":d,sensitive:y})}}else if(u==="json"||u==="config"||u==="cdk"||u==="tooling"||u==="dotnet")try{const p=JSON.parse(g);W(p,"",t,0)}catch{}else if(u==="django")for(const p of g.split(`
|
|
25
|
+
`)){const n=p.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.+)$/);if(n){const a=n[1],i=n[2].trim(),d=K.test(a);t.push({key:a,value:d?"***":i.slice(0,100),sensitive:d})}}return t}function W(g,u,t,p){if(!(p>3)&&g!=null&&typeof g=="object"&&!Array.isArray(g))for(const[n,a]of Object.entries(g)){const i=u?`${u}.${n}`:n;if(typeof a=="object"&&a!==null&&!Array.isArray(a))W(a,i,t,p+1);else{const d=K.test(n),y=Array.isArray(a)?`[${a.length} items]`:String(a);t.push({key:i,value:d?"***":y.slice(0,120),sensitive:d})}}}function me(g,u){const t=[];if(t.push(`## Configuration Values: ${u}
|
|
26
26
|
`),g.length===0)return t.push("No configuration files detected."),t.join(`
|
|
27
27
|
`);t.push(`**${g.length} config files** found
|
|
28
28
|
`);const p=new Map;for(const a of g)p.has(a.type)||p.set(a.type,[]),p.get(a.type)?.push(a);for(const[a,i]of p){if(a==="package-json"&&i.length>2){t.push(`### ${a}
|
|
29
|
-
`);const d=i.find(
|
|
30
|
-
`),t.push("| Key | Value | Sensitive |"),t.push("|-----|-------|-----------|");for(const
|
|
31
|
-
`);const
|
|
32
|
-
`),t.push("| Key | Value |"),t.push("|-----|-------|");for(const l of
|
|
33
|
-
`);const
|
|
34
|
-
`),t.push("| Key | Value | Sensitive |"),t.push("|-----|-------|-----------|");for(const l of
|
|
29
|
+
`);const d=i.find($=>$.file==="package.json");if(d){t.push(`#### ${d.file}
|
|
30
|
+
`),t.push("| Key | Value | Sensitive |"),t.push("|-----|-------|-----------|");for(const $ of d.values.slice(0,50)){const b=$.value.replace(/\|/g,"\\|");t.push(`| ${$.key} | ${b} | ${$.sensitive?"\u26A0\uFE0F yes":"no"} |`)}t.push("")}const y=i.filter($=>$.file!=="package.json");if(y.length>0){const $=new Map;for(const l of y)for(const r of l.values){const w=`${r.key}=${r.value}`;$.set(w,($.get(w)??0)+1)}const b=Math.max(2,Math.floor(y.length*.5));t.push(`#### Sub-packages (${y.length} packages)
|
|
31
|
+
`);const M=[...$.entries()].filter(([,l])=>l>=b).map(([l])=>{const[r,...w]=l.split("=");return{key:r,value:w.join("=")}});if(M.length>0){t.push(`**Common scripts** (shared by most sub-packages):
|
|
32
|
+
`),t.push("| Key | Value |"),t.push("|-----|-------|");for(const l of M)t.push(`| ${l.key} | ${l.value.replace(/\|/g,"\\|")} |`);t.push("")}const C=new Map;for(const l of y){const r=l.values.filter(P=>{const T=`${P.key}=${P.value}`;return($.get(T)??0)<b});if(r.length===0)continue;const w=r.map(P=>`${P.key}=${P.value}`).sort().join("||"),_=C.get(w);_?_.files.push(l.file):C.set(w,{files:[l.file],entries:r.map(P=>({key:P.key,value:P.value}))})}for(const[,l]of C){l.files.length>1?t.push(`**${l.files.length} packages** (${l.files.map(r=>r.split("/").slice(-2,-1)[0]||r).join(", ")}):`):t.push(`**${l.files[0]}**:`),t.push("| Key | Value |"),t.push("|-----|-------|");for(const r of l.entries)t.push(`| ${r.key} | ${r.value.replace(/\|/g,"\\|")} |`);t.push("")}}continue}if(i.length>3){const d=i.map(b=>b.values.map(M=>`${M.key}=${M.value}`).sort().join("||")),y=d.sort((b,M)=>d.filter(C=>C===M).length-d.filter(C=>C===b).length)[0];if(d.filter(b=>b===y).length>2){t.push(`### ${a}
|
|
33
|
+
`);const b=i[d.indexOf(y)],M=i.filter((l,r)=>d[r]===y).map(l=>l.file),C=i.filter((l,r)=>d[r]!==y);t.push(`**${M.length} identical files**: ${M.join(", ")}
|
|
34
|
+
`),t.push("| Key | Value | Sensitive |"),t.push("|-----|-------|-----------|");for(const l of b.values.slice(0,30)){const r=l.value.replace(/\|/g,"\\|");t.push(`| ${l.key} | ${r} | ${l.sensitive?"\u26A0\uFE0F yes":"no"} |`)}t.push("");for(const l of C){t.push(`#### ${l.file}
|
|
35
35
|
`),t.push("| Key | Value | Sensitive |"),t.push("|-----|-------|-----------|");for(const r of l.values.slice(0,30)){const w=r.value.replace(/\|/g,"\\|");t.push(`| ${r.key} | ${w} | ${r.sensitive?"\u26A0\uFE0F yes":"no"} |`)}t.push("")}continue}}t.push(`### ${a}
|
|
36
36
|
`);for(const d of i){t.push(`#### ${d.file}
|
|
37
|
-
`),t.push("| Key | Value | Sensitive |"),t.push("|-----|-------|-----------|");for(const y of d.values.slice(0,50)){const
|
|
37
|
+
`),t.push("| Key | Value | Sensitive |"),t.push("|-----|-------|-----------|");for(const y of d.values.slice(0,50)){const $=y.value.replace(/\|/g,"\\|");t.push(`| ${y.key} | ${$} | ${y.sensitive?"\u26A0\uFE0F yes":"no"} |`)}d.values.length>50&&t.push(`
|
|
38
38
|
_...and ${d.values.length-50} more values._`),t.push("")}}const n=g.reduce((a,i)=>a+i.values.filter(d=>d.sensitive).length,0);return n>0&&t.push(`
|
|
39
39
|
**\u26A0\uFE0F ${n} sensitive values detected** (values masked).`),t.join(`
|
|
40
|
-
`)}async function ve(g){const u=Date.now(),t=Q(g.path),p=
|
|
40
|
+
`)}async function ve(g){const u=Date.now(),t=Q(g.path),p=N(t),n=g.mode??"memory",a=g.outDir??O(t,".ai","kb"),i=new oe,d=new X,y=new re,$=new ne,b=new ee,M=new Y,C=[{name:"structure",fn:()=>i.analyze(t,{format:"markdown",maxDepth:3,sourceOnly:!0})},{name:"dependencies",fn:()=>d.analyze(t,{format:"markdown"})},{name:"entry-points",fn:()=>b.analyze(t)},{name:"symbols",fn:()=>y.analyze(t,{format:"markdown"})},{name:"patterns",fn:()=>$.analyze(t)},{name:"diagram",fn:()=>M.analyze(t,{diagramType:"architecture"})}],l=await Promise.allSettled(C.map(async e=>{const o=Date.now(),s=await e.fn();return{name:e.name,result:s,durationMs:Date.now()-o}})),r=[],w=new Map,_=new Map;for(const e of l)if(e.status==="fulfilled"){const{name:o,result:s,durationMs:c}=e.value,h=s;r.push({name:o,status:"success",output:h.output,durationMs:c}),w.set(o,h.output),_.set(o,h.data)}else{const o=e.reason,s=l.indexOf(e),c=C[s].name;r.push({name:c,status:"failed",output:"",durationMs:0,error:o.message})}const P=Date.now();let T=null;try{let e=await se(t);if((!e||e.edges.length===0)&&(e=await te(t)),e&&e.edges.length>0){T=new Map;for(const o of e.edges){let s=T.get(o.from);s||(s=new Map,T.set(o.from,s));const c=s.get(o.to);if(c)for(const h of o.symbols)c.includes(h)||c.push(h);else s.set(o.to,[...o.symbols])}}}catch{}const k=Date.now()-P,f=Date.now(),x=ce(_,p,T),v=Date.now()-f+k;if(r.push({name:"code-map",status:"success",output:x,durationMs:v}),w.set("code-map",x),T&&T.size>0){const e=le(T,_,p),o=r.find(s=>s.name==="diagram");o&&(o.output=e,w.set("diagram",e))}const j=Date.now(),D=await pe(t,p),m=Date.now()-j;r.push({name:"config-values",status:"success",output:D,durationMs:m}),w.set("config-values",D);const S=ie(r,n,p,_);if(r.push({name:"synthesis-guide",status:"success",output:S,durationMs:0}),w.set("synthesis-guide",S),n==="generate"){if(F(a))for(const s of q(a))(s.endsWith(".md")||s.endsWith(".json"))&&U(O(a,s),{force:!0});V(a,{recursive:!0});const e=new Date().toISOString();for(const[s,c]of w){const h=`${s}.md`,A=O(a,h),E=c.replaceAll(t,p),I=`<!-- Generated: ${e} -->
|
|
41
41
|
<!-- Project: ${p} -->
|
|
42
42
|
<!-- Source: ${t} -->
|
|
43
43
|
|
|
44
|
-
`;
|
|
44
|
+
`;B(A,I+E,"utf-8")}const o=[`<!-- Generated: ${e} -->`,`<!-- Project: ${p} -->`,`<!-- Source: ${t} -->`,"",`# ${p} \u2014 Codebase Knowledge`,"","## Contents",""];for(const s of r){const c=`${s.name}.md`,h=L[s.name]??s.name,A=s.status==="success"?"\u2713":"\u2717",E=s.durationMs>0?` (${s.durationMs}ms)`:"";o.push(`- ${A} [${h}](./${c})${E}`)}o.push(""),B(O(a,"README.md"),o.join(`
|
|
45
45
|
`),"utf-8")}return{path:t,mode:n,steps:r,outDir:n==="generate"?a:void 0,totalDurationMs:Date.now()-u}}export{ve as onboard};
|