wicked-bus 1.1.0 → 1.1.1
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 +88 -15
- package/package.json +1 -1
package/install.mjs
CHANGED
|
@@ -11,8 +11,46 @@ 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. Mirrors the 1.1.1 wicked-testing /
|
|
15
|
+
// wicked-brain fix: $CLAUDE_CONFIG_DIR is authoritative when set;
|
|
16
|
+
// otherwise probe common alt-config layouts. Claude Code's config root
|
|
17
|
+
// is redirectable, and hardcoded ~/.claude silently misses users on
|
|
18
|
+
// shared-home / multi-tenant setups.
|
|
19
|
+
function buildClaudeTarget(rootDir, source, { trusted = false } = {}) {
|
|
20
|
+
return {
|
|
21
|
+
name: "claude",
|
|
22
|
+
rootDir,
|
|
23
|
+
dir: join(rootDir, "skills"),
|
|
24
|
+
platform: "claude",
|
|
25
|
+
identityMarkers: ["settings.json", "plugins", "projects"],
|
|
26
|
+
source,
|
|
27
|
+
trusted,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resolveClaudeCandidates() {
|
|
32
|
+
const envDir = process.env.CLAUDE_CONFIG_DIR;
|
|
33
|
+
if (envDir && typeof envDir === "string" && envDir.trim()) {
|
|
34
|
+
// Function replacement avoids `$&` etc. being interpreted as regex
|
|
35
|
+
// back-references if $HOME contains those literals.
|
|
36
|
+
const root = resolve(envDir.trim().replace(/^~/, () => home));
|
|
37
|
+
return [buildClaudeTarget(root, "env:CLAUDE_CONFIG_DIR", { trusted: true })];
|
|
38
|
+
}
|
|
39
|
+
return [
|
|
40
|
+
buildClaudeTarget(join(home, ".claude"), "default"),
|
|
41
|
+
buildClaudeTarget(join(home, "alt-configs", ".claude"), "alt-configs"),
|
|
42
|
+
buildClaudeTarget(join(home, ".config", "claude"), "xdg"),
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function claudeHasIdentityMarker(target) {
|
|
47
|
+
if (target.trusted) return true;
|
|
48
|
+
if (!existsSync(target.rootDir)) return false;
|
|
49
|
+
return (target.identityMarkers || []).some(m => existsSync(join(target.rootDir, m)));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Non-claude canonical targets. Claude is expanded dynamically above.
|
|
14
53
|
const CLI_TARGETS = [
|
|
15
|
-
{ name: "claude", dir: join(home, ".claude", "skills"), platform: "claude" },
|
|
16
54
|
{ name: "gemini", dir: join(home, ".gemini", "skills"), platform: "gemini" },
|
|
17
55
|
{ name: "copilot", dir: join(home, ".github", "skills"), platform: "copilot" },
|
|
18
56
|
{ name: "codex", dir: join(home, ".codex", "skills"), platform: "codex" },
|
|
@@ -24,19 +62,43 @@ const CLI_TARGETS = [
|
|
|
24
62
|
console.log("wicked-bus installer\n");
|
|
25
63
|
|
|
26
64
|
const args = argv.slice(2);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
65
|
+
|
|
66
|
+
// Flag parser supporting both --flag=value and --flag value forms, plus
|
|
67
|
+
// narrow string-boolean coercion ("true" / "false" → booleans). Previously
|
|
68
|
+
// the ad-hoc parser silently dropped space-separated values — same bug
|
|
69
|
+
// that hit wicked-testing 0.3.2 / wicked-brain 0.3.7.
|
|
70
|
+
const flagValue = (name) => {
|
|
71
|
+
const f = args.find(a => a === `--${name}` || a.startsWith(`--${name}=`));
|
|
72
|
+
if (!f) return null;
|
|
73
|
+
let val;
|
|
74
|
+
if (f.includes("=")) {
|
|
75
|
+
// slice from the first '=' forward — split("=")[1] would truncate at
|
|
76
|
+
// the second '=' (e.g. --path=/volumes/build=artifacts).
|
|
77
|
+
val = f.slice(f.indexOf("=") + 1);
|
|
78
|
+
} else {
|
|
79
|
+
const idx = args.indexOf(f);
|
|
80
|
+
const next = args[idx + 1];
|
|
81
|
+
val = (next && !next.startsWith("-")) ? next : true;
|
|
82
|
+
}
|
|
83
|
+
if (val === "false") return false;
|
|
84
|
+
if (val === "true") return true;
|
|
85
|
+
return val;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const cliArg = flagValue("cli");
|
|
89
|
+
const pathArg = flagValue("path");
|
|
90
|
+
|
|
91
|
+
// Validate --cli upfront so a mistyped --cli / --cli= fails fast
|
|
92
|
+
// instead of silently falling through to "all detected".
|
|
93
|
+
if (cliArg === true || cliArg === "") {
|
|
94
|
+
console.error("Error: --cli requires a value (e.g. --cli=claude or --cli claude)");
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
30
97
|
|
|
31
98
|
let targets;
|
|
32
99
|
|
|
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));
|
|
100
|
+
if (pathArg && typeof pathArg === "string" && pathArg !== "") {
|
|
101
|
+
const customPath = resolve(pathArg.replace(/^~/, () => home));
|
|
40
102
|
const dirName = basename(customPath).replace(/^\./, "");
|
|
41
103
|
targets = [{
|
|
42
104
|
name: dirName,
|
|
@@ -44,18 +106,29 @@ if (pathArg) {
|
|
|
44
106
|
platform: dirName,
|
|
45
107
|
}];
|
|
46
108
|
console.log(`Custom path: ${customPath}\n`);
|
|
109
|
+
} else if (pathArg === true || pathArg === "") {
|
|
110
|
+
console.error("Error: --path requires a value (e.g. --path=~/.claude or --path ~/.claude)");
|
|
111
|
+
process.exit(1);
|
|
47
112
|
} else {
|
|
48
|
-
|
|
113
|
+
// Expanded detection: claude candidates (env var OR alt-config probes,
|
|
114
|
+
// identity-marker gated) + non-claude parent-dir-exists heuristic.
|
|
115
|
+
const claudeDetected = resolveClaudeCandidates().filter(claudeHasIdentityMarker);
|
|
116
|
+
const otherDetected = CLI_TARGETS.filter((t) => existsSync(resolve(t.dir, "..")));
|
|
117
|
+
const detected = [...claudeDetected, ...otherDetected];
|
|
49
118
|
|
|
50
119
|
if (detected.length === 0) {
|
|
51
120
|
console.log("No supported AI CLIs detected. Supported: claude, gemini, copilot, codex, cursor, kiro, antigravity");
|
|
52
|
-
console.log("Install skills manually by copying the skills/ directory.");
|
|
121
|
+
console.log("Install skills manually by copying the skills/ directory, or set CLAUDE_CONFIG_DIR.");
|
|
53
122
|
process.exit(1);
|
|
54
123
|
}
|
|
55
124
|
|
|
56
|
-
|
|
125
|
+
const claudeCount = claudeDetected.length;
|
|
126
|
+
const label = (d) => d.name === "claude" && claudeCount > 1 && d.source
|
|
127
|
+
? `${d.name}[${d.source}]`
|
|
128
|
+
: d.name;
|
|
129
|
+
console.log(`Detected CLIs: ${detected.map(label).join(", ")}\n`);
|
|
57
130
|
|
|
58
|
-
const cliFilter = cliArg ?
|
|
131
|
+
const cliFilter = (typeof cliArg === "string" && cliArg !== "") ? cliArg.split(",") : null;
|
|
59
132
|
targets = cliFilter ? detected.filter((d) => cliFilter.includes(d.name)) : detected;
|
|
60
133
|
}
|
|
61
134
|
|