aiblueprint-cli 1.1.4 → 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 +627 -245
- 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,26 +33475,26 @@ 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");
|
|
33286
33485
|
}
|
|
33287
33486
|
|
|
33288
33487
|
// src/utils/file-installer.ts
|
|
33289
|
-
var
|
|
33290
|
-
import
|
|
33488
|
+
var import_fs_extra8 = __toESM(require_lib4(), 1);
|
|
33489
|
+
import path9 from "path";
|
|
33291
33490
|
|
|
33292
33491
|
// src/utils/github.ts
|
|
33293
|
-
var
|
|
33294
|
-
import
|
|
33295
|
-
var
|
|
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";
|
|
33296
33495
|
async function downloadFromGitHub2(relativePath) {
|
|
33297
33496
|
try {
|
|
33298
|
-
const url = `${
|
|
33497
|
+
const url = `${GITHUB_RAW_BASE3}/${relativePath}`;
|
|
33299
33498
|
const response = await fetch(url);
|
|
33300
33499
|
if (!response.ok) {
|
|
33301
33500
|
return null;
|
|
@@ -33320,7 +33519,7 @@ async function listFilesFromGitHub(dirPath) {
|
|
|
33320
33519
|
}
|
|
33321
33520
|
async function isGitHubAvailable() {
|
|
33322
33521
|
try {
|
|
33323
|
-
const testUrl = `${
|
|
33522
|
+
const testUrl = `${GITHUB_RAW_BASE3}/commands/commit.md`;
|
|
33324
33523
|
const testResponse = await fetch(testUrl);
|
|
33325
33524
|
return testResponse.ok;
|
|
33326
33525
|
} catch {
|
|
@@ -33330,8 +33529,8 @@ async function isGitHubAvailable() {
|
|
|
33330
33529
|
async function downloadAndWriteFile(relativePath, targetPath) {
|
|
33331
33530
|
const content = await downloadFromGitHub2(relativePath);
|
|
33332
33531
|
if (content) {
|
|
33333
|
-
await
|
|
33334
|
-
await
|
|
33532
|
+
await import_fs_extra7.default.ensureDir(path8.dirname(targetPath));
|
|
33533
|
+
await import_fs_extra7.default.writeFile(targetPath, content);
|
|
33335
33534
|
return true;
|
|
33336
33535
|
}
|
|
33337
33536
|
return false;
|
|
@@ -33340,7 +33539,7 @@ async function downloadAndWriteFile(relativePath, targetPath) {
|
|
|
33340
33539
|
// src/utils/file-installer.ts
|
|
33341
33540
|
async function installFileWithGitHubFallback(options) {
|
|
33342
33541
|
const { sourceDir, targetPath, fileName } = options;
|
|
33343
|
-
await
|
|
33542
|
+
await import_fs_extra8.default.ensureDir(path9.dirname(targetPath));
|
|
33344
33543
|
const useGitHub = options.useGitHub ?? await isGitHubAvailable();
|
|
33345
33544
|
if (useGitHub) {
|
|
33346
33545
|
const relativePath = `${sourceDir}/${fileName}`;
|
|
@@ -33354,11 +33553,11 @@ async function installFileWithGitHubFallback(options) {
|
|
|
33354
33553
|
if (!localConfigDir) {
|
|
33355
33554
|
throw new Error(`Neither GitHub nor local ${sourceDir} directory found`);
|
|
33356
33555
|
}
|
|
33357
|
-
const localFilePath =
|
|
33358
|
-
if (!await
|
|
33556
|
+
const localFilePath = path9.join(localConfigDir, fileName);
|
|
33557
|
+
if (!await import_fs_extra8.default.pathExists(localFilePath)) {
|
|
33359
33558
|
throw new Error(`File not found: ${fileName}`);
|
|
33360
33559
|
}
|
|
33361
|
-
await
|
|
33560
|
+
await import_fs_extra8.default.copy(localFilePath, targetPath);
|
|
33362
33561
|
}
|
|
33363
33562
|
async function getFileContentWithGitHubFallback(sourceDir, fileName) {
|
|
33364
33563
|
const useGitHub = await isGitHubAvailable();
|
|
@@ -33373,11 +33572,11 @@ async function getFileContentWithGitHubFallback(sourceDir, fileName) {
|
|
|
33373
33572
|
if (!localConfigDir) {
|
|
33374
33573
|
throw new Error(`Neither GitHub nor local ${sourceDir} directory found`);
|
|
33375
33574
|
}
|
|
33376
|
-
const localFilePath =
|
|
33377
|
-
if (!await
|
|
33575
|
+
const localFilePath = path9.join(localConfigDir, fileName);
|
|
33576
|
+
if (!await import_fs_extra8.default.pathExists(localFilePath)) {
|
|
33378
33577
|
throw new Error(`File not found: ${fileName}`);
|
|
33379
33578
|
}
|
|
33380
|
-
return await
|
|
33579
|
+
return await import_fs_extra8.default.readFile(localFilePath, "utf-8");
|
|
33381
33580
|
}
|
|
33382
33581
|
|
|
33383
33582
|
// src/commands/addHook.ts
|
|
@@ -33417,10 +33616,10 @@ async function addHookCommand(hookType, options) {
|
|
|
33417
33616
|
const s = new SimpleSpinner2;
|
|
33418
33617
|
const targetDir = await getTargetDirectory(options);
|
|
33419
33618
|
const claudeDir = targetDir;
|
|
33420
|
-
const hooksDir =
|
|
33421
|
-
const hookFilePath =
|
|
33422
|
-
const settingsPath =
|
|
33423
|
-
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)) {
|
|
33424
33623
|
const overwriteAnswer = await lib_default.prompt([{
|
|
33425
33624
|
type: "confirm",
|
|
33426
33625
|
name: "overwrite",
|
|
@@ -33433,18 +33632,18 @@ async function addHookCommand(hookType, options) {
|
|
|
33433
33632
|
}
|
|
33434
33633
|
try {
|
|
33435
33634
|
s.start("Installing hook...");
|
|
33436
|
-
await
|
|
33635
|
+
await import_fs_extra9.default.ensureDir(hooksDir);
|
|
33437
33636
|
await installFileWithGitHubFallback({
|
|
33438
33637
|
sourceDir: "hooks",
|
|
33439
33638
|
targetPath: hookFilePath,
|
|
33440
33639
|
fileName: hook.hookFile
|
|
33441
33640
|
});
|
|
33442
|
-
await
|
|
33641
|
+
await import_fs_extra9.default.chmod(hookFilePath, 493);
|
|
33443
33642
|
s.stop("Hook file installed");
|
|
33444
33643
|
s.start("Updating settings.json...");
|
|
33445
33644
|
let settings = {};
|
|
33446
33645
|
try {
|
|
33447
|
-
const existingSettings = await
|
|
33646
|
+
const existingSettings = await import_fs_extra9.default.readFile(settingsPath, "utf-8");
|
|
33448
33647
|
settings = JSON.parse(existingSettings);
|
|
33449
33648
|
} catch {
|
|
33450
33649
|
settings = {};
|
|
@@ -33481,7 +33680,7 @@ async function addHookCommand(hookType, options) {
|
|
|
33481
33680
|
} else {
|
|
33482
33681
|
settings.hooks[hook.event].push(newHook);
|
|
33483
33682
|
}
|
|
33484
|
-
await
|
|
33683
|
+
await import_fs_extra9.default.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
33485
33684
|
s.stop("Settings updated");
|
|
33486
33685
|
console.log(source_default.green("✨ Hook installed successfully!"));
|
|
33487
33686
|
console.log(source_default.gray(`
|
|
@@ -33500,8 +33699,8 @@ The hook will run automatically when you edit TypeScript files with Claude Code.
|
|
|
33500
33699
|
}
|
|
33501
33700
|
|
|
33502
33701
|
// src/commands/addCommand.ts
|
|
33503
|
-
var
|
|
33504
|
-
import
|
|
33702
|
+
var import_fs_extra10 = __toESM(require_lib4(), 1);
|
|
33703
|
+
import path11 from "path";
|
|
33505
33704
|
class SimpleSpinner3 {
|
|
33506
33705
|
message = "";
|
|
33507
33706
|
start(message) {
|
|
@@ -33518,12 +33717,13 @@ async function discoverAvailableCommands() {
|
|
|
33518
33717
|
let mdFiles = [];
|
|
33519
33718
|
if (useGitHub) {
|
|
33520
33719
|
mdFiles = (await listFilesFromGitHub("commands")).filter((file) => file.endsWith(".md"));
|
|
33521
|
-
}
|
|
33720
|
+
}
|
|
33721
|
+
if (mdFiles.length === 0) {
|
|
33522
33722
|
const commandsDir = await findLocalConfigDir("commands");
|
|
33523
33723
|
if (!commandsDir) {
|
|
33524
33724
|
throw new Error("Commands directory not found");
|
|
33525
33725
|
}
|
|
33526
|
-
const files = await
|
|
33726
|
+
const files = await import_fs_extra10.default.readdir(commandsDir);
|
|
33527
33727
|
mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
33528
33728
|
}
|
|
33529
33729
|
for (const file of mdFiles) {
|
|
@@ -33584,9 +33784,9 @@ async function addCommandCommand(commandName, options = {}) {
|
|
|
33584
33784
|
if (options.folder) {
|
|
33585
33785
|
console.log(source_default.gray(`Using custom folder: ${targetDir}`));
|
|
33586
33786
|
}
|
|
33587
|
-
const commandsDir =
|
|
33588
|
-
const commandFilePath =
|
|
33589
|
-
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)) {
|
|
33590
33790
|
const overwriteAnswer = await lib_default.prompt([{
|
|
33591
33791
|
type: "confirm",
|
|
33592
33792
|
name: "overwrite",
|
|
@@ -33626,6 +33826,172 @@ The command will be available immediately in Claude Code.`));
|
|
|
33626
33826
|
}
|
|
33627
33827
|
}
|
|
33628
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
|
+
|
|
33629
33995
|
// src/cli.ts
|
|
33630
33996
|
import { readFileSync as readFileSync2 } from "fs";
|
|
33631
33997
|
import { dirname as dirname4, join } from "path";
|
|
@@ -33634,10 +34000,15 @@ var __dirname5 = dirname4(fileURLToPath4(import.meta.url));
|
|
|
33634
34000
|
var packageJson = JSON.parse(readFileSync2(join(__dirname5, "../package.json"), "utf8"));
|
|
33635
34001
|
var program2 = new Command;
|
|
33636
34002
|
program2.name("aiblueprint").description("AIBlueprint CLI for setting up Claude Code configurations").version(packageJson.version);
|
|
33637
|
-
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");
|
|
33638
34004
|
claudeCodeCmd.command("setup").description("Setup Claude Code configuration with AIBlueprint defaults").action((options, command) => {
|
|
33639
34005
|
const parentOptions = command.parent.opts();
|
|
33640
|
-
setupCommand(
|
|
34006
|
+
setupCommand({
|
|
34007
|
+
claudeCodeFolder: parentOptions.claudeCodeFolder || parentOptions.folder,
|
|
34008
|
+
codexFolder: parentOptions.codexFolder,
|
|
34009
|
+
openCodeFolder: parentOptions.openCodeFolder,
|
|
34010
|
+
skipInteractive: parentOptions.skip
|
|
34011
|
+
});
|
|
33641
34012
|
});
|
|
33642
34013
|
var addCmd = claudeCodeCmd.command("add").description(`Add components to your Claude Code configuration
|
|
33643
34014
|
` + `Examples:
|
|
@@ -33646,11 +34017,22 @@ var addCmd = claudeCodeCmd.command("add").description(`Add components to your Cl
|
|
|
33646
34017
|
` + " aiblueprint claude-code add commands commit");
|
|
33647
34018
|
addCmd.command("hook <type>").description("Add a hook to your Claude Code configuration. Available types: post-edit-typescript").action((type, options, command) => {
|
|
33648
34019
|
const parentOptions = command.parent.parent.opts();
|
|
33649
|
-
|
|
34020
|
+
const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
|
|
34021
|
+
addHookCommand(type, { folder: claudeCodeFolder });
|
|
33650
34022
|
});
|
|
33651
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) => {
|
|
33652
34024
|
const parentOptions = command.parent.parent.opts();
|
|
33653
|
-
|
|
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
|
+
});
|
|
33654
34036
|
});
|
|
33655
34037
|
program2.parse(process.argv);
|
|
33656
34038
|
if (!process.argv.slice(2).length) {
|