@hawon/nexus 0.2.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 (37) hide show
  1. package/dist/cli/index.js +44 -71
  2. package/dist/index.js +15 -24
  3. package/dist/mcp/server.js +7 -6
  4. package/package.json +1 -1
  5. package/scripts/benchmark.ts +13 -35
  6. package/src/cli/index.ts +45 -84
  7. package/src/index.ts +17 -27
  8. package/src/mcp/server.ts +8 -7
  9. package/src/memory-engine/index.ts +4 -6
  10. package/src/memory-engine/semantic.ts +38 -11
  11. package/src/promptguard/advanced-rules.ts +122 -5
  12. package/src/promptguard/entropy.ts +21 -2
  13. package/src/promptguard/rules.ts +87 -2
  14. package/src/promptguard/scanner.test.ts +1 -4
  15. package/src/promptguard/scanner.ts +1 -1
  16. package/src/promptguard/semantic.ts +19 -4
  17. package/src/promptguard/token-analysis.ts +17 -5
  18. package/src/review/analyzer.ts +106 -23
  19. package/src/skills/index.ts +11 -27
  20. package/src/testing/health-check.ts +19 -2
  21. package/src/memory-engine/compressor.ts +0 -97
  22. package/src/memory-engine/context-window.ts +0 -113
  23. package/src/memory-engine/store.ts +0 -371
  24. package/src/memory-engine/types.ts +0 -32
  25. package/src/skills/context-engine.ts +0 -863
  26. package/src/skills/extractor.ts +0 -224
  27. package/src/skills/global-context.ts +0 -731
  28. package/src/skills/library.ts +0 -189
  29. package/src/skills/pattern-engine.ts +0 -715
  30. package/src/skills/render-evolved.ts +0 -160
  31. package/src/skills/skill-reconciler.ts +0 -699
  32. package/src/skills/smart-extractor.ts +0 -849
  33. package/src/skills/types.ts +0 -18
  34. package/src/skills/wisdom-extractor.ts +0 -737
  35. package/src/superdev-evolution/index.ts +0 -3
  36. package/src/superdev-evolution/skill-manager.ts +0 -266
  37. package/src/superdev-evolution/types.ts +0 -20
@@ -1,3 +0,0 @@
1
- export { createSkillManager } from "./skill-manager.js";
2
- export type { SkillManager } from "./skill-manager.js";
3
- export type { Skill, EvolutionLog } from "./types.js";
@@ -1,266 +0,0 @@
1
- import { readFile, writeFile, mkdir } from "node:fs/promises";
2
- import { readFileSync } from "node:fs";
3
- import { join, dirname } from "node:path";
4
- import { randomUUID } from "node:crypto";
5
- import type { Skill, EvolutionLog } from "./types.js";
6
-
7
- const RETIRE_THRESHOLD = 0.3; // retire if success rate below 30%
8
- const MIN_INTERACTIONS_FOR_RETIRE = 5;
9
-
10
- export type SkillManager = {
11
- learn(interaction: { input: string; output: string; success: boolean }): Skill | null;
12
- match(input: string): Skill | null;
13
- evolve(): void;
14
- listSkills(): Skill[];
15
- getLog(): EvolutionLog;
16
- };
17
-
18
- type PersistedData = {
19
- skills: Skill[];
20
- totalInteractions: number;
21
- skillsCreated: number;
22
- skillsRetired: number;
23
- lastEvolvedAt: string;
24
- };
25
-
26
- function tokenize(text: string): string[] {
27
- return text
28
- .toLowerCase()
29
- .replace(/[^a-z0-9\s_-]/g, " ")
30
- .split(/\s+/)
31
- .filter((t) => t.length > 2);
32
- }
33
-
34
- function extractActionPattern(input: string): { name: string; trigger: string; template: string } | null {
35
- const tokens = tokenize(input);
36
- if (tokens.length < 2) return null;
37
-
38
- // Find action verbs and their objects
39
- const actionVerbs = [
40
- "create", "build", "generate", "fix", "debug", "test", "deploy",
41
- "refactor", "review", "analyze", "convert", "migrate", "update",
42
- "add", "remove", "delete", "install", "configure", "setup",
43
- "optimize", "format", "lint", "validate", "check", "run",
44
- "explain", "document", "search", "find", "replace", "transform",
45
- ];
46
-
47
- let verb: string | null = null;
48
- let object: string | null = null;
49
-
50
- for (const token of tokens) {
51
- if (!verb && actionVerbs.includes(token)) {
52
- verb = token;
53
- } else if (verb && !object && token.length > 2) {
54
- object = token;
55
- }
56
- }
57
-
58
- if (!verb || !object) return null;
59
-
60
- // Build a trigger regex from the action pattern
61
- const triggerPattern = `\\b${verb}\\b.*\\b${object}\\b`;
62
-
63
- return {
64
- name: `${verb}-${object}`,
65
- trigger: triggerPattern,
66
- template: `Action: ${verb} ${object}\nSteps from learned interaction.`,
67
- };
68
- }
69
-
70
- function extractKeyPhrases(input: string): string[] {
71
- const phrases: string[] = [];
72
- // Extract quoted strings
73
- const quoted = input.matchAll(/["']([^"']+)["']/g);
74
- for (const m of quoted) phrases.push(m[1]);
75
-
76
- // Extract code-like identifiers
77
- const identifiers = input.matchAll(/`([^`]+)`/g);
78
- for (const m of identifiers) phrases.push(m[1]);
79
-
80
- return phrases;
81
- }
82
-
83
- async function loadData(filePath: string): Promise<PersistedData> {
84
- try {
85
- const raw = await readFile(filePath, "utf-8");
86
- return JSON.parse(raw) as PersistedData;
87
- } catch {
88
- return {
89
- skills: [],
90
- totalInteractions: 0,
91
- skillsCreated: 0,
92
- skillsRetired: 0,
93
- lastEvolvedAt: new Date().toISOString(),
94
- };
95
- }
96
- }
97
-
98
- async function saveData(filePath: string, data: PersistedData): Promise<void> {
99
- await mkdir(dirname(filePath), { recursive: true });
100
- await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
101
- }
102
-
103
- export function createSkillManager(dataDir: string): SkillManager {
104
- const filePath = join(dataDir, "skills.json");
105
-
106
- let data: PersistedData = {
107
- skills: [],
108
- totalInteractions: 0,
109
- skillsCreated: 0,
110
- skillsRetired: 0,
111
- lastEvolvedAt: new Date().toISOString(),
112
- };
113
-
114
- let loaded = false;
115
-
116
- function ensureLoadedSync(): void {
117
- if (loaded) return;
118
- try {
119
- const raw = readFileSync(filePath, "utf-8");
120
- data = JSON.parse(raw) as PersistedData;
121
- } catch {
122
- // File doesn't exist yet — use defaults
123
- }
124
- loaded = true;
125
- }
126
-
127
- function persist(): void {
128
- saveData(filePath, data).catch((err) => {
129
- process.stderr.write(`superdev: skill persist failed: ${String(err)}\n`);
130
- });
131
- }
132
-
133
- return {
134
- learn(interaction: { input: string; output: string; success: boolean }): Skill | null {
135
- ensureLoadedSync();
136
-
137
- data.totalInteractions++;
138
-
139
- if (!interaction.success) {
140
- // Update failure count for matching skills
141
- const matchedSkill = this.match(interaction.input);
142
- if (matchedSkill) {
143
- const skill = data.skills.find((s) => s.id === matchedSkill.id);
144
- if (skill) {
145
- skill.failureCount++;
146
- skill.updatedAt = new Date().toISOString();
147
- persist();
148
- }
149
- }
150
- return null;
151
- }
152
-
153
- // Check if we already have a matching skill
154
- const existing = this.match(interaction.input);
155
- if (existing) {
156
- const skill = data.skills.find((s) => s.id === existing.id);
157
- if (skill) {
158
- skill.successCount++;
159
- skill.updatedAt = new Date().toISOString();
160
- persist();
161
- }
162
- return existing;
163
- }
164
-
165
- // Try to extract a new skill pattern
166
- const pattern = extractActionPattern(interaction.input);
167
- if (!pattern) return null;
168
-
169
- // Check for duplicate trigger patterns
170
- const isDuplicate = data.skills.some((s) => s.trigger === pattern.trigger);
171
- if (isDuplicate) return null;
172
-
173
- const keyPhrases = extractKeyPhrases(interaction.input);
174
- const description = keyPhrases.length > 0
175
- ? `Learned pattern for: ${pattern.name} (context: ${keyPhrases.join(", ")})`
176
- : `Learned pattern for: ${pattern.name}`;
177
-
178
- const now = new Date().toISOString();
179
- const newSkill: Skill = {
180
- id: randomUUID(),
181
- name: pattern.name,
182
- description,
183
- trigger: pattern.trigger,
184
- template: pattern.template,
185
- learnedFrom: interaction.input.slice(0, 200),
186
- successCount: 1,
187
- failureCount: 0,
188
- createdAt: now,
189
- updatedAt: now,
190
- };
191
-
192
- data.skills.push(newSkill);
193
- data.skillsCreated++;
194
- persist();
195
-
196
- return newSkill;
197
- },
198
-
199
- match(input: string): Skill | null {
200
- ensureLoadedSync();
201
- const lowerInput = input.toLowerCase();
202
- let bestMatch: Skill | null = null;
203
- let bestScore = 0;
204
-
205
- for (const skill of data.skills) {
206
- try {
207
- const regex = new RegExp(skill.trigger, "i");
208
- if (regex.test(lowerInput)) {
209
- // Score by success rate and specificity
210
- const total = skill.successCount + skill.failureCount;
211
- const successRate = total > 0 ? skill.successCount / total : 0.5;
212
- const specificity = skill.trigger.length;
213
- const score = successRate * specificity;
214
-
215
- if (score > bestScore) {
216
- bestScore = score;
217
- bestMatch = skill;
218
- }
219
- }
220
- } catch {
221
- // Invalid regex, skip
222
- continue;
223
- }
224
- }
225
-
226
- return bestMatch;
227
- },
228
-
229
- evolve(): void {
230
- ensureLoadedSync();
231
- const retired: string[] = [];
232
-
233
- data.skills = data.skills.filter((skill) => {
234
- const total = skill.successCount + skill.failureCount;
235
- if (total < MIN_INTERACTIONS_FOR_RETIRE) return true;
236
-
237
- const successRate = skill.successCount / total;
238
- if (successRate < RETIRE_THRESHOLD) {
239
- retired.push(skill.id);
240
- return false;
241
- }
242
- return true;
243
- });
244
-
245
- data.skillsRetired += retired.length;
246
- data.lastEvolvedAt = new Date().toISOString();
247
- persist();
248
- },
249
-
250
- listSkills(): Skill[] {
251
- ensureLoadedSync();
252
- return [...data.skills];
253
- },
254
-
255
- getLog(): EvolutionLog {
256
- ensureLoadedSync();
257
- return {
258
- skills: [...data.skills],
259
- totalInteractions: data.totalInteractions,
260
- skillsCreated: data.skillsCreated,
261
- skillsRetired: data.skillsRetired,
262
- lastEvolvedAt: data.lastEvolvedAt,
263
- };
264
- },
265
- };
266
- }
@@ -1,20 +0,0 @@
1
- export type Skill = {
2
- id: string;
3
- name: string;
4
- description: string;
5
- trigger: string;
6
- template: string;
7
- learnedFrom: string;
8
- successCount: number;
9
- failureCount: number;
10
- createdAt: string;
11
- updatedAt: string;
12
- };
13
-
14
- export type EvolutionLog = {
15
- skills: Skill[];
16
- totalInteractions: number;
17
- skillsCreated: number;
18
- skillsRetired: number;
19
- lastEvolvedAt: string;
20
- };