@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.
- package/README.md +60 -38
- package/dist/cli/index.js +76 -145
- package/dist/index.js +15 -26
- package/dist/mcp/server.js +61 -32
- package/package.json +2 -1
- package/scripts/auto-skill.sh +54 -0
- package/scripts/auto-sync.sh +11 -0
- package/scripts/benchmark.ts +444 -0
- package/scripts/scan-tool-result.sh +46 -0
- package/src/cli/index.ts +79 -172
- package/src/index.ts +17 -29
- package/src/mcp/server.ts +67 -41
- package/src/memory-engine/index.ts +4 -6
- package/src/memory-engine/nexus-memory.test.ts +437 -0
- package/src/memory-engine/nexus-memory.ts +631 -0
- package/src/memory-engine/semantic.ts +380 -0
- package/src/parser/parse.ts +1 -21
- package/src/promptguard/advanced-rules.ts +129 -12
- package/src/promptguard/entropy.ts +21 -2
- package/src/promptguard/evolution/auto-update.ts +16 -6
- package/src/promptguard/multilingual-rules.ts +68 -0
- package/src/promptguard/rules.ts +87 -2
- package/src/promptguard/scanner.test.ts +262 -0
- package/src/promptguard/scanner.ts +1 -1
- package/src/promptguard/semantic.ts +19 -4
- package/src/promptguard/token-analysis.ts +17 -5
- package/src/review/analyzer.test.ts +279 -0
- package/src/review/analyzer.ts +112 -28
- package/src/shared/stop-words.ts +21 -0
- package/src/skills/index.ts +11 -27
- package/src/skills/memory-skill-engine.ts +1044 -0
- package/src/testing/health-check.ts +19 -2
- package/src/cost/index.ts +0 -3
- package/src/cost/tracker.ts +0 -290
- package/src/cost/types.ts +0 -34
- package/src/memory-engine/compressor.ts +0 -97
- package/src/memory-engine/context-window.ts +0 -113
- package/src/memory-engine/store.ts +0 -371
- package/src/memory-engine/types.ts +0 -32
- package/src/skills/context-engine.ts +0 -863
- package/src/skills/extractor.ts +0 -224
- package/src/skills/global-context.ts +0 -726
- package/src/skills/library.ts +0 -189
- package/src/skills/pattern-engine.ts +0 -712
- package/src/skills/render-evolved.ts +0 -160
- package/src/skills/skill-reconciler.ts +0 -703
- package/src/skills/smart-extractor.ts +0 -843
- package/src/skills/types.ts +0 -18
- package/src/skills/wisdom-extractor.ts +0 -737
- package/src/superdev-evolution/index.ts +0 -3
- package/src/superdev-evolution/skill-manager.ts +0 -266
- 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
|
+
[](https://github.com/hawonb711-tech/nexus/stargazers)
|
|
6
|
+
[](https://www.npmjs.com/package/@hawon/nexus)
|
|
7
|
+
[](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
|
-
**
|
|
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
|
|
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** |
|
|
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
|
-
| **
|
|
23
|
-
| **
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
108
|
+
| `nexus_skills` | List knowledge (skills/tips/facts) |
|
|
104
109
|
|
|
105
|
-
##
|
|
110
|
+
## Auto-Hooks
|
|
106
111
|
|
|
107
|
-
|
|
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
|
-
|
|
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/
|
|
128
|
-
|
|
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/
|
|
141
|
-
├── mcp/ MCP server (
|
|
142
|
-
└── cli/ Unified CLI (
|
|
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 {
|
|
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 {
|
|
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(
|
|
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:
|
|
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
|
|
306
|
-
if (
|
|
307
|
-
logInfo("No
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
350
|
-
log(` ${c.cyan}
|
|
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:
|
|
412
|
-
logInfo("Extracting
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
//
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
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
|
|
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
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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}
|
|
454
|
-
log(` ${c.cyan}
|
|
455
|
-
log(` ${c.cyan}
|
|
456
|
-
log(` ${c.cyan}
|
|
457
|
-
log(` ${c.cyan}
|
|
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 =
|
|
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(
|
|
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
|
|
665
|
-
log(` ${c.cyan}${
|
|
666
|
-
log(` ${
|
|
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}
|
|
679
|
-
log(` ${c.cyan}
|
|
680
|
-
log(` ${c.cyan}
|
|
681
|
-
log(
|
|
682
|
-
|
|
683
|
-
|
|
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
|
-
|
|
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 —
|
|
11
|
-
export {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
16
|
-
export {
|
|
17
|
-
export {
|
|
18
|
-
//
|
|
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
|
|
24
|
+
// Codebase Mapping
|
|
22
25
|
export { mapCodebase } from "./codebase/mapper.js";
|
|
23
26
|
export { generateOnboardingGuide } from "./codebase/onboard.js";
|
|
24
|
-
// Test Health
|
|
27
|
+
// Test Health
|
|
25
28
|
export { checkTestHealth } from "./testing/health-check.js";
|
|
26
29
|
export { suggestFixes } from "./testing/test-fixer.js";
|
|
27
|
-
//
|
|
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";
|