wicked-brain 0.3.5 → 0.3.7
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 +19 -5
- package/install.mjs +31 -32
- package/package.json +1 -1
- package/server/lib/sqlite-search.mjs +17 -1
- package/server/package.json +1 -1
package/README.md
CHANGED
|
@@ -75,6 +75,12 @@ npx wicked-brain
|
|
|
75
75
|
|
|
76
76
|
That's it. The installer detects your AI CLIs and drops in the skills. First time you use any skill, it walks you through setup.
|
|
77
77
|
|
|
78
|
+
To install into a non-standard CLI config path:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx wicked-brain --path=~/alt-configs/.claude
|
|
82
|
+
```
|
|
83
|
+
|
|
78
84
|
Or install via [agent-skills-cli](https://github.com/Karanjot786/agent-skills-cli):
|
|
79
85
|
|
|
80
86
|
```bash
|
|
@@ -119,16 +125,22 @@ Every operation uses **progressive loading** — the agent never pulls more than
|
|
|
119
125
|
|
|
120
126
|
| Skill | What it does |
|
|
121
127
|
|---|---|
|
|
122
|
-
| `wicked-brain:init` | Set up a new brain
|
|
128
|
+
| `wicked-brain:init` | Set up a new brain — creates directory structure, then onboards your project in parallel |
|
|
123
129
|
| `wicked-brain:ingest` | Add source files — text extracted deterministically, binary docs read via LLM vision |
|
|
124
130
|
| `wicked-brain:search` | Parallel search across your brain and linked brains |
|
|
125
131
|
| `wicked-brain:read` | Progressive loading: depth 0 (stats), depth 1 (summary), depth 2 (full content) |
|
|
126
132
|
| `wicked-brain:query` | Answer questions with source citations |
|
|
127
133
|
| `wicked-brain:compile` | Synthesize wiki articles from chunks |
|
|
128
|
-
| `wicked-brain:lint` | Find broken links, orphan chunks, inconsistencies |
|
|
129
|
-
| `wicked-brain:enhance` | Identify and fill knowledge gaps |
|
|
134
|
+
| `wicked-brain:lint` | Find broken links, orphan chunks, inconsistencies; auto-fix where possible |
|
|
135
|
+
| `wicked-brain:enhance` | Identify and fill knowledge gaps with inferred content |
|
|
136
|
+
| `wicked-brain:memory` | Store and recall experiential learnings across sessions (working / episodic / semantic tiers) |
|
|
130
137
|
| `wicked-brain:status` | Brain health, stats, orientation |
|
|
131
138
|
| `wicked-brain:server` | Manage the background search server (auto-triggered) |
|
|
139
|
+
| `wicked-brain:configure` | Write brain-aware context into your CLI's config (CLAUDE.md, GEMINI.md, etc.) |
|
|
140
|
+
| `wicked-brain:batch` | Generate scripts for bulk operations — avoids burning context on repetitive tool calls |
|
|
141
|
+
| `wicked-brain:retag` | Backfill synonym-expanded tags across all chunks for better search recall |
|
|
142
|
+
| `wicked-brain:update` | Check npm for updates and reinstall skills across all detected CLIs |
|
|
143
|
+
| `wicked-brain:lsp` | Universal code intelligence via LSP — hover, go-to-definition, diagnostics, completions |
|
|
132
144
|
|
|
133
145
|
## Multi-Brain Federation
|
|
134
146
|
|
|
@@ -169,7 +181,7 @@ Modern LLMs read PDF, DOCX, PPTX, and XLSX natively. When you ingest a binary do
|
|
|
169
181
|
|
|
170
182
|
## Architecture
|
|
171
183
|
|
|
172
|
-
**~
|
|
184
|
+
**~300 lines of server JavaScript** (SQLite FTS5 + file watcher) + **~1,400 lines of skill markdown** (agent instructions).
|
|
173
185
|
|
|
174
186
|
That's the entire system. Compare that to a typical RAG stack:
|
|
175
187
|
|
|
@@ -182,7 +194,7 @@ Typical RAG: wicked-brain:
|
|
|
182
194
|
- Re-ranking model - LLM reasoning
|
|
183
195
|
- Orchestration layer - Skills (markdown)
|
|
184
196
|
───────────────── ─────────────────
|
|
185
|
-
~5,000+ lines, 10+ deps ~1,
|
|
197
|
+
~5,000+ lines, 10+ deps ~1,700 lines, 1 dep
|
|
186
198
|
```
|
|
187
199
|
|
|
188
200
|
## Supported CLIs
|
|
@@ -194,6 +206,8 @@ Typical RAG: wicked-brain:
|
|
|
194
206
|
| GitHub Copilot CLI | Supported |
|
|
195
207
|
| Cursor | Supported |
|
|
196
208
|
| Codex | Supported |
|
|
209
|
+
| Kiro | Supported |
|
|
210
|
+
| Antigravity | Supported |
|
|
197
211
|
|
|
198
212
|
Skills use only universally available operations (read files, write files, run shell commands, grep). No CLI-specific features.
|
|
199
213
|
|
package/install.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// wicked-brain installer — detects CLIs and installs skills + agents
|
|
3
3
|
|
|
4
4
|
import { existsSync, mkdirSync, cpSync, readdirSync } from "node:fs";
|
|
5
|
-
import { join, resolve } from "node:path";
|
|
5
|
+
import { join, resolve, basename } from "node:path";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { argv } from "node:process";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
@@ -12,56 +12,55 @@ const skillsSource = join(__dirname, "skills");
|
|
|
12
12
|
const home = homedir();
|
|
13
13
|
|
|
14
14
|
const CLI_TARGETS = [
|
|
15
|
-
{ name: "claude",
|
|
16
|
-
{ name: "gemini",
|
|
17
|
-
{ name: "copilot",
|
|
18
|
-
{ name: "codex",
|
|
19
|
-
{ name: "cursor",
|
|
20
|
-
{ name: "kiro",
|
|
21
|
-
{ name: "antigravity", dir: join(home, ".antigravity", "skills"), agentDir: join(home, ".antigravity", "rules"), platform: "antigravity" },
|
|
15
|
+
{ name: "claude", dir: join(home, ".claude", "skills"), agentDir: join(home, ".claude", "agents"), agentSubdir: "agents", platform: "claude" },
|
|
16
|
+
{ name: "gemini", dir: join(home, ".gemini", "skills"), agentDir: join(home, ".gemini", "agents"), agentSubdir: "agents", platform: "gemini" },
|
|
17
|
+
{ name: "copilot", dir: join(home, ".github", "skills"), agentDir: join(home, ".github", "agents"), agentSubdir: "agents", platform: "copilot" },
|
|
18
|
+
{ name: "codex", dir: join(home, ".codex", "skills"), agentDir: join(home, ".codex", "agents"), agentSubdir: "agents", platform: "codex" },
|
|
19
|
+
{ name: "cursor", dir: join(home, ".cursor", "skills"), agentDir: join(home, ".cursor", "agents"), agentSubdir: "agents", platform: "cursor" },
|
|
20
|
+
{ name: "kiro", dir: join(home, ".kiro", "skills"), agentDir: join(home, ".kiro", "agents"), agentSubdir: "agents", platform: "kiro" },
|
|
21
|
+
{ name: "antigravity", dir: join(home, ".antigravity", "skills"), agentDir: join(home, ".antigravity", "rules"), agentSubdir: "rules", platform: "antigravity" },
|
|
22
22
|
];
|
|
23
23
|
|
|
24
|
-
// Detect which CLIs are installed by checking if parent dir exists
|
|
25
|
-
const detected = CLI_TARGETS.filter((t) => {
|
|
26
|
-
const parentDir = resolve(t.dir, "..");
|
|
27
|
-
return existsSync(parentDir);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
24
|
console.log("wicked-brain installer\n");
|
|
31
25
|
|
|
32
|
-
if (detected.length === 0) {
|
|
33
|
-
console.log("No supported AI CLIs detected. Supported: claude, gemini, copilot, codex, cursor, kiro, antigravity");
|
|
34
|
-
console.log("Install skills manually by copying the skills/ directory.");
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
console.log(`Detected CLIs: ${detected.map((d) => d.name).join(", ")}\n`);
|
|
39
|
-
|
|
40
|
-
// Allow filtering via --cli flag or custom --path
|
|
41
26
|
const args = argv.slice(2);
|
|
27
|
+
const argValue = (a) => a.split("=")[1];
|
|
42
28
|
const cliArg = args.find((a) => a.startsWith("--cli="));
|
|
43
29
|
const pathArg = args.find((a) => a.startsWith("--path="));
|
|
44
30
|
|
|
45
31
|
let targets;
|
|
46
32
|
|
|
47
33
|
if (pathArg) {
|
|
48
|
-
const rawPath = pathArg
|
|
49
|
-
|
|
50
|
-
|
|
34
|
+
const rawPath = argValue(pathArg);
|
|
35
|
+
if (!rawPath) {
|
|
36
|
+
console.error("Error: --path requires a value (e.g. --path=~/.claude)");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
const customPath = resolve(rawPath.replace(/^~/, home));
|
|
40
|
+
// Strip leading dot to match CLI_TARGETS names (e.g. ".claude" → "claude")
|
|
41
|
+
const dirName = basename(customPath).replace(/^\./, "");
|
|
51
42
|
const knownPlatform = CLI_TARGETS.find((t) => t.name === dirName);
|
|
52
|
-
|
|
53
|
-
const agentSubdirName = knownPlatform
|
|
54
|
-
? knownPlatform.agentDir.split(/[\\/]/).pop()
|
|
55
|
-
: "agents";
|
|
43
|
+
const agentSubdir = knownPlatform?.agentSubdir ?? "agents";
|
|
56
44
|
targets = [{
|
|
57
45
|
name: dirName,
|
|
58
46
|
dir: join(customPath, "skills"),
|
|
59
|
-
agentDir: join(customPath,
|
|
47
|
+
agentDir: join(customPath, agentSubdir),
|
|
60
48
|
platform: knownPlatform?.platform ?? dirName,
|
|
61
49
|
}];
|
|
62
50
|
console.log(`Custom path: ${customPath}\n`);
|
|
63
51
|
} else {
|
|
64
|
-
|
|
52
|
+
// Detect which CLIs are installed by checking if parent dir exists
|
|
53
|
+
const detected = CLI_TARGETS.filter((t) => existsSync(resolve(t.dir, "..")));
|
|
54
|
+
|
|
55
|
+
if (detected.length === 0) {
|
|
56
|
+
console.log("No supported AI CLIs detected. Supported: claude, gemini, copilot, codex, cursor, kiro, antigravity");
|
|
57
|
+
console.log("Install skills manually by copying the skills/ directory.");
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log(`Detected CLIs: ${detected.map((d) => d.name).join(", ")}\n`);
|
|
62
|
+
|
|
63
|
+
const cliFilter = cliArg ? argValue(cliArg).split(",") : null;
|
|
65
64
|
targets = cliFilter ? detected.filter((d) => cliFilter.includes(d.name)) : detected;
|
|
66
65
|
}
|
|
67
66
|
|
package/package.json
CHANGED
|
@@ -2,6 +2,16 @@ import Database from "better-sqlite3";
|
|
|
2
2
|
import { parseWikilinks } from "./wikilinks.mjs";
|
|
3
3
|
import { statSync } from "node:fs";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Extracts body text from a document, stripping YAML frontmatter.
|
|
7
|
+
* Falls back to the raw content if no frontmatter is detected.
|
|
8
|
+
*/
|
|
9
|
+
function extractBodyExcerpt(content, maxLen = 300) {
|
|
10
|
+
const match = content.match(/^---\n[\s\S]*?\n---\n?([\s\S]*)/);
|
|
11
|
+
const body = match ? match[1] : content;
|
|
12
|
+
return body.trim().slice(0, maxLen);
|
|
13
|
+
}
|
|
14
|
+
|
|
5
15
|
function escapeFtsQuery(query) {
|
|
6
16
|
return query
|
|
7
17
|
.trim()
|
|
@@ -209,6 +219,7 @@ export class SqliteSearch {
|
|
|
209
219
|
d.path,
|
|
210
220
|
d.brain_id,
|
|
211
221
|
snippet(documents_fts, 2, '<b>', '</b>', '…', 32) AS snippet,
|
|
222
|
+
SUBSTR(d.content, 1, 1000) AS raw_content,
|
|
212
223
|
COALESCE(link_count.cnt, 0) AS backlink_count,
|
|
213
224
|
COALESCE(ac.cnt, 0) AS access_count
|
|
214
225
|
FROM documents_fts f
|
|
@@ -228,7 +239,12 @@ export class SqliteSearch {
|
|
|
228
239
|
ORDER BY (f.rank - (COALESCE(link_count.cnt, 0) * ${BACKLINK_WEIGHT}) - (COALESCE(ac.cnt, 0) * ${SEARCH_ACCESS_WEIGHT}))
|
|
229
240
|
LIMIT ? OFFSET ?
|
|
230
241
|
`)
|
|
231
|
-
.all(escaped, ...sinceParams, limit, offset)
|
|
242
|
+
.all(escaped, ...sinceParams, limit, offset)
|
|
243
|
+
.map((row) => {
|
|
244
|
+
const body_excerpt = extractBodyExcerpt(row.raw_content ?? "");
|
|
245
|
+
delete row.raw_content;
|
|
246
|
+
return { ...row, body_excerpt };
|
|
247
|
+
});
|
|
232
248
|
|
|
233
249
|
const countRow = this.#db
|
|
234
250
|
.prepare(
|