aiblueprint-cli 1.4.16 → 1.4.18
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 +0 -11
- package/claude-code-config/.claude-plugin/plugin.json +23 -0
- package/dist/cli.js +153 -558
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -276,17 +276,6 @@ The CLI automatically manages your `~/.claude/settings.json` with:
|
|
|
276
276
|
}
|
|
277
277
|
]
|
|
278
278
|
}
|
|
279
|
-
],
|
|
280
|
-
"PostToolUse": [
|
|
281
|
-
{
|
|
282
|
-
"matcher": "Edit|Write|MultiEdit",
|
|
283
|
-
"hooks": [
|
|
284
|
-
{
|
|
285
|
-
"type": "command",
|
|
286
|
-
"command": "bun ~/.claude/hooks/hook-post-file.ts"
|
|
287
|
-
}
|
|
288
|
-
]
|
|
289
|
-
}
|
|
290
279
|
]
|
|
291
280
|
}
|
|
292
281
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aibp-base",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "AIBlueprint base configuration with custom agents, slash commands, hooks, and productivity workflows for Claude Code",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Melvyn",
|
|
7
|
+
"url": "https://github.com/melvynx"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/melvynx/aiblueprint",
|
|
10
|
+
"repository": "https://github.com/melvynx/aiblueprint",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"aiblueprint",
|
|
14
|
+
"melvynx",
|
|
15
|
+
"productivity",
|
|
16
|
+
"agents",
|
|
17
|
+
"commands",
|
|
18
|
+
"hooks",
|
|
19
|
+
"workflows",
|
|
20
|
+
"statusline"
|
|
21
|
+
],
|
|
22
|
+
"category": "essentials"
|
|
23
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -33195,24 +33195,6 @@ async function updateSettings(options, claudeDir) {
|
|
|
33195
33195
|
}
|
|
33196
33196
|
}
|
|
33197
33197
|
}
|
|
33198
|
-
if (options.postEditTypeScript) {
|
|
33199
|
-
if (!settings.hooks.PostToolUse) {
|
|
33200
|
-
settings.hooks.PostToolUse = [];
|
|
33201
|
-
}
|
|
33202
|
-
const postEditHook = {
|
|
33203
|
-
matcher: "Edit|Write|MultiEdit",
|
|
33204
|
-
hooks: [
|
|
33205
|
-
{
|
|
33206
|
-
type: "command",
|
|
33207
|
-
command: `bun ${toPosixPath(path5.join(claudeDir, "scripts/hook-post-file.ts"))}`
|
|
33208
|
-
}
|
|
33209
|
-
]
|
|
33210
|
-
};
|
|
33211
|
-
const existingPostEditHook = settings.hooks.PostToolUse.find((h) => h.matcher === "Edit|Write|MultiEdit" && h.hooks?.some((hook) => hook.command?.includes("hook-post-file.ts")));
|
|
33212
|
-
if (!existingPostEditHook) {
|
|
33213
|
-
settings.hooks.PostToolUse.push(postEditHook);
|
|
33214
|
-
}
|
|
33215
|
-
}
|
|
33216
33198
|
await import_fs_extra3.default.writeJson(settingsPath, settings, { spaces: 2 });
|
|
33217
33199
|
}
|
|
33218
33200
|
|
|
@@ -33296,7 +33278,7 @@ function getVersion() {
|
|
|
33296
33278
|
const __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
33297
33279
|
const packageJson = JSON.parse(readFileSync2(join(__dirname2, "../package.json"), "utf8"));
|
|
33298
33280
|
cachedVersion = packageJson.version;
|
|
33299
|
-
return cachedVersion;
|
|
33281
|
+
return cachedVersion ?? "unknown";
|
|
33300
33282
|
} catch {
|
|
33301
33283
|
return "unknown";
|
|
33302
33284
|
}
|
|
@@ -33401,11 +33383,6 @@ async function setupCommand(params = {}) {
|
|
|
33401
33383
|
name: "Notification sounds - Audio alerts for events",
|
|
33402
33384
|
checked: true
|
|
33403
33385
|
},
|
|
33404
|
-
{
|
|
33405
|
-
value: "postEditTypeScript",
|
|
33406
|
-
name: "Post-edit TypeScript hook - Auto-format and lint TypeScript files",
|
|
33407
|
-
checked: false
|
|
33408
|
-
},
|
|
33409
33386
|
{
|
|
33410
33387
|
value: "codexSymlink",
|
|
33411
33388
|
name: "Codex symlink - Link commands to ~/.codex/prompts",
|
|
@@ -33431,8 +33408,8 @@ async function setupCommand(params = {}) {
|
|
|
33431
33408
|
customStatusline: features.includes("customStatusline"),
|
|
33432
33409
|
aiblueprintCommands: features.includes("aiblueprintCommands"),
|
|
33433
33410
|
aiblueprintAgents: features.includes("aiblueprintAgents"),
|
|
33411
|
+
aiblueprintSkills: false,
|
|
33434
33412
|
notificationSounds: features.includes("notificationSounds"),
|
|
33435
|
-
postEditTypeScript: features.includes("postEditTypeScript"),
|
|
33436
33413
|
codexSymlink: features.includes("codexSymlink"),
|
|
33437
33414
|
openCodeSymlink: features.includes("openCodeSymlink"),
|
|
33438
33415
|
skipInteractive
|
|
@@ -33484,7 +33461,7 @@ async function setupCommand(params = {}) {
|
|
|
33484
33461
|
await setupShellShortcuts();
|
|
33485
33462
|
s.stop("Shell shortcuts configured");
|
|
33486
33463
|
}
|
|
33487
|
-
if (options.commandValidation || options.customStatusline || options.notificationSounds
|
|
33464
|
+
if (options.commandValidation || options.customStatusline || options.notificationSounds) {
|
|
33488
33465
|
s.start("Setting up scripts");
|
|
33489
33466
|
if (useGitHub) {
|
|
33490
33467
|
const scriptsDir = path8.join(claudeDir, "scripts");
|
|
@@ -33492,9 +33469,6 @@ async function setupCommand(params = {}) {
|
|
|
33492
33469
|
if (options.commandValidation) {
|
|
33493
33470
|
await downloadDirectoryFromGitHub("scripts/command-validator", path8.join(scriptsDir, "command-validator"));
|
|
33494
33471
|
}
|
|
33495
|
-
if (options.postEditTypeScript) {
|
|
33496
|
-
await downloadFromGitHub("scripts/hook-post-file.ts", path8.join(scriptsDir, "hook-post-file.ts"));
|
|
33497
|
-
}
|
|
33498
33472
|
if (options.customStatusline) {
|
|
33499
33473
|
await downloadDirectoryFromGitHub("scripts/statusline", path8.join(scriptsDir, "statusline"));
|
|
33500
33474
|
await import_fs_extra6.default.ensureDir(path8.join(scriptsDir, "statusline/data"));
|
|
@@ -33712,7 +33686,7 @@ async function installOhMyZsh(homeDir) {
|
|
|
33712
33686
|
const env2 = { ...process.env, HOME: homeDir, ZSH: path9.join(homeDir, ".oh-my-zsh") };
|
|
33713
33687
|
exec(installCmd, { timeout: INSTALL_TIMEOUT, env: env2 }, (error, stdout, stderr) => {
|
|
33714
33688
|
if (error) {
|
|
33715
|
-
if (error.killed) {
|
|
33689
|
+
if ("killed" in error && error.killed) {
|
|
33716
33690
|
reject(new Error("Oh My ZSH installation timed out. Please check your network connection."));
|
|
33717
33691
|
} else {
|
|
33718
33692
|
reject(new Error(`Failed to install Oh My ZSH: ${stderr || error.message}`));
|
|
@@ -33737,7 +33711,7 @@ async function installPlugin(pluginName, repoUrl, homeDir) {
|
|
|
33737
33711
|
return new Promise((resolve, reject) => {
|
|
33738
33712
|
exec(`git clone ${repoUrl} "${customPluginsDir}"`, { timeout: PLUGIN_TIMEOUT }, (error, stdout, stderr) => {
|
|
33739
33713
|
if (error) {
|
|
33740
|
-
if (error.killed) {
|
|
33714
|
+
if ("killed" in error && error.killed) {
|
|
33741
33715
|
reject(new Error(`Plugin ${pluginName} installation timed out. Please check your network connection.`));
|
|
33742
33716
|
} else {
|
|
33743
33717
|
reject(new Error(`Failed to install ${pluginName}: ${stderr || error.message}`));
|
|
@@ -33941,438 +33915,6 @@ Next steps:`));
|
|
|
33941
33915
|
}
|
|
33942
33916
|
}
|
|
33943
33917
|
|
|
33944
|
-
// src/commands/addHook.ts
|
|
33945
|
-
var import_fs_extra11 = __toESM(require_lib4(), 1);
|
|
33946
|
-
import path13 from "path";
|
|
33947
|
-
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
33948
|
-
import { dirname as dirname4 } from "path";
|
|
33949
|
-
|
|
33950
|
-
// src/utils/claude-config.ts
|
|
33951
|
-
var import_fs_extra8 = __toESM(require_lib4(), 1);
|
|
33952
|
-
import path10 from "path";
|
|
33953
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
33954
|
-
import { dirname as dirname3 } from "path";
|
|
33955
|
-
var __filename3 = fileURLToPath3(import.meta.url);
|
|
33956
|
-
var __dirname3 = dirname3(__filename3);
|
|
33957
|
-
function parseYamlFrontmatter(content) {
|
|
33958
|
-
const lines = content.split(`
|
|
33959
|
-
`);
|
|
33960
|
-
if (lines[0] !== "---") {
|
|
33961
|
-
return { metadata: {}, body: content };
|
|
33962
|
-
}
|
|
33963
|
-
const endIndex = lines.findIndex((line, index) => index > 0 && line === "---");
|
|
33964
|
-
if (endIndex === -1) {
|
|
33965
|
-
return { metadata: {}, body: content };
|
|
33966
|
-
}
|
|
33967
|
-
const frontmatterLines = lines.slice(1, endIndex);
|
|
33968
|
-
const body = lines.slice(endIndex + 1).join(`
|
|
33969
|
-
`);
|
|
33970
|
-
const metadata = {};
|
|
33971
|
-
frontmatterLines.forEach((line) => {
|
|
33972
|
-
const colonIndex = line.indexOf(":");
|
|
33973
|
-
if (colonIndex > -1) {
|
|
33974
|
-
const key = line.substring(0, colonIndex).trim();
|
|
33975
|
-
const value = line.substring(colonIndex + 1).trim();
|
|
33976
|
-
metadata[key] = value;
|
|
33977
|
-
}
|
|
33978
|
-
});
|
|
33979
|
-
return { metadata, body };
|
|
33980
|
-
}
|
|
33981
|
-
function getLocalConfigPaths(subDir) {
|
|
33982
|
-
return [
|
|
33983
|
-
path10.join(__dirname3, `../claude-code-config/${subDir}`),
|
|
33984
|
-
path10.join(__dirname3, `../../claude-code-config/${subDir}`)
|
|
33985
|
-
];
|
|
33986
|
-
}
|
|
33987
|
-
async function findLocalConfigDir(subDir) {
|
|
33988
|
-
const possiblePaths = getLocalConfigPaths(subDir);
|
|
33989
|
-
for (const testPath of possiblePaths) {
|
|
33990
|
-
if (await import_fs_extra8.default.pathExists(testPath)) {
|
|
33991
|
-
return testPath;
|
|
33992
|
-
}
|
|
33993
|
-
}
|
|
33994
|
-
return null;
|
|
33995
|
-
}
|
|
33996
|
-
async function getTargetDirectory(options) {
|
|
33997
|
-
if (options.folder) {
|
|
33998
|
-
return options.folder;
|
|
33999
|
-
}
|
|
34000
|
-
const cwd = process.cwd();
|
|
34001
|
-
const localClaudeDir = path10.join(cwd, ".claude");
|
|
34002
|
-
const isGitRepo = await import_fs_extra8.default.pathExists(path10.join(cwd, ".git"));
|
|
34003
|
-
const hasClaudeConfig = await import_fs_extra8.default.pathExists(localClaudeDir);
|
|
34004
|
-
if (isGitRepo || hasClaudeConfig) {
|
|
34005
|
-
return localClaudeDir;
|
|
34006
|
-
}
|
|
34007
|
-
return path10.join(process.env.HOME || process.env.USERPROFILE || "~", ".claude");
|
|
34008
|
-
}
|
|
34009
|
-
|
|
34010
|
-
// src/utils/file-installer.ts
|
|
34011
|
-
var import_fs_extra10 = __toESM(require_lib4(), 1);
|
|
34012
|
-
import path12 from "path";
|
|
34013
|
-
|
|
34014
|
-
// src/utils/github.ts
|
|
34015
|
-
var import_fs_extra9 = __toESM(require_lib4(), 1);
|
|
34016
|
-
import path11 from "path";
|
|
34017
|
-
var GITHUB_RAW_BASE3 = "https://raw.githubusercontent.com/Melvynx/aiblueprint-cli/main/claude-code-config";
|
|
34018
|
-
async function downloadFromGitHub2(relativePath) {
|
|
34019
|
-
try {
|
|
34020
|
-
const url = `${GITHUB_RAW_BASE3}/${relativePath}`;
|
|
34021
|
-
const response = await fetch(url);
|
|
34022
|
-
if (!response.ok) {
|
|
34023
|
-
return null;
|
|
34024
|
-
}
|
|
34025
|
-
return await response.text();
|
|
34026
|
-
} catch (error) {
|
|
34027
|
-
return null;
|
|
34028
|
-
}
|
|
34029
|
-
}
|
|
34030
|
-
async function listFilesFromGitHub(dirPath) {
|
|
34031
|
-
try {
|
|
34032
|
-
const apiUrl = `https://api.github.com/repos/Melvynx/aiblueprint-cli/contents/claude-code-config/${dirPath}`;
|
|
34033
|
-
const response = await fetch(apiUrl);
|
|
34034
|
-
if (!response.ok) {
|
|
34035
|
-
return [];
|
|
34036
|
-
}
|
|
34037
|
-
const items = await response.json();
|
|
34038
|
-
const files = [];
|
|
34039
|
-
for (const item of items) {
|
|
34040
|
-
if (item.type === "file") {
|
|
34041
|
-
files.push(item.name);
|
|
34042
|
-
} else if (item.type === "dir") {
|
|
34043
|
-
const subFiles = await listFilesFromGitHub(`${dirPath}/${item.name}`);
|
|
34044
|
-
files.push(...subFiles.map((f) => `${item.name}/${f}`));
|
|
34045
|
-
}
|
|
34046
|
-
}
|
|
34047
|
-
return files;
|
|
34048
|
-
} catch (error) {
|
|
34049
|
-
return [];
|
|
34050
|
-
}
|
|
34051
|
-
}
|
|
34052
|
-
async function isGitHubAvailable() {
|
|
34053
|
-
try {
|
|
34054
|
-
const testUrl = `${GITHUB_RAW_BASE3}/commands/apex.md`;
|
|
34055
|
-
const testResponse = await fetch(testUrl);
|
|
34056
|
-
return testResponse.ok;
|
|
34057
|
-
} catch {
|
|
34058
|
-
return false;
|
|
34059
|
-
}
|
|
34060
|
-
}
|
|
34061
|
-
async function downloadAndWriteFile(relativePath, targetPath) {
|
|
34062
|
-
const content = await downloadFromGitHub2(relativePath);
|
|
34063
|
-
if (content) {
|
|
34064
|
-
await import_fs_extra9.default.ensureDir(path11.dirname(targetPath));
|
|
34065
|
-
await import_fs_extra9.default.writeFile(targetPath, content);
|
|
34066
|
-
return true;
|
|
34067
|
-
}
|
|
34068
|
-
return false;
|
|
34069
|
-
}
|
|
34070
|
-
|
|
34071
|
-
// src/utils/file-installer.ts
|
|
34072
|
-
async function installFileWithGitHubFallback(options) {
|
|
34073
|
-
const { sourceDir, targetPath, fileName } = options;
|
|
34074
|
-
await import_fs_extra10.default.ensureDir(path12.dirname(targetPath));
|
|
34075
|
-
const useGitHub = options.useGitHub ?? await isGitHubAvailable();
|
|
34076
|
-
if (useGitHub) {
|
|
34077
|
-
const relativePath = `${sourceDir}/${fileName}`;
|
|
34078
|
-
const success = await downloadAndWriteFile(relativePath, targetPath);
|
|
34079
|
-
if (success) {
|
|
34080
|
-
return;
|
|
34081
|
-
}
|
|
34082
|
-
console.log(source_default.yellow(`⚠️ GitHub download failed for ${fileName}, falling back to local files`));
|
|
34083
|
-
}
|
|
34084
|
-
const localConfigDir = await findLocalConfigDir(sourceDir);
|
|
34085
|
-
if (!localConfigDir) {
|
|
34086
|
-
throw new Error(`Neither GitHub nor local ${sourceDir} directory found`);
|
|
34087
|
-
}
|
|
34088
|
-
const localFilePath = path12.join(localConfigDir, fileName);
|
|
34089
|
-
if (!await import_fs_extra10.default.pathExists(localFilePath)) {
|
|
34090
|
-
throw new Error(`File not found: ${fileName}`);
|
|
34091
|
-
}
|
|
34092
|
-
await import_fs_extra10.default.copy(localFilePath, targetPath);
|
|
34093
|
-
}
|
|
34094
|
-
async function getFileContentWithGitHubFallback(sourceDir, fileName) {
|
|
34095
|
-
const useGitHub = await isGitHubAvailable();
|
|
34096
|
-
if (useGitHub) {
|
|
34097
|
-
const content = await downloadFromGitHub2(`${sourceDir}/${fileName}`);
|
|
34098
|
-
if (content) {
|
|
34099
|
-
return content;
|
|
34100
|
-
}
|
|
34101
|
-
console.log(source_default.yellow(`⚠️ GitHub download failed for ${fileName}, falling back to local files`));
|
|
34102
|
-
}
|
|
34103
|
-
const localConfigDir = await findLocalConfigDir(sourceDir);
|
|
34104
|
-
if (!localConfigDir) {
|
|
34105
|
-
throw new Error(`Neither GitHub nor local ${sourceDir} directory found`);
|
|
34106
|
-
}
|
|
34107
|
-
const localFilePath = path12.join(localConfigDir, fileName);
|
|
34108
|
-
if (!await import_fs_extra10.default.pathExists(localFilePath)) {
|
|
34109
|
-
throw new Error(`File not found: ${fileName}`);
|
|
34110
|
-
}
|
|
34111
|
-
return await import_fs_extra10.default.readFile(localFilePath, "utf-8");
|
|
34112
|
-
}
|
|
34113
|
-
|
|
34114
|
-
// src/commands/addHook.ts
|
|
34115
|
-
var __filename4 = fileURLToPath4(import.meta.url);
|
|
34116
|
-
var __dirname4 = dirname4(__filename4);
|
|
34117
|
-
|
|
34118
|
-
class SimpleSpinner2 {
|
|
34119
|
-
message = "";
|
|
34120
|
-
start(message) {
|
|
34121
|
-
this.message = message;
|
|
34122
|
-
console.log(source_default.gray(`⏳ ${message}...`));
|
|
34123
|
-
}
|
|
34124
|
-
stop(message) {
|
|
34125
|
-
console.log(source_default.green(`✓ ${message}`));
|
|
34126
|
-
}
|
|
34127
|
-
}
|
|
34128
|
-
var supportedHooks = {
|
|
34129
|
-
"post-edit-typescript": {
|
|
34130
|
-
name: "Post Edit TypeScript Hook",
|
|
34131
|
-
description: "Runs Prettier, ESLint, and TypeScript checks after editing TypeScript files",
|
|
34132
|
-
hookFile: "hook-post-file.ts",
|
|
34133
|
-
sourceDir: "scripts",
|
|
34134
|
-
targetDir: "scripts",
|
|
34135
|
-
event: "PostToolUse",
|
|
34136
|
-
matcher: "Edit|Write|MultiEdit"
|
|
34137
|
-
}
|
|
34138
|
-
};
|
|
34139
|
-
async function addHookCommand(hookType, options) {
|
|
34140
|
-
console.log(source_default.bgBlue(` aiblueprint-cli v${getVersion()} `));
|
|
34141
|
-
if (!supportedHooks[hookType]) {
|
|
34142
|
-
console.log(source_default.red(`❌ Unsupported hook type: ${hookType}`));
|
|
34143
|
-
console.log(source_default.gray("Available hooks:"));
|
|
34144
|
-
Object.entries(supportedHooks).forEach(([key, hook2]) => {
|
|
34145
|
-
console.log(source_default.gray(` • ${key}: ${hook2.description}`));
|
|
34146
|
-
});
|
|
34147
|
-
process.exit(1);
|
|
34148
|
-
}
|
|
34149
|
-
const hook = supportedHooks[hookType];
|
|
34150
|
-
const s = new SimpleSpinner2;
|
|
34151
|
-
const targetDir = await getTargetDirectory(options);
|
|
34152
|
-
const claudeDir = targetDir;
|
|
34153
|
-
const targetHookDir = path13.join(claudeDir, hook.targetDir || "hooks");
|
|
34154
|
-
const hookFilePath = path13.join(targetHookDir, hook.hookFile);
|
|
34155
|
-
const settingsPath = path13.join(claudeDir, "settings.json");
|
|
34156
|
-
if (await import_fs_extra11.default.pathExists(hookFilePath)) {
|
|
34157
|
-
const overwriteAnswer = await lib_default.prompt([{
|
|
34158
|
-
type: "confirm",
|
|
34159
|
-
name: "overwrite",
|
|
34160
|
-
message: `Hook file already exists at ${hookFilePath}. Overwrite?`
|
|
34161
|
-
}]);
|
|
34162
|
-
if (!overwriteAnswer.overwrite) {
|
|
34163
|
-
console.log(source_default.yellow("Hook installation cancelled."));
|
|
34164
|
-
process.exit(0);
|
|
34165
|
-
}
|
|
34166
|
-
}
|
|
34167
|
-
try {
|
|
34168
|
-
s.start("Installing hook...");
|
|
34169
|
-
await import_fs_extra11.default.ensureDir(targetHookDir);
|
|
34170
|
-
await installFileWithGitHubFallback({
|
|
34171
|
-
sourceDir: hook.sourceDir || "hooks",
|
|
34172
|
-
targetPath: hookFilePath,
|
|
34173
|
-
fileName: hook.hookFile
|
|
34174
|
-
});
|
|
34175
|
-
await import_fs_extra11.default.chmod(hookFilePath, 493);
|
|
34176
|
-
s.stop("Hook file installed");
|
|
34177
|
-
s.start("Updating settings.json...");
|
|
34178
|
-
let settings = {};
|
|
34179
|
-
try {
|
|
34180
|
-
const existingSettings = await import_fs_extra11.default.readFile(settingsPath, "utf-8");
|
|
34181
|
-
settings = JSON.parse(existingSettings);
|
|
34182
|
-
} catch {
|
|
34183
|
-
settings = {};
|
|
34184
|
-
}
|
|
34185
|
-
if (!settings.hooks) {
|
|
34186
|
-
settings.hooks = {};
|
|
34187
|
-
}
|
|
34188
|
-
if (!settings.hooks[hook.event]) {
|
|
34189
|
-
settings.hooks[hook.event] = [];
|
|
34190
|
-
}
|
|
34191
|
-
const newHook = {
|
|
34192
|
-
matcher: hook.matcher,
|
|
34193
|
-
hooks: [
|
|
34194
|
-
{
|
|
34195
|
-
type: "command",
|
|
34196
|
-
command: `bun $CLAUDE_PROJECT_DIR/.claude/${hook.targetDir || "hooks"}/${hook.hookFile}`
|
|
34197
|
-
}
|
|
34198
|
-
]
|
|
34199
|
-
};
|
|
34200
|
-
const existingHook = settings.hooks[hook.event].find((h) => h.matcher === hook.matcher && h.hooks?.some((subHook) => subHook.command?.includes(hook.hookFile)));
|
|
34201
|
-
if (existingHook) {
|
|
34202
|
-
const replaceAnswer = await lib_default.prompt([{
|
|
34203
|
-
type: "confirm",
|
|
34204
|
-
name: "replace",
|
|
34205
|
-
message: `A similar ${hook.event} hook already exists in settings.json. Replace it?`
|
|
34206
|
-
}]);
|
|
34207
|
-
if (!replaceAnswer.replace) {
|
|
34208
|
-
console.log(source_default.yellow("Hook installation cancelled."));
|
|
34209
|
-
process.exit(0);
|
|
34210
|
-
} else {
|
|
34211
|
-
settings.hooks[hook.event] = settings.hooks[hook.event].filter((h) => h !== existingHook);
|
|
34212
|
-
settings.hooks[hook.event].push(newHook);
|
|
34213
|
-
}
|
|
34214
|
-
} else {
|
|
34215
|
-
settings.hooks[hook.event].push(newHook);
|
|
34216
|
-
}
|
|
34217
|
-
await import_fs_extra11.default.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
34218
|
-
s.stop("Settings updated");
|
|
34219
|
-
console.log(source_default.green("✨ Hook installed successfully!"));
|
|
34220
|
-
console.log(source_default.gray(`
|
|
34221
|
-
Hook details:`));
|
|
34222
|
-
console.log(source_default.gray(` • Name: ${hook.name}`));
|
|
34223
|
-
console.log(source_default.gray(` • File: ${hookFilePath}`));
|
|
34224
|
-
console.log(source_default.gray(` • Event: ${hook.event}`));
|
|
34225
|
-
console.log(source_default.gray(` • Matcher: ${hook.matcher}`));
|
|
34226
|
-
console.log(source_default.gray(`
|
|
34227
|
-
The hook will run automatically when you edit TypeScript files with Claude Code.`));
|
|
34228
|
-
} catch (error) {
|
|
34229
|
-
s.stop("Installation failed");
|
|
34230
|
-
console.log(source_default.red(`❌ Failed to install hook: ${error}`));
|
|
34231
|
-
process.exit(1);
|
|
34232
|
-
}
|
|
34233
|
-
}
|
|
34234
|
-
|
|
34235
|
-
// src/commands/addCommand.ts
|
|
34236
|
-
var import_fs_extra12 = __toESM(require_lib4(), 1);
|
|
34237
|
-
import path14 from "path";
|
|
34238
|
-
class SimpleSpinner3 {
|
|
34239
|
-
message = "";
|
|
34240
|
-
start(message) {
|
|
34241
|
-
this.message = message;
|
|
34242
|
-
console.log(source_default.gray(`⏳ ${message}...`));
|
|
34243
|
-
}
|
|
34244
|
-
stop(message) {
|
|
34245
|
-
console.log(source_default.green(`✓ ${message}`));
|
|
34246
|
-
}
|
|
34247
|
-
}
|
|
34248
|
-
async function getLocalMdFilesRecursively(dir, basePath = "") {
|
|
34249
|
-
const files = [];
|
|
34250
|
-
const entries = await import_fs_extra12.default.readdir(dir, { withFileTypes: true });
|
|
34251
|
-
for (const entry of entries) {
|
|
34252
|
-
const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
|
|
34253
|
-
if (entry.isDirectory()) {
|
|
34254
|
-
const subFiles = await getLocalMdFilesRecursively(path14.join(dir, entry.name), relativePath);
|
|
34255
|
-
files.push(...subFiles);
|
|
34256
|
-
} else if (entry.name.endsWith(".md")) {
|
|
34257
|
-
files.push(relativePath);
|
|
34258
|
-
}
|
|
34259
|
-
}
|
|
34260
|
-
return files;
|
|
34261
|
-
}
|
|
34262
|
-
async function discoverAvailableCommands() {
|
|
34263
|
-
const commands = {};
|
|
34264
|
-
const useGitHub = await isGitHubAvailable();
|
|
34265
|
-
let mdFiles = [];
|
|
34266
|
-
if (useGitHub) {
|
|
34267
|
-
mdFiles = (await listFilesFromGitHub("commands")).filter((file) => file.endsWith(".md"));
|
|
34268
|
-
}
|
|
34269
|
-
if (mdFiles.length === 0) {
|
|
34270
|
-
const commandsDir = await findLocalConfigDir("commands");
|
|
34271
|
-
if (!commandsDir) {
|
|
34272
|
-
throw new Error("Commands directory not found");
|
|
34273
|
-
}
|
|
34274
|
-
mdFiles = await getLocalMdFilesRecursively(commandsDir);
|
|
34275
|
-
}
|
|
34276
|
-
for (const file of mdFiles) {
|
|
34277
|
-
const commandName = file.replace(".md", "");
|
|
34278
|
-
try {
|
|
34279
|
-
const content = await getFileContentWithGitHubFallback("commands", file);
|
|
34280
|
-
const { metadata } = parseYamlFrontmatter(content);
|
|
34281
|
-
commands[commandName] = {
|
|
34282
|
-
name: commandName.split("/").map((part) => part.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase())).join("/"),
|
|
34283
|
-
description: metadata.description || "No description available",
|
|
34284
|
-
allowedTools: metadata["allowed-tools"],
|
|
34285
|
-
argumentHint: metadata["argument-hint"],
|
|
34286
|
-
commandFile: file
|
|
34287
|
-
};
|
|
34288
|
-
} catch (error) {
|
|
34289
|
-
console.log(source_default.yellow(`⚠️ Warning: Could not process ${file}: ${error}`));
|
|
34290
|
-
}
|
|
34291
|
-
}
|
|
34292
|
-
return commands;
|
|
34293
|
-
}
|
|
34294
|
-
function displayAvailableCommands(commands) {
|
|
34295
|
-
console.log(source_default.bgBlue(" Available Claude Code Commands "));
|
|
34296
|
-
console.log();
|
|
34297
|
-
const maxNameLength = Math.max(...Object.values(commands).map((cmd) => cmd.name.length));
|
|
34298
|
-
Object.entries(commands).forEach(([key, command]) => {
|
|
34299
|
-
const paddedName = command.name.padEnd(maxNameLength);
|
|
34300
|
-
console.log(source_default.blue(` ${key}`) + source_default.gray(` • ${command.description}`));
|
|
34301
|
-
if (command.allowedTools) {
|
|
34302
|
-
console.log(source_default.gray(` Tools: ${command.allowedTools}`));
|
|
34303
|
-
}
|
|
34304
|
-
if (command.argumentHint) {
|
|
34305
|
-
console.log(source_default.gray(` Usage: ${key} ${command.argumentHint}`));
|
|
34306
|
-
}
|
|
34307
|
-
console.log();
|
|
34308
|
-
});
|
|
34309
|
-
console.log(source_default.gray("Usage:"));
|
|
34310
|
-
console.log(source_default.gray(" npx aiblueprint-cli@latest claude-code add commands <command-name> # Install specific command"));
|
|
34311
|
-
console.log(source_default.gray(" npx aiblueprint-cli@latest claude-code add commands # Show this list"));
|
|
34312
|
-
}
|
|
34313
|
-
async function addCommandCommand(commandName, options = {}) {
|
|
34314
|
-
console.log(source_default.bgBlue(` aiblueprint-cli v${getVersion()} `));
|
|
34315
|
-
const availableCommands = await discoverAvailableCommands();
|
|
34316
|
-
if (!commandName) {
|
|
34317
|
-
displayAvailableCommands(availableCommands);
|
|
34318
|
-
return;
|
|
34319
|
-
}
|
|
34320
|
-
if (!availableCommands[commandName]) {
|
|
34321
|
-
console.log(source_default.red(`❌ Command '${commandName}' not found.`));
|
|
34322
|
-
console.log(source_default.gray("Available commands:"));
|
|
34323
|
-
Object.keys(availableCommands).forEach((key) => {
|
|
34324
|
-
console.log(source_default.gray(` • ${key}: ${availableCommands[key].description}`));
|
|
34325
|
-
});
|
|
34326
|
-
process.exit(1);
|
|
34327
|
-
}
|
|
34328
|
-
const command = availableCommands[commandName];
|
|
34329
|
-
const s = new SimpleSpinner3;
|
|
34330
|
-
const targetDir = await getTargetDirectory(options);
|
|
34331
|
-
if (options.folder) {
|
|
34332
|
-
console.log(source_default.gray(`Using custom folder: ${targetDir}`));
|
|
34333
|
-
}
|
|
34334
|
-
const commandsDir = path14.join(targetDir, "commands");
|
|
34335
|
-
const commandFilePath = path14.join(commandsDir, command.commandFile);
|
|
34336
|
-
if (await import_fs_extra12.default.pathExists(commandFilePath)) {
|
|
34337
|
-
const overwriteAnswer = await lib_default.prompt([{
|
|
34338
|
-
type: "confirm",
|
|
34339
|
-
name: "overwrite",
|
|
34340
|
-
message: `Command file already exists at ${commandFilePath}. Overwrite?`
|
|
34341
|
-
}]);
|
|
34342
|
-
if (!overwriteAnswer.overwrite) {
|
|
34343
|
-
console.log(source_default.yellow("Command installation cancelled."));
|
|
34344
|
-
process.exit(0);
|
|
34345
|
-
}
|
|
34346
|
-
}
|
|
34347
|
-
try {
|
|
34348
|
-
s.start("Installing command...");
|
|
34349
|
-
await installFileWithGitHubFallback({
|
|
34350
|
-
sourceDir: "commands",
|
|
34351
|
-
targetPath: commandFilePath,
|
|
34352
|
-
fileName: command.commandFile
|
|
34353
|
-
});
|
|
34354
|
-
s.stop("Command file installed");
|
|
34355
|
-
console.log(source_default.green("✨ Command installed successfully!"));
|
|
34356
|
-
console.log(source_default.gray(`
|
|
34357
|
-
Command details:`));
|
|
34358
|
-
console.log(source_default.gray(` • Name: ${command.name}`));
|
|
34359
|
-
console.log(source_default.gray(` • File: ${commandFilePath}`));
|
|
34360
|
-
console.log(source_default.gray(` • Description: ${command.description}`));
|
|
34361
|
-
if (command.allowedTools) {
|
|
34362
|
-
console.log(source_default.gray(` • Tools: ${command.allowedTools}`));
|
|
34363
|
-
}
|
|
34364
|
-
if (command.argumentHint) {
|
|
34365
|
-
console.log(source_default.gray(` • Usage: ${commandName} ${command.argumentHint}`));
|
|
34366
|
-
}
|
|
34367
|
-
console.log(source_default.gray(`
|
|
34368
|
-
The command will be available immediately in Claude Code.`));
|
|
34369
|
-
} catch (error) {
|
|
34370
|
-
s.stop("Installation failed");
|
|
34371
|
-
console.log(source_default.red(`❌ Failed to install command: ${error}`));
|
|
34372
|
-
process.exit(1);
|
|
34373
|
-
}
|
|
34374
|
-
}
|
|
34375
|
-
|
|
34376
33918
|
// src/commands/symlink.ts
|
|
34377
33919
|
var TOOLS = [
|
|
34378
33920
|
{
|
|
@@ -34540,22 +34082,22 @@ async function symlinkCommand(params = {}) {
|
|
|
34540
34082
|
}
|
|
34541
34083
|
|
|
34542
34084
|
// src/commands/statusline.ts
|
|
34543
|
-
var
|
|
34544
|
-
import
|
|
34085
|
+
var import_fs_extra8 = __toESM(require_lib4(), 1);
|
|
34086
|
+
import path10 from "path";
|
|
34545
34087
|
import { homedir } from "os";
|
|
34546
34088
|
async function statuslineCommand(options) {
|
|
34547
|
-
const claudeDir = options.folder ?
|
|
34089
|
+
const claudeDir = options.folder ? path10.resolve(options.folder) : path10.join(homedir(), ".claude");
|
|
34548
34090
|
console.log(source_default.blue(`\uD83D\uDE80 Setting up AIBlueprint Statusline ${source_default.gray(`v${getVersion()}`)}...`));
|
|
34549
34091
|
console.log(source_default.gray(` Target: ${claudeDir}
|
|
34550
34092
|
`));
|
|
34551
|
-
await
|
|
34093
|
+
await import_fs_extra8.default.ensureDir(claudeDir);
|
|
34552
34094
|
console.log(source_default.cyan("\uD83D\uDCE6 Checking dependencies..."));
|
|
34553
34095
|
await checkAndInstallDependencies();
|
|
34554
34096
|
console.log(source_default.cyan(`
|
|
34555
34097
|
\uD83D\uDCE5 Downloading statusline files...`));
|
|
34556
|
-
const scriptsDir =
|
|
34557
|
-
await
|
|
34558
|
-
const success = await downloadDirectoryFromGitHub("scripts/statusline",
|
|
34098
|
+
const scriptsDir = path10.join(claudeDir, "scripts");
|
|
34099
|
+
await import_fs_extra8.default.ensureDir(scriptsDir);
|
|
34100
|
+
const success = await downloadDirectoryFromGitHub("scripts/statusline", path10.join(scriptsDir, "statusline"));
|
|
34559
34101
|
if (!success) {
|
|
34560
34102
|
console.log(source_default.red(" Failed to download statusline files from GitHub"));
|
|
34561
34103
|
return;
|
|
@@ -34565,18 +34107,18 @@ async function statuslineCommand(options) {
|
|
|
34565
34107
|
await installStatuslineDependencies(claudeDir);
|
|
34566
34108
|
console.log(source_default.cyan(`
|
|
34567
34109
|
⚙️ Configuring settings.json...`));
|
|
34568
|
-
const settingsPath =
|
|
34110
|
+
const settingsPath = path10.join(claudeDir, "settings.json");
|
|
34569
34111
|
let settings = {};
|
|
34570
34112
|
try {
|
|
34571
|
-
const existingSettings = await
|
|
34113
|
+
const existingSettings = await import_fs_extra8.default.readFile(settingsPath, "utf-8");
|
|
34572
34114
|
settings = JSON.parse(existingSettings);
|
|
34573
34115
|
} catch {}
|
|
34574
34116
|
settings.statusLine = {
|
|
34575
34117
|
type: "command",
|
|
34576
|
-
command: `bun ${
|
|
34118
|
+
command: `bun ${path10.join(claudeDir, "scripts/statusline/src/index.ts")}`,
|
|
34577
34119
|
padding: 0
|
|
34578
34120
|
};
|
|
34579
|
-
await
|
|
34121
|
+
await import_fs_extra8.default.writeJson(settingsPath, settings, { spaces: 2 });
|
|
34580
34122
|
console.log(source_default.green(`
|
|
34581
34123
|
✅ Statusline setup complete!`));
|
|
34582
34124
|
console.log(source_default.gray(`
|
|
@@ -35302,14 +34844,65 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
|
35302
34844
|
|
|
35303
34845
|
// src/commands/pro.ts
|
|
35304
34846
|
import os12 from "os";
|
|
35305
|
-
import
|
|
34847
|
+
import path13 from "path";
|
|
35306
34848
|
|
|
35307
34849
|
// src/lib/pro-installer.ts
|
|
35308
|
-
var
|
|
34850
|
+
var import_fs_extra9 = __toESM(require_lib4(), 1);
|
|
35309
34851
|
import os10 from "os";
|
|
35310
|
-
import
|
|
34852
|
+
import path11 from "path";
|
|
34853
|
+
import { exec as exec2 } from "child_process";
|
|
34854
|
+
import { promisify } from "util";
|
|
34855
|
+
var execAsync = promisify(exec2);
|
|
35311
34856
|
var PREMIUM_REPO = "Melvynx/aiblueprint-cli-premium";
|
|
35312
34857
|
var PREMIUM_BRANCH = "main";
|
|
34858
|
+
function getCacheRepoDir() {
|
|
34859
|
+
return path11.join(os10.homedir(), ".config", "aiblueprint", "pro-repos", "aiblueprint-cli-premium");
|
|
34860
|
+
}
|
|
34861
|
+
async function execGitWithAuth(command, token, cwd) {
|
|
34862
|
+
const authConfig = `http.https://github.com/.extraheader=AUTHORIZATION: token ${token}`;
|
|
34863
|
+
const fullCommand = `git -c "${authConfig}" ${command}`;
|
|
34864
|
+
try {
|
|
34865
|
+
await execAsync(fullCommand, { cwd, timeout: 120000 });
|
|
34866
|
+
} catch (error) {
|
|
34867
|
+
throw new Error(`Git command failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
34868
|
+
}
|
|
34869
|
+
}
|
|
34870
|
+
async function cloneOrUpdateRepo(token) {
|
|
34871
|
+
const cacheDir = getCacheRepoDir();
|
|
34872
|
+
const repoUrl = `https://github.com/${PREMIUM_REPO}.git`;
|
|
34873
|
+
if (await import_fs_extra9.default.pathExists(path11.join(cacheDir, ".git"))) {
|
|
34874
|
+
try {
|
|
34875
|
+
await execGitWithAuth("pull", token, cacheDir);
|
|
34876
|
+
} catch (error) {
|
|
34877
|
+
await import_fs_extra9.default.remove(cacheDir);
|
|
34878
|
+
await import_fs_extra9.default.ensureDir(path11.dirname(cacheDir));
|
|
34879
|
+
await execGitWithAuth(`clone ${repoUrl} ${cacheDir}`, token);
|
|
34880
|
+
}
|
|
34881
|
+
} else {
|
|
34882
|
+
await import_fs_extra9.default.ensureDir(path11.dirname(cacheDir));
|
|
34883
|
+
await execGitWithAuth(`clone ${repoUrl} ${cacheDir}`, token);
|
|
34884
|
+
}
|
|
34885
|
+
return path11.join(cacheDir, "claude-code-config");
|
|
34886
|
+
}
|
|
34887
|
+
async function copyConfigFromCache(cacheConfigDir, targetDir, onProgress) {
|
|
34888
|
+
const walk = async (dir, baseDir = dir) => {
|
|
34889
|
+
const entries = await import_fs_extra9.default.readdir(dir, { withFileTypes: true });
|
|
34890
|
+
for (const entry of entries) {
|
|
34891
|
+
const sourcePath = path11.join(dir, entry.name);
|
|
34892
|
+
const relativePath = path11.relative(baseDir, sourcePath);
|
|
34893
|
+
const targetPath = path11.join(targetDir, relativePath);
|
|
34894
|
+
if (entry.isDirectory()) {
|
|
34895
|
+
await import_fs_extra9.default.ensureDir(targetPath);
|
|
34896
|
+
onProgress?.(relativePath, "directory");
|
|
34897
|
+
await walk(sourcePath, baseDir);
|
|
34898
|
+
} else {
|
|
34899
|
+
await import_fs_extra9.default.copy(sourcePath, targetPath, { overwrite: true });
|
|
34900
|
+
onProgress?.(relativePath, "file");
|
|
34901
|
+
}
|
|
34902
|
+
}
|
|
34903
|
+
};
|
|
34904
|
+
await walk(cacheConfigDir);
|
|
34905
|
+
}
|
|
35313
34906
|
async function downloadFromPrivateGitHub(repo, branch, relativePath, targetPath, githubToken) {
|
|
35314
34907
|
try {
|
|
35315
34908
|
const url = `https://raw.githubusercontent.com/${repo}/${branch}/${relativePath}`;
|
|
@@ -35324,8 +34917,8 @@ async function downloadFromPrivateGitHub(repo, branch, relativePath, targetPath,
|
|
|
35324
34917
|
return false;
|
|
35325
34918
|
}
|
|
35326
34919
|
const content = await response.arrayBuffer();
|
|
35327
|
-
await
|
|
35328
|
-
await
|
|
34920
|
+
await import_fs_extra9.default.ensureDir(path11.dirname(targetPath));
|
|
34921
|
+
await import_fs_extra9.default.writeFile(targetPath, Buffer.from(content));
|
|
35329
34922
|
return true;
|
|
35330
34923
|
} catch (error) {
|
|
35331
34924
|
console.error(`Error downloading ${relativePath}:`, error);
|
|
@@ -35350,10 +34943,10 @@ async function downloadDirectoryFromPrivateGitHub(repo, branch, dirPath, targetD
|
|
|
35350
34943
|
console.error(`Unexpected response for directory ${dirPath}`);
|
|
35351
34944
|
return false;
|
|
35352
34945
|
}
|
|
35353
|
-
await
|
|
34946
|
+
await import_fs_extra9.default.ensureDir(targetDir);
|
|
35354
34947
|
for (const file of files) {
|
|
35355
34948
|
const relativePath = dirPath ? `${dirPath}/${file.name}` : file.name;
|
|
35356
|
-
const targetPath =
|
|
34949
|
+
const targetPath = path11.join(targetDir, file.name);
|
|
35357
34950
|
const displayPath = relativePath.replace("claude-code-config/", "");
|
|
35358
34951
|
if (file.type === "file") {
|
|
35359
34952
|
onProgress?.(displayPath, "file");
|
|
@@ -35370,55 +34963,61 @@ async function downloadDirectoryFromPrivateGitHub(repo, branch, dirPath, targetD
|
|
|
35370
34963
|
}
|
|
35371
34964
|
async function installProConfigs(options) {
|
|
35372
34965
|
const { githubToken, claudeCodeFolder, onProgress } = options;
|
|
35373
|
-
const claudeFolder = claudeCodeFolder ||
|
|
35374
|
-
|
|
34966
|
+
const claudeFolder = claudeCodeFolder || path11.join(os10.homedir(), ".claude");
|
|
34967
|
+
try {
|
|
34968
|
+
const cacheConfigDir = await cloneOrUpdateRepo(githubToken);
|
|
34969
|
+
await copyConfigFromCache(cacheConfigDir, claudeFolder, onProgress);
|
|
34970
|
+
return;
|
|
34971
|
+
} catch (error) {
|
|
34972
|
+
console.warn("Git caching failed, falling back to API download");
|
|
34973
|
+
}
|
|
34974
|
+
const tempDir = path11.join(os10.tmpdir(), `aiblueprint-premium-${Date.now()}`);
|
|
35375
34975
|
try {
|
|
35376
34976
|
const success = await downloadDirectoryFromPrivateGitHub(PREMIUM_REPO, PREMIUM_BRANCH, "claude-code-config", tempDir, githubToken, onProgress);
|
|
35377
34977
|
if (!success) {
|
|
35378
34978
|
throw new Error("Failed to download premium configurations");
|
|
35379
34979
|
}
|
|
35380
|
-
await
|
|
35381
|
-
overwrite: true
|
|
35382
|
-
recursive: true
|
|
34980
|
+
await import_fs_extra9.default.copy(tempDir, claudeFolder, {
|
|
34981
|
+
overwrite: true
|
|
35383
34982
|
});
|
|
35384
34983
|
} catch (error) {
|
|
35385
34984
|
throw new Error(`Failed to install premium configs: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
35386
34985
|
} finally {
|
|
35387
34986
|
try {
|
|
35388
|
-
await
|
|
34987
|
+
await import_fs_extra9.default.remove(tempDir);
|
|
35389
34988
|
} catch {}
|
|
35390
34989
|
}
|
|
35391
34990
|
}
|
|
35392
34991
|
|
|
35393
34992
|
// src/lib/token-storage.ts
|
|
35394
|
-
var
|
|
34993
|
+
var import_fs_extra10 = __toESM(require_lib4(), 1);
|
|
35395
34994
|
import os11 from "os";
|
|
35396
|
-
import
|
|
34995
|
+
import path12 from "path";
|
|
35397
34996
|
function getConfigDir() {
|
|
35398
34997
|
const platform = os11.platform();
|
|
35399
34998
|
if (platform === "win32") {
|
|
35400
|
-
const appData = process.env.APPDATA ||
|
|
35401
|
-
return
|
|
34999
|
+
const appData = process.env.APPDATA || path12.join(os11.homedir(), "AppData", "Roaming");
|
|
35000
|
+
return path12.join(appData, "aiblueprint");
|
|
35402
35001
|
} else {
|
|
35403
|
-
const configHome = process.env.XDG_CONFIG_HOME ||
|
|
35404
|
-
return
|
|
35002
|
+
const configHome = process.env.XDG_CONFIG_HOME || path12.join(os11.homedir(), ".config");
|
|
35003
|
+
return path12.join(configHome, "aiblueprint");
|
|
35405
35004
|
}
|
|
35406
35005
|
}
|
|
35407
35006
|
function getTokenFilePath() {
|
|
35408
|
-
return
|
|
35007
|
+
return path12.join(getConfigDir(), "token.txt");
|
|
35409
35008
|
}
|
|
35410
35009
|
async function saveToken(githubToken) {
|
|
35411
35010
|
const tokenFile = getTokenFilePath();
|
|
35412
|
-
await
|
|
35413
|
-
await
|
|
35011
|
+
await import_fs_extra10.default.ensureDir(path12.dirname(tokenFile));
|
|
35012
|
+
await import_fs_extra10.default.writeFile(tokenFile, githubToken, { mode: 384 });
|
|
35414
35013
|
}
|
|
35415
35014
|
async function getToken() {
|
|
35416
35015
|
const tokenFile = getTokenFilePath();
|
|
35417
|
-
if (!await
|
|
35016
|
+
if (!await import_fs_extra10.default.pathExists(tokenFile)) {
|
|
35418
35017
|
return null;
|
|
35419
35018
|
}
|
|
35420
35019
|
try {
|
|
35421
|
-
const token = await
|
|
35020
|
+
const token = await import_fs_extra10.default.readFile(tokenFile, "utf-8");
|
|
35422
35021
|
return token.trim();
|
|
35423
35022
|
} catch (error) {
|
|
35424
35023
|
return null;
|
|
@@ -35432,7 +35031,7 @@ function getTokenInfo() {
|
|
|
35432
35031
|
}
|
|
35433
35032
|
|
|
35434
35033
|
// src/commands/pro.ts
|
|
35435
|
-
var
|
|
35034
|
+
var import_fs_extra11 = __toESM(require_lib4(), 1);
|
|
35436
35035
|
var API_URL = "https://codeline.app/api/products";
|
|
35437
35036
|
var PRODUCT_IDS = ["prd_XJVgxVPbGG", "prd_NKabAkdOkw"];
|
|
35438
35037
|
async function countInstalledItems(claudeDir) {
|
|
@@ -35442,30 +35041,36 @@ async function countInstalledItems(claudeDir) {
|
|
|
35442
35041
|
skills: 0
|
|
35443
35042
|
};
|
|
35444
35043
|
try {
|
|
35445
|
-
const commandsDir =
|
|
35446
|
-
if (await
|
|
35447
|
-
const files = await
|
|
35044
|
+
const commandsDir = path13.join(claudeDir, "commands");
|
|
35045
|
+
if (await import_fs_extra11.default.pathExists(commandsDir)) {
|
|
35046
|
+
const files = await import_fs_extra11.default.readdir(commandsDir);
|
|
35448
35047
|
counts.commands = files.filter((f) => f.endsWith(".md")).length;
|
|
35449
35048
|
}
|
|
35450
|
-
} catch {
|
|
35049
|
+
} catch (error) {
|
|
35050
|
+
console.error("Failed to count commands:", error instanceof Error ? error.message : error);
|
|
35051
|
+
}
|
|
35451
35052
|
try {
|
|
35452
|
-
const agentsDir =
|
|
35453
|
-
if (await
|
|
35454
|
-
const files = await
|
|
35053
|
+
const agentsDir = path13.join(claudeDir, "agents");
|
|
35054
|
+
if (await import_fs_extra11.default.pathExists(agentsDir)) {
|
|
35055
|
+
const files = await import_fs_extra11.default.readdir(agentsDir);
|
|
35455
35056
|
counts.agents = files.filter((f) => f.endsWith(".md")).length;
|
|
35456
35057
|
}
|
|
35457
|
-
} catch {
|
|
35058
|
+
} catch (error) {
|
|
35059
|
+
console.error("Failed to count agents:", error instanceof Error ? error.message : error);
|
|
35060
|
+
}
|
|
35458
35061
|
try {
|
|
35459
|
-
const skillsDir =
|
|
35460
|
-
if (await
|
|
35461
|
-
const items = await
|
|
35062
|
+
const skillsDir = path13.join(claudeDir, "skills");
|
|
35063
|
+
if (await import_fs_extra11.default.pathExists(skillsDir)) {
|
|
35064
|
+
const items = await import_fs_extra11.default.readdir(skillsDir);
|
|
35462
35065
|
const dirs = await Promise.all(items.map(async (item) => {
|
|
35463
|
-
const stat = await
|
|
35066
|
+
const stat = await import_fs_extra11.default.stat(path13.join(skillsDir, item));
|
|
35464
35067
|
return stat.isDirectory();
|
|
35465
35068
|
}));
|
|
35466
35069
|
counts.skills = dirs.filter(Boolean).length;
|
|
35467
35070
|
}
|
|
35468
|
-
} catch {
|
|
35071
|
+
} catch (error) {
|
|
35072
|
+
console.error("Failed to count skills:", error instanceof Error ? error.message : error);
|
|
35073
|
+
}
|
|
35469
35074
|
return counts;
|
|
35470
35075
|
}
|
|
35471
35076
|
async function proActivateCommand(userToken) {
|
|
@@ -35571,7 +35176,7 @@ async function proSetupCommand(options = {}) {
|
|
|
35571
35176
|
Se(source_default.red("❌ Not activated"));
|
|
35572
35177
|
process.exit(1);
|
|
35573
35178
|
}
|
|
35574
|
-
const claudeDir = options.folder ?
|
|
35179
|
+
const claudeDir = options.folder ? path13.resolve(options.folder) : path13.join(os12.homedir(), ".claude");
|
|
35575
35180
|
const spinner = Y2();
|
|
35576
35181
|
const onProgress = (file, type) => {
|
|
35577
35182
|
spinner.message(`Installing: ${source_default.cyan(file)} ${source_default.gray(`(${type})`)}`);
|
|
@@ -35594,10 +35199,15 @@ async function proSetupCommand(options = {}) {
|
|
|
35594
35199
|
spinner.stop("Shell shortcuts configured");
|
|
35595
35200
|
spinner.start("Updating settings.json...");
|
|
35596
35201
|
await updateSettings({
|
|
35202
|
+
shellShortcuts: false,
|
|
35597
35203
|
commandValidation: true,
|
|
35598
35204
|
customStatusline: true,
|
|
35205
|
+
aiblueprintCommands: false,
|
|
35206
|
+
aiblueprintAgents: false,
|
|
35207
|
+
aiblueprintSkills: false,
|
|
35599
35208
|
notificationSounds: true,
|
|
35600
|
-
|
|
35209
|
+
codexSymlink: false,
|
|
35210
|
+
openCodeSymlink: false
|
|
35601
35211
|
}, claudeDir);
|
|
35602
35212
|
spinner.stop("Settings.json updated");
|
|
35603
35213
|
spinner.start("Counting installed items...");
|
|
@@ -35649,11 +35259,11 @@ async function proUpdateCommand(options = {}) {
|
|
|
35649
35259
|
|
|
35650
35260
|
// src/commands/sync.ts
|
|
35651
35261
|
import os13 from "os";
|
|
35652
|
-
import
|
|
35262
|
+
import path15 from "path";
|
|
35653
35263
|
|
|
35654
35264
|
// src/lib/sync-utils.ts
|
|
35655
|
-
var
|
|
35656
|
-
import
|
|
35265
|
+
var import_fs_extra12 = __toESM(require_lib4(), 1);
|
|
35266
|
+
import path14 from "path";
|
|
35657
35267
|
import crypto from "crypto";
|
|
35658
35268
|
var PREMIUM_REPO2 = "Melvynx/aiblueprint-cli-premium";
|
|
35659
35269
|
var PREMIUM_BRANCH2 = "main";
|
|
@@ -35702,7 +35312,7 @@ async function listRemoteFilesRecursive(dirPath, githubToken, basePath = "") {
|
|
|
35702
35312
|
}
|
|
35703
35313
|
async function computeLocalFileSha(filePath) {
|
|
35704
35314
|
try {
|
|
35705
|
-
const content = await
|
|
35315
|
+
const content = await import_fs_extra12.default.readFile(filePath);
|
|
35706
35316
|
return computeFileSha(content);
|
|
35707
35317
|
} catch {
|
|
35708
35318
|
return null;
|
|
@@ -35710,15 +35320,15 @@ async function computeLocalFileSha(filePath) {
|
|
|
35710
35320
|
}
|
|
35711
35321
|
async function listLocalFiles(dir) {
|
|
35712
35322
|
const files = [];
|
|
35713
|
-
if (!await
|
|
35323
|
+
if (!await import_fs_extra12.default.pathExists(dir)) {
|
|
35714
35324
|
return files;
|
|
35715
35325
|
}
|
|
35716
|
-
const items = await
|
|
35326
|
+
const items = await import_fs_extra12.default.readdir(dir);
|
|
35717
35327
|
for (const item of items) {
|
|
35718
35328
|
if (item === "node_modules" || item === ".DS_Store")
|
|
35719
35329
|
continue;
|
|
35720
|
-
const fullPath =
|
|
35721
|
-
const stat = await
|
|
35330
|
+
const fullPath = path14.join(dir, item);
|
|
35331
|
+
const stat = await import_fs_extra12.default.stat(fullPath);
|
|
35722
35332
|
if (stat.isDirectory()) {
|
|
35723
35333
|
files.push(item);
|
|
35724
35334
|
const subFiles = await listLocalFilesRecursive(fullPath, item);
|
|
@@ -35731,13 +35341,13 @@ async function listLocalFiles(dir) {
|
|
|
35731
35341
|
}
|
|
35732
35342
|
async function listLocalFilesRecursive(dir, basePath) {
|
|
35733
35343
|
const files = [];
|
|
35734
|
-
const items = await
|
|
35344
|
+
const items = await import_fs_extra12.default.readdir(dir);
|
|
35735
35345
|
for (const item of items) {
|
|
35736
35346
|
if (item === "node_modules" || item === ".DS_Store")
|
|
35737
35347
|
continue;
|
|
35738
|
-
const fullPath =
|
|
35348
|
+
const fullPath = path14.join(dir, item);
|
|
35739
35349
|
const relativePath = `${basePath}/${item}`;
|
|
35740
|
-
const stat = await
|
|
35350
|
+
const stat = await import_fs_extra12.default.stat(fullPath);
|
|
35741
35351
|
if (stat.isDirectory()) {
|
|
35742
35352
|
files.push(relativePath);
|
|
35743
35353
|
const subFiles = await listLocalFilesRecursive(fullPath, relativePath);
|
|
@@ -35750,7 +35360,7 @@ async function listLocalFilesRecursive(dir, basePath) {
|
|
|
35750
35360
|
}
|
|
35751
35361
|
async function analyzeCategory(category, claudeDir, githubToken) {
|
|
35752
35362
|
const items = [];
|
|
35753
|
-
const localDir =
|
|
35363
|
+
const localDir = path14.join(claudeDir, category);
|
|
35754
35364
|
const remoteFiles = await listRemoteFilesRecursive(category, githubToken);
|
|
35755
35365
|
const localFiles = await listLocalFiles(localDir);
|
|
35756
35366
|
const remoteSet = new Map;
|
|
@@ -35759,7 +35369,7 @@ async function analyzeCategory(category, claudeDir, githubToken) {
|
|
|
35759
35369
|
}
|
|
35760
35370
|
const localSet = new Set(localFiles);
|
|
35761
35371
|
for (const [remotePath, { sha, isFolder }] of remoteSet) {
|
|
35762
|
-
const localPath =
|
|
35372
|
+
const localPath = path14.join(localDir, remotePath);
|
|
35763
35373
|
if (isFolder) {
|
|
35764
35374
|
continue;
|
|
35765
35375
|
}
|
|
@@ -35802,8 +35412,8 @@ async function analyzeCategory(category, claudeDir, githubToken) {
|
|
|
35802
35412
|
if (parentAlreadyDeleted) {
|
|
35803
35413
|
continue;
|
|
35804
35414
|
}
|
|
35805
|
-
const fullPath =
|
|
35806
|
-
const stat = await
|
|
35415
|
+
const fullPath = path14.join(localDir, localPath);
|
|
35416
|
+
const stat = await import_fs_extra12.default.stat(fullPath).catch(() => null);
|
|
35807
35417
|
if (stat) {
|
|
35808
35418
|
const isFolder = stat.isDirectory();
|
|
35809
35419
|
items.push({
|
|
@@ -35839,9 +35449,9 @@ async function fetchRemoteSettings(githubToken) {
|
|
|
35839
35449
|
}
|
|
35840
35450
|
}
|
|
35841
35451
|
async function getLocalSettings(claudeDir) {
|
|
35842
|
-
const settingsPath =
|
|
35452
|
+
const settingsPath = path14.join(claudeDir, "settings.json");
|
|
35843
35453
|
try {
|
|
35844
|
-
const content = await
|
|
35454
|
+
const content = await import_fs_extra12.default.readFile(settingsPath, "utf-8");
|
|
35845
35455
|
return JSON.parse(content);
|
|
35846
35456
|
} catch {
|
|
35847
35457
|
return {};
|
|
@@ -35923,8 +35533,8 @@ async function downloadFromPrivateGitHub2(relativePath, targetPath, githubToken)
|
|
|
35923
35533
|
return false;
|
|
35924
35534
|
}
|
|
35925
35535
|
const content = await response.arrayBuffer();
|
|
35926
|
-
await
|
|
35927
|
-
await
|
|
35536
|
+
await import_fs_extra12.default.ensureDir(path14.dirname(targetPath));
|
|
35537
|
+
await import_fs_extra12.default.writeFile(targetPath, Buffer.from(content));
|
|
35928
35538
|
return true;
|
|
35929
35539
|
} catch {
|
|
35930
35540
|
return false;
|
|
@@ -35934,10 +35544,10 @@ async function syncSelectedHooks(claudeDir, hooks, onProgress) {
|
|
|
35934
35544
|
if (hooks.length === 0) {
|
|
35935
35545
|
return { success: 0, failed: 0 };
|
|
35936
35546
|
}
|
|
35937
|
-
const settingsPath =
|
|
35547
|
+
const settingsPath = path14.join(claudeDir, "settings.json");
|
|
35938
35548
|
let settings = {};
|
|
35939
35549
|
try {
|
|
35940
|
-
const content = await
|
|
35550
|
+
const content = await import_fs_extra12.default.readFile(settingsPath, "utf-8");
|
|
35941
35551
|
settings = JSON.parse(content);
|
|
35942
35552
|
} catch {
|
|
35943
35553
|
settings = {};
|
|
@@ -35965,7 +35575,7 @@ async function syncSelectedHooks(claudeDir, hooks, onProgress) {
|
|
|
35965
35575
|
failed++;
|
|
35966
35576
|
}
|
|
35967
35577
|
}
|
|
35968
|
-
await
|
|
35578
|
+
await import_fs_extra12.default.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
35969
35579
|
return { success, failed };
|
|
35970
35580
|
}
|
|
35971
35581
|
async function syncSelectedItems(claudeDir, items, githubToken, onProgress) {
|
|
@@ -35973,11 +35583,11 @@ async function syncSelectedItems(claudeDir, items, githubToken, onProgress) {
|
|
|
35973
35583
|
let failed = 0;
|
|
35974
35584
|
let deleted = 0;
|
|
35975
35585
|
for (const item of items) {
|
|
35976
|
-
const targetPath =
|
|
35586
|
+
const targetPath = path14.join(claudeDir, item.relativePath);
|
|
35977
35587
|
if (item.status === "deleted") {
|
|
35978
35588
|
onProgress?.(item.relativePath, "deleting");
|
|
35979
35589
|
try {
|
|
35980
|
-
await
|
|
35590
|
+
await import_fs_extra12.default.remove(targetPath);
|
|
35981
35591
|
deleted++;
|
|
35982
35592
|
} catch {
|
|
35983
35593
|
failed++;
|
|
@@ -36129,7 +35739,7 @@ async function proSyncCommand(options = {}) {
|
|
|
36129
35739
|
Se(source_default.red("❌ Not activated"));
|
|
36130
35740
|
process.exit(1);
|
|
36131
35741
|
}
|
|
36132
|
-
const claudeDir = options.folder ?
|
|
35742
|
+
const claudeDir = options.folder ? path15.resolve(options.folder) : path15.join(os13.homedir(), ".claude");
|
|
36133
35743
|
const spinner = Y2();
|
|
36134
35744
|
spinner.start("Analyzing changes...");
|
|
36135
35745
|
const result = await analyzeSyncChanges(claudeDir, githubToken);
|
|
@@ -36359,10 +35969,10 @@ async function proSyncCommand(options = {}) {
|
|
|
36359
35969
|
|
|
36360
35970
|
// src/cli.ts
|
|
36361
35971
|
import { readFileSync as readFileSync3 } from "fs";
|
|
36362
|
-
import { dirname as
|
|
36363
|
-
import { fileURLToPath as
|
|
36364
|
-
var
|
|
36365
|
-
var packageJson = JSON.parse(readFileSync3(join2(
|
|
35972
|
+
import { dirname as dirname3, join as join2 } from "path";
|
|
35973
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
35974
|
+
var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
|
|
35975
|
+
var packageJson = JSON.parse(readFileSync3(join2(__dirname3, "../package.json"), "utf8"));
|
|
36366
35976
|
var program2 = new Command;
|
|
36367
35977
|
program2.name("aiblueprint").description("AIBlueprint CLI for setting up Claude Code configurations").version(packageJson.version);
|
|
36368
35978
|
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");
|
|
@@ -36382,21 +35992,6 @@ claudeCodeCmd.command("setup-terminal").description("Setup terminal with Oh My Z
|
|
|
36382
35992
|
homeDir: parentOptions.claudeCodeFolder || parentOptions.folder
|
|
36383
35993
|
});
|
|
36384
35994
|
});
|
|
36385
|
-
var addCmd = claudeCodeCmd.command("add").description(`Add components to your Claude Code configuration
|
|
36386
|
-
` + `Examples:
|
|
36387
|
-
` + ` npx aiblueprint-cli@latest claude-code add hook post-edit-typescript
|
|
36388
|
-
` + ` npx aiblueprint-cli@latest claude-code add commands
|
|
36389
|
-
` + " npx aiblueprint-cli@latest claude-code add commands commit");
|
|
36390
|
-
addCmd.command("hook <type>").description("Add a hook to your Claude Code configuration. Available types: post-edit-typescript").action((type, options, command) => {
|
|
36391
|
-
const parentOptions = command.parent.parent.opts();
|
|
36392
|
-
const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
|
|
36393
|
-
addHookCommand(type, { folder: claudeCodeFolder });
|
|
36394
|
-
});
|
|
36395
|
-
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) => {
|
|
36396
|
-
const parentOptions = command.parent.parent.opts();
|
|
36397
|
-
const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
|
|
36398
|
-
addCommandCommand(commandName, { folder: claudeCodeFolder });
|
|
36399
|
-
});
|
|
36400
35995
|
claudeCodeCmd.command("symlink").description("Create symlinks between different CLI tools (Claude Code, Codex, OpenCode, FactoryAI)").action((options, command) => {
|
|
36401
35996
|
const parentOptions = command.parent.opts();
|
|
36402
35997
|
symlinkCommand({
|