@hawon/nexus 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +60 -38
  2. package/dist/cli/index.js +76 -145
  3. package/dist/index.js +15 -26
  4. package/dist/mcp/server.js +61 -32
  5. package/package.json +2 -1
  6. package/scripts/auto-skill.sh +54 -0
  7. package/scripts/auto-sync.sh +11 -0
  8. package/scripts/benchmark.ts +444 -0
  9. package/scripts/scan-tool-result.sh +46 -0
  10. package/src/cli/index.ts +79 -172
  11. package/src/index.ts +17 -29
  12. package/src/mcp/server.ts +67 -41
  13. package/src/memory-engine/index.ts +4 -6
  14. package/src/memory-engine/nexus-memory.test.ts +437 -0
  15. package/src/memory-engine/nexus-memory.ts +631 -0
  16. package/src/memory-engine/semantic.ts +380 -0
  17. package/src/parser/parse.ts +1 -21
  18. package/src/promptguard/advanced-rules.ts +129 -12
  19. package/src/promptguard/entropy.ts +21 -2
  20. package/src/promptguard/evolution/auto-update.ts +16 -6
  21. package/src/promptguard/multilingual-rules.ts +68 -0
  22. package/src/promptguard/rules.ts +87 -2
  23. package/src/promptguard/scanner.test.ts +262 -0
  24. package/src/promptguard/scanner.ts +1 -1
  25. package/src/promptguard/semantic.ts +19 -4
  26. package/src/promptguard/token-analysis.ts +17 -5
  27. package/src/review/analyzer.test.ts +279 -0
  28. package/src/review/analyzer.ts +112 -28
  29. package/src/shared/stop-words.ts +21 -0
  30. package/src/skills/index.ts +11 -27
  31. package/src/skills/memory-skill-engine.ts +1044 -0
  32. package/src/testing/health-check.ts +19 -2
  33. package/src/cost/index.ts +0 -3
  34. package/src/cost/tracker.ts +0 -290
  35. package/src/cost/types.ts +0 -34
  36. package/src/memory-engine/compressor.ts +0 -97
  37. package/src/memory-engine/context-window.ts +0 -113
  38. package/src/memory-engine/store.ts +0 -371
  39. package/src/memory-engine/types.ts +0 -32
  40. package/src/skills/context-engine.ts +0 -863
  41. package/src/skills/extractor.ts +0 -224
  42. package/src/skills/global-context.ts +0 -726
  43. package/src/skills/library.ts +0 -189
  44. package/src/skills/pattern-engine.ts +0 -712
  45. package/src/skills/render-evolved.ts +0 -160
  46. package/src/skills/skill-reconciler.ts +0 -703
  47. package/src/skills/smart-extractor.ts +0 -843
  48. package/src/skills/types.ts +0 -18
  49. package/src/skills/wisdom-extractor.ts +0 -737
  50. package/src/superdev-evolution/index.ts +0 -3
  51. package/src/superdev-evolution/skill-manager.ts +0 -266
  52. package/src/superdev-evolution/types.ts +0 -20
package/README.md CHANGED
@@ -1,8 +1,16 @@
1
1
  # nexus
2
2
 
3
+ ### If you find this useful, please give it a star! It helps a lot.
4
+
5
+ [![GitHub stars](https://img.shields.io/github/stars/hawonb711-tech/nexus?style=social)](https://github.com/hawonb711-tech/nexus/stargazers)
6
+ [![npm](https://img.shields.io/npm/v/@hawon/nexus)](https://www.npmjs.com/package/@hawon/nexus)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
3
9
  The all-in-one AI developer framework — session intelligence, code review, prompt injection defense, infinite memory, and self-evolving skills.
4
10
 
5
- **15 modules · 15 CLI commands · 14 MCP tools · 14,000+ lines · zero deps**
11
+ **14 modules · 14 CLI commands · 13 MCP tools · 15,000+ lines · zero deps**
12
+
13
+ > *"Claude Code를 더 안전하고, 더 똑똑하게"*
6
14
 
7
15
  ## Features
8
16
 
@@ -10,19 +18,18 @@ The all-in-one AI developer framework — session intelligence, code review, pro
10
18
  |--------|-------------|
11
19
  | **Multi-platform Parser** | Discover and parse sessions from Claude Code and OpenClaw |
12
20
  | **Obsidian Export** | Structured markdown with frontmatter, backlinks, MOC, Daily Notes |
13
- | **Prompt Injection Guard** | 6-layer, 82-rule detection across 8 languages |
21
+ | **Prompt Injection Guard** | 6-layer, 82-rule detection across 10 languages |
14
22
  | **Code Review** | 19 detectors: AI slop, bugs, security, performance, dead code |
15
23
  | **Codebase Mapping** | Architecture map, dependency graph, entry points, hotspots |
16
24
  | **Test Health** | Broken imports, stale mocks, missing tests, coverage estimate |
17
- | **Cost Monitor** | AI API cost tracking, budget alerts, spike detection |
18
25
  | **Config Validator** | Exposed secrets, missing env vars, insecure defaults |
19
- | **Infinite Memory** | 4-tier hierarchical store with TF-IDF search, auto-compression |
26
+ | **Infinite Memory** | BM25 + semantic search, knowledge graph, progressive retrieval |
27
+ | **Skill Auto-Generation** | LLM auto-generates SKILL.md after each session (Hermes-style) |
28
+ | **3-Tier Knowledge** | Skills (complex), Tips (quick), Facts (reference) → Obsidian |
20
29
  | **Context Engine** | Bayesian intent classifier + conversation state machine |
21
30
  | **Global Context** | Thread weaving, user state model, topic switch detection |
22
- | **Pattern Engine** | Cross-session pattern evolution with drift analysis |
23
- | **Smart Extractor** | Episode segmentation + decision point identification |
24
- | **Wisdom Extractor** | Extracts principles ("when X, do Y because Z"), not procedures |
25
- | **Skill Reconciler** | Quality gate, conditional branches, preference learning |
31
+ | **Semantic Engine** | 75 synonym groups (EN↔KO), PMI co-occurrence, query expansion |
32
+ | **Auto-Scan Hook** | Real-time prompt injection defense via PostToolUse hook |
26
33
 
27
34
  ## Install
28
35
 
@@ -45,7 +52,7 @@ nexus review src/app.ts
45
52
  # Map codebase architecture
46
53
  nexus map .
47
54
 
48
- # Full vault reorganization with wisdom pipeline
55
+ # Full vault reorganization with knowledge pipeline
49
56
  nexus reorganize
50
57
  ```
51
58
 
@@ -54,10 +61,10 @@ nexus reorganize
54
61
  | Command | Description |
55
62
  |---------|-------------|
56
63
  | `sync` | Sync all sessions to Obsidian (multi-platform) |
57
- | `reorganize` | Clean rebuild with wisdom + skill pipeline |
64
+ | `reorganize` | Clean rebuild with knowledge pipeline |
58
65
  | `sessions` | List all discovered sessions |
59
66
  | `export <id>` | Export a single session |
60
- | `skills` | View extracted refined skills |
67
+ | `skills` | View extracted knowledge (skills/tips/facts) |
61
68
  | `skills search <q>` | Search skills by keyword |
62
69
  | `status` | Vault sync status |
63
70
  | `scan <text>` | Prompt injection detection |
@@ -66,12 +73,11 @@ nexus reorganize
66
73
  | `onboard [dir]` | Onboarding guide generation |
67
74
  | `test-health [dir]` | Test suite health check |
68
75
  | `config [dir]` | Config/env validation |
69
- | `cost` | AI API cost report |
70
76
  | `memory <search\|stats>` | Persistent memory operations |
71
77
 
72
78
  ## MCP Server
73
79
 
74
- Nexus runs as an MCP server with 14 tools for Claude Code, OpenClaw, and any MCP-compatible agent.
80
+ Nexus runs as an MCP server with 13 tools for Claude Code, OpenClaw, and any MCP-compatible agent.
75
81
 
76
82
  ```json
77
83
  {
@@ -97,26 +103,49 @@ Nexus runs as an MCP server with 14 tools for Claude Code, OpenClaw, and any MCP
97
103
  | `nexus_onboard` | Onboarding guide generation |
98
104
  | `nexus_test_health` | Test suite health check |
99
105
  | `nexus_config` | Config/env validation |
100
- | `nexus_cost` | AI API cost report |
101
106
  | `nexus_memory_search` | Search persistent memory |
102
107
  | `nexus_memory_save` | Save to persistent memory |
103
- | `nexus_skills` | List refined skills |
108
+ | `nexus_skills` | List knowledge (skills/tips/facts) |
104
109
 
105
- ## Skill Extraction Pipeline
110
+ ## Auto-Hooks
106
111
 
107
- 6-layer pipeline that turns raw AI conversations into refined, reusable knowledge:
112
+ ### Prompt Injection Defense (PostToolUse)
108
113
 
114
+ Auto-scans every WebFetch/WebSearch result before Claude sees it:
115
+
116
+ ```json
117
+ {
118
+ "hooks": {
119
+ "PostToolUse": [{
120
+ "matcher": "WebFetch",
121
+ "hooks": [{
122
+ "type": "command",
123
+ "command": "bash /path/to/nexus/scripts/scan-tool-result.sh",
124
+ "timeout": 10
125
+ }]
126
+ }]
127
+ }
128
+ }
109
129
  ```
110
- Session JSONL → Smart Extractor (episode segmentation)
111
- → Context Engine (Bayesian intent + state machine)
112
- → Global Context (thread weaving + user state)
113
- → Pattern Engine (cross-session evolution)
114
- → Wisdom Extractor (principles, not procedures)
115
- → Skill Reconciler (quality gate + preferences)
116
- → Refined Skills → Obsidian
117
- ```
118
130
 
119
- **"이럴 때는 이렇게"** — not "Edit src/file.ts at line 42"
131
+ ### Auto-Skill Generation (SessionEnd)
132
+
133
+ Claude auto-generates SKILL.md after each session (Hermes Agent style):
134
+
135
+ ```json
136
+ {
137
+ "hooks": {
138
+ "SessionEnd": [{
139
+ "hooks": [{
140
+ "type": "command",
141
+ "command": "bash /path/to/nexus/scripts/auto-skill.sh",
142
+ "timeout": 60,
143
+ "async": true
144
+ }]
145
+ }]
146
+ }
147
+ }
148
+ ```
120
149
 
121
150
  ## Architecture
122
151
 
@@ -124,22 +153,15 @@ Session JSONL → Smart Extractor (episode segmentation)
124
153
  nexus
125
154
  ├── parser/ Multi-platform (Claude Code + OpenClaw)
126
155
  ├── obsidian/ Markdown + MOC + Daily Notes
127
- ├── skills/ 6-layer extraction pipeline
128
- ├── context-engine Bayesian intent + state machine
129
- │ ├── global-context Thread weaving + user state
130
- │ ├── pattern-engine Cross-session evolution
131
- │ ├── smart-extractor Episode segmentation
132
- │ ├── wisdom-extractor Principles, not procedures
133
- │ └── skill-reconciler Quality gate + preferences
134
- ├── promptguard/ Prompt injection (82 rules, 8 languages)
156
+ ├── skills/ Knowledge extraction + auto-generation
157
+ ├── promptguard/ Prompt injection (82 rules, 10 languages)
135
158
  ├── review/ Code review (19 detectors)
136
159
  ├── codebase/ Architecture mapping + onboarding
137
160
  ├── testing/ Test health + fix suggestions
138
- ├── cost/ API cost tracking + budget alerts
139
161
  ├── config/ Config/env validation
140
- ├── memory-engine/ Infinite hierarchical memory
141
- ├── mcp/ MCP server (14 tools)
142
- └── cli/ Unified CLI (15 commands)
162
+ ├── memory-engine/ BM25 + semantic search + knowledge graph
163
+ ├── mcp/ MCP server (13 tools)
164
+ └── cli/ Unified CLI (14 commands)
143
165
  ```
144
166
 
145
167
  ## License
package/dist/cli/index.js CHANGED
@@ -6,19 +6,15 @@ import { discoverSessions } from "../parser/discover.js";
6
6
  import { discoverAllSessions } from "../parser/unified.js";
7
7
  import { parseSession } from "../parser/parse.js";
8
8
  import { exportSession } from "../obsidian/exporter.js";
9
- import { extractSkills } from "../skills/extractor.js";
10
9
  import { reviewCode } from "../review/analyzer.js";
11
10
  import { mapCodebase } from "../codebase/mapper.js";
12
11
  import { generateOnboardingGuide } from "../codebase/onboard.js";
13
12
  import { checkTestHealth } from "../testing/health-check.js";
14
13
  import { suggestFixes } from "../testing/test-fixer.js";
15
14
  import { validateConfig } from "../config/validator.js";
16
- import { createCostTracker } from "../cost/tracker.js";
17
- import { createMemoryStore } from "../memory-engine/store.js";
15
+ import { createNexusMemory } from "../memory-engine/nexus-memory.js";
18
16
  import { scan as scanPrompt } from "../promptguard/scanner.js";
19
- import { addSkills, exportToObsidian, loadSkillLibrary, saveSkillLibrary, searchSkills, } from "../skills/library.js";
20
- import { extractWisdom } from "../skills/wisdom-extractor.js";
21
- import { reconcileWisdom, loadRefinedLibrary, saveRefinedLibrary, exportRefinedSkills, } from "../skills/skill-reconciler.js";
17
+ import { extractMemorySkills, renderKnowledgeBase } from "../skills/memory-skill-engine.js";
22
18
  import { readdirSync, rmSync } from "node:fs";
23
19
  // ── ANSI Colors ──────────────────────────────────────────────────
24
20
  const c = {
@@ -56,7 +52,7 @@ function resolveConfig(flags) {
56
52
  const vaultPath = flags["--vault"] ??
57
53
  process.env["NEXUS_VAULT_PATH"] ??
58
54
  join(homedir(), "ObsidianVault", "Claude");
59
- const dataDir = join(vaultPath, ".nexus");
55
+ const dataDir = process.env["NEXUS_DATA"] ?? join(homedir(), ".nexus");
60
56
  return { vaultPath, dataDir };
61
57
  }
62
58
  function loadStatus(dataDir) {
@@ -191,30 +187,20 @@ function cmdSync(flags) {
191
187
  }
192
188
  const parsedSessions = [];
193
189
  const exportedFiles = [];
194
- let skillsExtracted = 0;
195
- const library = loadSkillLibrary(config.dataDir);
196
190
  for (let i = 0; i < allSessionPaths.length; i++) {
197
191
  const { path: sessionPath } = allSessionPaths[i];
198
192
  logProgress(i + 1, allSessionPaths.length, `Syncing session ${i + 1}/${allSessionPaths.length}...`);
199
193
  try {
200
194
  const session = parseSession(sessionPath);
201
195
  parsedSessions.push(session);
202
- // 3. Export to Obsidian
203
196
  const filePath = exportSessionToObsidian(session, config.vaultPath);
204
197
  exportedFiles.push(filePath);
205
- // 4. Extract skills
206
- const skills = extractSkills(session);
207
- const added = addSkills(library, skills);
208
- skillsExtracted += added;
209
198
  }
210
199
  catch (err) {
211
200
  const msg = err instanceof Error ? err.message : String(err);
212
201
  log(`\n${c.yellow}Warning:${c.reset} Failed to parse ${sessionPath}: ${msg}`);
213
202
  }
214
203
  }
215
- // 5. Save skill library & export to Obsidian
216
- saveSkillLibrary(library, config.dataDir);
217
- const skillFiles = exportToObsidian(library, config.vaultPath);
218
204
  // 6. Update MOC and daily notes
219
205
  logInfo("Updating MOC and daily notes...");
220
206
  updateMOC(parsedSessions, config.vaultPath);
@@ -223,18 +209,15 @@ function cmdSync(flags) {
223
209
  const status = {
224
210
  lastSync: new Date().toISOString(),
225
211
  totalSessions: parsedSessions.length,
226
- totalSkills: library.skills.length,
212
+ totalSkills: 0,
227
213
  sessionsExported: parsedSessions.map((s) => s.sessionId),
228
214
  };
229
215
  saveStatus(status, config.dataDir);
230
- // Summary
231
216
  log("");
232
217
  log(`${c.bold}${c.green}Sync complete!${c.reset}`);
233
218
  log(` ${c.cyan}Sessions exported:${c.reset} ${exportedFiles.length}`);
234
- log(` ${c.cyan}New skills found:${c.reset} ${skillsExtracted}`);
235
- log(` ${c.cyan}Total skills:${c.reset} ${library.skills.length}`);
236
- log(` ${c.cyan}Skill files:${c.reset} ${skillFiles.length}`);
237
219
  log(` ${c.cyan}Vault path:${c.reset} ${config.vaultPath}`);
220
+ log(` ${c.dim}Run \`nexus reorganize\` to extract knowledge.${c.reset}`);
238
221
  }
239
222
  function cmdSessions() {
240
223
  const discovery = discoverSessions();
@@ -291,30 +274,36 @@ function cmdExport(sessionId, flags) {
291
274
  const session = parseSession(matchedPath);
292
275
  const filePath = exportSessionToObsidian(session, config.vaultPath);
293
276
  logSuccess(`Exported to ${filePath}`);
294
- // Extract skills too
295
- const library = loadSkillLibrary(config.dataDir);
296
- const skills = extractSkills(session);
297
- const added = addSkills(library, skills);
298
- if (added > 0) {
299
- saveSkillLibrary(library, config.dataDir);
300
- logSuccess(`Extracted ${added} new skill(s)`);
301
- }
302
277
  }
303
278
  function cmdSkills(flags) {
304
279
  const config = resolveConfig(flags);
305
- const library = loadSkillLibrary(config.dataDir);
306
- if (library.skills.length === 0) {
307
- logInfo("No skills extracted yet. Run `nexus sync` first.");
280
+ const kbPath = join(config.dataDir, "knowledge.json");
281
+ if (!existsSync(kbPath)) {
282
+ logInfo("No knowledge extracted yet. Run `nexus reorganize` first.");
308
283
  return;
309
284
  }
310
- log(`\n${c.bold}Extracted Skills${c.reset} (${library.skills.length} total)\n`);
311
- log(`${"Name".padEnd(45)} ${"Confidence".padEnd(12)} Tools`);
312
- log(`${"-".repeat(45)} ${"-".repeat(12)} ${"-".repeat(30)}`);
313
- for (const skill of library.skills) {
314
- const name = skill.name.slice(0, 43).padEnd(45);
315
- const conf = `${(skill.confidence * 100).toFixed(0)}%`.padEnd(12);
316
- const tools = skill.toolsUsed.join(", ");
317
- log(`${c.cyan}${name}${c.reset} ${c.yellow}${conf}${c.reset} ${tools}`);
285
+ const kb = JSON.parse(readFileSync(kbPath, "utf-8"));
286
+ const skills = kb.skills ?? [];
287
+ const tips = kb.tips ?? [];
288
+ const facts = kb.facts ?? [];
289
+ log(`\n${c.bold}Knowledge Base${c.reset} (${skills.length} skills | ${tips.length} tips | ${facts.length} facts)\n`);
290
+ if (skills.length > 0) {
291
+ log(`${c.bold}Skills:${c.reset}`);
292
+ for (const s of skills) {
293
+ log(` ${c.cyan}${s.name.slice(0, 50)}${c.reset} — ${(s.confidence * 100).toFixed(0)}% | ${s.evidenceCount} evidence`);
294
+ }
295
+ }
296
+ if (tips.length > 0) {
297
+ log(`\n${c.bold}Tips:${c.reset}`);
298
+ for (const t of tips) {
299
+ log(` 💡 ${t.advice?.slice(0, 60) ?? t.name}`);
300
+ }
301
+ }
302
+ if (facts.length > 0) {
303
+ log(`\n${c.bold}Facts:${c.reset}`);
304
+ for (const f of facts) {
305
+ log(` 📌 ${f.statement?.slice(0, 60) ?? f.name}`);
306
+ }
318
307
  }
319
308
  log("");
320
309
  }
@@ -323,32 +312,16 @@ function cmdSkillsSearch(query, flags) {
323
312
  logError("Usage: nexus skills search <query>");
324
313
  process.exit(1);
325
314
  }
326
- const config = resolveConfig(flags);
327
- const library = loadSkillLibrary(config.dataDir);
328
- const results = searchSkills(library, query);
329
- if (results.length === 0) {
330
- logInfo(`No skills matching "${query}".`);
331
- return;
332
- }
333
- log(`\n${c.bold}Skills matching "${query}"${c.reset} (${results.length} results)\n`);
334
- for (const skill of results) {
335
- log(`${c.cyan}${c.bold}${skill.name}${c.reset} ${c.dim}(${(skill.confidence * 100).toFixed(0)}% confidence)${c.reset}`);
336
- log(` ${c.dim}Trigger:${c.reset} ${skill.trigger}`);
337
- log(` ${c.dim}Tools:${c.reset} ${skill.toolsUsed.join(", ")}`);
338
- log(` ${c.dim}Steps:${c.reset} ${skill.steps.length}`);
339
- log("");
340
- }
315
+ logInfo(`Search not available yet. Use \`nexus skills\` to view all knowledge.`);
341
316
  }
342
317
  function cmdStatus(flags) {
343
318
  const config = resolveConfig(flags);
344
319
  const status = loadStatus(config.dataDir);
345
- const library = loadSkillLibrary(config.dataDir);
346
- log(`\n${c.bold}Claude Vault Status${c.reset}\n`);
320
+ log(`\n${c.bold}Nexus Status${c.reset}\n`);
347
321
  log(` ${c.cyan}Vault path:${c.reset} ${config.vaultPath}`);
348
322
  log(` ${c.cyan}Last sync:${c.reset} ${status.lastSync || "never"}`);
349
- log(` ${c.cyan}Total sessions:${c.reset} ${status.totalSessions}`);
350
- log(` ${c.cyan}Total skills:${c.reset} ${library.skills.length}`);
351
- log(` ${c.cyan}Library ver:${c.reset} ${library.version}`);
323
+ log(` ${c.cyan}Sessions:${c.reset} ${status.sessionsExported ?? 0}`);
324
+ log(` ${c.cyan}Knowledge:${c.reset} ${status.totalKnowledge ?? "run reorganize"}`);
352
325
  log("");
353
326
  }
354
327
  function cmdReorganize(flags) {
@@ -408,41 +381,38 @@ function cmdReorganize(flags) {
408
381
  }
409
382
  process.stdout.write("\n");
410
383
  logInfo(`Exported ${exportCount} sessions`);
411
- // Step 3: Extract wisdom from all sessions
412
- logInfo("Extracting wisdom...");
413
- const allWisdoms = [];
414
- for (const session of parsedSessions) {
415
- const wisdoms = extractWisdom(session.messages, session.sessionId);
416
- allWisdoms.push(...wisdoms);
417
- }
418
- logInfo(`Extracted ${allWisdoms.length} raw wisdoms`);
419
- // Step 4: Reconcile into refined skills
420
- logInfo("Reconciling into refined skills...");
421
- const library = loadRefinedLibrary(config.dataDir);
422
- // Clear old skills for full reorg
423
- library.skills = [];
424
- library.version = 1;
425
- const result = reconcileWisdom(allWisdoms, library);
426
- saveRefinedLibrary(library, config.dataDir);
427
- logInfo(`Quality gate: ${result.rejected.length} rejected, ${result.created.length + result.updated.length} passed`);
428
- logInfo(`Refined skills: ${library.skills.length}`);
429
- logInfo(`Preferences learned: ${result.preferencesLearned.length}`);
430
- // Step 5: Export refined skills to Obsidian
431
- const skillFiles = exportRefinedSkills(library, config.vaultPath);
432
- logInfo(`Exported ${skillFiles.length} refined skill files`);
433
- // Step 6: Update MOC and daily notes
384
+ // Step 3: Memory-based knowledge extraction (Skills + Tips + Facts)
385
+ logInfo("Extracting knowledge from observations...");
386
+ const knowledgeResult = extractMemorySkills(parsedSessions, config.dataDir, 2);
387
+ logInfo(`Observations: ${knowledgeResult.observationsIngested} | Clusters: ${knowledgeResult.clustersFormed}`);
388
+ logInfo(`Skills: ${knowledgeResult.skills.length} | Tips: ${knowledgeResult.tips.length} | Facts: ${knowledgeResult.facts.length}`);
389
+ // Step 4: Export knowledge base to Obsidian
390
+ const kbPath = join(config.vaultPath, "Knowledge Base.md");
391
+ writeFileSync(kbPath, renderKnowledgeBase(knowledgeResult), "utf-8");
392
+ // Also save as JSON for MCP tool access
393
+ const knowledgeJson = {
394
+ skills: knowledgeResult.skills,
395
+ tips: knowledgeResult.tips,
396
+ facts: knowledgeResult.facts,
397
+ };
398
+ writeFileSync(join(config.dataDir, "knowledge.json"), JSON.stringify(knowledgeJson, null, 2), "utf-8");
399
+ logInfo("Exported Knowledge Base to Obsidian + MCP cache");
400
+ // Step 5: Update MOC and daily notes
434
401
  logInfo("Updating MOC and daily notes...");
435
402
  updateMOC(parsedSessions, config.vaultPath);
436
403
  updateDailyNotes(parsedSessions, config.vaultPath);
437
- // Step 7: Save status
404
+ // Step 6: Save status
405
+ const totalKnowledge = knowledgeResult.skills.length + knowledgeResult.tips.length + knowledgeResult.facts.length;
438
406
  const status = {
439
407
  lastSync: new Date().toISOString(),
440
408
  lastReorg: new Date().toISOString(),
441
409
  sessionsExported: exportCount,
442
- refinedSkills: library.skills.length,
443
- wisdomsExtracted: allWisdoms.length,
444
- wisdomsRejected: result.rejected.length,
445
- preferencesLearned: result.preferencesLearned.length,
410
+ skills: knowledgeResult.skills.length,
411
+ tips: knowledgeResult.tips.length,
412
+ facts: knowledgeResult.facts.length,
413
+ totalKnowledge,
414
+ observations: knowledgeResult.observationsIngested,
415
+ durationMs: knowledgeResult.durationMs,
446
416
  };
447
417
  mkdirSync(config.dataDir, { recursive: true });
448
418
  writeFileSync(join(config.dataDir, "status.json"), JSON.stringify(status, null, 2), "utf-8");
@@ -450,11 +420,11 @@ function cmdReorganize(flags) {
450
420
  log("");
451
421
  logSuccess("Reorganization complete!");
452
422
  log(` ${c.cyan}Sessions:${c.reset} ${exportCount}`);
453
- log(` ${c.cyan}Raw wisdoms:${c.reset} ${allWisdoms.length}`);
454
- log(` ${c.cyan}Rejected (noise):${c.reset} ${result.rejected.length}`);
455
- log(` ${c.cyan}Refined skills:${c.reset} ${library.skills.length}`);
456
- log(` ${c.cyan}Preferences:${c.reset} ${result.preferencesLearned.length}`);
457
- log(` ${c.cyan}Old folders cleaned:${c.reset} ${foldersToClean.filter((f) => existsSync(join(config.vaultPath, f))).length === 0 ? "yes" : "partial"}`);
423
+ log(` ${c.cyan}Observations:${c.reset} ${knowledgeResult.observationsIngested}`);
424
+ log(` ${c.cyan}Skills:${c.reset} ${knowledgeResult.skills.length}`);
425
+ log(` ${c.cyan}Tips:${c.reset} ${knowledgeResult.tips.length}`);
426
+ log(` ${c.cyan}Facts:${c.reset} ${knowledgeResult.facts.length}`);
427
+ log(` ${c.cyan}Total knowledge:${c.reset} ${totalKnowledge}`);
458
428
  log(` ${c.cyan}Vault:${c.reset} ${config.vaultPath}`);
459
429
  }
460
430
  function cmdReview(filePath, flags) {
@@ -607,51 +577,15 @@ async function cmdConfig(dir, flags) {
607
577
  }
608
578
  log("");
609
579
  }
610
- function cmdCost(flags) {
611
- const config = resolveConfig(flags);
612
- const tracker = createCostTracker(config.dataDir);
613
- const report = tracker.getReport();
614
- const projected = tracker.getProjectedCost();
615
- if ("--json" in flags) {
616
- log(JSON.stringify({ ...report, projectedMonthlyCost: projected }, null, 2));
617
- return;
618
- }
619
- log(`\n${c.bold}AI Cost Report${c.reset}\n`);
620
- log(` ${c.cyan}Total cost:${c.reset} $${report.totalCost.toFixed(4)}`);
621
- log(` ${c.cyan}Total requests:${c.reset} ${report.totalRequests}`);
622
- log(` ${c.cyan}Avg per request:${c.reset} $${report.averageCostPerRequest.toFixed(4)}`);
623
- log(` ${c.cyan}Projected/month:${c.reset} $${report.projectedMonthlyCost.toFixed(2)}`);
624
- const providers = Object.entries(report.byProvider);
625
- if (providers.length > 0) {
626
- log(`\n${c.bold}By Provider:${c.reset}`);
627
- for (const [provider, cost] of providers) {
628
- log(` ${c.yellow}${provider}${c.reset}: $${cost.toFixed(4)}`);
629
- }
630
- }
631
- const models = Object.entries(report.byModel);
632
- if (models.length > 0) {
633
- log(`\n${c.bold}By Model:${c.reset}`);
634
- for (const [model, cost] of models) {
635
- log(` ${c.yellow}${model}${c.reset}: $${cost.toFixed(4)}`);
636
- }
637
- }
638
- if (report.alerts.length > 0) {
639
- log(`\n${c.bold}Alerts:${c.reset}`);
640
- for (const alert of report.alerts) {
641
- log(` ${c.red}[${alert.type}]${c.reset} ${alert.message}`);
642
- }
643
- }
644
- log("");
645
- }
646
580
  function cmdMemory(subcommand, query, flags) {
647
581
  const config = resolveConfig(flags);
648
- const store = createMemoryStore(config.dataDir);
582
+ const store = createNexusMemory(config.dataDir);
649
583
  if (subcommand === "search") {
650
584
  if (!query) {
651
585
  logError("Usage: nexus memory search <query>");
652
586
  process.exit(1);
653
587
  }
654
- const results = store.search({ query });
588
+ const results = store.search(query);
655
589
  if ("--json" in flags) {
656
590
  log(JSON.stringify(results, null, 2));
657
591
  return;
@@ -661,10 +595,9 @@ function cmdMemory(subcommand, query, flags) {
661
595
  return;
662
596
  }
663
597
  log(`\n${c.bold}Memory Search: "${query}"${c.reset} (${results.length} results)\n`);
664
- for (const entry of results) {
665
- log(` ${c.cyan}${c.bold}${entry.id}${c.reset} ${c.dim}[${entry.tier}]${c.reset}`);
666
- log(` ${c.dim}Tags:${c.reset} ${entry.tags.join(", ")}`);
667
- log(` ${entry.content.slice(0, 120)}${entry.content.length > 120 ? "..." : ""}`);
598
+ for (const r of results) {
599
+ log(` ${c.cyan}[${r.retrievalLevel}]${c.reset} score=${r.score.toFixed(2)}`);
600
+ log(` ${r.observation.content.slice(0, 120)}`);
668
601
  log("");
669
602
  }
670
603
  }
@@ -675,13 +608,12 @@ function cmdMemory(subcommand, query, flags) {
675
608
  return;
676
609
  }
677
610
  log(`\n${c.bold}Memory Stats${c.reset}\n`);
678
- log(` ${c.cyan}Total entries:${c.reset} ${stats.totalEntries}`);
679
- log(` ${c.cyan}Total size:${c.reset} ${(stats.totalSizeBytes / 1024).toFixed(1)} KB`);
680
- log(` ${c.cyan}Compression ratio:${c.reset} ${(stats.compressionRatio * 100).toFixed(1)}%`);
681
- log(`\n${c.bold}By Tier:${c.reset}`);
682
- for (const [tier, count] of Object.entries(stats.byTier)) {
683
- log(` ${c.yellow}${tier}${c.reset}: ${count}`);
684
- }
611
+ log(` ${c.cyan}Observations:${c.reset} ${stats.totalObservations}`);
612
+ log(` ${c.cyan}Valid:${c.reset} ${stats.validObservations}`);
613
+ log(` ${c.cyan}Graph nodes:${c.reset} ${stats.graphNodes}`);
614
+ log(` ${c.cyan}Graph edges:${c.reset} ${stats.graphEdges}`);
615
+ log(` ${c.cyan}Tunnels:${c.reset} ${stats.tunnels}`);
616
+ log(` ${c.cyan}Domains:${c.reset} ${stats.domains.join(", ")}`);
685
617
  log("");
686
618
  }
687
619
  else {
@@ -734,7 +666,6 @@ ${c.bold}Commands:${c.reset}
734
666
  ${c.cyan}onboard${c.reset} [dir] Generate onboarding guide
735
667
  ${c.cyan}test-health${c.reset} [dir] Check test suite health
736
668
  ${c.cyan}config${c.reset} [dir] Validate config files
737
- ${c.cyan}cost${c.reset} Show AI cost report
738
669
  ${c.cyan}memory${c.reset} <search|stats> [query] Memory operations
739
670
  ${c.cyan}scan${c.reset} <text> Scan text for prompt injection
740
671
  ${c.cyan}--help${c.reset} Show this help
@@ -832,7 +763,7 @@ async function main() {
832
763
  await cmdConfig(args[0], flags);
833
764
  break;
834
765
  case "cost":
835
- cmdCost(flags);
766
+ logError("Cost tracking has been removed.");
836
767
  break;
837
768
  case "memory":
838
769
  cmdMemory(args[0], args.slice(1).join(" ") || undefined, flags);
package/dist/index.js CHANGED
@@ -7,36 +7,25 @@ export { discoverOpenClawSessions, parseOpenClawSession } from "./parser/opencla
7
7
  export { exportSession } from "./obsidian/exporter.js";
8
8
  export { updateMOC } from "./obsidian/moc.js";
9
9
  export { appendToDailyNote } from "./obsidian/daily-note.js";
10
- // Skills — Wisdom Pipeline
11
- export { extractWisdom, renderWisdomMarkdown } from "./skills/wisdom-extractor.js";
12
- export { reconcileWisdom, loadRefinedLibrary, saveRefinedLibrary, exportRefinedSkills } from "./skills/skill-reconciler.js";
13
- // Skills Context Engine
14
- export { createContextEngine } from "./skills/context-engine.js";
15
- export { createGlobalContext } from "./skills/global-context.js";
16
- export { analyzePatternEvolution } from "./skills/pattern-engine.js";
17
- export { smartExtract } from "./skills/smart-extractor.js";
18
- // Code Review (from superdev)
10
+ // Skills — Memory-based Knowledge Extraction
11
+ export { extractMemorySkills, renderKnowledgeBase } from "./skills/memory-skill-engine.js";
12
+ // Prompt Injection Detection
13
+ export { scan, isInjected, guard, scanBatch, PromptInjectionError } from "./promptguard/scanner.js";
14
+ export { BUILTIN_RULES } from "./promptguard/rules.js";
15
+ export { ADVANCED_RULES } from "./promptguard/advanced-rules.js";
16
+ export { MULTILINGUAL_RULES } from "./promptguard/multilingual-rules.js";
17
+ export { normalizeText } from "./promptguard/normalize.js";
18
+ // Memory Engine
19
+ export { createNexusMemory } from "./memory-engine/nexus-memory.js";
20
+ export { semanticSimilarity, expandQuery, getSynonyms } from "./memory-engine/semantic.js";
21
+ // Code Review
19
22
  export { reviewCode } from "./review/analyzer.js";
20
23
  export { reviewDiff } from "./review/diff-reviewer.js";
21
- // Codebase Mapping (from superdev)
24
+ // Codebase Mapping
22
25
  export { mapCodebase } from "./codebase/mapper.js";
23
26
  export { generateOnboardingGuide } from "./codebase/onboard.js";
24
- // Test Health (from superdev)
27
+ // Test Health
25
28
  export { checkTestHealth } from "./testing/health-check.js";
26
29
  export { suggestFixes } from "./testing/test-fixer.js";
27
- // Cost Monitor (from superdev)
28
- export { createCostTracker } from "./cost/tracker.js";
29
- // Config Validator (from superdev)
30
+ // Config Validator
30
31
  export { validateConfig } from "./config/validator.js";
31
- // Infinite Memory (from superdev)
32
- export { createMemoryStore } from "./memory-engine/store.js";
33
- export { createContextWindow } from "./memory-engine/context-window.js";
34
- // Prompt Injection Detection (from promptguard)
35
- export { scan, isInjected, guard, scanBatch, PromptInjectionError } from "./promptguard/scanner.js";
36
- export { BUILTIN_RULES } from "./promptguard/rules.js";
37
- export { ADVANCED_RULES } from "./promptguard/advanced-rules.js";
38
- export { MULTILINGUAL_RULES } from "./promptguard/multilingual-rules.js";
39
- export { normalizeText } from "./promptguard/normalize.js";
40
- export { analyzeEntropy } from "./promptguard/entropy.js";
41
- export { classifyIntent } from "./promptguard/semantic.js";
42
- export { analyzeTokens } from "./promptguard/token-analysis.js";