aiblueprint-cli 1.3.6 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +451 -205
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -32488,9 +32488,9 @@ var inquirer = {
32488
32488
  var lib_default = inquirer;
32489
32489
 
32490
32490
  // src/commands/setup.ts
32491
- var import_fs_extra5 = __toESM(require_lib4(), 1);
32492
- import path7 from "path";
32493
- import os7 from "os";
32491
+ var import_fs_extra6 = __toESM(require_lib4(), 1);
32492
+ import path8 from "path";
32493
+ import os8 from "os";
32494
32494
 
32495
32495
  // node_modules/chalk/source/vendor/ansi-styles/index.js
32496
32496
  var ANSI_BACKGROUND_OFFSET = 10;
@@ -33212,16 +33212,94 @@ async function installStatuslineDependencies(claudeDir) {
33212
33212
  // src/commands/setup/settings.ts
33213
33213
  var import_fs_extra3 = __toESM(require_lib4(), 1);
33214
33214
  import path5 from "path";
33215
+
33216
+ // src/lib/platform.ts
33215
33217
  import os6 from "os";
33218
+ import { execSync as execSync2 } from "child_process";
33219
+ function escapeShellArg(arg) {
33220
+ return "'" + arg.replace(/'/g, "'\\''") + "'";
33221
+ }
33222
+ var cachedAudioPlayer = undefined;
33223
+ function detectAudioPlayer() {
33224
+ if (cachedAudioPlayer !== undefined)
33225
+ return cachedAudioPlayer;
33226
+ const platform = os6.platform();
33227
+ if (platform === "darwin") {
33228
+ cachedAudioPlayer = "afplay";
33229
+ return cachedAudioPlayer;
33230
+ }
33231
+ if (platform === "win32") {
33232
+ cachedAudioPlayer = "powershell";
33233
+ return cachedAudioPlayer;
33234
+ }
33235
+ const linuxPlayers = ["paplay", "aplay", "mpv", "ffplay"];
33236
+ for (const player of linuxPlayers) {
33237
+ try {
33238
+ execSync2(`which ${player}`, { stdio: "ignore" });
33239
+ cachedAudioPlayer = player;
33240
+ return cachedAudioPlayer;
33241
+ } catch {
33242
+ continue;
33243
+ }
33244
+ }
33245
+ cachedAudioPlayer = null;
33246
+ return cachedAudioPlayer;
33247
+ }
33216
33248
  function getPlaySoundCommand(soundPath) {
33249
+ const player = detectAudioPlayer();
33250
+ if (!player)
33251
+ return null;
33217
33252
  const platform = os6.platform();
33253
+ const safePath = escapeShellArg(soundPath);
33218
33254
  if (platform === "darwin") {
33219
- return `afplay -v 0.1 "${soundPath}"`;
33220
- } else if (platform === "win32") {
33221
- return `powershell -c "(New-Object Media.SoundPlayer '${soundPath}').PlaySync()"`;
33222
- } else {
33223
- return `paplay "${soundPath}" 2>/dev/null || aplay "${soundPath}" 2>/dev/null || true`;
33255
+ return `afplay -v 0.1 ${safePath}`;
33224
33256
  }
33257
+ if (platform === "win32") {
33258
+ const escapedPath = soundPath.replace(/'/g, "''");
33259
+ return `powershell -c "(New-Object Media.SoundPlayer '${escapedPath}').PlaySync()"`;
33260
+ }
33261
+ switch (player) {
33262
+ case "paplay":
33263
+ return `paplay ${safePath} 2>/dev/null || true`;
33264
+ case "aplay":
33265
+ return `aplay ${safePath} 2>/dev/null || true`;
33266
+ case "mpv":
33267
+ return `mpv --no-video --volume=10 ${safePath} 2>/dev/null || true`;
33268
+ case "ffplay":
33269
+ return `ffplay -nodisp -autoexit -volume 10 ${safePath} 2>/dev/null || true`;
33270
+ default:
33271
+ return null;
33272
+ }
33273
+ }
33274
+ var KNOWN_CLAUDE_PATHS = [
33275
+ /\/Users\/[^/]+\/\.claude\//,
33276
+ /\/home\/[^/]+\/\.claude\//,
33277
+ /C:\\Users\\[^\\]+\\\.claude\\/i
33278
+ ];
33279
+ function transformHookCommand(command, claudeDir) {
33280
+ let transformed = command;
33281
+ for (const pattern of KNOWN_CLAUDE_PATHS) {
33282
+ transformed = transformed.replace(pattern, `${claudeDir}/`);
33283
+ }
33284
+ transformed = transformed.replace(/\\/g, "/");
33285
+ return transformed;
33286
+ }
33287
+ function transformHook(hook, claudeDir) {
33288
+ if (!hook)
33289
+ return hook;
33290
+ const transformed = { ...hook };
33291
+ if (transformed.command && typeof transformed.command === "string") {
33292
+ transformed.command = transformHookCommand(transformed.command, claudeDir);
33293
+ }
33294
+ if (Array.isArray(transformed.hooks)) {
33295
+ transformed.hooks = transformed.hooks.map((h) => transformHook(h, claudeDir));
33296
+ }
33297
+ return transformed;
33298
+ }
33299
+
33300
+ // src/commands/setup/settings.ts
33301
+ function toPosixPath(p) {
33302
+ return p.replace(/\\/g, "/");
33225
33303
  }
33226
33304
  async function hasExistingStatusLine(claudeDir) {
33227
33305
  const settingsPath = path5.join(claudeDir, "settings.json");
@@ -33246,7 +33324,7 @@ async function updateSettings(options, claudeDir) {
33246
33324
  if (shouldReplace) {
33247
33325
  settings.statusLine = {
33248
33326
  type: "command",
33249
- command: `bun ${path5.join(claudeDir, "scripts/statusline/src/index.ts")}`,
33327
+ command: `bun ${toPosixPath(path5.join(claudeDir, "scripts/statusline/src/index.ts"))}`,
33250
33328
  padding: 0
33251
33329
  };
33252
33330
  }
@@ -33263,7 +33341,7 @@ async function updateSettings(options, claudeDir) {
33263
33341
  hooks: [
33264
33342
  {
33265
33343
  type: "command",
33266
- command: `bun ${path5.join(claudeDir, "scripts/command-validator/src/cli.ts")}`
33344
+ command: `bun ${toPosixPath(path5.join(claudeDir, "scripts/command-validator/src/cli.ts"))}`
33267
33345
  }
33268
33346
  ]
33269
33347
  };
@@ -33273,39 +33351,45 @@ async function updateSettings(options, claudeDir) {
33273
33351
  }
33274
33352
  }
33275
33353
  if (options.notificationSounds) {
33276
- if (!settings.hooks.Stop) {
33277
- settings.hooks.Stop = [];
33278
- }
33279
- const finishSoundPath = path5.join(claudeDir, "song/finish.mp3");
33280
- const stopHook = {
33281
- matcher: "",
33282
- hooks: [
33283
- {
33284
- type: "command",
33285
- command: getPlaySoundCommand(finishSoundPath)
33286
- }
33287
- ]
33288
- };
33289
- const existingStopHook = settings.hooks.Stop.find((h) => h.hooks?.some((hook) => hook.command?.includes("finish.mp3")));
33290
- if (!existingStopHook) {
33291
- settings.hooks.Stop.push(stopHook);
33292
- }
33293
- if (!settings.hooks.Notification) {
33294
- settings.hooks.Notification = [];
33354
+ const finishSoundPath = toPosixPath(path5.join(claudeDir, "song/finish.mp3"));
33355
+ const finishSoundCommand = getPlaySoundCommand(finishSoundPath);
33356
+ if (finishSoundCommand) {
33357
+ if (!settings.hooks.Stop) {
33358
+ settings.hooks.Stop = [];
33359
+ }
33360
+ const stopHook = {
33361
+ matcher: "",
33362
+ hooks: [
33363
+ {
33364
+ type: "command",
33365
+ command: finishSoundCommand
33366
+ }
33367
+ ]
33368
+ };
33369
+ const existingStopHook = settings.hooks.Stop.find((h) => h.hooks?.some((hook) => hook.command?.includes("finish.mp3")));
33370
+ if (!existingStopHook) {
33371
+ settings.hooks.Stop.push(stopHook);
33372
+ }
33295
33373
  }
33296
- const needHumanSoundPath = path5.join(claudeDir, "song/need-human.mp3");
33297
- const notificationHook = {
33298
- matcher: "",
33299
- hooks: [
33300
- {
33301
- type: "command",
33302
- command: getPlaySoundCommand(needHumanSoundPath)
33303
- }
33304
- ]
33305
- };
33306
- const existingNotificationHook = settings.hooks.Notification.find((h) => h.hooks?.some((hook) => hook.command?.includes("need-human.mp3")));
33307
- if (!existingNotificationHook) {
33308
- settings.hooks.Notification.push(notificationHook);
33374
+ const needHumanSoundPath = toPosixPath(path5.join(claudeDir, "song/need-human.mp3"));
33375
+ const needHumanSoundCommand = getPlaySoundCommand(needHumanSoundPath);
33376
+ if (needHumanSoundCommand) {
33377
+ if (!settings.hooks.Notification) {
33378
+ settings.hooks.Notification = [];
33379
+ }
33380
+ const notificationHook = {
33381
+ matcher: "",
33382
+ hooks: [
33383
+ {
33384
+ type: "command",
33385
+ command: needHumanSoundCommand
33386
+ }
33387
+ ]
33388
+ };
33389
+ const existingNotificationHook = settings.hooks.Notification.find((h) => h.hooks?.some((hook) => hook.command?.includes("need-human.mp3")));
33390
+ if (!existingNotificationHook) {
33391
+ settings.hooks.Notification.push(notificationHook);
33392
+ }
33309
33393
  }
33310
33394
  }
33311
33395
  if (options.postEditTypeScript) {
@@ -33317,7 +33401,7 @@ async function updateSettings(options, claudeDir) {
33317
33401
  hooks: [
33318
33402
  {
33319
33403
  type: "command",
33320
- command: `bun ${path5.join(claudeDir, "scripts/hook-post-file.ts")}`
33404
+ command: `bun ${toPosixPath(path5.join(claudeDir, "scripts/hook-post-file.ts"))}`
33321
33405
  }
33322
33406
  ]
33323
33407
  };
@@ -33415,6 +33499,39 @@ function getVersion() {
33415
33499
  }
33416
33500
  }
33417
33501
 
33502
+ // src/lib/backup-utils.ts
33503
+ var import_fs_extra5 = __toESM(require_lib4(), 1);
33504
+ import path7 from "path";
33505
+ import os7 from "os";
33506
+ var BACKUP_BASE_DIR = path7.join(os7.homedir(), ".config", "aiblueprint", "backup");
33507
+ function formatDate(date) {
33508
+ const pad = (n) => n.toString().padStart(2, "0");
33509
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}-${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}`;
33510
+ }
33511
+ async function createBackup(claudeDir) {
33512
+ const exists = await import_fs_extra5.default.pathExists(claudeDir);
33513
+ if (!exists) {
33514
+ return null;
33515
+ }
33516
+ const files = await import_fs_extra5.default.readdir(claudeDir);
33517
+ const hasContent = files.some((f) => f !== ".DS_Store");
33518
+ if (!hasContent) {
33519
+ return null;
33520
+ }
33521
+ const timestamp = formatDate(new Date);
33522
+ const backupPath = path7.join(BACKUP_BASE_DIR, timestamp);
33523
+ await import_fs_extra5.default.ensureDir(backupPath);
33524
+ const itemsToCopy = ["commands", "agents", "skills", "scripts", "song", "settings.json"];
33525
+ for (const item of itemsToCopy) {
33526
+ const sourcePath = path7.join(claudeDir, item);
33527
+ const destPath = path7.join(backupPath, item);
33528
+ if (await import_fs_extra5.default.pathExists(sourcePath)) {
33529
+ await import_fs_extra5.default.copy(sourcePath, destPath, { overwrite: true });
33530
+ }
33531
+ }
33532
+ return backupPath;
33533
+ }
33534
+
33418
33535
  // src/commands/setup.ts
33419
33536
  var __filename2 = fileURLToPath2(import.meta.url);
33420
33537
  var __dirname2 = dirname2(__filename2);
@@ -33518,9 +33635,16 @@ async function setupCommand(params = {}) {
33518
33635
  skipInteractive
33519
33636
  };
33520
33637
  const s = new SimpleSpinner;
33521
- const claudeDir = customClaudeCodeFolder ? path7.resolve(customClaudeCodeFolder) : path7.join(os7.homedir(), ".claude");
33638
+ const claudeDir = customClaudeCodeFolder ? path8.resolve(customClaudeCodeFolder) : path8.join(os8.homedir(), ".claude");
33522
33639
  console.log(source_default.gray(`Installing to: ${claudeDir}`));
33523
- await import_fs_extra5.default.ensureDir(claudeDir);
33640
+ await import_fs_extra6.default.ensureDir(claudeDir);
33641
+ s.start("Creating backup of existing configuration");
33642
+ const backupPath = await createBackup(claudeDir);
33643
+ if (backupPath) {
33644
+ s.stop(`Backup created: ${source_default.gray(backupPath)}`);
33645
+ } else {
33646
+ s.stop("No existing config to backup");
33647
+ }
33524
33648
  let useGitHub = true;
33525
33649
  let sourceDir;
33526
33650
  const testUrl = `${GITHUB_RAW_BASE2}/scripts/validate-command.js`;
@@ -33533,14 +33657,14 @@ async function setupCommand(params = {}) {
33533
33657
  if (!useGitHub) {
33534
33658
  const currentDir = process.cwd();
33535
33659
  const possiblePaths = [
33536
- path7.join(currentDir, "claude-code-config"),
33537
- path7.join(__dirname2, "../../claude-code-config"),
33538
- path7.join(__dirname2, "../claude-code-config"),
33539
- path7.join(path7.dirname(process.argv[1]), "../claude-code-config")
33660
+ path8.join(currentDir, "claude-code-config"),
33661
+ path8.join(__dirname2, "../../claude-code-config"),
33662
+ path8.join(__dirname2, "../claude-code-config"),
33663
+ path8.join(path8.dirname(process.argv[1]), "../claude-code-config")
33540
33664
  ];
33541
33665
  sourceDir = possiblePaths.find((p) => {
33542
33666
  try {
33543
- return import_fs_extra5.default.existsSync(p);
33667
+ return import_fs_extra6.default.existsSync(p);
33544
33668
  } catch {
33545
33669
  return false;
33546
33670
  }
@@ -33560,28 +33684,32 @@ async function setupCommand(params = {}) {
33560
33684
  if (options.commandValidation || options.customStatusline || options.notificationSounds || options.postEditTypeScript) {
33561
33685
  s.start("Setting up scripts");
33562
33686
  if (useGitHub) {
33563
- const scriptsDir = path7.join(claudeDir, "scripts");
33564
- await import_fs_extra5.default.ensureDir(scriptsDir);
33687
+ const scriptsDir = path8.join(claudeDir, "scripts");
33688
+ await import_fs_extra6.default.ensureDir(scriptsDir);
33565
33689
  if (options.commandValidation) {
33566
- await downloadDirectoryFromGitHub("scripts/command-validator", path7.join(scriptsDir, "command-validator"));
33690
+ await downloadDirectoryFromGitHub("scripts/command-validator", path8.join(scriptsDir, "command-validator"));
33567
33691
  }
33568
33692
  if (options.postEditTypeScript) {
33569
- await downloadFromGitHub("scripts/hook-post-file.ts", path7.join(scriptsDir, "hook-post-file.ts"));
33693
+ await downloadFromGitHub("scripts/hook-post-file.ts", path8.join(scriptsDir, "hook-post-file.ts"));
33570
33694
  }
33571
33695
  if (options.customStatusline) {
33572
- await downloadDirectoryFromGitHub("scripts/statusline", path7.join(scriptsDir, "statusline"));
33696
+ await downloadDirectoryFromGitHub("scripts/statusline", path8.join(scriptsDir, "statusline"));
33697
+ await import_fs_extra6.default.ensureDir(path8.join(scriptsDir, "statusline/data"));
33573
33698
  }
33574
33699
  } else {
33575
- await import_fs_extra5.default.copy(path7.join(sourceDir, "scripts"), path7.join(claudeDir, "scripts"), { overwrite: true });
33700
+ await import_fs_extra6.default.copy(path8.join(sourceDir, "scripts"), path8.join(claudeDir, "scripts"), { overwrite: true });
33701
+ if (options.customStatusline) {
33702
+ await import_fs_extra6.default.ensureDir(path8.join(claudeDir, "scripts/statusline/data"));
33703
+ }
33576
33704
  }
33577
33705
  s.stop("Scripts installed");
33578
33706
  }
33579
33707
  if (options.aiblueprintCommands) {
33580
33708
  s.start("Setting up AIBlueprint commands");
33581
33709
  if (useGitHub) {
33582
- await downloadDirectoryFromGitHub("commands", path7.join(claudeDir, "commands"));
33710
+ await downloadDirectoryFromGitHub("commands", path8.join(claudeDir, "commands"));
33583
33711
  } else {
33584
- await import_fs_extra5.default.copy(path7.join(sourceDir, "commands"), path7.join(claudeDir, "commands"), { overwrite: true });
33712
+ await import_fs_extra6.default.copy(path8.join(sourceDir, "commands"), path8.join(claudeDir, "commands"), { overwrite: true });
33585
33713
  }
33586
33714
  s.stop("Commands installed");
33587
33715
  }
@@ -33598,9 +33726,9 @@ async function setupCommand(params = {}) {
33598
33726
  if (options.aiblueprintAgents) {
33599
33727
  s.start("Setting up AIBlueprint agents");
33600
33728
  if (useGitHub) {
33601
- await downloadDirectoryFromGitHub("agents", path7.join(claudeDir, "agents"));
33729
+ await downloadDirectoryFromGitHub("agents", path8.join(claudeDir, "agents"));
33602
33730
  } else {
33603
- await import_fs_extra5.default.copy(path7.join(sourceDir, "agents"), path7.join(claudeDir, "agents"), { overwrite: true });
33731
+ await import_fs_extra6.default.copy(path8.join(sourceDir, "agents"), path8.join(claudeDir, "agents"), { overwrite: true });
33604
33732
  }
33605
33733
  s.stop("Agents installed");
33606
33734
  }
@@ -33611,7 +33739,7 @@ async function setupCommand(params = {}) {
33611
33739
  try {
33612
33740
  const testResponse = await fetch(testSkillsUrl);
33613
33741
  if (testResponse.ok) {
33614
- await downloadDirectoryFromGitHub("skills", path7.join(claudeDir, "skills"));
33742
+ await downloadDirectoryFromGitHub("skills", path8.join(claudeDir, "skills"));
33615
33743
  s.stop("Skills installed");
33616
33744
  } else {
33617
33745
  s.stop("Skills not available in repository");
@@ -33620,9 +33748,9 @@ async function setupCommand(params = {}) {
33620
33748
  s.stop("Skills not available in repository");
33621
33749
  }
33622
33750
  } else {
33623
- const skillsSourcePath = path7.join(sourceDir, "skills");
33624
- if (await import_fs_extra5.default.pathExists(skillsSourcePath)) {
33625
- await import_fs_extra5.default.copy(skillsSourcePath, path7.join(claudeDir, "skills"), { overwrite: true });
33751
+ const skillsSourcePath = path8.join(sourceDir, "skills");
33752
+ if (await import_fs_extra6.default.pathExists(skillsSourcePath)) {
33753
+ await import_fs_extra6.default.copy(skillsSourcePath, path8.join(claudeDir, "skills"), { overwrite: true });
33626
33754
  s.stop("Skills installed");
33627
33755
  } else {
33628
33756
  s.stop("Skills not available in local repository");
@@ -33632,12 +33760,12 @@ async function setupCommand(params = {}) {
33632
33760
  if (options.notificationSounds) {
33633
33761
  s.start("Setting up notification sounds");
33634
33762
  if (useGitHub) {
33635
- const songDir = path7.join(claudeDir, "song");
33636
- await import_fs_extra5.default.ensureDir(songDir);
33637
- await downloadFromGitHub("song/finish.mp3", path7.join(songDir, "finish.mp3"));
33638
- await downloadFromGitHub("song/need-human.mp3", path7.join(songDir, "need-human.mp3"));
33763
+ const songDir = path8.join(claudeDir, "song");
33764
+ await import_fs_extra6.default.ensureDir(songDir);
33765
+ await downloadFromGitHub("song/finish.mp3", path8.join(songDir, "finish.mp3"));
33766
+ await downloadFromGitHub("song/need-human.mp3", path8.join(songDir, "need-human.mp3"));
33639
33767
  } else {
33640
- await import_fs_extra5.default.copy(path7.join(sourceDir, "song"), path7.join(claudeDir, "song"), { overwrite: true });
33768
+ await import_fs_extra6.default.copy(path8.join(sourceDir, "song"), path8.join(claudeDir, "song"), { overwrite: true });
33641
33769
  }
33642
33770
  s.stop("Notification sounds installed");
33643
33771
  }
@@ -33673,7 +33801,7 @@ async function setupCommand(params = {}) {
33673
33801
  console.log(source_default.gray(`
33674
33802
  Next steps:`));
33675
33803
  if (options.shellShortcuts) {
33676
- const platform = os7.platform();
33804
+ const platform = os8.platform();
33677
33805
  if (platform === "win32") {
33678
33806
  console.log(source_default.gray(" • Restart PowerShell to load the new functions"));
33679
33807
  } else {
@@ -33694,14 +33822,14 @@ Next steps:`));
33694
33822
  }
33695
33823
 
33696
33824
  // src/commands/addHook.ts
33697
- var import_fs_extra9 = __toESM(require_lib4(), 1);
33698
- import path11 from "path";
33825
+ var import_fs_extra10 = __toESM(require_lib4(), 1);
33826
+ import path12 from "path";
33699
33827
  import { fileURLToPath as fileURLToPath4 } from "url";
33700
33828
  import { dirname as dirname4 } from "path";
33701
33829
 
33702
33830
  // src/utils/claude-config.ts
33703
- var import_fs_extra6 = __toESM(require_lib4(), 1);
33704
- import path8 from "path";
33831
+ var import_fs_extra7 = __toESM(require_lib4(), 1);
33832
+ import path9 from "path";
33705
33833
  import { fileURLToPath as fileURLToPath3 } from "url";
33706
33834
  import { dirname as dirname3 } from "path";
33707
33835
  var __filename3 = fileURLToPath3(import.meta.url);
@@ -33732,14 +33860,14 @@ function parseYamlFrontmatter(content) {
33732
33860
  }
33733
33861
  function getLocalConfigPaths(subDir) {
33734
33862
  return [
33735
- path8.join(__dirname3, `../claude-code-config/${subDir}`),
33736
- path8.join(__dirname3, `../../claude-code-config/${subDir}`)
33863
+ path9.join(__dirname3, `../claude-code-config/${subDir}`),
33864
+ path9.join(__dirname3, `../../claude-code-config/${subDir}`)
33737
33865
  ];
33738
33866
  }
33739
33867
  async function findLocalConfigDir(subDir) {
33740
33868
  const possiblePaths = getLocalConfigPaths(subDir);
33741
33869
  for (const testPath of possiblePaths) {
33742
- if (await import_fs_extra6.default.pathExists(testPath)) {
33870
+ if (await import_fs_extra7.default.pathExists(testPath)) {
33743
33871
  return testPath;
33744
33872
  }
33745
33873
  }
@@ -33750,22 +33878,22 @@ async function getTargetDirectory(options) {
33750
33878
  return options.folder;
33751
33879
  }
33752
33880
  const cwd = process.cwd();
33753
- const localClaudeDir = path8.join(cwd, ".claude");
33754
- const isGitRepo = await import_fs_extra6.default.pathExists(path8.join(cwd, ".git"));
33755
- const hasClaudeConfig = await import_fs_extra6.default.pathExists(localClaudeDir);
33881
+ const localClaudeDir = path9.join(cwd, ".claude");
33882
+ const isGitRepo = await import_fs_extra7.default.pathExists(path9.join(cwd, ".git"));
33883
+ const hasClaudeConfig = await import_fs_extra7.default.pathExists(localClaudeDir);
33756
33884
  if (isGitRepo || hasClaudeConfig) {
33757
33885
  return localClaudeDir;
33758
33886
  }
33759
- return path8.join(process.env.HOME || process.env.USERPROFILE || "~", ".claude");
33887
+ return path9.join(process.env.HOME || process.env.USERPROFILE || "~", ".claude");
33760
33888
  }
33761
33889
 
33762
33890
  // src/utils/file-installer.ts
33763
- var import_fs_extra8 = __toESM(require_lib4(), 1);
33764
- import path10 from "path";
33891
+ var import_fs_extra9 = __toESM(require_lib4(), 1);
33892
+ import path11 from "path";
33765
33893
 
33766
33894
  // src/utils/github.ts
33767
- var import_fs_extra7 = __toESM(require_lib4(), 1);
33768
- import path9 from "path";
33895
+ var import_fs_extra8 = __toESM(require_lib4(), 1);
33896
+ import path10 from "path";
33769
33897
  var GITHUB_RAW_BASE3 = "https://raw.githubusercontent.com/Melvynx/aiblueprint-cli/main/claude-code-config";
33770
33898
  async function downloadFromGitHub2(relativePath) {
33771
33899
  try {
@@ -33813,8 +33941,8 @@ async function isGitHubAvailable() {
33813
33941
  async function downloadAndWriteFile(relativePath, targetPath) {
33814
33942
  const content = await downloadFromGitHub2(relativePath);
33815
33943
  if (content) {
33816
- await import_fs_extra7.default.ensureDir(path9.dirname(targetPath));
33817
- await import_fs_extra7.default.writeFile(targetPath, content);
33944
+ await import_fs_extra8.default.ensureDir(path10.dirname(targetPath));
33945
+ await import_fs_extra8.default.writeFile(targetPath, content);
33818
33946
  return true;
33819
33947
  }
33820
33948
  return false;
@@ -33823,7 +33951,7 @@ async function downloadAndWriteFile(relativePath, targetPath) {
33823
33951
  // src/utils/file-installer.ts
33824
33952
  async function installFileWithGitHubFallback(options) {
33825
33953
  const { sourceDir, targetPath, fileName } = options;
33826
- await import_fs_extra8.default.ensureDir(path10.dirname(targetPath));
33954
+ await import_fs_extra9.default.ensureDir(path11.dirname(targetPath));
33827
33955
  const useGitHub = options.useGitHub ?? await isGitHubAvailable();
33828
33956
  if (useGitHub) {
33829
33957
  const relativePath = `${sourceDir}/${fileName}`;
@@ -33837,11 +33965,11 @@ async function installFileWithGitHubFallback(options) {
33837
33965
  if (!localConfigDir) {
33838
33966
  throw new Error(`Neither GitHub nor local ${sourceDir} directory found`);
33839
33967
  }
33840
- const localFilePath = path10.join(localConfigDir, fileName);
33841
- if (!await import_fs_extra8.default.pathExists(localFilePath)) {
33968
+ const localFilePath = path11.join(localConfigDir, fileName);
33969
+ if (!await import_fs_extra9.default.pathExists(localFilePath)) {
33842
33970
  throw new Error(`File not found: ${fileName}`);
33843
33971
  }
33844
- await import_fs_extra8.default.copy(localFilePath, targetPath);
33972
+ await import_fs_extra9.default.copy(localFilePath, targetPath);
33845
33973
  }
33846
33974
  async function getFileContentWithGitHubFallback(sourceDir, fileName) {
33847
33975
  const useGitHub = await isGitHubAvailable();
@@ -33856,11 +33984,11 @@ async function getFileContentWithGitHubFallback(sourceDir, fileName) {
33856
33984
  if (!localConfigDir) {
33857
33985
  throw new Error(`Neither GitHub nor local ${sourceDir} directory found`);
33858
33986
  }
33859
- const localFilePath = path10.join(localConfigDir, fileName);
33860
- if (!await import_fs_extra8.default.pathExists(localFilePath)) {
33987
+ const localFilePath = path11.join(localConfigDir, fileName);
33988
+ if (!await import_fs_extra9.default.pathExists(localFilePath)) {
33861
33989
  throw new Error(`File not found: ${fileName}`);
33862
33990
  }
33863
- return await import_fs_extra8.default.readFile(localFilePath, "utf-8");
33991
+ return await import_fs_extra9.default.readFile(localFilePath, "utf-8");
33864
33992
  }
33865
33993
 
33866
33994
  // src/commands/addHook.ts
@@ -33902,10 +34030,10 @@ async function addHookCommand(hookType, options) {
33902
34030
  const s = new SimpleSpinner2;
33903
34031
  const targetDir = await getTargetDirectory(options);
33904
34032
  const claudeDir = targetDir;
33905
- const targetHookDir = path11.join(claudeDir, hook.targetDir || "hooks");
33906
- const hookFilePath = path11.join(targetHookDir, hook.hookFile);
33907
- const settingsPath = path11.join(claudeDir, "settings.json");
33908
- if (await import_fs_extra9.default.pathExists(hookFilePath)) {
34033
+ const targetHookDir = path12.join(claudeDir, hook.targetDir || "hooks");
34034
+ const hookFilePath = path12.join(targetHookDir, hook.hookFile);
34035
+ const settingsPath = path12.join(claudeDir, "settings.json");
34036
+ if (await import_fs_extra10.default.pathExists(hookFilePath)) {
33909
34037
  const overwriteAnswer = await lib_default.prompt([{
33910
34038
  type: "confirm",
33911
34039
  name: "overwrite",
@@ -33918,18 +34046,18 @@ async function addHookCommand(hookType, options) {
33918
34046
  }
33919
34047
  try {
33920
34048
  s.start("Installing hook...");
33921
- await import_fs_extra9.default.ensureDir(targetHookDir);
34049
+ await import_fs_extra10.default.ensureDir(targetHookDir);
33922
34050
  await installFileWithGitHubFallback({
33923
34051
  sourceDir: hook.sourceDir || "hooks",
33924
34052
  targetPath: hookFilePath,
33925
34053
  fileName: hook.hookFile
33926
34054
  });
33927
- await import_fs_extra9.default.chmod(hookFilePath, 493);
34055
+ await import_fs_extra10.default.chmod(hookFilePath, 493);
33928
34056
  s.stop("Hook file installed");
33929
34057
  s.start("Updating settings.json...");
33930
34058
  let settings = {};
33931
34059
  try {
33932
- const existingSettings = await import_fs_extra9.default.readFile(settingsPath, "utf-8");
34060
+ const existingSettings = await import_fs_extra10.default.readFile(settingsPath, "utf-8");
33933
34061
  settings = JSON.parse(existingSettings);
33934
34062
  } catch {
33935
34063
  settings = {};
@@ -33966,7 +34094,7 @@ async function addHookCommand(hookType, options) {
33966
34094
  } else {
33967
34095
  settings.hooks[hook.event].push(newHook);
33968
34096
  }
33969
- await import_fs_extra9.default.writeFile(settingsPath, JSON.stringify(settings, null, 2));
34097
+ await import_fs_extra10.default.writeFile(settingsPath, JSON.stringify(settings, null, 2));
33970
34098
  s.stop("Settings updated");
33971
34099
  console.log(source_default.green("✨ Hook installed successfully!"));
33972
34100
  console.log(source_default.gray(`
@@ -33985,8 +34113,8 @@ The hook will run automatically when you edit TypeScript files with Claude Code.
33985
34113
  }
33986
34114
 
33987
34115
  // src/commands/addCommand.ts
33988
- var import_fs_extra10 = __toESM(require_lib4(), 1);
33989
- import path12 from "path";
34116
+ var import_fs_extra11 = __toESM(require_lib4(), 1);
34117
+ import path13 from "path";
33990
34118
  class SimpleSpinner3 {
33991
34119
  message = "";
33992
34120
  start(message) {
@@ -33999,11 +34127,11 @@ class SimpleSpinner3 {
33999
34127
  }
34000
34128
  async function getLocalMdFilesRecursively(dir, basePath = "") {
34001
34129
  const files = [];
34002
- const entries = await import_fs_extra10.default.readdir(dir, { withFileTypes: true });
34130
+ const entries = await import_fs_extra11.default.readdir(dir, { withFileTypes: true });
34003
34131
  for (const entry of entries) {
34004
34132
  const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
34005
34133
  if (entry.isDirectory()) {
34006
- const subFiles = await getLocalMdFilesRecursively(path12.join(dir, entry.name), relativePath);
34134
+ const subFiles = await getLocalMdFilesRecursively(path13.join(dir, entry.name), relativePath);
34007
34135
  files.push(...subFiles);
34008
34136
  } else if (entry.name.endsWith(".md")) {
34009
34137
  files.push(relativePath);
@@ -34083,9 +34211,9 @@ async function addCommandCommand(commandName, options = {}) {
34083
34211
  if (options.folder) {
34084
34212
  console.log(source_default.gray(`Using custom folder: ${targetDir}`));
34085
34213
  }
34086
- const commandsDir = path12.join(targetDir, "commands");
34087
- const commandFilePath = path12.join(commandsDir, command.commandFile);
34088
- if (await import_fs_extra10.default.pathExists(commandFilePath)) {
34214
+ const commandsDir = path13.join(targetDir, "commands");
34215
+ const commandFilePath = path13.join(commandsDir, command.commandFile);
34216
+ if (await import_fs_extra11.default.pathExists(commandFilePath)) {
34089
34217
  const overwriteAnswer = await lib_default.prompt([{
34090
34218
  type: "confirm",
34091
34219
  name: "overwrite",
@@ -34292,22 +34420,22 @@ async function symlinkCommand(params = {}) {
34292
34420
  }
34293
34421
 
34294
34422
  // src/commands/statusline.ts
34295
- var import_fs_extra11 = __toESM(require_lib4(), 1);
34296
- import path13 from "path";
34423
+ var import_fs_extra12 = __toESM(require_lib4(), 1);
34424
+ import path14 from "path";
34297
34425
  import { homedir } from "os";
34298
34426
  async function statuslineCommand(options) {
34299
- const claudeDir = options.folder ? path13.resolve(options.folder) : path13.join(homedir(), ".claude");
34427
+ const claudeDir = options.folder ? path14.resolve(options.folder) : path14.join(homedir(), ".claude");
34300
34428
  console.log(source_default.blue(`\uD83D\uDE80 Setting up AIBlueprint Statusline ${source_default.gray(`v${getVersion()}`)}...`));
34301
34429
  console.log(source_default.gray(` Target: ${claudeDir}
34302
34430
  `));
34303
- await import_fs_extra11.default.ensureDir(claudeDir);
34431
+ await import_fs_extra12.default.ensureDir(claudeDir);
34304
34432
  console.log(source_default.cyan("\uD83D\uDCE6 Checking dependencies..."));
34305
34433
  await checkAndInstallDependencies();
34306
34434
  console.log(source_default.cyan(`
34307
34435
  \uD83D\uDCE5 Downloading statusline files...`));
34308
- const scriptsDir = path13.join(claudeDir, "scripts");
34309
- await import_fs_extra11.default.ensureDir(scriptsDir);
34310
- const success = await downloadDirectoryFromGitHub("scripts/statusline", path13.join(scriptsDir, "statusline"));
34436
+ const scriptsDir = path14.join(claudeDir, "scripts");
34437
+ await import_fs_extra12.default.ensureDir(scriptsDir);
34438
+ const success = await downloadDirectoryFromGitHub("scripts/statusline", path14.join(scriptsDir, "statusline"));
34311
34439
  if (!success) {
34312
34440
  console.log(source_default.red(" Failed to download statusline files from GitHub"));
34313
34441
  return;
@@ -34317,19 +34445,19 @@ async function statuslineCommand(options) {
34317
34445
  await installStatuslineDependencies(claudeDir);
34318
34446
  console.log(source_default.cyan(`
34319
34447
  ⚙️ Configuring settings.json...`));
34320
- const settingsPath = path13.join(claudeDir, "settings.json");
34448
+ const settingsPath = path14.join(claudeDir, "settings.json");
34321
34449
  let settings = {};
34322
34450
  try {
34323
- const existingSettings = await import_fs_extra11.default.readFile(settingsPath, "utf-8");
34451
+ const existingSettings = await import_fs_extra12.default.readFile(settingsPath, "utf-8");
34324
34452
  settings = JSON.parse(existingSettings);
34325
34453
  } catch {
34326
34454
  }
34327
34455
  settings.statusLine = {
34328
34456
  type: "command",
34329
- command: `bun ${path13.join(claudeDir, "scripts/statusline/src/index.ts")}`,
34457
+ command: `bun ${path14.join(claudeDir, "scripts/statusline/src/index.ts")}`,
34330
34458
  padding: 0
34331
34459
  };
34332
- await import_fs_extra11.default.writeJson(settingsPath, settings, { spaces: 2 });
34460
+ await import_fs_extra12.default.writeJson(settingsPath, settings, { spaces: 2 });
34333
34461
  console.log(source_default.green(`
34334
34462
  ✅ Statusline setup complete!`));
34335
34463
  console.log(source_default.gray(`
@@ -34704,6 +34832,32 @@ var vD = class extends x {
34704
34832
  this.value = u ? this.value.filter((F) => F !== this._value) : [...this.value, this._value];
34705
34833
  }
34706
34834
  };
34835
+ var wD = Object.defineProperty;
34836
+ var yD = (e, u, F) => (u in e) ? wD(e, u, { enumerable: true, configurable: true, writable: true, value: F }) : e[u] = F;
34837
+ var Z = (e, u, F) => (yD(e, typeof u != "symbol" ? u + "" : u, F), F);
34838
+ var $D = class extends x {
34839
+ constructor(u) {
34840
+ super(u, false), Z(this, "options"), Z(this, "cursor", 0), this.options = u.options, this.cursor = this.options.findIndex(({ value: F }) => F === u.initialValue), this.cursor === -1 && (this.cursor = 0), this.changeValue(), this.on("cursor", (F) => {
34841
+ switch (F) {
34842
+ case "left":
34843
+ case "up":
34844
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
34845
+ break;
34846
+ case "down":
34847
+ case "right":
34848
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
34849
+ break;
34850
+ }
34851
+ this.changeValue();
34852
+ });
34853
+ }
34854
+ get _value() {
34855
+ return this.options[this.cursor];
34856
+ }
34857
+ changeValue() {
34858
+ this.value = this._value.value;
34859
+ }
34860
+ };
34707
34861
  var TD = Object.defineProperty;
34708
34862
  var jD = (e, u, F) => (u in e) ? TD(e, u, { enumerable: true, configurable: true, writable: true, value: F }) : e[u] = F;
34709
34863
  var MD = (e, u, F) => (jD(e, typeof u != "symbol" ? u + "" : u, F), F);
@@ -34771,7 +34925,7 @@ var w2 = o("◼", "[+]");
34771
34925
  var M2 = o("◻", "[ ]");
34772
34926
  var U2 = o("▪", "•");
34773
34927
  var B = o("─", "-");
34774
- var Z = o("╮", "+");
34928
+ var Z2 = o("╮", "+");
34775
34929
  var z2 = o("├", "+");
34776
34930
  var X2 = o("╯", "+");
34777
34931
  var J2 = o("●", "•");
@@ -34831,6 +34985,34 @@ ${import_picocolors2.default.cyan(d2)}
34831
34985
  }
34832
34986
  } }).prompt();
34833
34987
  };
34988
+ var ie = (r2) => {
34989
+ const n = (t, s) => {
34990
+ const c2 = t.label ?? String(t.value);
34991
+ return s === "active" ? `${import_picocolors2.default.green(b2)} ${c2} ${t.hint ? import_picocolors2.default.dim(`(${t.hint})`) : ""}` : s === "selected" ? `${import_picocolors2.default.dim(c2)}` : s === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(c2))}` : `${import_picocolors2.default.dim(E)} ${import_picocolors2.default.dim(c2)}`;
34992
+ };
34993
+ let i = 0;
34994
+ return new $D({ options: r2.options, initialValue: r2.initialValue, render() {
34995
+ const t = `${import_picocolors2.default.gray(a2)}
34996
+ ${y2(this.state)} ${r2.message}
34997
+ `;
34998
+ switch (this.state) {
34999
+ case "submit":
35000
+ return `${t}${import_picocolors2.default.gray(a2)} ${n(this.options[this.cursor], "selected")}`;
35001
+ case "cancel":
35002
+ return `${t}${import_picocolors2.default.gray(a2)} ${n(this.options[this.cursor], "cancelled")}
35003
+ ${import_picocolors2.default.gray(a2)}`;
35004
+ default: {
35005
+ const s = r2.maxItems === undefined ? 1 / 0 : Math.max(r2.maxItems, 5);
35006
+ this.cursor >= i + s - 3 ? i = Math.max(Math.min(this.cursor - s + 3, this.options.length - s), 0) : this.cursor < i + 2 && (i = Math.max(this.cursor - 2, 0));
35007
+ const c2 = s < this.options.length && i > 0, l2 = s < this.options.length && i + s < this.options.length;
35008
+ return `${t}${import_picocolors2.default.cyan(a2)} ${this.options.slice(i, i + s).map((u, m2, $2) => m2 === 0 && c2 ? import_picocolors2.default.dim("...") : m2 === $2.length - 1 && l2 ? import_picocolors2.default.dim("...") : n(u, m2 + i === this.cursor ? "active" : "inactive")).join(`
35009
+ ${import_picocolors2.default.cyan(a2)} `)}
35010
+ ${import_picocolors2.default.cyan(d2)}
35011
+ `;
35012
+ }
35013
+ }
35014
+ } }).prompt();
35015
+ };
34834
35016
  var ae = (r2) => {
34835
35017
  const n = (i, t) => {
34836
35018
  const s = i.label ?? String(i.value);
@@ -34939,13 +35121,13 @@ var de = () => {
34939
35121
  };
34940
35122
 
34941
35123
  // src/commands/pro.ts
34942
- import os10 from "os";
34943
- import path16 from "path";
35124
+ import os11 from "os";
35125
+ import path17 from "path";
34944
35126
 
34945
35127
  // src/lib/pro-installer.ts
34946
- var import_fs_extra12 = __toESM(require_lib4(), 1);
34947
- import os8 from "os";
34948
- import path14 from "path";
35128
+ var import_fs_extra13 = __toESM(require_lib4(), 1);
35129
+ import os9 from "os";
35130
+ import path15 from "path";
34949
35131
  var PREMIUM_REPO = "Melvynx/aiblueprint-cli-premium";
34950
35132
  var PREMIUM_BRANCH = "main";
34951
35133
  async function downloadFromPrivateGitHub(repo, branch, relativePath, targetPath, githubToken) {
@@ -34962,8 +35144,8 @@ async function downloadFromPrivateGitHub(repo, branch, relativePath, targetPath,
34962
35144
  return false;
34963
35145
  }
34964
35146
  const content = await response.arrayBuffer();
34965
- await import_fs_extra12.default.ensureDir(path14.dirname(targetPath));
34966
- await import_fs_extra12.default.writeFile(targetPath, Buffer.from(content));
35147
+ await import_fs_extra13.default.ensureDir(path15.dirname(targetPath));
35148
+ await import_fs_extra13.default.writeFile(targetPath, Buffer.from(content));
34967
35149
  return true;
34968
35150
  } catch (error) {
34969
35151
  console.error(`Error downloading ${relativePath}:`, error);
@@ -34988,10 +35170,10 @@ async function downloadDirectoryFromPrivateGitHub(repo, branch, dirPath, targetD
34988
35170
  console.error(`Unexpected response for directory ${dirPath}`);
34989
35171
  return false;
34990
35172
  }
34991
- await import_fs_extra12.default.ensureDir(targetDir);
35173
+ await import_fs_extra13.default.ensureDir(targetDir);
34992
35174
  for (const file of files) {
34993
35175
  const relativePath = dirPath ? `${dirPath}/${file.name}` : file.name;
34994
- const targetPath = path14.join(targetDir, file.name);
35176
+ const targetPath = path15.join(targetDir, file.name);
34995
35177
  const displayPath = relativePath.replace("claude-code-config/", "");
34996
35178
  if (file.type === "file") {
34997
35179
  onProgress?.(displayPath, "file");
@@ -35008,14 +35190,14 @@ async function downloadDirectoryFromPrivateGitHub(repo, branch, dirPath, targetD
35008
35190
  }
35009
35191
  async function installProConfigs(options) {
35010
35192
  const { githubToken, claudeCodeFolder, onProgress } = options;
35011
- const claudeFolder = claudeCodeFolder || path14.join(os8.homedir(), ".claude");
35012
- const tempDir = path14.join(os8.tmpdir(), `aiblueprint-premium-${Date.now()}`);
35193
+ const claudeFolder = claudeCodeFolder || path15.join(os9.homedir(), ".claude");
35194
+ const tempDir = path15.join(os9.tmpdir(), `aiblueprint-premium-${Date.now()}`);
35013
35195
  try {
35014
35196
  const success = await downloadDirectoryFromPrivateGitHub(PREMIUM_REPO, PREMIUM_BRANCH, "claude-code-config", tempDir, githubToken, onProgress);
35015
35197
  if (!success) {
35016
35198
  throw new Error("Failed to download premium configurations");
35017
35199
  }
35018
- await import_fs_extra12.default.copy(tempDir, claudeFolder, {
35200
+ await import_fs_extra13.default.copy(tempDir, claudeFolder, {
35019
35201
  overwrite: true,
35020
35202
  recursive: true
35021
35203
  });
@@ -35023,41 +35205,41 @@ async function installProConfigs(options) {
35023
35205
  throw new Error(`Failed to install premium configs: ${error instanceof Error ? error.message : "Unknown error"}`);
35024
35206
  } finally {
35025
35207
  try {
35026
- await import_fs_extra12.default.remove(tempDir);
35208
+ await import_fs_extra13.default.remove(tempDir);
35027
35209
  } catch {
35028
35210
  }
35029
35211
  }
35030
35212
  }
35031
35213
 
35032
35214
  // src/lib/token-storage.ts
35033
- var import_fs_extra13 = __toESM(require_lib4(), 1);
35034
- import os9 from "os";
35035
- import path15 from "path";
35215
+ var import_fs_extra14 = __toESM(require_lib4(), 1);
35216
+ import os10 from "os";
35217
+ import path16 from "path";
35036
35218
  function getConfigDir() {
35037
- const platform = os9.platform();
35219
+ const platform = os10.platform();
35038
35220
  if (platform === "win32") {
35039
- const appData = process.env.APPDATA || path15.join(os9.homedir(), "AppData", "Roaming");
35040
- return path15.join(appData, "aiblueprint");
35221
+ const appData = process.env.APPDATA || path16.join(os10.homedir(), "AppData", "Roaming");
35222
+ return path16.join(appData, "aiblueprint");
35041
35223
  } else {
35042
- const configHome = process.env.XDG_CONFIG_HOME || path15.join(os9.homedir(), ".config");
35043
- return path15.join(configHome, "aiblueprint");
35224
+ const configHome = process.env.XDG_CONFIG_HOME || path16.join(os10.homedir(), ".config");
35225
+ return path16.join(configHome, "aiblueprint");
35044
35226
  }
35045
35227
  }
35046
35228
  function getTokenFilePath() {
35047
- return path15.join(getConfigDir(), "token.txt");
35229
+ return path16.join(getConfigDir(), "token.txt");
35048
35230
  }
35049
35231
  async function saveToken(githubToken) {
35050
35232
  const tokenFile = getTokenFilePath();
35051
- await import_fs_extra13.default.ensureDir(path15.dirname(tokenFile));
35052
- await import_fs_extra13.default.writeFile(tokenFile, githubToken, { mode: 384 });
35233
+ await import_fs_extra14.default.ensureDir(path16.dirname(tokenFile));
35234
+ await import_fs_extra14.default.writeFile(tokenFile, githubToken, { mode: 384 });
35053
35235
  }
35054
35236
  async function getToken() {
35055
35237
  const tokenFile = getTokenFilePath();
35056
- if (!await import_fs_extra13.default.pathExists(tokenFile)) {
35238
+ if (!await import_fs_extra14.default.pathExists(tokenFile)) {
35057
35239
  return null;
35058
35240
  }
35059
35241
  try {
35060
- const token = await import_fs_extra13.default.readFile(tokenFile, "utf-8");
35242
+ const token = await import_fs_extra14.default.readFile(tokenFile, "utf-8");
35061
35243
  return token.trim();
35062
35244
  } catch (error) {
35063
35245
  return null;
@@ -35066,12 +35248,12 @@ async function getToken() {
35066
35248
  function getTokenInfo() {
35067
35249
  return {
35068
35250
  path: getTokenFilePath(),
35069
- platform: os9.platform()
35251
+ platform: os10.platform()
35070
35252
  };
35071
35253
  }
35072
35254
 
35073
35255
  // src/commands/pro.ts
35074
- var import_fs_extra14 = __toESM(require_lib4(), 1);
35256
+ var import_fs_extra15 = __toESM(require_lib4(), 1);
35075
35257
  var API_URL = "https://codeline.app/api/products";
35076
35258
  var PRODUCT_ID = "prd_XJVgxVPbGG";
35077
35259
  async function countInstalledItems(claudeDir) {
@@ -35081,27 +35263,27 @@ async function countInstalledItems(claudeDir) {
35081
35263
  skills: 0
35082
35264
  };
35083
35265
  try {
35084
- const commandsDir = path16.join(claudeDir, "commands");
35085
- if (await import_fs_extra14.default.pathExists(commandsDir)) {
35086
- const files = await import_fs_extra14.default.readdir(commandsDir);
35266
+ const commandsDir = path17.join(claudeDir, "commands");
35267
+ if (await import_fs_extra15.default.pathExists(commandsDir)) {
35268
+ const files = await import_fs_extra15.default.readdir(commandsDir);
35087
35269
  counts.commands = files.filter((f3) => f3.endsWith(".md")).length;
35088
35270
  }
35089
35271
  } catch {
35090
35272
  }
35091
35273
  try {
35092
- const agentsDir = path16.join(claudeDir, "agents");
35093
- if (await import_fs_extra14.default.pathExists(agentsDir)) {
35094
- const files = await import_fs_extra14.default.readdir(agentsDir);
35274
+ const agentsDir = path17.join(claudeDir, "agents");
35275
+ if (await import_fs_extra15.default.pathExists(agentsDir)) {
35276
+ const files = await import_fs_extra15.default.readdir(agentsDir);
35095
35277
  counts.agents = files.filter((f3) => f3.endsWith(".md")).length;
35096
35278
  }
35097
35279
  } catch {
35098
35280
  }
35099
35281
  try {
35100
- const skillsDir = path16.join(claudeDir, "skills");
35101
- if (await import_fs_extra14.default.pathExists(skillsDir)) {
35102
- const items = await import_fs_extra14.default.readdir(skillsDir);
35282
+ const skillsDir = path17.join(claudeDir, "skills");
35283
+ if (await import_fs_extra15.default.pathExists(skillsDir)) {
35284
+ const items = await import_fs_extra15.default.readdir(skillsDir);
35103
35285
  const dirs = await Promise.all(items.map(async (item) => {
35104
- const stat = await import_fs_extra14.default.stat(path16.join(skillsDir, item));
35286
+ const stat = await import_fs_extra15.default.stat(path17.join(skillsDir, item));
35105
35287
  return stat.isDirectory();
35106
35288
  }));
35107
35289
  counts.skills = dirs.filter(Boolean).length;
@@ -35208,7 +35390,7 @@ async function proSetupCommand(options = {}) {
35208
35390
  $e(source_default.red("❌ Not activated"));
35209
35391
  process.exit(1);
35210
35392
  }
35211
- const claudeDir = options.folder ? path16.resolve(options.folder) : path16.join(os10.homedir(), ".claude");
35393
+ const claudeDir = options.folder ? path17.resolve(options.folder) : path17.join(os11.homedir(), ".claude");
35212
35394
  const spinner = de();
35213
35395
  const onProgress = (file, type) => {
35214
35396
  spinner.message(`Installing: ${source_default.cyan(file)} ${source_default.gray(`(${type})`)}`);
@@ -35285,12 +35467,12 @@ async function proUpdateCommand(options = {}) {
35285
35467
  }
35286
35468
 
35287
35469
  // src/commands/sync.ts
35288
- import os11 from "os";
35289
- import path18 from "path";
35470
+ import os12 from "os";
35471
+ import path19 from "path";
35290
35472
 
35291
35473
  // src/lib/sync-utils.ts
35292
- var import_fs_extra15 = __toESM(require_lib4(), 1);
35293
- import path17 from "path";
35474
+ var import_fs_extra16 = __toESM(require_lib4(), 1);
35475
+ import path18 from "path";
35294
35476
  import crypto from "crypto";
35295
35477
  var PREMIUM_REPO2 = "Melvynx/aiblueprint-cli-premium";
35296
35478
  var PREMIUM_BRANCH2 = "main";
@@ -35339,7 +35521,7 @@ async function listRemoteFilesRecursive(dirPath, githubToken, basePath = "") {
35339
35521
  }
35340
35522
  async function computeLocalFileSha(filePath) {
35341
35523
  try {
35342
- const content = await import_fs_extra15.default.readFile(filePath);
35524
+ const content = await import_fs_extra16.default.readFile(filePath);
35343
35525
  return computeFileSha(content);
35344
35526
  } catch {
35345
35527
  return null;
@@ -35347,15 +35529,15 @@ async function computeLocalFileSha(filePath) {
35347
35529
  }
35348
35530
  async function listLocalFiles(dir) {
35349
35531
  const files = [];
35350
- if (!await import_fs_extra15.default.pathExists(dir)) {
35532
+ if (!await import_fs_extra16.default.pathExists(dir)) {
35351
35533
  return files;
35352
35534
  }
35353
- const items = await import_fs_extra15.default.readdir(dir);
35535
+ const items = await import_fs_extra16.default.readdir(dir);
35354
35536
  for (const item of items) {
35355
35537
  if (item === "node_modules" || item === ".DS_Store")
35356
35538
  continue;
35357
- const fullPath = path17.join(dir, item);
35358
- const stat = await import_fs_extra15.default.stat(fullPath);
35539
+ const fullPath = path18.join(dir, item);
35540
+ const stat = await import_fs_extra16.default.stat(fullPath);
35359
35541
  if (stat.isDirectory()) {
35360
35542
  files.push(item);
35361
35543
  const subFiles = await listLocalFilesRecursive(fullPath, item);
@@ -35368,13 +35550,13 @@ async function listLocalFiles(dir) {
35368
35550
  }
35369
35551
  async function listLocalFilesRecursive(dir, basePath) {
35370
35552
  const files = [];
35371
- const items = await import_fs_extra15.default.readdir(dir);
35553
+ const items = await import_fs_extra16.default.readdir(dir);
35372
35554
  for (const item of items) {
35373
35555
  if (item === "node_modules" || item === ".DS_Store")
35374
35556
  continue;
35375
- const fullPath = path17.join(dir, item);
35557
+ const fullPath = path18.join(dir, item);
35376
35558
  const relativePath = `${basePath}/${item}`;
35377
- const stat = await import_fs_extra15.default.stat(fullPath);
35559
+ const stat = await import_fs_extra16.default.stat(fullPath);
35378
35560
  if (stat.isDirectory()) {
35379
35561
  files.push(relativePath);
35380
35562
  const subFiles = await listLocalFilesRecursive(fullPath, relativePath);
@@ -35387,7 +35569,7 @@ async function listLocalFilesRecursive(dir, basePath) {
35387
35569
  }
35388
35570
  async function analyzeCategory(category, claudeDir, githubToken) {
35389
35571
  const items = [];
35390
- const localDir = path17.join(claudeDir, category);
35572
+ const localDir = path18.join(claudeDir, category);
35391
35573
  const remoteFiles = await listRemoteFilesRecursive(category, githubToken);
35392
35574
  const localFiles = await listLocalFiles(localDir);
35393
35575
  const remoteSet = new Map;
@@ -35396,7 +35578,7 @@ async function analyzeCategory(category, claudeDir, githubToken) {
35396
35578
  }
35397
35579
  const localSet = new Set(localFiles);
35398
35580
  for (const [remotePath, { sha, isFolder }] of remoteSet) {
35399
- const localPath = path17.join(localDir, remotePath);
35581
+ const localPath = path18.join(localDir, remotePath);
35400
35582
  if (isFolder) {
35401
35583
  continue;
35402
35584
  }
@@ -35428,8 +35610,8 @@ async function analyzeCategory(category, claudeDir, githubToken) {
35428
35610
  }
35429
35611
  for (const localPath of localSet) {
35430
35612
  if (!remoteSet.has(localPath)) {
35431
- const fullPath = path17.join(localDir, localPath);
35432
- const stat = await import_fs_extra15.default.stat(fullPath).catch(() => null);
35613
+ const fullPath = path18.join(localDir, localPath);
35614
+ const stat = await import_fs_extra16.default.stat(fullPath).catch(() => null);
35433
35615
  if (stat && !stat.isDirectory()) {
35434
35616
  items.push({
35435
35617
  name: localPath,
@@ -35460,9 +35642,9 @@ async function fetchRemoteSettings(githubToken) {
35460
35642
  }
35461
35643
  }
35462
35644
  async function getLocalSettings(claudeDir) {
35463
- const settingsPath = path17.join(claudeDir, "settings.json");
35645
+ const settingsPath = path18.join(claudeDir, "settings.json");
35464
35646
  try {
35465
- const content = await import_fs_extra15.default.readFile(settingsPath, "utf-8");
35647
+ const content = await import_fs_extra16.default.readFile(settingsPath, "utf-8");
35466
35648
  return JSON.parse(content);
35467
35649
  } catch {
35468
35650
  return {};
@@ -35543,8 +35725,8 @@ async function downloadFromPrivateGitHub2(relativePath, targetPath, githubToken)
35543
35725
  return false;
35544
35726
  }
35545
35727
  const content = await response.arrayBuffer();
35546
- await import_fs_extra15.default.ensureDir(path17.dirname(targetPath));
35547
- await import_fs_extra15.default.writeFile(targetPath, Buffer.from(content));
35728
+ await import_fs_extra16.default.ensureDir(path18.dirname(targetPath));
35729
+ await import_fs_extra16.default.writeFile(targetPath, Buffer.from(content));
35548
35730
  return true;
35549
35731
  } catch {
35550
35732
  return false;
@@ -35554,10 +35736,10 @@ async function syncSelectedHooks(claudeDir, hooks, onProgress) {
35554
35736
  if (hooks.length === 0) {
35555
35737
  return { success: 0, failed: 0 };
35556
35738
  }
35557
- const settingsPath = path17.join(claudeDir, "settings.json");
35739
+ const settingsPath = path18.join(claudeDir, "settings.json");
35558
35740
  let settings = {};
35559
35741
  try {
35560
- const content = await import_fs_extra15.default.readFile(settingsPath, "utf-8");
35742
+ const content = await import_fs_extra16.default.readFile(settingsPath, "utf-8");
35561
35743
  settings = JSON.parse(content);
35562
35744
  } catch {
35563
35745
  settings = {};
@@ -35574,17 +35756,18 @@ async function syncSelectedHooks(claudeDir, hooks, onProgress) {
35574
35756
  settings.hooks[hook.hookType] = [];
35575
35757
  }
35576
35758
  const existingIndex = settings.hooks[hook.hookType].findIndex((h2) => h2.matcher === hook.matcher);
35759
+ const transformedHook = transformHook(hook.remoteHook, claudeDir);
35577
35760
  if (existingIndex >= 0) {
35578
- settings.hooks[hook.hookType][existingIndex] = hook.remoteHook;
35761
+ settings.hooks[hook.hookType][existingIndex] = transformedHook;
35579
35762
  } else {
35580
- settings.hooks[hook.hookType].push(hook.remoteHook);
35763
+ settings.hooks[hook.hookType].push(transformedHook);
35581
35764
  }
35582
35765
  success++;
35583
35766
  } catch {
35584
35767
  failed++;
35585
35768
  }
35586
35769
  }
35587
- await import_fs_extra15.default.writeFile(settingsPath, JSON.stringify(settings, null, 2));
35770
+ await import_fs_extra16.default.writeFile(settingsPath, JSON.stringify(settings, null, 2));
35588
35771
  return { success, failed };
35589
35772
  }
35590
35773
  async function syncSelectedItems(claudeDir, items, githubToken, onProgress) {
@@ -35592,11 +35775,11 @@ async function syncSelectedItems(claudeDir, items, githubToken, onProgress) {
35592
35775
  let failed = 0;
35593
35776
  let deleted = 0;
35594
35777
  for (const item of items) {
35595
- const targetPath = path17.join(claudeDir, item.relativePath);
35778
+ const targetPath = path18.join(claudeDir, item.relativePath);
35596
35779
  if (item.status === "deleted") {
35597
35780
  onProgress?.(item.relativePath, "deleting");
35598
35781
  try {
35599
- await import_fs_extra15.default.remove(targetPath);
35782
+ await import_fs_extra16.default.remove(targetPath);
35600
35783
  deleted++;
35601
35784
  } catch {
35602
35785
  failed++;
@@ -35747,7 +35930,7 @@ async function proSyncCommand(options = {}) {
35747
35930
  $e(source_default.red("❌ Not activated"));
35748
35931
  process.exit(1);
35749
35932
  }
35750
- const claudeDir = options.folder ? path18.resolve(options.folder) : path18.join(os11.homedir(), ".claude");
35933
+ const claudeDir = options.folder ? path19.resolve(options.folder) : path19.join(os12.homedir(), ".claude");
35751
35934
  const spinner = de();
35752
35935
  spinner.start("Analyzing changes...");
35753
35936
  const result = await analyzeSyncChanges(claudeDir, githubToken);
@@ -35769,8 +35952,8 @@ async function proSyncCommand(options = {}) {
35769
35952
  f2.message(source_default.cyan.bold(` ${category.toUpperCase()}`));
35770
35953
  if (folderedCategories.includes(category)) {
35771
35954
  const folderSummaries = aggregateByTopLevelFolder(items);
35772
- for (const summary2 of folderSummaries) {
35773
- f2.message(` ${formatFolderSummary(summary2)}`);
35955
+ for (const summary of folderSummaries) {
35956
+ f2.message(` ${formatFolderSummary(summary)}`);
35774
35957
  }
35775
35958
  } else {
35776
35959
  for (const item of items) {
@@ -35790,19 +35973,70 @@ async function proSyncCommand(options = {}) {
35790
35973
  }
35791
35974
  f2.message("");
35792
35975
  const choices = createSelectionChoices(changedItems, changedHooks);
35793
- const selected = await ae({
35794
- message: "Select items to sync:",
35795
- options: choices,
35796
- initialValues: choices.map((c2) => c2.value),
35797
- required: false
35976
+ const newItems = changedItems.filter((i) => i.status === "new");
35977
+ const modifiedItems = changedItems.filter((i) => i.status === "modified");
35978
+ const deletedItems = changedItems.filter((i) => i.status === "deleted");
35979
+ const newHooks = changedHooks.filter((h2) => h2.status === "new");
35980
+ const modifiedHooks = changedHooks.filter((h2) => h2.status === "modified");
35981
+ const hasDeletions = deletedItems.length > 0;
35982
+ const syncModeOptions = [
35983
+ {
35984
+ value: "updates",
35985
+ label: "Import all updates",
35986
+ hint: `add ${newItems.length + newHooks.length} + update ${modifiedItems.length + modifiedHooks.length} files`
35987
+ }
35988
+ ];
35989
+ if (hasDeletions) {
35990
+ syncModeOptions.push({
35991
+ value: "updates_and_delete",
35992
+ label: "Import all updates and delete files",
35993
+ hint: `add ${newItems.length + newHooks.length} + update ${modifiedItems.length + modifiedHooks.length} + delete ${deletedItems.length} files`
35994
+ });
35995
+ }
35996
+ syncModeOptions.push({
35997
+ value: "custom",
35998
+ label: "Custom choice",
35999
+ hint: "select specific files to sync"
35798
36000
  });
35799
- if (lD(selected)) {
36001
+ const syncMode = await ie({
36002
+ message: "How would you like to sync?",
36003
+ options: syncModeOptions
36004
+ });
36005
+ if (lD(syncMode)) {
35800
36006
  ue("Sync cancelled");
35801
36007
  process.exit(0);
35802
36008
  }
35803
- const expanded = expandSelections(selected);
35804
- const selectedItems = expanded.items;
35805
- const selectedHooks = expanded.hooks;
36009
+ let selectedItems = [];
36010
+ let selectedHooks = [];
36011
+ if (syncMode === "updates") {
36012
+ selectedItems = [...newItems, ...modifiedItems];
36013
+ selectedHooks = [...newHooks, ...modifiedHooks];
36014
+ } else if (syncMode === "updates_and_delete") {
36015
+ selectedItems = [...newItems, ...modifiedItems, ...deletedItems];
36016
+ selectedHooks = [...newHooks, ...modifiedHooks];
36017
+ } else {
36018
+ const nonDeleteChoices = choices.filter((c2) => {
36019
+ if (c2.value.type === "file")
36020
+ return c2.value.item.status !== "deleted";
36021
+ if (c2.value.type === "folder")
36022
+ return !c2.value.items.every((i) => i.status === "deleted");
36023
+ return true;
36024
+ });
36025
+ const nonDeleteInitialValues = nonDeleteChoices.map((c2) => c2.value);
36026
+ const customSelected = await ae({
36027
+ message: "Select items to sync (deletions excluded by default):",
36028
+ options: choices,
36029
+ initialValues: nonDeleteInitialValues,
36030
+ required: false
36031
+ });
36032
+ if (lD(customSelected)) {
36033
+ ue("Sync cancelled");
36034
+ process.exit(0);
36035
+ }
36036
+ const expanded = expandSelections(customSelected);
36037
+ selectedItems = expanded.items;
36038
+ selectedHooks = expanded.hooks;
36039
+ }
35806
36040
  if (selectedItems.length === 0 && selectedHooks.length === 0) {
35807
36041
  f2.warn("No items selected");
35808
36042
  $e(source_default.yellow("⚠️ Nothing to sync"));
@@ -35811,19 +36045,31 @@ async function proSyncCommand(options = {}) {
35811
36045
  const toAdd = selectedItems.filter((i) => i.status === "new").length + selectedHooks.filter((h2) => h2.status === "new").length;
35812
36046
  const toUpdate = selectedItems.filter((i) => i.status === "modified").length + selectedHooks.filter((h2) => h2.status === "modified").length;
35813
36047
  const toRemove = selectedItems.filter((i) => i.status === "deleted").length;
35814
- const summary = [
35815
- toAdd > 0 ? `add ${toAdd}` : "",
35816
- toUpdate > 0 ? `update ${toUpdate}` : "",
35817
- toRemove > 0 ? `remove ${toRemove}` : ""
35818
- ].filter(Boolean).join(", ");
36048
+ f2.message("");
36049
+ f2.message(source_default.bold("What will happen:"));
36050
+ if (toAdd > 0)
36051
+ f2.message(source_default.green(` ✓ Add ${toAdd} new file${toAdd > 1 ? "s" : ""}`));
36052
+ if (toUpdate > 0)
36053
+ f2.message(source_default.yellow(` ✓ Update ${toUpdate} file${toUpdate > 1 ? "s" : ""}`));
36054
+ if (toRemove > 0)
36055
+ f2.message(source_default.red(` ✓ Delete ${toRemove} file${toRemove > 1 ? "s" : ""}`));
36056
+ f2.message(source_default.gray(` ✓ Backup current config to ~/.config/aiblueprint/backup/`));
36057
+ f2.message("");
35819
36058
  const confirmResult = await se({
35820
- message: `Proceed? (${summary})`,
36059
+ message: "Proceed with sync?",
35821
36060
  initialValue: true
35822
36061
  });
35823
36062
  if (lD(confirmResult) || !confirmResult) {
35824
36063
  ue("Sync cancelled");
35825
36064
  process.exit(0);
35826
36065
  }
36066
+ spinner.start("Creating backup...");
36067
+ const backupPath = await createBackup(claudeDir);
36068
+ if (backupPath) {
36069
+ spinner.stop(`Backup created: ${source_default.gray(backupPath)}`);
36070
+ } else {
36071
+ spinner.stop("No existing config to backup");
36072
+ }
35827
36073
  spinner.start("Syncing...");
35828
36074
  const syncResult = await syncSelectedItems(claudeDir, selectedItems, githubToken, (file, action) => {
35829
36075
  spinner.message(`${action}: ${source_default.cyan(file)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiblueprint-cli",
3
- "version": "1.3.6",
3
+ "version": "1.4.1",
4
4
  "description": "AIBlueprint CLI for setting up Claude Code configurations",
5
5
  "author": "AIBlueprint",
6
6
  "license": "MIT",