aiblueprint-cli 1.2.3 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -32490,7 +32490,7 @@ var lib_default = inquirer;
32490
32490
  // src/commands/setup.ts
32491
32491
  var import_fs_extra5 = __toESM(require_lib4(), 1);
32492
32492
  import path7 from "path";
32493
- import os5 from "os";
32493
+ import os7 from "os";
32494
32494
 
32495
32495
  // node_modules/chalk/source/vendor/ansi-styles/index.js
32496
32496
  var ANSI_BACKGROUND_OFFSET = 10;
@@ -32994,8 +32994,14 @@ async function setupShellShortcuts() {
32994
32994
  try {
32995
32995
  const platform = os3.platform();
32996
32996
  let shellConfigFile;
32997
+ let aliases;
32997
32998
  if (platform === "darwin") {
32998
32999
  shellConfigFile = path2.join(os3.homedir(), ".zshenv");
33000
+ aliases = `
33001
+ # AIBlueprint Claude Code aliases
33002
+ alias cc="claude --dangerously-skip-permissions"
33003
+ alias ccc="claude --dangerously-skip-permissions -c"
33004
+ `;
32999
33005
  } else if (platform === "linux") {
33000
33006
  const shell = process.env.SHELL || "";
33001
33007
  if (shell.includes("zsh")) {
@@ -33003,17 +33009,35 @@ async function setupShellShortcuts() {
33003
33009
  } else {
33004
33010
  shellConfigFile = path2.join(os3.homedir(), ".bashrc");
33005
33011
  }
33006
- } else {
33007
- console.log(source_default.yellow("Shell shortcuts are only supported on macOS and Linux"));
33008
- return;
33009
- }
33010
- const aliases = `
33012
+ aliases = `
33011
33013
  # AIBlueprint Claude Code aliases
33012
33014
  alias cc="claude --dangerously-skip-permissions"
33013
33015
  alias ccc="claude --dangerously-skip-permissions -c"
33014
33016
  `;
33017
+ } else if (platform === "win32") {
33018
+ const pwshProfileDir = path2.join(os3.homedir(), "Documents", "PowerShell");
33019
+ const windowsPwshProfileDir = path2.join(os3.homedir(), "Documents", "WindowsPowerShell");
33020
+ let profileDir;
33021
+ if (await import_fs_extra.default.pathExists(pwshProfileDir)) {
33022
+ profileDir = pwshProfileDir;
33023
+ } else if (await import_fs_extra.default.pathExists(windowsPwshProfileDir)) {
33024
+ profileDir = windowsPwshProfileDir;
33025
+ } else {
33026
+ profileDir = pwshProfileDir;
33027
+ await import_fs_extra.default.ensureDir(profileDir);
33028
+ }
33029
+ shellConfigFile = path2.join(profileDir, "Profile.ps1");
33030
+ aliases = `
33031
+ # AIBlueprint Claude Code shortcuts
33032
+ function cc { claude --dangerously-skip-permissions $args }
33033
+ function ccc { claude --dangerously-skip-permissions -c $args }
33034
+ `;
33035
+ } else {
33036
+ console.log(source_default.yellow(`Shell shortcuts are not supported on platform: ${platform}`));
33037
+ return;
33038
+ }
33015
33039
  const existingContent = await import_fs_extra.default.readFile(shellConfigFile, "utf-8").catch(() => "");
33016
- if (!existingContent.includes("AIBlueprint Claude Code aliases")) {
33040
+ if (!existingContent.includes("AIBlueprint Claude Code")) {
33017
33041
  await import_fs_extra.default.appendFile(shellConfigFile, aliases);
33018
33042
  }
33019
33043
  } catch (error) {
@@ -33078,7 +33102,12 @@ async function createSymlink(sourcePath, targetPath, options = {}) {
33078
33102
  return false;
33079
33103
  }
33080
33104
  }
33081
- await import_fs_extra2.default.symlink(sourcePath, targetPath);
33105
+ const isWindows = os4.platform() === "win32";
33106
+ if (isWindows) {
33107
+ await import_fs_extra2.default.symlink(sourcePath, targetPath, "junction");
33108
+ } else {
33109
+ await import_fs_extra2.default.symlink(sourcePath, targetPath);
33110
+ }
33082
33111
  return true;
33083
33112
  } catch (error) {
33084
33113
  console.error(source_default.red(options.errorPrefix || "Error creating symlink:"), error);
@@ -33131,10 +33160,13 @@ async function setupOpenCodeSymlink(claudeDir, customOpenCodeFolder, customClaud
33131
33160
  // src/commands/setup/dependencies.ts
33132
33161
  import { execSync } from "child_process";
33133
33162
  import path4 from "path";
33163
+ import os5 from "os";
33134
33164
  async function checkAndInstallDependencies() {
33165
+ const isWindows = os5.platform() === "win32";
33135
33166
  const checkCommand = (cmd) => {
33136
33167
  try {
33137
- execSync(`which ${cmd}`, { stdio: "ignore" });
33168
+ const whichCmd = isWindows ? `where ${cmd}` : `which ${cmd}`;
33169
+ execSync(whichCmd, { stdio: "ignore" });
33138
33170
  return true;
33139
33171
  } catch {
33140
33172
  return false;
@@ -33177,6 +33209,27 @@ async function installStatuslineDependencies(claudeDir) {
33177
33209
  // src/commands/setup/settings.ts
33178
33210
  var import_fs_extra3 = __toESM(require_lib4(), 1);
33179
33211
  import path5 from "path";
33212
+ import os6 from "os";
33213
+ function getPlaySoundCommand(soundPath) {
33214
+ const platform = os6.platform();
33215
+ if (platform === "darwin") {
33216
+ return `afplay -v 0.1 "${soundPath}"`;
33217
+ } else if (platform === "win32") {
33218
+ return `powershell -c "(New-Object Media.SoundPlayer '${soundPath}').PlaySync()"`;
33219
+ } else {
33220
+ return `paplay "${soundPath}" 2>/dev/null || aplay "${soundPath}" 2>/dev/null || true`;
33221
+ }
33222
+ }
33223
+ async function hasExistingStatusLine(claudeDir) {
33224
+ const settingsPath = path5.join(claudeDir, "settings.json");
33225
+ try {
33226
+ const existingSettings = await import_fs_extra3.default.readFile(settingsPath, "utf-8");
33227
+ const settings = JSON.parse(existingSettings);
33228
+ return !!settings.statusLine;
33229
+ } catch {
33230
+ return false;
33231
+ }
33232
+ }
33180
33233
  async function updateSettings(options, claudeDir) {
33181
33234
  const settingsPath = path5.join(claudeDir, "settings.json");
33182
33235
  let settings = {};
@@ -33186,24 +33239,8 @@ async function updateSettings(options, claudeDir) {
33186
33239
  } catch {
33187
33240
  }
33188
33241
  if (options.customStatusline) {
33189
- if (settings.statusLine) {
33190
- const confirmAnswer = await lib_default.prompt([
33191
- {
33192
- type: "confirm",
33193
- name: "replace",
33194
- message: "You already have a statusLine configuration. Replace it?"
33195
- }
33196
- ]);
33197
- if (!confirmAnswer.replace) {
33198
- console.log(source_default.yellow(" Keeping existing statusLine configuration"));
33199
- } else {
33200
- settings.statusLine = {
33201
- type: "command",
33202
- command: `bun ${path5.join(claudeDir, "scripts/statusline/src/index.ts")}`,
33203
- padding: 0
33204
- };
33205
- }
33206
- } else {
33242
+ const shouldReplace = options.replaceStatusline !== false;
33243
+ if (shouldReplace) {
33207
33244
  settings.statusLine = {
33208
33245
  type: "command",
33209
33246
  command: `bun ${path5.join(claudeDir, "scripts/statusline/src/index.ts")}`,
@@ -33236,12 +33273,13 @@ async function updateSettings(options, claudeDir) {
33236
33273
  if (!settings.hooks.Stop) {
33237
33274
  settings.hooks.Stop = [];
33238
33275
  }
33276
+ const finishSoundPath = path5.join(claudeDir, "song/finish.mp3");
33239
33277
  const stopHook = {
33240
33278
  matcher: "",
33241
33279
  hooks: [
33242
33280
  {
33243
33281
  type: "command",
33244
- command: `afplay -v 0.1 ${path5.join(claudeDir, "song/finish.mp3")}`
33282
+ command: getPlaySoundCommand(finishSoundPath)
33245
33283
  }
33246
33284
  ]
33247
33285
  };
@@ -33252,12 +33290,13 @@ async function updateSettings(options, claudeDir) {
33252
33290
  if (!settings.hooks.Notification) {
33253
33291
  settings.hooks.Notification = [];
33254
33292
  }
33293
+ const needHumanSoundPath = path5.join(claudeDir, "song/need-human.mp3");
33255
33294
  const notificationHook = {
33256
33295
  matcher: "",
33257
33296
  hooks: [
33258
33297
  {
33259
33298
  type: "command",
33260
- command: `afplay -v 0.1 ${path5.join(claudeDir, "song/need-human.mp3")}`
33299
+ command: getPlaySoundCommand(needHumanSoundPath)
33261
33300
  }
33262
33301
  ]
33263
33302
  };
@@ -33322,24 +33361,35 @@ async function downloadDirectoryFromGitHub(dirPath, targetDir) {
33322
33361
  const apiUrl = `https://api.github.com/repos/Melvynx/aiblueprint-cli/contents/claude-code-config/${dirPath}`;
33323
33362
  const response = await fetch(apiUrl);
33324
33363
  if (!response.ok) {
33364
+ console.error(source_default.yellow(` Warning: Failed to fetch directory from GitHub: ${dirPath} (HTTP ${response.status})`));
33325
33365
  return false;
33326
33366
  }
33327
33367
  const files = await response.json();
33328
33368
  if (!Array.isArray(files)) {
33369
+ console.error(source_default.yellow(` Warning: Invalid response from GitHub API for: ${dirPath}`));
33329
33370
  return false;
33330
33371
  }
33331
33372
  await import_fs_extra4.default.ensureDir(targetDir);
33373
+ let allSuccess = true;
33332
33374
  for (const file of files) {
33333
33375
  const relativePath = `${dirPath}/${file.name}`;
33334
33376
  const targetPath = path6.join(targetDir, file.name);
33335
33377
  if (file.type === "file") {
33336
- await downloadFromGitHub(relativePath, targetPath);
33378
+ const success = await downloadFromGitHub(relativePath, targetPath);
33379
+ if (!success) {
33380
+ console.error(source_default.yellow(` Warning: Failed to download file: ${relativePath}`));
33381
+ allSuccess = false;
33382
+ }
33337
33383
  } else if (file.type === "dir") {
33338
- await downloadDirectoryFromGitHub(relativePath, targetPath);
33384
+ const success = await downloadDirectoryFromGitHub(relativePath, targetPath);
33385
+ if (!success) {
33386
+ allSuccess = false;
33387
+ }
33339
33388
  }
33340
33389
  }
33341
- return true;
33390
+ return allSuccess;
33342
33391
  } catch (error) {
33392
+ console.error(source_default.yellow(` Warning: Error downloading directory ${dirPath}: ${error instanceof Error ? error.message : String(error)}`));
33343
33393
  return false;
33344
33394
  }
33345
33395
  }
@@ -33443,10 +33493,11 @@ async function setupCommand(params = {}) {
33443
33493
  notificationSounds: features.includes("notificationSounds"),
33444
33494
  postEditTypeScript: features.includes("postEditTypeScript"),
33445
33495
  codexSymlink: features.includes("codexSymlink"),
33446
- openCodeSymlink: features.includes("openCodeSymlink")
33496
+ openCodeSymlink: features.includes("openCodeSymlink"),
33497
+ skipInteractive
33447
33498
  };
33448
33499
  const s = new SimpleSpinner;
33449
- const claudeDir = customClaudeCodeFolder ? path7.resolve(customClaudeCodeFolder) : path7.join(os5.homedir(), ".claude");
33500
+ const claudeDir = customClaudeCodeFolder ? path7.resolve(customClaudeCodeFolder) : path7.join(os7.homedir(), ".claude");
33450
33501
  console.log(source_default.gray(`Installing to: ${claudeDir}`));
33451
33502
  await import_fs_extra5.default.ensureDir(claudeDir);
33452
33503
  let useGitHub = true;
@@ -33577,6 +33628,23 @@ async function setupCommand(params = {}) {
33577
33628
  await installStatuslineDependencies(claudeDir);
33578
33629
  s.stop("Statusline dependencies installed");
33579
33630
  }
33631
+ if (options.customStatusline && !skipInteractive) {
33632
+ const existingStatusLine = await hasExistingStatusLine(claudeDir);
33633
+ if (existingStatusLine) {
33634
+ const confirmAnswer = await lib_default.prompt([
33635
+ {
33636
+ type: "confirm",
33637
+ name: "replace",
33638
+ message: "You already have a statusLine configuration. Replace it?",
33639
+ default: true
33640
+ }
33641
+ ]);
33642
+ options.replaceStatusline = confirmAnswer.replace;
33643
+ if (!confirmAnswer.replace) {
33644
+ console.log(source_default.yellow(" Keeping existing statusLine configuration"));
33645
+ }
33646
+ }
33647
+ }
33580
33648
  s.start("Updating settings.json");
33581
33649
  await updateSettings(options, claudeDir);
33582
33650
  s.stop("Settings updated");
@@ -33584,7 +33652,12 @@ async function setupCommand(params = {}) {
33584
33652
  console.log(source_default.gray(`
33585
33653
  Next steps:`));
33586
33654
  if (options.shellShortcuts) {
33587
- console.log(source_default.gray(" • Restart your terminal or run: source ~/.zshenv (macOS) or source ~/.bashrc (Linux)"));
33655
+ const platform = os7.platform();
33656
+ if (platform === "win32") {
33657
+ console.log(source_default.gray(" • Restart PowerShell to load the new functions"));
33658
+ } else {
33659
+ console.log(source_default.gray(" • Restart your terminal or run: source ~/.zshenv (macOS) or source ~/.bashrc (Linux)"));
33660
+ }
33588
33661
  console.log(source_default.gray(' • Use "cc" for Claude Code with permissions skipped'));
33589
33662
  console.log(source_default.gray(' • Use "ccc" for Claude Code with permissions skipped and continue mode'));
33590
33663
  }
@@ -33692,15 +33765,24 @@ async function listFilesFromGitHub(dirPath) {
33692
33765
  if (!response.ok) {
33693
33766
  return [];
33694
33767
  }
33695
- const files = await response.json();
33696
- return files.filter((file) => file.type === "file").map((file) => file.name);
33768
+ const items = await response.json();
33769
+ const files = [];
33770
+ for (const item of items) {
33771
+ if (item.type === "file") {
33772
+ files.push(item.name);
33773
+ } else if (item.type === "dir") {
33774
+ const subFiles = await listFilesFromGitHub(`${dirPath}/${item.name}`);
33775
+ files.push(...subFiles.map((f) => `${item.name}/${f}`));
33776
+ }
33777
+ }
33778
+ return files;
33697
33779
  } catch (error) {
33698
33780
  return [];
33699
33781
  }
33700
33782
  }
33701
33783
  async function isGitHubAvailable() {
33702
33784
  try {
33703
- const testUrl = `${GITHUB_RAW_BASE3}/commands/commit.md`;
33785
+ const testUrl = `${GITHUB_RAW_BASE3}/commands/apex.md`;
33704
33786
  const testResponse = await fetch(testUrl);
33705
33787
  return testResponse.ok;
33706
33788
  } catch {
@@ -33894,6 +33976,20 @@ class SimpleSpinner3 {
33894
33976
  console.log(source_default.green(`✓ ${message}`));
33895
33977
  }
33896
33978
  }
33979
+ async function getLocalMdFilesRecursively(dir, basePath = "") {
33980
+ const files = [];
33981
+ const entries = await import_fs_extra10.default.readdir(dir, { withFileTypes: true });
33982
+ for (const entry of entries) {
33983
+ const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
33984
+ if (entry.isDirectory()) {
33985
+ const subFiles = await getLocalMdFilesRecursively(path12.join(dir, entry.name), relativePath);
33986
+ files.push(...subFiles);
33987
+ } else if (entry.name.endsWith(".md")) {
33988
+ files.push(relativePath);
33989
+ }
33990
+ }
33991
+ return files;
33992
+ }
33897
33993
  async function discoverAvailableCommands() {
33898
33994
  const commands = {};
33899
33995
  const useGitHub = await isGitHubAvailable();
@@ -33906,8 +34002,7 @@ async function discoverAvailableCommands() {
33906
34002
  if (!commandsDir) {
33907
34003
  throw new Error("Commands directory not found");
33908
34004
  }
33909
- const files = await import_fs_extra10.default.readdir(commandsDir);
33910
- mdFiles = files.filter((file) => file.endsWith(".md"));
34005
+ mdFiles = await getLocalMdFilesRecursively(commandsDir);
33911
34006
  }
33912
34007
  for (const file of mdFiles) {
33913
34008
  const commandName = file.replace(".md", "");
@@ -33915,7 +34010,7 @@ async function discoverAvailableCommands() {
33915
34010
  const content = await getFileContentWithGitHubFallback("commands", file);
33916
34011
  const { metadata } = parseYamlFrontmatter(content);
33917
34012
  commands[commandName] = {
33918
- name: commandName.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
34013
+ name: commandName.split("/").map((part) => part.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase())).join("/"),
33919
34014
  description: metadata.description || "No description available",
33920
34015
  allowedTools: metadata["allowed-tools"],
33921
34016
  argumentHint: metadata["argument-hint"],
@@ -34535,6 +34630,59 @@ class x {
34535
34630
  }
34536
34631
  }
34537
34632
  }
34633
+
34634
+ class BD extends x {
34635
+ get cursor() {
34636
+ return this.value ? 0 : 1;
34637
+ }
34638
+ get _value() {
34639
+ return this.cursor === 0;
34640
+ }
34641
+ constructor(u) {
34642
+ super(u, false), this.value = !!u.initialValue, this.on("value", () => {
34643
+ this.value = this._value;
34644
+ }), this.on("confirm", (F) => {
34645
+ this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = F, this.state = "submit", this.close();
34646
+ }), this.on("cursor", () => {
34647
+ this.value = !this.value;
34648
+ });
34649
+ }
34650
+ }
34651
+ var fD = Object.defineProperty;
34652
+ var gD = (e, u, F) => (u in e) ? fD(e, u, { enumerable: true, configurable: true, writable: true, value: F }) : e[u] = F;
34653
+ var K = (e, u, F) => (gD(e, typeof u != "symbol" ? u + "" : u, F), F);
34654
+ var vD = class extends x {
34655
+ constructor(u) {
34656
+ super(u, false), K(this, "options"), K(this, "cursor", 0), this.options = u.options, this.value = [...u.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: F }) => F === u.cursorAt), 0), this.on("key", (F) => {
34657
+ F === "a" && this.toggleAll();
34658
+ }), this.on("cursor", (F) => {
34659
+ switch (F) {
34660
+ case "left":
34661
+ case "up":
34662
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
34663
+ break;
34664
+ case "down":
34665
+ case "right":
34666
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
34667
+ break;
34668
+ case "space":
34669
+ this.toggleValue();
34670
+ break;
34671
+ }
34672
+ });
34673
+ }
34674
+ get _value() {
34675
+ return this.options[this.cursor].value;
34676
+ }
34677
+ toggleAll() {
34678
+ const u = this.value.length === this.options.length;
34679
+ this.value = u ? [] : this.options.map((F) => F.value);
34680
+ }
34681
+ toggleValue() {
34682
+ const u = this.value.includes(this._value);
34683
+ this.value = u ? this.value.filter((F) => F !== this._value) : [...this.value, this._value];
34684
+ }
34685
+ };
34538
34686
  var TD = Object.defineProperty;
34539
34687
  var jD = (e, u, F) => (u in e) ? TD(e, u, { enumerable: true, configurable: true, writable: true, value: F }) : e[u] = F;
34540
34688
  var MD = (e, u, F) => (jD(e, typeof u != "symbol" ? u + "" : u, F), F);
@@ -34592,7 +34740,7 @@ var H = o("◆", "*");
34592
34740
  var I2 = o("■", "x");
34593
34741
  var x2 = o("▲", "x");
34594
34742
  var S2 = o("◇", "o");
34595
- var K = o("┌", "T");
34743
+ var K2 = o("┌", "T");
34596
34744
  var a2 = o("│", "|");
34597
34745
  var d2 = o("└", "—");
34598
34746
  var b2 = o("●", ">");
@@ -34643,13 +34791,76 @@ ${import_picocolors2.default.cyan(d2)}
34643
34791
  `;
34644
34792
  }
34645
34793
  } }).prompt();
34794
+ var se = (r2) => {
34795
+ const n = r2.active ?? "Yes", i = r2.inactive ?? "No";
34796
+ return new BD({ active: n, inactive: i, initialValue: r2.initialValue ?? true, render() {
34797
+ const t = `${import_picocolors2.default.gray(a2)}
34798
+ ${y2(this.state)} ${r2.message}
34799
+ `, s = this.value ? n : i;
34800
+ switch (this.state) {
34801
+ case "submit":
34802
+ return `${t}${import_picocolors2.default.gray(a2)} ${import_picocolors2.default.dim(s)}`;
34803
+ case "cancel":
34804
+ return `${t}${import_picocolors2.default.gray(a2)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
34805
+ ${import_picocolors2.default.gray(a2)}`;
34806
+ default:
34807
+ return `${t}${import_picocolors2.default.cyan(a2)} ${this.value ? `${import_picocolors2.default.green(b2)} ${n}` : `${import_picocolors2.default.dim(E)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(E)} ${import_picocolors2.default.dim(i)}` : `${import_picocolors2.default.green(b2)} ${i}`}
34808
+ ${import_picocolors2.default.cyan(d2)}
34809
+ `;
34810
+ }
34811
+ } }).prompt();
34812
+ };
34813
+ var ae = (r2) => {
34814
+ const n = (i, t) => {
34815
+ const s = i.label ?? String(i.value);
34816
+ return t === "active" ? `${import_picocolors2.default.cyan(C)} ${s} ${i.hint ? import_picocolors2.default.dim(`(${i.hint})`) : ""}` : t === "selected" ? `${import_picocolors2.default.green(w2)} ${import_picocolors2.default.dim(s)}` : t === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : t === "active-selected" ? `${import_picocolors2.default.green(w2)} ${s} ${i.hint ? import_picocolors2.default.dim(`(${i.hint})`) : ""}` : t === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(M2)} ${import_picocolors2.default.dim(s)}`;
34817
+ };
34818
+ return new vD({ options: r2.options, initialValues: r2.initialValues, required: r2.required ?? true, cursorAt: r2.cursorAt, validate(i) {
34819
+ if (this.required && i.length === 0)
34820
+ return `Please select at least one option.
34821
+ ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
34822
+ }, render() {
34823
+ let i = `${import_picocolors2.default.gray(a2)}
34824
+ ${y2(this.state)} ${r2.message}
34825
+ `;
34826
+ switch (this.state) {
34827
+ case "submit":
34828
+ return `${i}${import_picocolors2.default.gray(a2)} ${this.options.filter(({ value: t }) => this.value.includes(t)).map((t) => n(t, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
34829
+ case "cancel": {
34830
+ const t = this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "cancelled")).join(import_picocolors2.default.dim(", "));
34831
+ return `${i}${import_picocolors2.default.gray(a2)} ${t.trim() ? `${t}
34832
+ ${import_picocolors2.default.gray(a2)}` : ""}`;
34833
+ }
34834
+ case "error": {
34835
+ const t = this.error.split(`
34836
+ `).map((s, c2) => c2 === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(s)}` : ` ${s}`).join(`
34837
+ `);
34838
+ return i + import_picocolors2.default.yellow(a2) + " " + this.options.map((s, c2) => {
34839
+ const l2 = this.value.includes(s.value), u = c2 === this.cursor;
34840
+ return u && l2 ? n(s, "active-selected") : l2 ? n(s, "selected") : n(s, u ? "active" : "inactive");
34841
+ }).join(`
34842
+ ${import_picocolors2.default.yellow(a2)} `) + `
34843
+ ` + t + `
34844
+ `;
34845
+ }
34846
+ default:
34847
+ return `${i}${import_picocolors2.default.cyan(a2)} ${this.options.map((t, s) => {
34848
+ const c2 = this.value.includes(t.value), l2 = s === this.cursor;
34849
+ return l2 && c2 ? n(t, "active-selected") : c2 ? n(t, "selected") : n(t, l2 ? "active" : "inactive");
34850
+ }).join(`
34851
+ ${import_picocolors2.default.cyan(a2)} `)}
34852
+ ${import_picocolors2.default.cyan(d2)}
34853
+ `;
34854
+ }
34855
+ } }).prompt();
34856
+ };
34646
34857
  var ue = (r2 = "") => {
34647
34858
  process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(r2)}
34648
34859
 
34649
34860
  `);
34650
34861
  };
34651
34862
  var oe = (r2 = "") => {
34652
- process.stdout.write(`${import_picocolors2.default.gray(K)} ${r2}
34863
+ process.stdout.write(`${import_picocolors2.default.gray(K2)} ${r2}
34653
34864
  `);
34654
34865
  };
34655
34866
  var $e = (r2 = "") => {
@@ -34708,7 +34919,7 @@ var de = () => {
34708
34919
 
34709
34920
  // src/lib/pro-installer.ts
34710
34921
  var import_fs_extra12 = __toESM(require_lib4(), 1);
34711
- import os6 from "os";
34922
+ import os8 from "os";
34712
34923
  import path14 from "path";
34713
34924
  var PREMIUM_REPO = "Melvynx/aiblueprint-cli-premium";
34714
34925
  var PREMIUM_BRANCH = "main";
@@ -34770,8 +34981,8 @@ async function downloadDirectoryFromPrivateGitHub(repo, branch, dirPath, targetD
34770
34981
  }
34771
34982
  async function installProConfigs(options) {
34772
34983
  const { githubToken, claudeCodeFolder } = options;
34773
- const claudeFolder = claudeCodeFolder || path14.join(os6.homedir(), ".claude");
34774
- const tempDir = path14.join(os6.tmpdir(), `aiblueprint-premium-${Date.now()}`);
34984
+ const claudeFolder = claudeCodeFolder || path14.join(os8.homedir(), ".claude");
34985
+ const tempDir = path14.join(os8.tmpdir(), `aiblueprint-premium-${Date.now()}`);
34775
34986
  try {
34776
34987
  const success = await downloadDirectoryFromPrivateGitHub(PREMIUM_REPO, PREMIUM_BRANCH, "claude-code-config", tempDir, githubToken);
34777
34988
  if (!success) {
@@ -34795,9 +35006,9 @@ async function installProConfigs(options) {
34795
35006
  // src/lib/setup-helper.ts
34796
35007
  var import_fs_extra13 = __toESM(require_lib4(), 1);
34797
35008
  import path15 from "path";
34798
- import os7 from "os";
35009
+ import os9 from "os";
34799
35010
  async function installBasicConfigs(options = {}, skipStatusline = false) {
34800
- const claudeDir = options.claudeCodeFolder || path15.join(os7.homedir(), ".claude");
35011
+ const claudeDir = options.claudeCodeFolder || path15.join(os9.homedir(), ".claude");
34801
35012
  await import_fs_extra13.default.ensureDir(claudeDir);
34802
35013
  console.log(source_default.gray("\uD83D\uDCE6 Installing free configurations..."));
34803
35014
  console.log(source_default.gray(" • Commands..."));
@@ -34814,15 +35025,15 @@ async function installBasicConfigs(options = {}, skipStatusline = false) {
34814
35025
 
34815
35026
  // src/lib/token-storage.ts
34816
35027
  var import_fs_extra14 = __toESM(require_lib4(), 1);
34817
- import os8 from "os";
35028
+ import os10 from "os";
34818
35029
  import path16 from "path";
34819
35030
  function getConfigDir() {
34820
- const platform = os8.platform();
35031
+ const platform = os10.platform();
34821
35032
  if (platform === "win32") {
34822
- const appData = process.env.APPDATA || path16.join(os8.homedir(), "AppData", "Roaming");
35033
+ const appData = process.env.APPDATA || path16.join(os10.homedir(), "AppData", "Roaming");
34823
35034
  return path16.join(appData, "aiblueprint");
34824
35035
  } else {
34825
- const configHome = process.env.XDG_CONFIG_HOME || path16.join(os8.homedir(), ".config");
35036
+ const configHome = process.env.XDG_CONFIG_HOME || path16.join(os10.homedir(), ".config");
34826
35037
  return path16.join(configHome, "aiblueprint");
34827
35038
  }
34828
35039
  }
@@ -34849,7 +35060,7 @@ async function getToken() {
34849
35060
  function getTokenInfo() {
34850
35061
  return {
34851
35062
  path: getTokenFilePath(),
34852
- platform: os8.platform()
35063
+ platform: os10.platform()
34853
35064
  };
34854
35065
  }
34855
35066
 
@@ -35060,6 +35271,348 @@ async function proUpdateCommand(options = {}) {
35060
35271
  }
35061
35272
  }
35062
35273
 
35274
+ // src/commands/sync.ts
35275
+ import os11 from "os";
35276
+ import path19 from "path";
35277
+
35278
+ // src/lib/sync-utils.ts
35279
+ var import_fs_extra16 = __toESM(require_lib4(), 1);
35280
+ import path18 from "path";
35281
+ import crypto from "crypto";
35282
+ var PREMIUM_REPO2 = "Melvynx/aiblueprint-cli-premium";
35283
+ var PREMIUM_BRANCH2 = "main";
35284
+ function computeFileSha(content) {
35285
+ const size = content.length;
35286
+ const header = `blob ${size}\x00`;
35287
+ const fullContent = Buffer.concat([Buffer.from(header), content]);
35288
+ return crypto.createHash("sha1").update(fullContent).digest("hex");
35289
+ }
35290
+ async function listRemoteDirectory(dirPath, githubToken) {
35291
+ const apiUrl = `https://api.github.com/repos/${PREMIUM_REPO2}/contents/claude-code-config/${dirPath}?ref=${PREMIUM_BRANCH2}`;
35292
+ const response = await fetch(apiUrl, {
35293
+ headers: {
35294
+ Authorization: `token ${githubToken}`,
35295
+ Accept: "application/vnd.github.v3+json"
35296
+ }
35297
+ });
35298
+ if (!response.ok) {
35299
+ if (response.status === 404) {
35300
+ return [];
35301
+ }
35302
+ throw new Error(`Failed to list directory ${dirPath}: ${response.status}`);
35303
+ }
35304
+ const files = await response.json();
35305
+ if (!Array.isArray(files)) {
35306
+ return [];
35307
+ }
35308
+ return files;
35309
+ }
35310
+ async function computeLocalFileSha(filePath) {
35311
+ try {
35312
+ const content = await import_fs_extra16.default.readFile(filePath);
35313
+ return computeFileSha(content);
35314
+ } catch {
35315
+ return null;
35316
+ }
35317
+ }
35318
+ async function computeFolderSha(folderPath) {
35319
+ try {
35320
+ if (!await import_fs_extra16.default.pathExists(folderPath)) {
35321
+ return null;
35322
+ }
35323
+ const files = await getAllFilesRecursive(folderPath);
35324
+ if (files.length === 0) {
35325
+ return null;
35326
+ }
35327
+ const hashes = [];
35328
+ for (const file of files.sort()) {
35329
+ const content = await import_fs_extra16.default.readFile(file);
35330
+ hashes.push(computeFileSha(content));
35331
+ }
35332
+ return crypto.createHash("sha1").update(hashes.join("")).digest("hex");
35333
+ } catch {
35334
+ return null;
35335
+ }
35336
+ }
35337
+ async function getAllFilesRecursive(dir) {
35338
+ const files = [];
35339
+ const items = await import_fs_extra16.default.readdir(dir);
35340
+ for (const item of items) {
35341
+ const fullPath = path18.join(dir, item);
35342
+ const stat = await import_fs_extra16.default.stat(fullPath);
35343
+ if (stat.isDirectory()) {
35344
+ const subFiles = await getAllFilesRecursive(fullPath);
35345
+ files.push(...subFiles);
35346
+ } else {
35347
+ files.push(fullPath);
35348
+ }
35349
+ }
35350
+ return files;
35351
+ }
35352
+ async function computeRemoteFolderSha(dirPath, githubToken) {
35353
+ const hashes = [];
35354
+ await collectRemoteFolderHashes(dirPath, githubToken, hashes);
35355
+ hashes.sort();
35356
+ return crypto.createHash("sha1").update(hashes.join("")).digest("hex");
35357
+ }
35358
+ async function collectRemoteFolderHashes(dirPath, githubToken, hashes) {
35359
+ const files = await listRemoteDirectory(dirPath, githubToken);
35360
+ for (const file of files) {
35361
+ if (file.type === "file") {
35362
+ hashes.push(file.sha);
35363
+ } else if (file.type === "dir") {
35364
+ await collectRemoteFolderHashes(`${dirPath}/${file.name}`, githubToken, hashes);
35365
+ }
35366
+ }
35367
+ }
35368
+ async function analyzeSyncChanges(claudeDir, githubToken) {
35369
+ const items = [];
35370
+ const commandsRemote = await listRemoteDirectory("commands", githubToken);
35371
+ for (const file of commandsRemote) {
35372
+ if (file.type === "file" && file.name.endsWith(".md")) {
35373
+ const localPath = path18.join(claudeDir, "commands", file.name);
35374
+ const localSha = await computeLocalFileSha(localPath);
35375
+ let status = "new";
35376
+ if (localSha) {
35377
+ status = localSha === file.sha ? "unchanged" : "modified";
35378
+ }
35379
+ items.push({
35380
+ name: file.name.replace(".md", ""),
35381
+ relativePath: `commands/${file.name}`,
35382
+ type: "file",
35383
+ status,
35384
+ remoteSha: file.sha,
35385
+ localSha: localSha || undefined,
35386
+ category: "commands"
35387
+ });
35388
+ }
35389
+ }
35390
+ const agentsRemote = await listRemoteDirectory("agents", githubToken);
35391
+ for (const file of agentsRemote) {
35392
+ if (file.type === "file" && file.name.endsWith(".md")) {
35393
+ const localPath = path18.join(claudeDir, "agents", file.name);
35394
+ const localSha = await computeLocalFileSha(localPath);
35395
+ let status = "new";
35396
+ if (localSha) {
35397
+ status = localSha === file.sha ? "unchanged" : "modified";
35398
+ }
35399
+ items.push({
35400
+ name: file.name.replace(".md", ""),
35401
+ relativePath: `agents/${file.name}`,
35402
+ type: "file",
35403
+ status,
35404
+ remoteSha: file.sha,
35405
+ localSha: localSha || undefined,
35406
+ category: "agents"
35407
+ });
35408
+ }
35409
+ }
35410
+ const skillsRemote = await listRemoteDirectory("skills", githubToken);
35411
+ if (skillsRemote.length > 0) {
35412
+ const remoteSha = await computeRemoteFolderSha("skills", githubToken);
35413
+ const localSha = await computeFolderSha(path18.join(claudeDir, "skills"));
35414
+ let status = "new";
35415
+ if (localSha) {
35416
+ status = localSha === remoteSha ? "unchanged" : "modified";
35417
+ }
35418
+ items.push({
35419
+ name: "skills",
35420
+ relativePath: "skills",
35421
+ type: "folder",
35422
+ status,
35423
+ remoteSha,
35424
+ localSha: localSha || undefined,
35425
+ category: "skills"
35426
+ });
35427
+ }
35428
+ const scriptsRemote = await listRemoteDirectory("scripts", githubToken);
35429
+ if (scriptsRemote.length > 0) {
35430
+ const remoteSha = await computeRemoteFolderSha("scripts", githubToken);
35431
+ const localSha = await computeFolderSha(path18.join(claudeDir, "scripts"));
35432
+ let status = "new";
35433
+ if (localSha) {
35434
+ status = localSha === remoteSha ? "unchanged" : "modified";
35435
+ }
35436
+ items.push({
35437
+ name: "scripts",
35438
+ relativePath: "scripts",
35439
+ type: "folder",
35440
+ status,
35441
+ remoteSha,
35442
+ localSha: localSha || undefined,
35443
+ category: "scripts"
35444
+ });
35445
+ }
35446
+ return {
35447
+ items,
35448
+ newCount: items.filter((i) => i.status === "new").length,
35449
+ modifiedCount: items.filter((i) => i.status === "modified").length,
35450
+ unchangedCount: items.filter((i) => i.status === "unchanged").length
35451
+ };
35452
+ }
35453
+ async function downloadFromPrivateGitHub2(relativePath, targetPath, githubToken) {
35454
+ try {
35455
+ const url = `https://raw.githubusercontent.com/${PREMIUM_REPO2}/${PREMIUM_BRANCH2}/claude-code-config/${relativePath}`;
35456
+ const response = await fetch(url, {
35457
+ headers: {
35458
+ Authorization: `token ${githubToken}`,
35459
+ Accept: "application/vnd.github.v3.raw"
35460
+ }
35461
+ });
35462
+ if (!response.ok) {
35463
+ return false;
35464
+ }
35465
+ const content = await response.arrayBuffer();
35466
+ await import_fs_extra16.default.ensureDir(path18.dirname(targetPath));
35467
+ await import_fs_extra16.default.writeFile(targetPath, Buffer.from(content));
35468
+ return true;
35469
+ } catch {
35470
+ return false;
35471
+ }
35472
+ }
35473
+ async function downloadDirectoryFromPrivateGitHub2(dirPath, targetDir, githubToken) {
35474
+ try {
35475
+ const files = await listRemoteDirectory(dirPath, githubToken);
35476
+ await import_fs_extra16.default.ensureDir(targetDir);
35477
+ for (const file of files) {
35478
+ const relativePath = `${dirPath}/${file.name}`;
35479
+ const targetPath = path18.join(targetDir, file.name);
35480
+ if (file.type === "file") {
35481
+ await downloadFromPrivateGitHub2(relativePath, targetPath, githubToken);
35482
+ } else if (file.type === "dir") {
35483
+ await downloadDirectoryFromPrivateGitHub2(relativePath, targetPath, githubToken);
35484
+ }
35485
+ }
35486
+ return true;
35487
+ } catch {
35488
+ return false;
35489
+ }
35490
+ }
35491
+ async function syncSelectedItems(claudeDir, items, githubToken) {
35492
+ let success = 0;
35493
+ let failed = 0;
35494
+ for (const item of items) {
35495
+ const targetPath = path18.join(claudeDir, item.relativePath);
35496
+ if (item.type === "file") {
35497
+ const ok = await downloadFromPrivateGitHub2(item.relativePath, targetPath, githubToken);
35498
+ if (ok) {
35499
+ success++;
35500
+ } else {
35501
+ failed++;
35502
+ }
35503
+ } else {
35504
+ const ok = await downloadDirectoryFromPrivateGitHub2(item.relativePath, targetPath, githubToken);
35505
+ if (ok) {
35506
+ success++;
35507
+ } else {
35508
+ failed++;
35509
+ }
35510
+ }
35511
+ }
35512
+ return { success, failed };
35513
+ }
35514
+
35515
+ // src/commands/sync.ts
35516
+ async function proSyncCommand(options = {}) {
35517
+ oe(source_default.blue("\uD83D\uDD04 Sync Premium Configurations"));
35518
+ try {
35519
+ const githubToken = await getToken();
35520
+ if (!githubToken) {
35521
+ f2.error("No token found");
35522
+ f2.info("Run: aiblueprint claude-code pro activate <token>");
35523
+ $e(source_default.red("❌ Not activated"));
35524
+ process.exit(1);
35525
+ }
35526
+ const claudeDir = options.folder ? path19.resolve(options.folder) : path19.join(os11.homedir(), ".claude");
35527
+ const spinner = de();
35528
+ spinner.start("Analyzing changes...");
35529
+ const result = await analyzeSyncChanges(claudeDir, githubToken);
35530
+ spinner.stop("Analysis complete");
35531
+ if (result.newCount === 0 && result.modifiedCount === 0) {
35532
+ f2.success("Everything is up to date!");
35533
+ $e(source_default.green("✅ No changes needed"));
35534
+ return;
35535
+ }
35536
+ f2.info(`Found ${result.newCount} new, ${result.modifiedCount} modified, ${result.unchangedCount} unchanged`);
35537
+ const newItems = result.items.filter((i) => i.status === "new");
35538
+ const modifiedItems = result.items.filter((i) => i.status === "modified");
35539
+ const choices = [];
35540
+ if (newItems.length > 0) {
35541
+ for (const item of newItems) {
35542
+ choices.push({
35543
+ value: item,
35544
+ label: `\uD83C\uDD95 ${item.name}`,
35545
+ hint: `${item.category} (new ${item.type})`
35546
+ });
35547
+ }
35548
+ }
35549
+ if (modifiedItems.length > 0) {
35550
+ for (const item of modifiedItems) {
35551
+ choices.push({
35552
+ value: item,
35553
+ label: `\uD83D\uDCDD ${item.name}`,
35554
+ hint: `${item.category} (modified ${item.type})`
35555
+ });
35556
+ }
35557
+ }
35558
+ const selected = await ae({
35559
+ message: "Select items to sync:",
35560
+ options: choices,
35561
+ initialValues: choices.map((c2) => c2.value),
35562
+ required: false
35563
+ });
35564
+ if (lD(selected)) {
35565
+ ue("Sync cancelled");
35566
+ process.exit(0);
35567
+ }
35568
+ const selectedItems = selected;
35569
+ if (selectedItems.length === 0) {
35570
+ f2.warn("No items selected");
35571
+ $e(source_default.yellow("⚠️ Nothing to sync"));
35572
+ return;
35573
+ }
35574
+ const confirmResult = await se({
35575
+ message: `Sync ${selectedItems.length} item(s)?`,
35576
+ initialValue: true
35577
+ });
35578
+ if (lD(confirmResult) || !confirmResult) {
35579
+ ue("Sync cancelled");
35580
+ process.exit(0);
35581
+ }
35582
+ spinner.start(`Syncing ${selectedItems.length} item(s)...`);
35583
+ const syncResult = await syncSelectedItems(claudeDir, selectedItems, githubToken);
35584
+ spinner.stop("Sync complete");
35585
+ if (syncResult.failed > 0) {
35586
+ f2.warn(`${syncResult.success} succeeded, ${syncResult.failed} failed`);
35587
+ } else {
35588
+ f2.success(`${syncResult.success} item(s) synced successfully`);
35589
+ }
35590
+ const syncedByCategory = {
35591
+ commands: selectedItems.filter((i) => i.category === "commands").length,
35592
+ agents: selectedItems.filter((i) => i.category === "agents").length,
35593
+ skills: selectedItems.filter((i) => i.category === "skills").length,
35594
+ scripts: selectedItems.filter((i) => i.category === "scripts").length
35595
+ };
35596
+ const summary = [];
35597
+ if (syncedByCategory.commands > 0)
35598
+ summary.push(`${syncedByCategory.commands} command(s)`);
35599
+ if (syncedByCategory.agents > 0)
35600
+ summary.push(`${syncedByCategory.agents} agent(s)`);
35601
+ if (syncedByCategory.skills > 0)
35602
+ summary.push("skills folder");
35603
+ if (syncedByCategory.scripts > 0)
35604
+ summary.push("scripts folder");
35605
+ f2.info(`Synced: ${summary.join(", ")}`);
35606
+ $e(source_default.green("✅ Sync completed"));
35607
+ } catch (error) {
35608
+ if (error instanceof Error) {
35609
+ f2.error(error.message);
35610
+ }
35611
+ $e(source_default.red("❌ Sync failed"));
35612
+ process.exit(1);
35613
+ }
35614
+ }
35615
+
35063
35616
  // src/cli.ts
35064
35617
  import { readFileSync as readFileSync2 } from "fs";
35065
35618
  import { dirname as dirname4, join } from "path";
@@ -35124,6 +35677,11 @@ proCmd.command("update").description("Update premium configurations").action((op
35124
35677
  const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
35125
35678
  proUpdateCommand({ folder: claudeCodeFolder });
35126
35679
  });
35680
+ proCmd.command("sync").description("Sync premium configurations with selective update").action((options, command) => {
35681
+ const parentOptions = command.parent.parent.opts();
35682
+ const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
35683
+ proSyncCommand({ folder: claudeCodeFolder });
35684
+ });
35127
35685
  program2.parse(process.argv);
35128
35686
  if (!process.argv.slice(2).length) {
35129
35687
  console.log(source_default.blue("\uD83D\uDE80 AIBlueprint CLI"));