wicked-brain 0.12.0 → 0.13.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/install.mjs +109 -18
- package/package.json +3 -2
- package/server/bin/wicked-brain-call.mjs +575 -0
- package/server/package.json +3 -2
- package/skills/wicked-brain-agent/SKILL.md +7 -1
- package/skills/wicked-brain-compile/SKILL.md +11 -19
- package/skills/wicked-brain-configure/SKILL.md +12 -16
- package/skills/wicked-brain-confirm/SKILL.md +8 -14
- package/skills/wicked-brain-enhance/SKILL.md +7 -14
- package/skills/wicked-brain-forget/SKILL.md +9 -13
- package/skills/wicked-brain-ingest/SKILL.md +16 -25
- package/skills/wicked-brain-init/SKILL.md +20 -17
- package/skills/wicked-brain-lint/SKILL.md +9 -20
- package/skills/wicked-brain-lsp/SKILL.md +22 -28
- package/skills/wicked-brain-memory/SKILL.md +9 -13
- package/skills/wicked-brain-migrate/SKILL.md +10 -14
- package/skills/wicked-brain-query/SKILL.md +8 -19
- package/skills/wicked-brain-review/SKILL.md +10 -16
- package/skills/wicked-brain-search/SKILL.md +12 -19
- package/skills/wicked-brain-server/SKILL.md +43 -65
- package/skills/wicked-brain-status/SKILL.md +13 -32
- package/skills/wicked-brain-synonyms/SKILL.md +6 -15
- package/skills/wicked-brain-ui/SKILL.md +16 -10
- package/skills/wicked-brain-update/SKILL.md +1 -3
package/install.mjs
CHANGED
|
@@ -11,8 +11,44 @@ const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
|
11
11
|
const skillsSource = join(__dirname, "skills");
|
|
12
12
|
const home = homedir();
|
|
13
13
|
|
|
14
|
+
// Claude-root candidate builder. Claude Code's config root is redirectable
|
|
15
|
+
// via $CLAUDE_CONFIG_DIR (multi-tenant setups, alt-config layouts, corporate
|
|
16
|
+
// home-dir overrides). Mirrors the 0.3.3 wicked-testing fix: env var is
|
|
17
|
+
// authoritative when set; otherwise we probe ~/.claude + common alt-config
|
|
18
|
+
// paths and install into each that carries Claude identity markers.
|
|
19
|
+
function buildClaudeTarget(rootDir, source, { trusted = false } = {}) {
|
|
20
|
+
return {
|
|
21
|
+
name: "claude",
|
|
22
|
+
rootDir,
|
|
23
|
+
dir: join(rootDir, "skills"),
|
|
24
|
+
agentDir: join(rootDir, "agents"),
|
|
25
|
+
agentSubdir: "agents",
|
|
26
|
+
platform: "claude",
|
|
27
|
+
identityMarkers: ["settings.json", "plugins", "projects"],
|
|
28
|
+
source,
|
|
29
|
+
trusted,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function resolveClaudeCandidates() {
|
|
34
|
+
const envDir = process.env.CLAUDE_CONFIG_DIR;
|
|
35
|
+
if (envDir && typeof envDir === "string" && envDir.trim()) {
|
|
36
|
+
// Function replacement avoids `$&` etc. being interpreted as regex
|
|
37
|
+
// back-references if $HOME contains those literals (pathological but
|
|
38
|
+
// cheap to defend against — flagged by gemini on the sibling PRs).
|
|
39
|
+
const root = resolve(envDir.trim().replace(/^~/, () => home));
|
|
40
|
+
return [buildClaudeTarget(root, "env:CLAUDE_CONFIG_DIR", { trusted: true })];
|
|
41
|
+
}
|
|
42
|
+
return [
|
|
43
|
+
buildClaudeTarget(join(home, ".claude"), "default"),
|
|
44
|
+
buildClaudeTarget(join(home, "alt-configs", ".claude"), "alt-configs"),
|
|
45
|
+
buildClaudeTarget(join(home, ".config", "claude"), "xdg"),
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Canonical non-claude targets. Claude is expanded dynamically via
|
|
50
|
+
// resolveClaudeCandidates() below so CLI_TARGETS stays a flat spec.
|
|
14
51
|
const CLI_TARGETS = [
|
|
15
|
-
{ name: "claude", dir: join(home, ".claude", "skills"), agentDir: join(home, ".claude", "agents"), agentSubdir: "agents", platform: "claude" },
|
|
16
52
|
{ name: "gemini", dir: join(home, ".gemini", "skills"), agentDir: join(home, ".gemini", "agents"), agentSubdir: "agents", platform: "gemini" },
|
|
17
53
|
{ name: "copilot", dir: join(home, ".github", "skills"), agentDir: join(home, ".github", "agents"), agentSubdir: "agents", platform: "copilot" },
|
|
18
54
|
{ name: "codex", dir: join(home, ".codex", "skills"), agentDir: join(home, ".codex", "agents"), agentSubdir: "agents", platform: "codex" },
|
|
@@ -21,22 +57,61 @@ const CLI_TARGETS = [
|
|
|
21
57
|
{ name: "antigravity", dir: join(home, ".antigravity", "skills"), agentDir: join(home, ".antigravity", "rules"), agentSubdir: "rules", platform: "antigravity" },
|
|
22
58
|
];
|
|
23
59
|
|
|
60
|
+
// Identity-marker gate for claude candidates. Without this, probing
|
|
61
|
+
// ~/.claude, ~/alt-configs/.claude, and ~/.config/claude would install
|
|
62
|
+
// into every path that happens to exist — risky if one was created by a
|
|
63
|
+
// different tool. Env-var / --path targets are `trusted` and skip this.
|
|
64
|
+
function claudeHasIdentityMarker(target) {
|
|
65
|
+
if (target.trusted) return true;
|
|
66
|
+
if (!existsSync(target.rootDir)) return false;
|
|
67
|
+
return (target.identityMarkers || []).some(m => existsSync(join(target.rootDir, m)));
|
|
68
|
+
}
|
|
69
|
+
|
|
24
70
|
console.log("wicked-brain installer\n");
|
|
25
71
|
|
|
26
72
|
const args = argv.slice(2);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
73
|
+
|
|
74
|
+
// Flag parser supporting both forms:
|
|
75
|
+
// --flag=value (canonical)
|
|
76
|
+
// --flag value (common shell muscle-memory; previously silently
|
|
77
|
+
// dropped the value and fell through to default
|
|
78
|
+
// detection — same bug that hit wicked-testing 0.3.2).
|
|
79
|
+
// Narrow string-boolean coercion: literal "true" / "false" become
|
|
80
|
+
// booleans so `--hooks=false` doesn't install hooks.
|
|
81
|
+
const flagValue = (name) => {
|
|
82
|
+
const f = args.find(a => a === `--${name}` || a.startsWith(`--${name}=`));
|
|
83
|
+
if (!f) return null;
|
|
84
|
+
let val;
|
|
85
|
+
if (f.includes("=")) {
|
|
86
|
+
// slice from the first '=' forward — split("=")[1] would truncate at
|
|
87
|
+
// the second '=' (e.g. --path=/volumes/build=artifacts would silently
|
|
88
|
+
// drop "=artifacts").
|
|
89
|
+
val = f.slice(f.indexOf("=") + 1);
|
|
90
|
+
} else {
|
|
91
|
+
const idx = args.indexOf(f);
|
|
92
|
+
const next = args[idx + 1];
|
|
93
|
+
val = (next && !next.startsWith("-")) ? next : true;
|
|
94
|
+
}
|
|
95
|
+
if (val === "false") return false;
|
|
96
|
+
if (val === "true") return true;
|
|
97
|
+
return val;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const cliArg = flagValue("cli");
|
|
101
|
+
const pathArg = flagValue("path");
|
|
102
|
+
|
|
103
|
+
// Validate --cli upfront — if the user passed a bare --cli or --cli=,
|
|
104
|
+
// they misspoke and we should not silently fall through to "install
|
|
105
|
+
// everywhere". Applies regardless of whether --path is also set.
|
|
106
|
+
if (cliArg === true || cliArg === "") {
|
|
107
|
+
console.error("Error: --cli requires a value (e.g. --cli=claude or --cli claude)");
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
30
110
|
|
|
31
111
|
let targets;
|
|
32
112
|
|
|
33
|
-
if (pathArg) {
|
|
34
|
-
const
|
|
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));
|
|
113
|
+
if (pathArg && typeof pathArg === "string" && pathArg !== "") {
|
|
114
|
+
const customPath = resolve(pathArg.replace(/^~/, () => home));
|
|
40
115
|
// Strip leading dot to match CLI_TARGETS names (e.g. ".claude" → "claude")
|
|
41
116
|
const dirName = basename(customPath).replace(/^\./, "");
|
|
42
117
|
const knownPlatform = CLI_TARGETS.find((t) => t.name === dirName);
|
|
@@ -48,19 +123,33 @@ if (pathArg) {
|
|
|
48
123
|
platform: knownPlatform?.platform ?? dirName,
|
|
49
124
|
}];
|
|
50
125
|
console.log(`Custom path: ${customPath}\n`);
|
|
126
|
+
} else if (pathArg === true || pathArg === "") {
|
|
127
|
+
console.error("Error: --path requires a value (e.g. --path=~/.claude or --path ~/.claude)");
|
|
128
|
+
process.exit(1);
|
|
51
129
|
} else {
|
|
52
|
-
//
|
|
53
|
-
|
|
130
|
+
// Build the detection set: expanded claude candidates (env var OR alt-config
|
|
131
|
+
// probes) + all non-claude targets. Claude candidates pass an identity-marker
|
|
132
|
+
// check so we don't install into a bare ~/.claude that belongs to some other
|
|
133
|
+
// tool. Non-claude targets keep the original parent-dir-exists heuristic.
|
|
134
|
+
const claudeDetected = resolveClaudeCandidates().filter(claudeHasIdentityMarker);
|
|
135
|
+
const otherDetected = CLI_TARGETS.filter((t) => existsSync(resolve(t.dir, "..")));
|
|
136
|
+
const detected = [...claudeDetected, ...otherDetected];
|
|
54
137
|
|
|
55
138
|
if (detected.length === 0) {
|
|
56
139
|
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.");
|
|
140
|
+
console.log("Install skills manually by copying the skills/ directory, or set CLAUDE_CONFIG_DIR.");
|
|
58
141
|
process.exit(1);
|
|
59
142
|
}
|
|
60
143
|
|
|
61
|
-
|
|
144
|
+
// Annotate claude candidates with their source when more than one was
|
|
145
|
+
// detected, so the log is not ambiguous.
|
|
146
|
+
const claudeCount = claudeDetected.length;
|
|
147
|
+
const label = (d) => d.name === "claude" && claudeCount > 1 && d.source
|
|
148
|
+
? `${d.name}[${d.source}]`
|
|
149
|
+
: d.name;
|
|
150
|
+
console.log(`Detected CLIs: ${detected.map(label).join(", ")}\n`);
|
|
62
151
|
|
|
63
|
-
const cliFilter = cliArg ?
|
|
152
|
+
const cliFilter = (typeof cliArg === "string" && cliArg !== "") ? cliArg.split(",") : null;
|
|
64
153
|
targets = cliFilter ? detected.filter((d) => cliFilter.includes(d.name)) : detected;
|
|
65
154
|
}
|
|
66
155
|
|
|
@@ -106,8 +195,10 @@ for (const target of targets) {
|
|
|
106
195
|
console.log(` Installed ${agentCount} agents to ${target.agentDir}`);
|
|
107
196
|
}
|
|
108
197
|
|
|
109
|
-
// Optional hook installation (--hooks flag)
|
|
110
|
-
|
|
198
|
+
// Optional hook installation (--hooks flag). Goes through flagValue so
|
|
199
|
+
// `--hooks=false` correctly disables; bare `--hooks` and `--hooks=true`
|
|
200
|
+
// both enable (flagValue coerces "true"/"false" literals to booleans).
|
|
201
|
+
const installHooks = flagValue("hooks") === true;
|
|
111
202
|
|
|
112
203
|
if (installHooks) {
|
|
113
204
|
console.log("\nInstalling hooks...");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wicked-brain",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Digital brain as skills for AI coding CLIs — no vector DB, no embeddings, no infrastructure",
|
|
6
6
|
"keywords": [
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"bugs": "https://github.com/mikeparcewski/wicked-brain/issues",
|
|
29
29
|
"bin": {
|
|
30
30
|
"wicked-brain": "./install.mjs",
|
|
31
|
-
"wicked-brain-server": "./server/bin/wicked-brain-server.mjs"
|
|
31
|
+
"wicked-brain-server": "./server/bin/wicked-brain-server.mjs",
|
|
32
|
+
"wicked-brain-call": "./server/bin/wicked-brain-call.mjs"
|
|
32
33
|
},
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"better-sqlite3": "^12.0.0",
|