aiblueprint-cli 1.1.3 → 1.1.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 +425 -41
- package/claude-code-config/agents/explore-codebase.md +1 -0
- package/claude-code-config/agents/explore-docs.md +88 -0
- package/claude-code-config/agents/snipper.md +2 -0
- package/claude-code-config/agents/websearch.md +1 -0
- package/claude-code-config/commands/debug.md +91 -0
- package/claude-code-config/commands/explore.md +45 -0
- package/dist/cli.js +711 -326
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -32360,10 +32360,9 @@ var inquirer = {
|
|
|
32360
32360
|
var lib_default = inquirer;
|
|
32361
32361
|
|
|
32362
32362
|
// src/commands/setup.ts
|
|
32363
|
-
var
|
|
32364
|
-
import
|
|
32365
|
-
import
|
|
32366
|
-
import { execSync } from "child_process";
|
|
32363
|
+
var import_fs_extra5 = __toESM(require_lib4(), 1);
|
|
32364
|
+
import path6 from "path";
|
|
32365
|
+
import os5 from "os";
|
|
32367
32366
|
|
|
32368
32367
|
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
32369
32368
|
var ANSI_BACKGROUND_OFFSET = 10;
|
|
@@ -32858,8 +32857,278 @@ var source_default = chalk;
|
|
|
32858
32857
|
// src/commands/setup.ts
|
|
32859
32858
|
import { fileURLToPath } from "url";
|
|
32860
32859
|
import { dirname } from "path";
|
|
32861
|
-
|
|
32862
|
-
|
|
32860
|
+
|
|
32861
|
+
// src/commands/setup/shell-shortcuts.ts
|
|
32862
|
+
var import_fs_extra = __toESM(require_lib4(), 1);
|
|
32863
|
+
import path2 from "path";
|
|
32864
|
+
import os3 from "os";
|
|
32865
|
+
async function setupShellShortcuts() {
|
|
32866
|
+
try {
|
|
32867
|
+
const platform = os3.platform();
|
|
32868
|
+
let shellConfigFile;
|
|
32869
|
+
if (platform === "darwin") {
|
|
32870
|
+
shellConfigFile = path2.join(os3.homedir(), ".zshenv");
|
|
32871
|
+
} else if (platform === "linux") {
|
|
32872
|
+
const shell = process.env.SHELL || "";
|
|
32873
|
+
if (shell.includes("zsh")) {
|
|
32874
|
+
shellConfigFile = path2.join(os3.homedir(), ".zshrc");
|
|
32875
|
+
} else {
|
|
32876
|
+
shellConfigFile = path2.join(os3.homedir(), ".bashrc");
|
|
32877
|
+
}
|
|
32878
|
+
} else {
|
|
32879
|
+
console.log(source_default.yellow("Shell shortcuts are only supported on macOS and Linux"));
|
|
32880
|
+
return;
|
|
32881
|
+
}
|
|
32882
|
+
const aliases = `
|
|
32883
|
+
# AIBlueprint Claude Code aliases
|
|
32884
|
+
alias cc="claude --dangerously-skip-permissions"
|
|
32885
|
+
alias ccc="claude --dangerously-skip-permissions -c"
|
|
32886
|
+
`;
|
|
32887
|
+
const existingContent = await import_fs_extra.default.readFile(shellConfigFile, "utf-8").catch(() => "");
|
|
32888
|
+
if (!existingContent.includes("AIBlueprint Claude Code aliases")) {
|
|
32889
|
+
await import_fs_extra.default.appendFile(shellConfigFile, aliases);
|
|
32890
|
+
}
|
|
32891
|
+
} catch (error) {
|
|
32892
|
+
console.error(source_default.red("Error setting up shell shortcuts:"), error);
|
|
32893
|
+
throw error;
|
|
32894
|
+
}
|
|
32895
|
+
}
|
|
32896
|
+
|
|
32897
|
+
// src/commands/setup/symlinks.ts
|
|
32898
|
+
var import_fs_extra2 = __toESM(require_lib4(), 1);
|
|
32899
|
+
import path3 from "path";
|
|
32900
|
+
import os4 from "os";
|
|
32901
|
+
async function getToolPaths(tool, customFolder) {
|
|
32902
|
+
let baseDir;
|
|
32903
|
+
switch (tool) {
|
|
32904
|
+
case "claude-code":
|
|
32905
|
+
baseDir = customFolder ? path3.resolve(customFolder) : path3.join(os4.homedir(), ".claude");
|
|
32906
|
+
return {
|
|
32907
|
+
baseDir,
|
|
32908
|
+
commandsPath: path3.join(baseDir, "commands"),
|
|
32909
|
+
agentsPath: path3.join(baseDir, "agents")
|
|
32910
|
+
};
|
|
32911
|
+
case "codex":
|
|
32912
|
+
baseDir = customFolder ? path3.resolve(customFolder) : path3.join(os4.homedir(), ".codex");
|
|
32913
|
+
return {
|
|
32914
|
+
baseDir,
|
|
32915
|
+
commandsPath: path3.join(baseDir, "prompts")
|
|
32916
|
+
};
|
|
32917
|
+
case "opencode":
|
|
32918
|
+
baseDir = customFolder ? path3.resolve(customFolder) : path3.join(os4.homedir(), ".config", "opencode");
|
|
32919
|
+
return {
|
|
32920
|
+
baseDir,
|
|
32921
|
+
commandsPath: path3.join(baseDir, "command")
|
|
32922
|
+
};
|
|
32923
|
+
case "factoryai":
|
|
32924
|
+
baseDir = customFolder ? path3.resolve(customFolder) : path3.join(os4.homedir(), ".factory");
|
|
32925
|
+
return {
|
|
32926
|
+
baseDir,
|
|
32927
|
+
commandsPath: path3.join(baseDir, "commands"),
|
|
32928
|
+
agentsPath: path3.join(baseDir, "droids")
|
|
32929
|
+
};
|
|
32930
|
+
default:
|
|
32931
|
+
throw new Error(`Unknown tool type: ${tool}`);
|
|
32932
|
+
}
|
|
32933
|
+
}
|
|
32934
|
+
async function createSymlink(sourcePath, targetPath, options = {}) {
|
|
32935
|
+
try {
|
|
32936
|
+
const sourceExists = await import_fs_extra2.default.pathExists(sourcePath);
|
|
32937
|
+
if (!sourceExists) {
|
|
32938
|
+
console.log(source_default.yellow(` Source path ${sourcePath} does not exist. Skipping symlink creation...`));
|
|
32939
|
+
return false;
|
|
32940
|
+
}
|
|
32941
|
+
const targetDir = path3.dirname(targetPath);
|
|
32942
|
+
await import_fs_extra2.default.ensureDir(targetDir);
|
|
32943
|
+
const targetExists = await import_fs_extra2.default.pathExists(targetPath);
|
|
32944
|
+
if (targetExists) {
|
|
32945
|
+
const stat = await import_fs_extra2.default.lstat(targetPath);
|
|
32946
|
+
if (stat.isSymbolicLink()) {
|
|
32947
|
+
await import_fs_extra2.default.remove(targetPath);
|
|
32948
|
+
} else {
|
|
32949
|
+
console.log(source_default.yellow(options.skipMessage || ` ${targetPath} already exists and is not a symlink. Skipping...`));
|
|
32950
|
+
return false;
|
|
32951
|
+
}
|
|
32952
|
+
}
|
|
32953
|
+
await import_fs_extra2.default.symlink(sourcePath, targetPath);
|
|
32954
|
+
return true;
|
|
32955
|
+
} catch (error) {
|
|
32956
|
+
console.error(source_default.red(options.errorPrefix || "Error creating symlink:"), error);
|
|
32957
|
+
throw error;
|
|
32958
|
+
}
|
|
32959
|
+
}
|
|
32960
|
+
async function setupCodexSymlink(claudeDir, customCodexFolder, customClaudeCodeFolder) {
|
|
32961
|
+
try {
|
|
32962
|
+
let codexDir;
|
|
32963
|
+
if (customCodexFolder) {
|
|
32964
|
+
codexDir = path3.resolve(customCodexFolder);
|
|
32965
|
+
} else if (customClaudeCodeFolder) {
|
|
32966
|
+
const parentDir = path3.dirname(claudeDir);
|
|
32967
|
+
codexDir = path3.join(parentDir, "codex");
|
|
32968
|
+
} else {
|
|
32969
|
+
codexDir = path3.join(os4.homedir(), ".codex");
|
|
32970
|
+
}
|
|
32971
|
+
const promptsPath = path3.join(codexDir, "prompts");
|
|
32972
|
+
const commandsPath = path3.join(claudeDir, "commands");
|
|
32973
|
+
await createSymlink(commandsPath, promptsPath, {
|
|
32974
|
+
skipMessage: " ~/.codex/prompts already exists and is not a symlink. Skipping...",
|
|
32975
|
+
errorPrefix: "Error setting up Codex symlink:"
|
|
32976
|
+
});
|
|
32977
|
+
} catch (error) {
|
|
32978
|
+
console.error(source_default.red("Error setting up Codex symlink:"), error);
|
|
32979
|
+
}
|
|
32980
|
+
}
|
|
32981
|
+
async function setupOpenCodeSymlink(claudeDir, customOpenCodeFolder, customClaudeCodeFolder) {
|
|
32982
|
+
try {
|
|
32983
|
+
let openCodeDir;
|
|
32984
|
+
if (customOpenCodeFolder) {
|
|
32985
|
+
openCodeDir = path3.resolve(customOpenCodeFolder);
|
|
32986
|
+
} else if (customClaudeCodeFolder) {
|
|
32987
|
+
const parentDir = path3.dirname(claudeDir);
|
|
32988
|
+
openCodeDir = path3.join(parentDir, ".opencode");
|
|
32989
|
+
} else {
|
|
32990
|
+
openCodeDir = path3.join(os4.homedir(), ".config", "opencode");
|
|
32991
|
+
}
|
|
32992
|
+
const commandPath = path3.join(openCodeDir, "command");
|
|
32993
|
+
const commandsPath = path3.join(claudeDir, "commands");
|
|
32994
|
+
await createSymlink(commandsPath, commandPath, {
|
|
32995
|
+
skipMessage: " ~/.config/opencode/command already exists and is not a symlink. Skipping...",
|
|
32996
|
+
errorPrefix: "Error setting up OpenCode symlink:"
|
|
32997
|
+
});
|
|
32998
|
+
} catch (error) {
|
|
32999
|
+
console.error(source_default.red("Error setting up OpenCode symlink:"), error);
|
|
33000
|
+
}
|
|
33001
|
+
}
|
|
33002
|
+
|
|
33003
|
+
// src/commands/setup/dependencies.ts
|
|
33004
|
+
import { execSync } from "child_process";
|
|
33005
|
+
async function checkAndInstallDependencies() {
|
|
33006
|
+
const checkCommand = (cmd) => {
|
|
33007
|
+
try {
|
|
33008
|
+
execSync(`which ${cmd}`, { stdio: "ignore" });
|
|
33009
|
+
return true;
|
|
33010
|
+
} catch {
|
|
33011
|
+
return false;
|
|
33012
|
+
}
|
|
33013
|
+
};
|
|
33014
|
+
if (!checkCommand("bun")) {
|
|
33015
|
+
console.log(source_default.yellow(`
|
|
33016
|
+
Installing bun...`));
|
|
33017
|
+
try {
|
|
33018
|
+
execSync("npm install -g bun", { stdio: "inherit" });
|
|
33019
|
+
} catch (error) {
|
|
33020
|
+
console.log(source_default.red(" Failed to install bun. Please install it manually: npm install -g bun"));
|
|
33021
|
+
}
|
|
33022
|
+
}
|
|
33023
|
+
if (!checkCommand("ccusage")) {
|
|
33024
|
+
console.log(source_default.yellow(`
|
|
33025
|
+
Installing ccusage...`));
|
|
33026
|
+
try {
|
|
33027
|
+
execSync("npm install -g ccusage", { stdio: "inherit" });
|
|
33028
|
+
} catch (error) {
|
|
33029
|
+
console.log(source_default.red(" Failed to install ccusage. Please install it manually: npm install -g ccusage"));
|
|
33030
|
+
}
|
|
33031
|
+
}
|
|
33032
|
+
}
|
|
33033
|
+
|
|
33034
|
+
// src/commands/setup/settings.ts
|
|
33035
|
+
var import_fs_extra3 = __toESM(require_lib4(), 1);
|
|
33036
|
+
import path4 from "path";
|
|
33037
|
+
async function updateSettings(options, claudeDir) {
|
|
33038
|
+
const settingsPath = path4.join(claudeDir, "settings.json");
|
|
33039
|
+
let settings = {};
|
|
33040
|
+
try {
|
|
33041
|
+
const existingSettings = await import_fs_extra3.default.readFile(settingsPath, "utf-8");
|
|
33042
|
+
settings = JSON.parse(existingSettings);
|
|
33043
|
+
} catch {
|
|
33044
|
+
}
|
|
33045
|
+
if (options.customStatusline) {
|
|
33046
|
+
if (settings.statusLine) {
|
|
33047
|
+
const confirmAnswer = await lib_default.prompt([
|
|
33048
|
+
{
|
|
33049
|
+
type: "confirm",
|
|
33050
|
+
name: "replace",
|
|
33051
|
+
message: "You already have a statusLine configuration. Replace it?"
|
|
33052
|
+
}
|
|
33053
|
+
]);
|
|
33054
|
+
if (!confirmAnswer.replace) {
|
|
33055
|
+
console.log(source_default.yellow(" Keeping existing statusLine configuration"));
|
|
33056
|
+
} else {
|
|
33057
|
+
settings.statusLine = {
|
|
33058
|
+
type: "command",
|
|
33059
|
+
command: `bash ${path4.join(claudeDir, "scripts/statusline-ccusage.sh")}`,
|
|
33060
|
+
padding: 0
|
|
33061
|
+
};
|
|
33062
|
+
}
|
|
33063
|
+
} else {
|
|
33064
|
+
settings.statusLine = {
|
|
33065
|
+
type: "command",
|
|
33066
|
+
command: `bash ${path4.join(claudeDir, "scripts/statusline-ccusage.sh")}`,
|
|
33067
|
+
padding: 0
|
|
33068
|
+
};
|
|
33069
|
+
}
|
|
33070
|
+
}
|
|
33071
|
+
if (!settings.hooks) {
|
|
33072
|
+
settings.hooks = {};
|
|
33073
|
+
}
|
|
33074
|
+
if (options.commandValidation) {
|
|
33075
|
+
if (!settings.hooks.PreToolUse) {
|
|
33076
|
+
settings.hooks.PreToolUse = [];
|
|
33077
|
+
}
|
|
33078
|
+
const bashHook = {
|
|
33079
|
+
matcher: "Bash",
|
|
33080
|
+
hooks: [
|
|
33081
|
+
{
|
|
33082
|
+
type: "command",
|
|
33083
|
+
command: `bun ${path4.join(claudeDir, "scripts/validate-command.js")}`
|
|
33084
|
+
}
|
|
33085
|
+
]
|
|
33086
|
+
};
|
|
33087
|
+
const existingBashHook = settings.hooks.PreToolUse.find((h) => h.matcher === "Bash");
|
|
33088
|
+
if (!existingBashHook) {
|
|
33089
|
+
settings.hooks.PreToolUse.push(bashHook);
|
|
33090
|
+
}
|
|
33091
|
+
}
|
|
33092
|
+
if (options.notificationSounds) {
|
|
33093
|
+
if (!settings.hooks.Stop) {
|
|
33094
|
+
settings.hooks.Stop = [];
|
|
33095
|
+
}
|
|
33096
|
+
const stopHook = {
|
|
33097
|
+
matcher: "",
|
|
33098
|
+
hooks: [
|
|
33099
|
+
{
|
|
33100
|
+
type: "command",
|
|
33101
|
+
command: `afplay -v 0.1 ${path4.join(claudeDir, "song/finish.mp3")}`
|
|
33102
|
+
}
|
|
33103
|
+
]
|
|
33104
|
+
};
|
|
33105
|
+
const existingStopHook = settings.hooks.Stop.find((h) => h.hooks?.some((hook) => hook.command?.includes("finish.mp3")));
|
|
33106
|
+
if (!existingStopHook) {
|
|
33107
|
+
settings.hooks.Stop.push(stopHook);
|
|
33108
|
+
}
|
|
33109
|
+
if (!settings.hooks.Notification) {
|
|
33110
|
+
settings.hooks.Notification = [];
|
|
33111
|
+
}
|
|
33112
|
+
const notificationHook = {
|
|
33113
|
+
matcher: "",
|
|
33114
|
+
hooks: [
|
|
33115
|
+
{
|
|
33116
|
+
type: "command",
|
|
33117
|
+
command: `afplay -v 0.1 ${path4.join(claudeDir, "song/need-human.mp3")}`
|
|
33118
|
+
}
|
|
33119
|
+
]
|
|
33120
|
+
};
|
|
33121
|
+
const existingNotificationHook = settings.hooks.Notification.find((h) => h.hooks?.some((hook) => hook.command?.includes("need-human.mp3")));
|
|
33122
|
+
if (!existingNotificationHook) {
|
|
33123
|
+
settings.hooks.Notification.push(notificationHook);
|
|
33124
|
+
}
|
|
33125
|
+
}
|
|
33126
|
+
await import_fs_extra3.default.writeJson(settingsPath, settings, { spaces: 2 });
|
|
33127
|
+
}
|
|
33128
|
+
|
|
33129
|
+
// src/commands/setup/utils.ts
|
|
33130
|
+
var import_fs_extra4 = __toESM(require_lib4(), 1);
|
|
33131
|
+
import path5 from "path";
|
|
32863
33132
|
|
|
32864
33133
|
class SimpleSpinner {
|
|
32865
33134
|
message = "";
|
|
@@ -32880,8 +33149,8 @@ async function downloadFromGitHub(relativePath, targetPath) {
|
|
|
32880
33149
|
return false;
|
|
32881
33150
|
}
|
|
32882
33151
|
const content = await response.arrayBuffer();
|
|
32883
|
-
await
|
|
32884
|
-
await
|
|
33152
|
+
await import_fs_extra4.default.ensureDir(path5.dirname(targetPath));
|
|
33153
|
+
await import_fs_extra4.default.writeFile(targetPath, Buffer.from(content));
|
|
32885
33154
|
return true;
|
|
32886
33155
|
} catch (error) {
|
|
32887
33156
|
return false;
|
|
@@ -32898,10 +33167,10 @@ async function downloadDirectoryFromGitHub(dirPath, targetDir) {
|
|
|
32898
33167
|
if (!Array.isArray(files)) {
|
|
32899
33168
|
return false;
|
|
32900
33169
|
}
|
|
32901
|
-
await
|
|
33170
|
+
await import_fs_extra4.default.ensureDir(targetDir);
|
|
32902
33171
|
for (const file of files) {
|
|
32903
33172
|
const relativePath = `${dirPath}/${file.name}`;
|
|
32904
|
-
const targetPath =
|
|
33173
|
+
const targetPath = path5.join(targetDir, file.name);
|
|
32905
33174
|
if (file.type === "file") {
|
|
32906
33175
|
await downloadFromGitHub(relativePath, targetPath);
|
|
32907
33176
|
} else if (file.type === "dir") {
|
|
@@ -32913,7 +33182,18 @@ async function downloadDirectoryFromGitHub(dirPath, targetDir) {
|
|
|
32913
33182
|
return false;
|
|
32914
33183
|
}
|
|
32915
33184
|
}
|
|
32916
|
-
|
|
33185
|
+
|
|
33186
|
+
// src/commands/setup.ts
|
|
33187
|
+
var __filename2 = fileURLToPath(import.meta.url);
|
|
33188
|
+
var __dirname2 = dirname(__filename2);
|
|
33189
|
+
var GITHUB_RAW_BASE2 = "https://raw.githubusercontent.com/Melvynx/aiblueprint-cli/main/claude-code-config";
|
|
33190
|
+
async function setupCommand(params = {}) {
|
|
33191
|
+
const {
|
|
33192
|
+
claudeCodeFolder: customClaudeCodeFolder,
|
|
33193
|
+
codexFolder: customCodexFolder,
|
|
33194
|
+
openCodeFolder: customOpenCodeFolder,
|
|
33195
|
+
skipInteractive
|
|
33196
|
+
} = params;
|
|
32917
33197
|
try {
|
|
32918
33198
|
console.log(source_default.blue.bold(`
|
|
32919
33199
|
\uD83D\uDE80 AIBlueprint Claude Code Setup
|
|
@@ -32921,23 +33201,73 @@ async function setupCommand(customFolder, skipInteractive) {
|
|
|
32921
33201
|
console.log(source_default.bgBlue(" Setting up your Claude Code environment "));
|
|
32922
33202
|
let features;
|
|
32923
33203
|
if (skipInteractive) {
|
|
32924
|
-
features = [
|
|
33204
|
+
features = [
|
|
33205
|
+
"shellShortcuts",
|
|
33206
|
+
"commandValidation",
|
|
33207
|
+
"customStatusline",
|
|
33208
|
+
"aiblueprintCommands",
|
|
33209
|
+
"aiblueprintAgents",
|
|
33210
|
+
"outputStyles",
|
|
33211
|
+
"notificationSounds",
|
|
33212
|
+
"codexSymlink",
|
|
33213
|
+
"openCodeSymlink"
|
|
33214
|
+
];
|
|
32925
33215
|
console.log(source_default.green("✓ Installing all features (--skip mode)"));
|
|
32926
33216
|
} else {
|
|
32927
|
-
const answers = await lib_default.prompt([
|
|
32928
|
-
|
|
32929
|
-
|
|
32930
|
-
|
|
32931
|
-
|
|
32932
|
-
|
|
32933
|
-
|
|
32934
|
-
|
|
32935
|
-
|
|
32936
|
-
|
|
32937
|
-
|
|
32938
|
-
|
|
32939
|
-
|
|
32940
|
-
|
|
33217
|
+
const answers = await lib_default.prompt([
|
|
33218
|
+
{
|
|
33219
|
+
type: "checkbox",
|
|
33220
|
+
name: "features",
|
|
33221
|
+
message: "Which features would you like to install?",
|
|
33222
|
+
choices: [
|
|
33223
|
+
{
|
|
33224
|
+
value: "shellShortcuts",
|
|
33225
|
+
name: "Shell shortcuts (cc, ccc aliases) - Quick access to Claude Code",
|
|
33226
|
+
checked: true
|
|
33227
|
+
},
|
|
33228
|
+
{
|
|
33229
|
+
value: "commandValidation",
|
|
33230
|
+
name: "Command validation - Security hook for bash commands",
|
|
33231
|
+
checked: true
|
|
33232
|
+
},
|
|
33233
|
+
{
|
|
33234
|
+
value: "customStatusline",
|
|
33235
|
+
name: "Custom statusline - Shows git, costs, tokens info",
|
|
33236
|
+
checked: true
|
|
33237
|
+
},
|
|
33238
|
+
{
|
|
33239
|
+
value: "aiblueprintCommands",
|
|
33240
|
+
name: "AIBlueprint commands - Pre-configured command templates",
|
|
33241
|
+
checked: true
|
|
33242
|
+
},
|
|
33243
|
+
{
|
|
33244
|
+
value: "aiblueprintAgents",
|
|
33245
|
+
name: "AIBlueprint agents - Specialized AI agents",
|
|
33246
|
+
checked: true
|
|
33247
|
+
},
|
|
33248
|
+
{
|
|
33249
|
+
value: "outputStyles",
|
|
33250
|
+
name: "Output styles - Custom output formatting",
|
|
33251
|
+
checked: true
|
|
33252
|
+
},
|
|
33253
|
+
{
|
|
33254
|
+
value: "notificationSounds",
|
|
33255
|
+
name: "Notification sounds - Audio alerts for events",
|
|
33256
|
+
checked: true
|
|
33257
|
+
},
|
|
33258
|
+
{
|
|
33259
|
+
value: "codexSymlink",
|
|
33260
|
+
name: "Codex symlink - Link commands to ~/.codex/prompts",
|
|
33261
|
+
checked: false
|
|
33262
|
+
},
|
|
33263
|
+
{
|
|
33264
|
+
value: "openCodeSymlink",
|
|
33265
|
+
name: "OpenCode symlink - Link commands to ~/.config/opencode/command",
|
|
33266
|
+
checked: false
|
|
33267
|
+
}
|
|
33268
|
+
]
|
|
33269
|
+
}
|
|
33270
|
+
]);
|
|
32941
33271
|
features = answers.features;
|
|
32942
33272
|
if (!features || features.length === 0) {
|
|
32943
33273
|
console.log(source_default.yellow("Setup cancelled - no features selected"));
|
|
@@ -32951,15 +33281,17 @@ async function setupCommand(customFolder, skipInteractive) {
|
|
|
32951
33281
|
aiblueprintCommands: features.includes("aiblueprintCommands"),
|
|
32952
33282
|
aiblueprintAgents: features.includes("aiblueprintAgents"),
|
|
32953
33283
|
outputStyles: features.includes("outputStyles"),
|
|
32954
|
-
notificationSounds: features.includes("notificationSounds")
|
|
33284
|
+
notificationSounds: features.includes("notificationSounds"),
|
|
33285
|
+
codexSymlink: features.includes("codexSymlink"),
|
|
33286
|
+
openCodeSymlink: features.includes("openCodeSymlink")
|
|
32955
33287
|
};
|
|
32956
33288
|
const s = new SimpleSpinner;
|
|
32957
|
-
const claudeDir =
|
|
33289
|
+
const claudeDir = customClaudeCodeFolder ? path6.resolve(customClaudeCodeFolder) : path6.join(os5.homedir(), ".claude");
|
|
32958
33290
|
console.log(source_default.gray(`Installing to: ${claudeDir}`));
|
|
32959
|
-
await
|
|
33291
|
+
await import_fs_extra5.default.ensureDir(claudeDir);
|
|
32960
33292
|
let useGitHub = true;
|
|
32961
33293
|
let sourceDir;
|
|
32962
|
-
const testUrl = `${
|
|
33294
|
+
const testUrl = `${GITHUB_RAW_BASE2}/scripts/validate-command.js`;
|
|
32963
33295
|
try {
|
|
32964
33296
|
const testResponse = await fetch(testUrl);
|
|
32965
33297
|
useGitHub = testResponse.ok;
|
|
@@ -32969,14 +33301,14 @@ async function setupCommand(customFolder, skipInteractive) {
|
|
|
32969
33301
|
if (!useGitHub) {
|
|
32970
33302
|
const currentDir = process.cwd();
|
|
32971
33303
|
const possiblePaths = [
|
|
32972
|
-
|
|
32973
|
-
|
|
32974
|
-
|
|
32975
|
-
|
|
33304
|
+
path6.join(currentDir, "claude-code-config"),
|
|
33305
|
+
path6.join(__dirname2, "../../claude-code-config"),
|
|
33306
|
+
path6.join(__dirname2, "../claude-code-config"),
|
|
33307
|
+
path6.join(path6.dirname(process.argv[1]), "../claude-code-config")
|
|
32976
33308
|
];
|
|
32977
33309
|
sourceDir = possiblePaths.find((p) => {
|
|
32978
33310
|
try {
|
|
32979
|
-
return
|
|
33311
|
+
return import_fs_extra5.default.existsSync(p);
|
|
32980
33312
|
} catch {
|
|
32981
33313
|
return false;
|
|
32982
33314
|
}
|
|
@@ -32996,53 +33328,68 @@ async function setupCommand(customFolder, skipInteractive) {
|
|
|
32996
33328
|
if (options.commandValidation || options.customStatusline || options.notificationSounds) {
|
|
32997
33329
|
s.start("Setting up scripts");
|
|
32998
33330
|
if (useGitHub) {
|
|
32999
|
-
const scriptsDir =
|
|
33000
|
-
await
|
|
33001
|
-
const scriptFiles = [
|
|
33331
|
+
const scriptsDir = path6.join(claudeDir, "scripts");
|
|
33332
|
+
await import_fs_extra5.default.ensureDir(scriptsDir);
|
|
33333
|
+
const scriptFiles = [
|
|
33334
|
+
"validate-command.js",
|
|
33335
|
+
"statusline-ccusage.sh",
|
|
33336
|
+
"validate-command.readme.md",
|
|
33337
|
+
"statusline.readme.md"
|
|
33338
|
+
];
|
|
33002
33339
|
for (const file of scriptFiles) {
|
|
33003
|
-
await downloadFromGitHub(`scripts/${file}`,
|
|
33340
|
+
await downloadFromGitHub(`scripts/${file}`, path6.join(scriptsDir, file));
|
|
33004
33341
|
}
|
|
33005
33342
|
} else {
|
|
33006
|
-
await
|
|
33343
|
+
await import_fs_extra5.default.copy(path6.join(sourceDir, "scripts"), path6.join(claudeDir, "scripts"), { overwrite: true });
|
|
33007
33344
|
}
|
|
33008
33345
|
s.stop("Scripts installed");
|
|
33009
33346
|
}
|
|
33010
33347
|
if (options.aiblueprintCommands) {
|
|
33011
33348
|
s.start("Setting up AIBlueprint commands");
|
|
33012
33349
|
if (useGitHub) {
|
|
33013
|
-
await downloadDirectoryFromGitHub("commands",
|
|
33350
|
+
await downloadDirectoryFromGitHub("commands", path6.join(claudeDir, "commands"));
|
|
33014
33351
|
} else {
|
|
33015
|
-
await
|
|
33352
|
+
await import_fs_extra5.default.copy(path6.join(sourceDir, "commands"), path6.join(claudeDir, "commands"), { overwrite: true });
|
|
33016
33353
|
}
|
|
33017
33354
|
s.stop("Commands installed");
|
|
33018
33355
|
}
|
|
33356
|
+
if (options.codexSymlink && options.aiblueprintCommands) {
|
|
33357
|
+
s.start("Setting up Codex symlink");
|
|
33358
|
+
await setupCodexSymlink(claudeDir, customCodexFolder, customClaudeCodeFolder);
|
|
33359
|
+
s.stop("Codex symlink configured");
|
|
33360
|
+
}
|
|
33361
|
+
if (options.openCodeSymlink && options.aiblueprintCommands) {
|
|
33362
|
+
s.start("Setting up OpenCode symlink");
|
|
33363
|
+
await setupOpenCodeSymlink(claudeDir, customOpenCodeFolder, customClaudeCodeFolder);
|
|
33364
|
+
s.stop("OpenCode symlink configured");
|
|
33365
|
+
}
|
|
33019
33366
|
if (options.aiblueprintAgents) {
|
|
33020
33367
|
s.start("Setting up AIBlueprint agents");
|
|
33021
33368
|
if (useGitHub) {
|
|
33022
|
-
await downloadDirectoryFromGitHub("agents",
|
|
33369
|
+
await downloadDirectoryFromGitHub("agents", path6.join(claudeDir, "agents"));
|
|
33023
33370
|
} else {
|
|
33024
|
-
await
|
|
33371
|
+
await import_fs_extra5.default.copy(path6.join(sourceDir, "agents"), path6.join(claudeDir, "agents"), { overwrite: true });
|
|
33025
33372
|
}
|
|
33026
33373
|
s.stop("Agents installed");
|
|
33027
33374
|
}
|
|
33028
33375
|
if (options.outputStyles) {
|
|
33029
33376
|
s.start("Setting up output styles");
|
|
33030
33377
|
if (useGitHub) {
|
|
33031
|
-
await downloadDirectoryFromGitHub("output-styles",
|
|
33378
|
+
await downloadDirectoryFromGitHub("output-styles", path6.join(claudeDir, "output-styles"));
|
|
33032
33379
|
} else {
|
|
33033
|
-
await
|
|
33380
|
+
await import_fs_extra5.default.copy(path6.join(sourceDir, "output-styles"), path6.join(claudeDir, "output-styles"), { overwrite: true });
|
|
33034
33381
|
}
|
|
33035
33382
|
s.stop("Output styles installed");
|
|
33036
33383
|
}
|
|
33037
33384
|
if (options.notificationSounds) {
|
|
33038
33385
|
s.start("Setting up notification sounds");
|
|
33039
33386
|
if (useGitHub) {
|
|
33040
|
-
const songDir =
|
|
33041
|
-
await
|
|
33042
|
-
await downloadFromGitHub("song/finish.mp3",
|
|
33043
|
-
await downloadFromGitHub("song/need-human.mp3",
|
|
33387
|
+
const songDir = path6.join(claudeDir, "song");
|
|
33388
|
+
await import_fs_extra5.default.ensureDir(songDir);
|
|
33389
|
+
await downloadFromGitHub("song/finish.mp3", path6.join(songDir, "finish.mp3"));
|
|
33390
|
+
await downloadFromGitHub("song/need-human.mp3", path6.join(songDir, "need-human.mp3"));
|
|
33044
33391
|
} else {
|
|
33045
|
-
await
|
|
33392
|
+
await import_fs_extra5.default.copy(path6.join(sourceDir, "song"), path6.join(claudeDir, "song"), { overwrite: true });
|
|
33046
33393
|
}
|
|
33047
33394
|
s.stop("Notification sounds installed");
|
|
33048
33395
|
}
|
|
@@ -33070,164 +33417,16 @@ Next steps:`));
|
|
|
33070
33417
|
process.exit(1);
|
|
33071
33418
|
}
|
|
33072
33419
|
}
|
|
33073
|
-
async function setupShellShortcuts() {
|
|
33074
|
-
try {
|
|
33075
|
-
const platform = os3.platform();
|
|
33076
|
-
let shellConfigFile;
|
|
33077
|
-
if (platform === "darwin") {
|
|
33078
|
-
shellConfigFile = path2.join(os3.homedir(), ".zshenv");
|
|
33079
|
-
} else if (platform === "linux") {
|
|
33080
|
-
const shell = process.env.SHELL || "";
|
|
33081
|
-
if (shell.includes("zsh")) {
|
|
33082
|
-
shellConfigFile = path2.join(os3.homedir(), ".zshrc");
|
|
33083
|
-
} else {
|
|
33084
|
-
shellConfigFile = path2.join(os3.homedir(), ".bashrc");
|
|
33085
|
-
}
|
|
33086
|
-
} else {
|
|
33087
|
-
console.log(source_default.yellow("Shell shortcuts are only supported on macOS and Linux"));
|
|
33088
|
-
return;
|
|
33089
|
-
}
|
|
33090
|
-
const aliases = `
|
|
33091
|
-
# AIBlueprint Claude Code aliases
|
|
33092
|
-
alias cc="claude --dangerously-skip-permissions"
|
|
33093
|
-
alias ccc="claude --dangerously-skip-permissions -c"
|
|
33094
|
-
`;
|
|
33095
|
-
const existingContent = await import_fs_extra.default.readFile(shellConfigFile, "utf-8").catch(() => "");
|
|
33096
|
-
if (!existingContent.includes("AIBlueprint Claude Code aliases")) {
|
|
33097
|
-
await import_fs_extra.default.appendFile(shellConfigFile, aliases);
|
|
33098
|
-
}
|
|
33099
|
-
} catch (error) {
|
|
33100
|
-
console.error(source_default.red("Error setting up shell shortcuts:"), error);
|
|
33101
|
-
throw error;
|
|
33102
|
-
}
|
|
33103
|
-
}
|
|
33104
|
-
async function checkAndInstallDependencies() {
|
|
33105
|
-
const checkCommand = (cmd) => {
|
|
33106
|
-
try {
|
|
33107
|
-
execSync(`which ${cmd}`, { stdio: "ignore" });
|
|
33108
|
-
return true;
|
|
33109
|
-
} catch {
|
|
33110
|
-
return false;
|
|
33111
|
-
}
|
|
33112
|
-
};
|
|
33113
|
-
if (!checkCommand("bun")) {
|
|
33114
|
-
console.log(source_default.yellow(`
|
|
33115
|
-
Installing bun...`));
|
|
33116
|
-
try {
|
|
33117
|
-
execSync("npm install -g bun", { stdio: "inherit" });
|
|
33118
|
-
} catch (error) {
|
|
33119
|
-
console.log(source_default.red(" Failed to install bun. Please install it manually: npm install -g bun"));
|
|
33120
|
-
}
|
|
33121
|
-
}
|
|
33122
|
-
if (!checkCommand("ccusage")) {
|
|
33123
|
-
console.log(source_default.yellow(`
|
|
33124
|
-
Installing ccusage...`));
|
|
33125
|
-
try {
|
|
33126
|
-
execSync("npm install -g ccusage", { stdio: "inherit" });
|
|
33127
|
-
} catch (error) {
|
|
33128
|
-
console.log(source_default.red(" Failed to install ccusage. Please install it manually: npm install -g ccusage"));
|
|
33129
|
-
}
|
|
33130
|
-
}
|
|
33131
|
-
}
|
|
33132
|
-
async function updateSettings(options, claudeDir) {
|
|
33133
|
-
const settingsPath = path2.join(claudeDir, "settings.json");
|
|
33134
|
-
let settings = {};
|
|
33135
|
-
try {
|
|
33136
|
-
const existingSettings = await import_fs_extra.default.readFile(settingsPath, "utf-8");
|
|
33137
|
-
settings = JSON.parse(existingSettings);
|
|
33138
|
-
} catch {
|
|
33139
|
-
}
|
|
33140
|
-
if (options.customStatusline) {
|
|
33141
|
-
if (settings.statusLine) {
|
|
33142
|
-
const confirmAnswer = await lib_default.prompt([{
|
|
33143
|
-
type: "confirm",
|
|
33144
|
-
name: "replace",
|
|
33145
|
-
message: "You already have a statusLine configuration. Replace it?"
|
|
33146
|
-
}]);
|
|
33147
|
-
if (!confirmAnswer.replace) {
|
|
33148
|
-
console.log(source_default.yellow(" Keeping existing statusLine configuration"));
|
|
33149
|
-
} else {
|
|
33150
|
-
settings.statusLine = {
|
|
33151
|
-
type: "command",
|
|
33152
|
-
command: `bash ${path2.join(claudeDir, "scripts/statusline-ccusage.sh")}`,
|
|
33153
|
-
padding: 0
|
|
33154
|
-
};
|
|
33155
|
-
}
|
|
33156
|
-
} else {
|
|
33157
|
-
settings.statusLine = {
|
|
33158
|
-
type: "command",
|
|
33159
|
-
command: `bash ${path2.join(claudeDir, "scripts/statusline-ccusage.sh")}`,
|
|
33160
|
-
padding: 0
|
|
33161
|
-
};
|
|
33162
|
-
}
|
|
33163
|
-
}
|
|
33164
|
-
if (!settings.hooks) {
|
|
33165
|
-
settings.hooks = {};
|
|
33166
|
-
}
|
|
33167
|
-
if (options.commandValidation) {
|
|
33168
|
-
if (!settings.hooks.PreToolUse) {
|
|
33169
|
-
settings.hooks.PreToolUse = [];
|
|
33170
|
-
}
|
|
33171
|
-
const bashHook = {
|
|
33172
|
-
matcher: "Bash",
|
|
33173
|
-
hooks: [
|
|
33174
|
-
{
|
|
33175
|
-
type: "command",
|
|
33176
|
-
command: `bun ${path2.join(claudeDir, "scripts/validate-command.js")}`
|
|
33177
|
-
}
|
|
33178
|
-
]
|
|
33179
|
-
};
|
|
33180
|
-
const existingBashHook = settings.hooks.PreToolUse.find((h) => h.matcher === "Bash");
|
|
33181
|
-
if (!existingBashHook) {
|
|
33182
|
-
settings.hooks.PreToolUse.push(bashHook);
|
|
33183
|
-
}
|
|
33184
|
-
}
|
|
33185
|
-
if (options.notificationSounds) {
|
|
33186
|
-
if (!settings.hooks.Stop) {
|
|
33187
|
-
settings.hooks.Stop = [];
|
|
33188
|
-
}
|
|
33189
|
-
const stopHook = {
|
|
33190
|
-
matcher: "",
|
|
33191
|
-
hooks: [
|
|
33192
|
-
{
|
|
33193
|
-
type: "command",
|
|
33194
|
-
command: `afplay -v 0.1 ${path2.join(claudeDir, "song/finish.mp3")}`
|
|
33195
|
-
}
|
|
33196
|
-
]
|
|
33197
|
-
};
|
|
33198
|
-
const existingStopHook = settings.hooks.Stop.find((h) => h.hooks?.some((hook) => hook.command?.includes("finish.mp3")));
|
|
33199
|
-
if (!existingStopHook) {
|
|
33200
|
-
settings.hooks.Stop.push(stopHook);
|
|
33201
|
-
}
|
|
33202
|
-
if (!settings.hooks.Notification) {
|
|
33203
|
-
settings.hooks.Notification = [];
|
|
33204
|
-
}
|
|
33205
|
-
const notificationHook = {
|
|
33206
|
-
matcher: "",
|
|
33207
|
-
hooks: [
|
|
33208
|
-
{
|
|
33209
|
-
type: "command",
|
|
33210
|
-
command: `afplay -v 0.1 ${path2.join(claudeDir, "song/need-human.mp3")}`
|
|
33211
|
-
}
|
|
33212
|
-
]
|
|
33213
|
-
};
|
|
33214
|
-
const existingNotificationHook = settings.hooks.Notification.find((h) => h.hooks?.some((hook) => hook.command?.includes("need-human.mp3")));
|
|
33215
|
-
if (!existingNotificationHook) {
|
|
33216
|
-
settings.hooks.Notification.push(notificationHook);
|
|
33217
|
-
}
|
|
33218
|
-
}
|
|
33219
|
-
await import_fs_extra.default.writeJson(settingsPath, settings, { spaces: 2 });
|
|
33220
|
-
}
|
|
33221
33420
|
|
|
33222
33421
|
// src/commands/addHook.ts
|
|
33223
|
-
var
|
|
33224
|
-
import
|
|
33422
|
+
var import_fs_extra9 = __toESM(require_lib4(), 1);
|
|
33423
|
+
import path10 from "path";
|
|
33225
33424
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
33226
33425
|
import { dirname as dirname3 } from "path";
|
|
33227
33426
|
|
|
33228
33427
|
// src/utils/claude-config.ts
|
|
33229
|
-
var
|
|
33230
|
-
import
|
|
33428
|
+
var import_fs_extra6 = __toESM(require_lib4(), 1);
|
|
33429
|
+
import path7 from "path";
|
|
33231
33430
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
33232
33431
|
import { dirname as dirname2 } from "path";
|
|
33233
33432
|
var __filename3 = fileURLToPath2(import.meta.url);
|
|
@@ -33258,14 +33457,14 @@ function parseYamlFrontmatter(content) {
|
|
|
33258
33457
|
}
|
|
33259
33458
|
function getLocalConfigPaths(subDir) {
|
|
33260
33459
|
return [
|
|
33261
|
-
|
|
33262
|
-
|
|
33460
|
+
path7.join(__dirname3, `../claude-code-config/${subDir}`),
|
|
33461
|
+
path7.join(__dirname3, `../../claude-code-config/${subDir}`)
|
|
33263
33462
|
];
|
|
33264
33463
|
}
|
|
33265
33464
|
async function findLocalConfigDir(subDir) {
|
|
33266
33465
|
const possiblePaths = getLocalConfigPaths(subDir);
|
|
33267
33466
|
for (const testPath of possiblePaths) {
|
|
33268
|
-
if (await
|
|
33467
|
+
if (await import_fs_extra6.default.pathExists(testPath)) {
|
|
33269
33468
|
return testPath;
|
|
33270
33469
|
}
|
|
33271
33470
|
}
|
|
@@ -33276,13 +33475,108 @@ async function getTargetDirectory(options) {
|
|
|
33276
33475
|
return options.folder;
|
|
33277
33476
|
}
|
|
33278
33477
|
const cwd = process.cwd();
|
|
33279
|
-
const localClaudeDir =
|
|
33280
|
-
const isGitRepo = await
|
|
33281
|
-
const hasClaudeConfig = await
|
|
33478
|
+
const localClaudeDir = path7.join(cwd, ".claude");
|
|
33479
|
+
const isGitRepo = await import_fs_extra6.default.pathExists(path7.join(cwd, ".git"));
|
|
33480
|
+
const hasClaudeConfig = await import_fs_extra6.default.pathExists(localClaudeDir);
|
|
33282
33481
|
if (isGitRepo || hasClaudeConfig) {
|
|
33283
33482
|
return localClaudeDir;
|
|
33284
33483
|
}
|
|
33285
|
-
return
|
|
33484
|
+
return path7.join(process.env.HOME || process.env.USERPROFILE || "~", ".claude");
|
|
33485
|
+
}
|
|
33486
|
+
|
|
33487
|
+
// src/utils/file-installer.ts
|
|
33488
|
+
var import_fs_extra8 = __toESM(require_lib4(), 1);
|
|
33489
|
+
import path9 from "path";
|
|
33490
|
+
|
|
33491
|
+
// src/utils/github.ts
|
|
33492
|
+
var import_fs_extra7 = __toESM(require_lib4(), 1);
|
|
33493
|
+
import path8 from "path";
|
|
33494
|
+
var GITHUB_RAW_BASE3 = "https://raw.githubusercontent.com/Melvynx/aiblueprint-cli/main/claude-code-config";
|
|
33495
|
+
async function downloadFromGitHub2(relativePath) {
|
|
33496
|
+
try {
|
|
33497
|
+
const url = `${GITHUB_RAW_BASE3}/${relativePath}`;
|
|
33498
|
+
const response = await fetch(url);
|
|
33499
|
+
if (!response.ok) {
|
|
33500
|
+
return null;
|
|
33501
|
+
}
|
|
33502
|
+
return await response.text();
|
|
33503
|
+
} catch (error) {
|
|
33504
|
+
return null;
|
|
33505
|
+
}
|
|
33506
|
+
}
|
|
33507
|
+
async function listFilesFromGitHub(dirPath) {
|
|
33508
|
+
try {
|
|
33509
|
+
const apiUrl = `https://api.github.com/repos/Melvynx/aiblueprint-cli/contents/claude-code-config/${dirPath}`;
|
|
33510
|
+
const response = await fetch(apiUrl);
|
|
33511
|
+
if (!response.ok) {
|
|
33512
|
+
return [];
|
|
33513
|
+
}
|
|
33514
|
+
const files = await response.json();
|
|
33515
|
+
return files.filter((file) => file.type === "file").map((file) => file.name);
|
|
33516
|
+
} catch (error) {
|
|
33517
|
+
return [];
|
|
33518
|
+
}
|
|
33519
|
+
}
|
|
33520
|
+
async function isGitHubAvailable() {
|
|
33521
|
+
try {
|
|
33522
|
+
const testUrl = `${GITHUB_RAW_BASE3}/commands/commit.md`;
|
|
33523
|
+
const testResponse = await fetch(testUrl);
|
|
33524
|
+
return testResponse.ok;
|
|
33525
|
+
} catch {
|
|
33526
|
+
return false;
|
|
33527
|
+
}
|
|
33528
|
+
}
|
|
33529
|
+
async function downloadAndWriteFile(relativePath, targetPath) {
|
|
33530
|
+
const content = await downloadFromGitHub2(relativePath);
|
|
33531
|
+
if (content) {
|
|
33532
|
+
await import_fs_extra7.default.ensureDir(path8.dirname(targetPath));
|
|
33533
|
+
await import_fs_extra7.default.writeFile(targetPath, content);
|
|
33534
|
+
return true;
|
|
33535
|
+
}
|
|
33536
|
+
return false;
|
|
33537
|
+
}
|
|
33538
|
+
|
|
33539
|
+
// src/utils/file-installer.ts
|
|
33540
|
+
async function installFileWithGitHubFallback(options) {
|
|
33541
|
+
const { sourceDir, targetPath, fileName } = options;
|
|
33542
|
+
await import_fs_extra8.default.ensureDir(path9.dirname(targetPath));
|
|
33543
|
+
const useGitHub = options.useGitHub ?? await isGitHubAvailable();
|
|
33544
|
+
if (useGitHub) {
|
|
33545
|
+
const relativePath = `${sourceDir}/${fileName}`;
|
|
33546
|
+
const success = await downloadAndWriteFile(relativePath, targetPath);
|
|
33547
|
+
if (success) {
|
|
33548
|
+
return;
|
|
33549
|
+
}
|
|
33550
|
+
console.log(source_default.yellow(`⚠️ GitHub download failed for ${fileName}, falling back to local files`));
|
|
33551
|
+
}
|
|
33552
|
+
const localConfigDir = await findLocalConfigDir(sourceDir);
|
|
33553
|
+
if (!localConfigDir) {
|
|
33554
|
+
throw new Error(`Neither GitHub nor local ${sourceDir} directory found`);
|
|
33555
|
+
}
|
|
33556
|
+
const localFilePath = path9.join(localConfigDir, fileName);
|
|
33557
|
+
if (!await import_fs_extra8.default.pathExists(localFilePath)) {
|
|
33558
|
+
throw new Error(`File not found: ${fileName}`);
|
|
33559
|
+
}
|
|
33560
|
+
await import_fs_extra8.default.copy(localFilePath, targetPath);
|
|
33561
|
+
}
|
|
33562
|
+
async function getFileContentWithGitHubFallback(sourceDir, fileName) {
|
|
33563
|
+
const useGitHub = await isGitHubAvailable();
|
|
33564
|
+
if (useGitHub) {
|
|
33565
|
+
const content = await downloadFromGitHub2(`${sourceDir}/${fileName}`);
|
|
33566
|
+
if (content) {
|
|
33567
|
+
return content;
|
|
33568
|
+
}
|
|
33569
|
+
console.log(source_default.yellow(`⚠️ GitHub download failed for ${fileName}, falling back to local files`));
|
|
33570
|
+
}
|
|
33571
|
+
const localConfigDir = await findLocalConfigDir(sourceDir);
|
|
33572
|
+
if (!localConfigDir) {
|
|
33573
|
+
throw new Error(`Neither GitHub nor local ${sourceDir} directory found`);
|
|
33574
|
+
}
|
|
33575
|
+
const localFilePath = path9.join(localConfigDir, fileName);
|
|
33576
|
+
if (!await import_fs_extra8.default.pathExists(localFilePath)) {
|
|
33577
|
+
throw new Error(`File not found: ${fileName}`);
|
|
33578
|
+
}
|
|
33579
|
+
return await import_fs_extra8.default.readFile(localFilePath, "utf-8");
|
|
33286
33580
|
}
|
|
33287
33581
|
|
|
33288
33582
|
// src/commands/addHook.ts
|
|
@@ -33322,10 +33616,10 @@ async function addHookCommand(hookType, options) {
|
|
|
33322
33616
|
const s = new SimpleSpinner2;
|
|
33323
33617
|
const targetDir = await getTargetDirectory(options);
|
|
33324
33618
|
const claudeDir = targetDir;
|
|
33325
|
-
const hooksDir =
|
|
33326
|
-
const hookFilePath =
|
|
33327
|
-
const settingsPath =
|
|
33328
|
-
if (await
|
|
33619
|
+
const hooksDir = path10.join(claudeDir, "hooks");
|
|
33620
|
+
const hookFilePath = path10.join(hooksDir, hook.hookFile);
|
|
33621
|
+
const settingsPath = path10.join(claudeDir, "settings.json");
|
|
33622
|
+
if (await import_fs_extra9.default.pathExists(hookFilePath)) {
|
|
33329
33623
|
const overwriteAnswer = await lib_default.prompt([{
|
|
33330
33624
|
type: "confirm",
|
|
33331
33625
|
name: "overwrite",
|
|
@@ -33338,15 +33632,18 @@ async function addHookCommand(hookType, options) {
|
|
|
33338
33632
|
}
|
|
33339
33633
|
try {
|
|
33340
33634
|
s.start("Installing hook...");
|
|
33341
|
-
await
|
|
33342
|
-
|
|
33343
|
-
|
|
33344
|
-
|
|
33635
|
+
await import_fs_extra9.default.ensureDir(hooksDir);
|
|
33636
|
+
await installFileWithGitHubFallback({
|
|
33637
|
+
sourceDir: "hooks",
|
|
33638
|
+
targetPath: hookFilePath,
|
|
33639
|
+
fileName: hook.hookFile
|
|
33640
|
+
});
|
|
33641
|
+
await import_fs_extra9.default.chmod(hookFilePath, 493);
|
|
33345
33642
|
s.stop("Hook file installed");
|
|
33346
33643
|
s.start("Updating settings.json...");
|
|
33347
33644
|
let settings = {};
|
|
33348
33645
|
try {
|
|
33349
|
-
const existingSettings = await
|
|
33646
|
+
const existingSettings = await import_fs_extra9.default.readFile(settingsPath, "utf-8");
|
|
33350
33647
|
settings = JSON.parse(existingSettings);
|
|
33351
33648
|
} catch {
|
|
33352
33649
|
settings = {};
|
|
@@ -33383,7 +33680,7 @@ async function addHookCommand(hookType, options) {
|
|
|
33383
33680
|
} else {
|
|
33384
33681
|
settings.hooks[hook.event].push(newHook);
|
|
33385
33682
|
}
|
|
33386
|
-
await
|
|
33683
|
+
await import_fs_extra9.default.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
33387
33684
|
s.stop("Settings updated");
|
|
33388
33685
|
console.log(source_default.green("✨ Hook installed successfully!"));
|
|
33389
33686
|
console.log(source_default.gray(`
|
|
@@ -33402,103 +33699,8 @@ The hook will run automatically when you edit TypeScript files with Claude Code.
|
|
|
33402
33699
|
}
|
|
33403
33700
|
|
|
33404
33701
|
// src/commands/addCommand.ts
|
|
33405
|
-
var
|
|
33406
|
-
import
|
|
33407
|
-
|
|
33408
|
-
// src/utils/github.ts
|
|
33409
|
-
var import_fs_extra4 = __toESM(require_lib4(), 1);
|
|
33410
|
-
import path5 from "path";
|
|
33411
|
-
var GITHUB_RAW_BASE2 = "https://raw.githubusercontent.com/Melvynx/aiblueprint-cli/main/claude-code-config";
|
|
33412
|
-
async function downloadFromGitHub2(relativePath) {
|
|
33413
|
-
try {
|
|
33414
|
-
const url = `${GITHUB_RAW_BASE2}/${relativePath}`;
|
|
33415
|
-
const response = await fetch(url);
|
|
33416
|
-
if (!response.ok) {
|
|
33417
|
-
return null;
|
|
33418
|
-
}
|
|
33419
|
-
return await response.text();
|
|
33420
|
-
} catch (error) {
|
|
33421
|
-
return null;
|
|
33422
|
-
}
|
|
33423
|
-
}
|
|
33424
|
-
async function listFilesFromGitHub(dirPath) {
|
|
33425
|
-
try {
|
|
33426
|
-
const apiUrl = `https://api.github.com/repos/Melvynx/aiblueprint-cli/contents/claude-code-config/${dirPath}`;
|
|
33427
|
-
const response = await fetch(apiUrl);
|
|
33428
|
-
if (!response.ok) {
|
|
33429
|
-
return [];
|
|
33430
|
-
}
|
|
33431
|
-
const files = await response.json();
|
|
33432
|
-
return files.filter((file) => file.type === "file").map((file) => file.name);
|
|
33433
|
-
} catch (error) {
|
|
33434
|
-
return [];
|
|
33435
|
-
}
|
|
33436
|
-
}
|
|
33437
|
-
async function isGitHubAvailable() {
|
|
33438
|
-
try {
|
|
33439
|
-
const testUrl = `${GITHUB_RAW_BASE2}/commands/commit.md`;
|
|
33440
|
-
const testResponse = await fetch(testUrl);
|
|
33441
|
-
return testResponse.ok;
|
|
33442
|
-
} catch {
|
|
33443
|
-
return false;
|
|
33444
|
-
}
|
|
33445
|
-
}
|
|
33446
|
-
async function downloadAndWriteFile(relativePath, targetPath) {
|
|
33447
|
-
const content = await downloadFromGitHub2(relativePath);
|
|
33448
|
-
if (content) {
|
|
33449
|
-
await import_fs_extra4.default.ensureDir(path5.dirname(targetPath));
|
|
33450
|
-
await import_fs_extra4.default.writeFile(targetPath, content);
|
|
33451
|
-
return true;
|
|
33452
|
-
}
|
|
33453
|
-
return false;
|
|
33454
|
-
}
|
|
33455
|
-
|
|
33456
|
-
// src/utils/file-installer.ts
|
|
33457
|
-
var import_fs_extra5 = __toESM(require_lib4(), 1);
|
|
33458
|
-
import path6 from "path";
|
|
33459
|
-
async function installFileWithGitHubFallback(options) {
|
|
33460
|
-
const { sourceDir, targetPath, fileName } = options;
|
|
33461
|
-
await import_fs_extra5.default.ensureDir(path6.dirname(targetPath));
|
|
33462
|
-
const useGitHub = options.useGitHub ?? await isGitHubAvailable();
|
|
33463
|
-
if (useGitHub) {
|
|
33464
|
-
const relativePath = `${sourceDir}/${fileName}`;
|
|
33465
|
-
const success = await downloadAndWriteFile(relativePath, targetPath);
|
|
33466
|
-
if (success) {
|
|
33467
|
-
return;
|
|
33468
|
-
}
|
|
33469
|
-
console.log(source_default.yellow(`⚠️ GitHub download failed for ${fileName}, falling back to local files`));
|
|
33470
|
-
}
|
|
33471
|
-
const localConfigDir = await findLocalConfigDir(sourceDir);
|
|
33472
|
-
if (!localConfigDir) {
|
|
33473
|
-
throw new Error(`Neither GitHub nor local ${sourceDir} directory found`);
|
|
33474
|
-
}
|
|
33475
|
-
const localFilePath = path6.join(localConfigDir, fileName);
|
|
33476
|
-
if (!await import_fs_extra5.default.pathExists(localFilePath)) {
|
|
33477
|
-
throw new Error(`File not found: ${fileName}`);
|
|
33478
|
-
}
|
|
33479
|
-
await import_fs_extra5.default.copy(localFilePath, targetPath);
|
|
33480
|
-
}
|
|
33481
|
-
async function getFileContentWithGitHubFallback(sourceDir, fileName) {
|
|
33482
|
-
const useGitHub = await isGitHubAvailable();
|
|
33483
|
-
if (useGitHub) {
|
|
33484
|
-
const content = await downloadFromGitHub2(`${sourceDir}/${fileName}`);
|
|
33485
|
-
if (content) {
|
|
33486
|
-
return content;
|
|
33487
|
-
}
|
|
33488
|
-
console.log(source_default.yellow(`⚠️ GitHub download failed for ${fileName}, falling back to local files`));
|
|
33489
|
-
}
|
|
33490
|
-
const localConfigDir = await findLocalConfigDir(sourceDir);
|
|
33491
|
-
if (!localConfigDir) {
|
|
33492
|
-
throw new Error(`Neither GitHub nor local ${sourceDir} directory found`);
|
|
33493
|
-
}
|
|
33494
|
-
const localFilePath = path6.join(localConfigDir, fileName);
|
|
33495
|
-
if (!await import_fs_extra5.default.pathExists(localFilePath)) {
|
|
33496
|
-
throw new Error(`File not found: ${fileName}`);
|
|
33497
|
-
}
|
|
33498
|
-
return await import_fs_extra5.default.readFile(localFilePath, "utf-8");
|
|
33499
|
-
}
|
|
33500
|
-
|
|
33501
|
-
// src/commands/addCommand.ts
|
|
33702
|
+
var import_fs_extra10 = __toESM(require_lib4(), 1);
|
|
33703
|
+
import path11 from "path";
|
|
33502
33704
|
class SimpleSpinner3 {
|
|
33503
33705
|
message = "";
|
|
33504
33706
|
start(message) {
|
|
@@ -33515,12 +33717,13 @@ async function discoverAvailableCommands() {
|
|
|
33515
33717
|
let mdFiles = [];
|
|
33516
33718
|
if (useGitHub) {
|
|
33517
33719
|
mdFiles = (await listFilesFromGitHub("commands")).filter((file) => file.endsWith(".md"));
|
|
33518
|
-
}
|
|
33720
|
+
}
|
|
33721
|
+
if (mdFiles.length === 0) {
|
|
33519
33722
|
const commandsDir = await findLocalConfigDir("commands");
|
|
33520
33723
|
if (!commandsDir) {
|
|
33521
33724
|
throw new Error("Commands directory not found");
|
|
33522
33725
|
}
|
|
33523
|
-
const files = await
|
|
33726
|
+
const files = await import_fs_extra10.default.readdir(commandsDir);
|
|
33524
33727
|
mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
33525
33728
|
}
|
|
33526
33729
|
for (const file of mdFiles) {
|
|
@@ -33581,9 +33784,9 @@ async function addCommandCommand(commandName, options = {}) {
|
|
|
33581
33784
|
if (options.folder) {
|
|
33582
33785
|
console.log(source_default.gray(`Using custom folder: ${targetDir}`));
|
|
33583
33786
|
}
|
|
33584
|
-
const commandsDir =
|
|
33585
|
-
const commandFilePath =
|
|
33586
|
-
if (await
|
|
33787
|
+
const commandsDir = path11.join(targetDir, "commands");
|
|
33788
|
+
const commandFilePath = path11.join(commandsDir, command.commandFile);
|
|
33789
|
+
if (await import_fs_extra10.default.pathExists(commandFilePath)) {
|
|
33587
33790
|
const overwriteAnswer = await lib_default.prompt([{
|
|
33588
33791
|
type: "confirm",
|
|
33589
33792
|
name: "overwrite",
|
|
@@ -33623,6 +33826,172 @@ The command will be available immediately in Claude Code.`));
|
|
|
33623
33826
|
}
|
|
33624
33827
|
}
|
|
33625
33828
|
|
|
33829
|
+
// src/commands/symlink.ts
|
|
33830
|
+
var TOOLS = [
|
|
33831
|
+
{
|
|
33832
|
+
name: "Claude Code",
|
|
33833
|
+
value: "claude-code",
|
|
33834
|
+
supportsCommands: true,
|
|
33835
|
+
supportsAgents: true
|
|
33836
|
+
},
|
|
33837
|
+
{
|
|
33838
|
+
name: "Codex",
|
|
33839
|
+
value: "codex",
|
|
33840
|
+
supportsCommands: true,
|
|
33841
|
+
supportsAgents: false
|
|
33842
|
+
},
|
|
33843
|
+
{
|
|
33844
|
+
name: "OpenCode",
|
|
33845
|
+
value: "opencode",
|
|
33846
|
+
supportsCommands: true,
|
|
33847
|
+
supportsAgents: false
|
|
33848
|
+
},
|
|
33849
|
+
{
|
|
33850
|
+
name: "FactoryAI",
|
|
33851
|
+
value: "factoryai",
|
|
33852
|
+
supportsCommands: true,
|
|
33853
|
+
supportsAgents: true
|
|
33854
|
+
}
|
|
33855
|
+
];
|
|
33856
|
+
async function symlinkCommand(params = {}) {
|
|
33857
|
+
try {
|
|
33858
|
+
console.log(source_default.blue.bold(`
|
|
33859
|
+
\uD83D\uDD17 Symlink Manager
|
|
33860
|
+
`));
|
|
33861
|
+
console.log(source_default.gray("Create symlinks between different CLI tool configurations"));
|
|
33862
|
+
const sourceAnswer = await lib_default.prompt([
|
|
33863
|
+
{
|
|
33864
|
+
type: "list",
|
|
33865
|
+
name: "source",
|
|
33866
|
+
message: "Select source tool:",
|
|
33867
|
+
choices: TOOLS.map((tool) => ({
|
|
33868
|
+
name: tool.name,
|
|
33869
|
+
value: tool.value
|
|
33870
|
+
}))
|
|
33871
|
+
}
|
|
33872
|
+
]);
|
|
33873
|
+
const sourceTool = sourceAnswer.source;
|
|
33874
|
+
const sourceConfig = TOOLS.find((t) => t.value === sourceTool);
|
|
33875
|
+
const contentTypeChoices = [];
|
|
33876
|
+
if (sourceConfig.supportsCommands) {
|
|
33877
|
+
contentTypeChoices.push({ name: "Commands only", value: "commands" });
|
|
33878
|
+
}
|
|
33879
|
+
if (sourceConfig.supportsAgents) {
|
|
33880
|
+
contentTypeChoices.push({ name: "Agents only", value: "agents" });
|
|
33881
|
+
}
|
|
33882
|
+
if (sourceConfig.supportsCommands && sourceConfig.supportsAgents) {
|
|
33883
|
+
contentTypeChoices.push({ name: "Both", value: "both" });
|
|
33884
|
+
}
|
|
33885
|
+
if (contentTypeChoices.length === 0) {
|
|
33886
|
+
console.log(source_default.red(`
|
|
33887
|
+
❌ Error: ${sourceConfig.name} doesn't support any syncable content`));
|
|
33888
|
+
process.exit(1);
|
|
33889
|
+
}
|
|
33890
|
+
const contentAnswer = await lib_default.prompt([
|
|
33891
|
+
{
|
|
33892
|
+
type: "list",
|
|
33893
|
+
name: "contentType",
|
|
33894
|
+
message: "What would you like to sync?",
|
|
33895
|
+
choices: contentTypeChoices
|
|
33896
|
+
}
|
|
33897
|
+
]);
|
|
33898
|
+
const syncType = contentAnswer.contentType;
|
|
33899
|
+
const syncCommands = syncType === "commands" || syncType === "both";
|
|
33900
|
+
const syncAgents = syncType === "agents" || syncType === "both";
|
|
33901
|
+
const destinationChoices = [];
|
|
33902
|
+
for (const tool of TOOLS) {
|
|
33903
|
+
if (tool.value === sourceTool)
|
|
33904
|
+
continue;
|
|
33905
|
+
if (syncCommands && tool.supportsCommands) {
|
|
33906
|
+
destinationChoices.push({
|
|
33907
|
+
name: syncAgents ? `${tool.name} (commands)` : tool.name,
|
|
33908
|
+
value: `${tool.value}-commands`,
|
|
33909
|
+
tool: tool.value,
|
|
33910
|
+
contentType: "commands"
|
|
33911
|
+
});
|
|
33912
|
+
}
|
|
33913
|
+
if (syncAgents && tool.supportsAgents) {
|
|
33914
|
+
destinationChoices.push({
|
|
33915
|
+
name: syncCommands ? `${tool.name} (agents)` : tool.name,
|
|
33916
|
+
value: `${tool.value}-agents`,
|
|
33917
|
+
tool: tool.value,
|
|
33918
|
+
contentType: "agents"
|
|
33919
|
+
});
|
|
33920
|
+
}
|
|
33921
|
+
}
|
|
33922
|
+
if (destinationChoices.length === 0) {
|
|
33923
|
+
console.log(source_default.yellow(`
|
|
33924
|
+
⚠️ No compatible destination tools found for the selected sync type`));
|
|
33925
|
+
process.exit(0);
|
|
33926
|
+
}
|
|
33927
|
+
const destinationAnswer = await lib_default.prompt([
|
|
33928
|
+
{
|
|
33929
|
+
type: "checkbox",
|
|
33930
|
+
name: "destinations",
|
|
33931
|
+
message: "Select destination tools (multi-select):",
|
|
33932
|
+
choices: destinationChoices.map((choice) => ({
|
|
33933
|
+
name: choice.name,
|
|
33934
|
+
value: choice.value,
|
|
33935
|
+
checked: false
|
|
33936
|
+
})),
|
|
33937
|
+
validate: (answer) => {
|
|
33938
|
+
if (answer.length === 0) {
|
|
33939
|
+
return "Please select at least one destination";
|
|
33940
|
+
}
|
|
33941
|
+
return true;
|
|
33942
|
+
}
|
|
33943
|
+
}
|
|
33944
|
+
]);
|
|
33945
|
+
const selectedDestinations = destinationAnswer.destinations;
|
|
33946
|
+
const customFolders = {
|
|
33947
|
+
"claude-code": params.claudeCodeFolder,
|
|
33948
|
+
codex: params.codexFolder,
|
|
33949
|
+
opencode: params.openCodeFolder,
|
|
33950
|
+
factoryai: params.factoryAiFolder
|
|
33951
|
+
};
|
|
33952
|
+
const sourcePaths = await getToolPaths(sourceTool, customFolders[sourceTool]);
|
|
33953
|
+
console.log(source_default.blue(`
|
|
33954
|
+
\uD83D\uDCE6 Creating symlinks...
|
|
33955
|
+
`));
|
|
33956
|
+
let successCount = 0;
|
|
33957
|
+
let skipCount = 0;
|
|
33958
|
+
for (const destValue of selectedDestinations) {
|
|
33959
|
+
const destChoice = destinationChoices.find((c) => c.value === destValue);
|
|
33960
|
+
const destPaths = await getToolPaths(destChoice.tool, customFolders[destChoice.tool]);
|
|
33961
|
+
let sourcePath;
|
|
33962
|
+
let targetPath;
|
|
33963
|
+
if (destChoice.contentType === "commands") {
|
|
33964
|
+
sourcePath = sourcePaths.commandsPath;
|
|
33965
|
+
targetPath = destPaths.commandsPath;
|
|
33966
|
+
} else {
|
|
33967
|
+
sourcePath = sourcePaths.agentsPath;
|
|
33968
|
+
targetPath = destPaths.agentsPath;
|
|
33969
|
+
}
|
|
33970
|
+
const toolName = TOOLS.find((t) => t.value === destChoice.tool)?.name || destChoice.tool;
|
|
33971
|
+
const contentLabel = destChoice.contentType === "commands" ? "commands" : "agents";
|
|
33972
|
+
try {
|
|
33973
|
+
const success = await createSymlink(sourcePath, targetPath, {
|
|
33974
|
+
skipMessage: source_default.yellow(` ⚠️ ${toolName} ${contentLabel} path already exists and is not a symlink. Skipping...`)
|
|
33975
|
+
});
|
|
33976
|
+
if (success) {
|
|
33977
|
+
console.log(source_default.green(` ✓ ${toolName} (${contentLabel}) symlink created`));
|
|
33978
|
+
successCount++;
|
|
33979
|
+
} else {
|
|
33980
|
+
skipCount++;
|
|
33981
|
+
}
|
|
33982
|
+
} catch (error) {
|
|
33983
|
+
console.error(source_default.red(` ✗ Failed to create ${toolName} (${contentLabel}) symlink:`), error);
|
|
33984
|
+
}
|
|
33985
|
+
}
|
|
33986
|
+
console.log(source_default.green(`
|
|
33987
|
+
✨ Symlink setup complete! ${successCount} created, ${skipCount} skipped`));
|
|
33988
|
+
} catch (error) {
|
|
33989
|
+
console.error(source_default.red(`
|
|
33990
|
+
❌ Symlink setup failed:`), error);
|
|
33991
|
+
process.exit(1);
|
|
33992
|
+
}
|
|
33993
|
+
}
|
|
33994
|
+
|
|
33626
33995
|
// src/cli.ts
|
|
33627
33996
|
import { readFileSync as readFileSync2 } from "fs";
|
|
33628
33997
|
import { dirname as dirname4, join } from "path";
|
|
@@ -33631,10 +34000,15 @@ var __dirname5 = dirname4(fileURLToPath4(import.meta.url));
|
|
|
33631
34000
|
var packageJson = JSON.parse(readFileSync2(join(__dirname5, "../package.json"), "utf8"));
|
|
33632
34001
|
var program2 = new Command;
|
|
33633
34002
|
program2.name("aiblueprint").description("AIBlueprint CLI for setting up Claude Code configurations").version(packageJson.version);
|
|
33634
|
-
var claudeCodeCmd = program2.command("claude-code").description("Claude Code configuration commands").option("-f, --folder <path>", "Specify custom folder path (default: ~/.claude)").option("-s, --skip", "Skip interactive prompts and install all features");
|
|
34003
|
+
var claudeCodeCmd = program2.command("claude-code").description("Claude Code configuration commands").option("-f, --folder <path>", "Specify custom Claude Code folder path (default: ~/.claude) - alias for --claudeCodeFolder").option("--claudeCodeFolder <path>", "Specify custom Claude Code folder path (default: ~/.claude)").option("--codexFolder <path>", "Specify custom Codex folder path (default: ~/.codex)").option("--openCodeFolder <path>", "Specify custom OpenCode folder path (default: ~/.config/opencode)").option("--factoryAiFolder <path>", "Specify custom FactoryAI folder path (default: ~/.factory)").option("-s, --skip", "Skip interactive prompts and install all features");
|
|
33635
34004
|
claudeCodeCmd.command("setup").description("Setup Claude Code configuration with AIBlueprint defaults").action((options, command) => {
|
|
33636
34005
|
const parentOptions = command.parent.opts();
|
|
33637
|
-
setupCommand(
|
|
34006
|
+
setupCommand({
|
|
34007
|
+
claudeCodeFolder: parentOptions.claudeCodeFolder || parentOptions.folder,
|
|
34008
|
+
codexFolder: parentOptions.codexFolder,
|
|
34009
|
+
openCodeFolder: parentOptions.openCodeFolder,
|
|
34010
|
+
skipInteractive: parentOptions.skip
|
|
34011
|
+
});
|
|
33638
34012
|
});
|
|
33639
34013
|
var addCmd = claudeCodeCmd.command("add").description(`Add components to your Claude Code configuration
|
|
33640
34014
|
` + `Examples:
|
|
@@ -33643,11 +34017,22 @@ var addCmd = claudeCodeCmd.command("add").description(`Add components to your Cl
|
|
|
33643
34017
|
` + " aiblueprint claude-code add commands commit");
|
|
33644
34018
|
addCmd.command("hook <type>").description("Add a hook to your Claude Code configuration. Available types: post-edit-typescript").action((type, options, command) => {
|
|
33645
34019
|
const parentOptions = command.parent.parent.opts();
|
|
33646
|
-
|
|
34020
|
+
const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
|
|
34021
|
+
addHookCommand(type, { folder: claudeCodeFolder });
|
|
33647
34022
|
});
|
|
33648
34023
|
addCmd.command("commands [command-name]").description("Install a Claude Code command or list all available commands (use without argument to list)").action((commandName, options, command) => {
|
|
33649
34024
|
const parentOptions = command.parent.parent.opts();
|
|
33650
|
-
|
|
34025
|
+
const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
|
|
34026
|
+
addCommandCommand(commandName, { folder: claudeCodeFolder });
|
|
34027
|
+
});
|
|
34028
|
+
claudeCodeCmd.command("symlink").description("Create symlinks between different CLI tools (Claude Code, Codex, OpenCode, FactoryAI)").action((options, command) => {
|
|
34029
|
+
const parentOptions = command.parent.opts();
|
|
34030
|
+
symlinkCommand({
|
|
34031
|
+
claudeCodeFolder: parentOptions.claudeCodeFolder || parentOptions.folder,
|
|
34032
|
+
codexFolder: parentOptions.codexFolder,
|
|
34033
|
+
openCodeFolder: parentOptions.openCodeFolder,
|
|
34034
|
+
factoryAiFolder: parentOptions.factoryAiFolder
|
|
34035
|
+
});
|
|
33651
34036
|
});
|
|
33652
34037
|
program2.parse(process.argv);
|
|
33653
34038
|
if (!process.argv.slice(2).length) {
|