aiblueprint-cli 1.3.5 → 1.3.6

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 +154 -18
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -35324,7 +35324,7 @@ async function listRemoteFilesRecursive(dirPath, githubToken, basePath = "") {
35324
35324
  const results = [];
35325
35325
  const files = await listRemoteDirectory(dirPath, githubToken);
35326
35326
  for (const file of files) {
35327
- if (file.name === "node_modules")
35327
+ if (file.name === "node_modules" || file.name === ".DS_Store")
35328
35328
  continue;
35329
35329
  const relativePath = basePath ? `${basePath}/${file.name}` : file.name;
35330
35330
  if (file.type === "file") {
@@ -35352,7 +35352,7 @@ async function listLocalFiles(dir) {
35352
35352
  }
35353
35353
  const items = await import_fs_extra15.default.readdir(dir);
35354
35354
  for (const item of items) {
35355
- if (item === "node_modules")
35355
+ if (item === "node_modules" || item === ".DS_Store")
35356
35356
  continue;
35357
35357
  const fullPath = path17.join(dir, item);
35358
35358
  const stat = await import_fs_extra15.default.stat(fullPath);
@@ -35370,7 +35370,7 @@ async function listLocalFilesRecursive(dir, basePath) {
35370
35370
  const files = [];
35371
35371
  const items = await import_fs_extra15.default.readdir(dir);
35372
35372
  for (const item of items) {
35373
- if (item === "node_modules")
35373
+ if (item === "node_modules" || item === ".DS_Store")
35374
35374
  continue;
35375
35375
  const fullPath = path17.join(dir, item);
35376
35376
  const relativePath = `${basePath}/${item}`;
@@ -35442,6 +35442,68 @@ async function analyzeCategory(category, claudeDir, githubToken) {
35442
35442
  }
35443
35443
  return items;
35444
35444
  }
35445
+ async function fetchRemoteSettings(githubToken) {
35446
+ try {
35447
+ const url = `https://raw.githubusercontent.com/${PREMIUM_REPO2}/${PREMIUM_BRANCH2}/claude-code-config/settings.json`;
35448
+ const response = await fetch(url, {
35449
+ headers: {
35450
+ Authorization: `token ${githubToken}`,
35451
+ Accept: "application/vnd.github.v3.raw"
35452
+ }
35453
+ });
35454
+ if (!response.ok) {
35455
+ return null;
35456
+ }
35457
+ return await response.json();
35458
+ } catch {
35459
+ return null;
35460
+ }
35461
+ }
35462
+ async function getLocalSettings(claudeDir) {
35463
+ const settingsPath = path17.join(claudeDir, "settings.json");
35464
+ try {
35465
+ const content = await import_fs_extra15.default.readFile(settingsPath, "utf-8");
35466
+ return JSON.parse(content);
35467
+ } catch {
35468
+ return {};
35469
+ }
35470
+ }
35471
+ function analyzeHooksChanges(remoteSettings, localSettings) {
35472
+ const hookItems = [];
35473
+ if (!remoteSettings?.hooks) {
35474
+ return hookItems;
35475
+ }
35476
+ const localHooks = localSettings?.hooks || {};
35477
+ for (const [hookType, remoteHookArray] of Object.entries(remoteSettings.hooks)) {
35478
+ if (!Array.isArray(remoteHookArray))
35479
+ continue;
35480
+ const localHookArray = localHooks[hookType] || [];
35481
+ for (const remoteHook of remoteHookArray) {
35482
+ const matcher = remoteHook.matcher || "";
35483
+ const existingLocal = localHookArray.find((h2) => h2.matcher === matcher);
35484
+ if (!existingLocal) {
35485
+ hookItems.push({
35486
+ hookType,
35487
+ matcher,
35488
+ status: "new",
35489
+ remoteHook
35490
+ });
35491
+ } else {
35492
+ const remoteStr = JSON.stringify(remoteHook);
35493
+ const localStr = JSON.stringify(existingLocal);
35494
+ if (remoteStr !== localStr) {
35495
+ hookItems.push({
35496
+ hookType,
35497
+ matcher,
35498
+ status: "modified",
35499
+ remoteHook
35500
+ });
35501
+ }
35502
+ }
35503
+ }
35504
+ }
35505
+ return hookItems;
35506
+ }
35445
35507
  async function analyzeSyncChanges(claudeDir, githubToken) {
35446
35508
  const allItems = [];
35447
35509
  const categories = [
@@ -35454,10 +35516,16 @@ async function analyzeSyncChanges(claudeDir, githubToken) {
35454
35516
  const items = await analyzeCategory(category, claudeDir, githubToken);
35455
35517
  allItems.push(...items);
35456
35518
  }
35519
+ const remoteSettings = await fetchRemoteSettings(githubToken);
35520
+ const localSettings = await getLocalSettings(claudeDir);
35521
+ const hooks = remoteSettings ? analyzeHooksChanges(remoteSettings, localSettings) : [];
35522
+ const hooksNewCount = hooks.filter((h2) => h2.status === "new").length;
35523
+ const hooksModifiedCount = hooks.filter((h2) => h2.status === "modified").length;
35457
35524
  return {
35458
35525
  items: allItems,
35459
- newCount: allItems.filter((i) => i.status === "new").length,
35460
- modifiedCount: allItems.filter((i) => i.status === "modified").length,
35526
+ hooks,
35527
+ newCount: allItems.filter((i) => i.status === "new").length + hooksNewCount,
35528
+ modifiedCount: allItems.filter((i) => i.status === "modified").length + hooksModifiedCount,
35461
35529
  deletedCount: allItems.filter((i) => i.status === "deleted").length,
35462
35530
  unchangedCount: allItems.filter((i) => i.status === "unchanged").length
35463
35531
  };
@@ -35482,6 +35550,43 @@ async function downloadFromPrivateGitHub2(relativePath, targetPath, githubToken)
35482
35550
  return false;
35483
35551
  }
35484
35552
  }
35553
+ async function syncSelectedHooks(claudeDir, hooks, onProgress) {
35554
+ if (hooks.length === 0) {
35555
+ return { success: 0, failed: 0 };
35556
+ }
35557
+ const settingsPath = path17.join(claudeDir, "settings.json");
35558
+ let settings = {};
35559
+ try {
35560
+ const content = await import_fs_extra15.default.readFile(settingsPath, "utf-8");
35561
+ settings = JSON.parse(content);
35562
+ } catch {
35563
+ settings = {};
35564
+ }
35565
+ if (!settings.hooks) {
35566
+ settings.hooks = {};
35567
+ }
35568
+ let success = 0;
35569
+ let failed = 0;
35570
+ for (const hook of hooks) {
35571
+ onProgress?.(`${hook.hookType}[${hook.matcher || "*"}]`, hook.status === "new" ? "adding" : "updating");
35572
+ try {
35573
+ if (!settings.hooks[hook.hookType]) {
35574
+ settings.hooks[hook.hookType] = [];
35575
+ }
35576
+ const existingIndex = settings.hooks[hook.hookType].findIndex((h2) => h2.matcher === hook.matcher);
35577
+ if (existingIndex >= 0) {
35578
+ settings.hooks[hook.hookType][existingIndex] = hook.remoteHook;
35579
+ } else {
35580
+ settings.hooks[hook.hookType].push(hook.remoteHook);
35581
+ }
35582
+ success++;
35583
+ } catch {
35584
+ failed++;
35585
+ }
35586
+ }
35587
+ await import_fs_extra15.default.writeFile(settingsPath, JSON.stringify(settings, null, 2));
35588
+ return { success, failed };
35589
+ }
35485
35590
  async function syncSelectedItems(claudeDir, items, githubToken, onProgress) {
35486
35591
  let success = 0;
35487
35592
  let failed = 0;
@@ -35563,7 +35668,7 @@ function formatFolderSummary(summary) {
35563
35668
  const countStr = parts.length > 0 ? ` (${parts.join(", ")})` : "";
35564
35669
  return `\uD83D\uDCC1 ${summary.name}${countStr}`;
35565
35670
  }
35566
- function createSelectionChoices(changedItems) {
35671
+ function createSelectionChoices(changedItems, hooks = []) {
35567
35672
  const choices = [];
35568
35673
  const folderedCategories = ["scripts", "skills"];
35569
35674
  const grouped = groupByCategory(changedItems);
@@ -35596,6 +35701,16 @@ function createSelectionChoices(changedItems) {
35596
35701
  }
35597
35702
  }
35598
35703
  }
35704
+ for (const hook of hooks) {
35705
+ const icon = hook.status === "new" ? "\uD83C\uDD95" : "\uD83D\uDCDD";
35706
+ const action = hook.status === "new" ? "add" : "update";
35707
+ const matcherDisplay = hook.matcher || "*";
35708
+ choices.push({
35709
+ value: { type: "hook", hook },
35710
+ label: `${icon} settings.json → ${hook.hookType}[${matcherDisplay}]`,
35711
+ hint: action
35712
+ });
35713
+ }
35599
35714
  return choices;
35600
35715
  }
35601
35716
  function formatFolderHint(summary) {
@@ -35610,14 +35725,17 @@ function formatFolderHint(summary) {
35610
35725
  }
35611
35726
  function expandSelections(selections) {
35612
35727
  const items = [];
35728
+ const hooks = [];
35613
35729
  for (const sel of selections) {
35614
35730
  if (sel.type === "file") {
35615
35731
  items.push(sel.item);
35616
- } else {
35732
+ } else if (sel.type === "folder") {
35617
35733
  items.push(...sel.items);
35734
+ } else if (sel.type === "hook") {
35735
+ hooks.push(sel.hook);
35618
35736
  }
35619
35737
  }
35620
- return items;
35738
+ return { items, hooks };
35621
35739
  }
35622
35740
  async function proSyncCommand(options = {}) {
35623
35741
  oe(source_default.blue(`\uD83D\uDD04 Sync Premium Configurations ${source_default.gray(`v${getVersion()}`)}`));
@@ -35635,7 +35753,8 @@ async function proSyncCommand(options = {}) {
35635
35753
  const result = await analyzeSyncChanges(claudeDir, githubToken);
35636
35754
  spinner.stop("Analysis complete");
35637
35755
  const changedItems = result.items.filter((i) => i.status !== "unchanged");
35638
- if (changedItems.length === 0) {
35756
+ const changedHooks = result.hooks;
35757
+ if (changedItems.length === 0 && changedHooks.length === 0) {
35639
35758
  f2.success("Everything is up to date!");
35640
35759
  $e(source_default.green("✅ No changes needed"));
35641
35760
  return;
@@ -35659,8 +35778,18 @@ async function proSyncCommand(options = {}) {
35659
35778
  }
35660
35779
  }
35661
35780
  }
35781
+ if (changedHooks.length > 0) {
35782
+ f2.message("");
35783
+ f2.message(source_default.cyan.bold(` SETTINGS (hooks)`));
35784
+ for (const hook of changedHooks) {
35785
+ const icon = hook.status === "new" ? "\uD83C\uDD95" : "\uD83D\uDCDD";
35786
+ const color = hook.status === "new" ? source_default.green : source_default.yellow;
35787
+ const matcherDisplay = hook.matcher || "*";
35788
+ f2.message(` ${icon} ${color(`${hook.hookType}[${matcherDisplay}]`)}`);
35789
+ }
35790
+ }
35662
35791
  f2.message("");
35663
- const choices = createSelectionChoices(changedItems);
35792
+ const choices = createSelectionChoices(changedItems, changedHooks);
35664
35793
  const selected = await ae({
35665
35794
  message: "Select items to sync:",
35666
35795
  options: choices,
@@ -35671,14 +35800,16 @@ async function proSyncCommand(options = {}) {
35671
35800
  ue("Sync cancelled");
35672
35801
  process.exit(0);
35673
35802
  }
35674
- const selectedItems = expandSelections(selected);
35675
- if (selectedItems.length === 0) {
35803
+ const expanded = expandSelections(selected);
35804
+ const selectedItems = expanded.items;
35805
+ const selectedHooks = expanded.hooks;
35806
+ if (selectedItems.length === 0 && selectedHooks.length === 0) {
35676
35807
  f2.warn("No items selected");
35677
35808
  $e(source_default.yellow("⚠️ Nothing to sync"));
35678
35809
  return;
35679
35810
  }
35680
- const toAdd = selectedItems.filter((i) => i.status === "new").length;
35681
- const toUpdate = selectedItems.filter((i) => i.status === "modified").length;
35811
+ const toAdd = selectedItems.filter((i) => i.status === "new").length + selectedHooks.filter((h2) => h2.status === "new").length;
35812
+ const toUpdate = selectedItems.filter((i) => i.status === "modified").length + selectedHooks.filter((h2) => h2.status === "modified").length;
35682
35813
  const toRemove = selectedItems.filter((i) => i.status === "deleted").length;
35683
35814
  const summary = [
35684
35815
  toAdd > 0 ? `add ${toAdd}` : "",
@@ -35697,14 +35828,19 @@ async function proSyncCommand(options = {}) {
35697
35828
  const syncResult = await syncSelectedItems(claudeDir, selectedItems, githubToken, (file, action) => {
35698
35829
  spinner.message(`${action}: ${source_default.cyan(file)}`);
35699
35830
  });
35831
+ const hooksResult = await syncSelectedHooks(claudeDir, selectedHooks, (hook, action) => {
35832
+ spinner.message(`${action}: ${source_default.cyan(hook)}`);
35833
+ });
35700
35834
  spinner.stop("Sync complete");
35835
+ const totalSuccess = syncResult.success + hooksResult.success;
35836
+ const totalFailed = syncResult.failed + hooksResult.failed;
35701
35837
  const results = [];
35702
- if (syncResult.success > 0)
35703
- results.push(source_default.green(`${syncResult.success} added/updated`));
35838
+ if (totalSuccess > 0)
35839
+ results.push(source_default.green(`${totalSuccess} added/updated`));
35704
35840
  if (syncResult.deleted > 0)
35705
35841
  results.push(source_default.red(`${syncResult.deleted} removed`));
35706
- if (syncResult.failed > 0)
35707
- results.push(source_default.yellow(`${syncResult.failed} failed`));
35842
+ if (totalFailed > 0)
35843
+ results.push(source_default.yellow(`${totalFailed} failed`));
35708
35844
  f2.success(results.join(", "));
35709
35845
  const scriptsWereSynced = selectedItems.some((i) => i.category === "scripts");
35710
35846
  if (scriptsWereSynced) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiblueprint-cli",
3
- "version": "1.3.5",
3
+ "version": "1.3.6",
4
4
  "description": "AIBlueprint CLI for setting up Claude Code configurations",
5
5
  "author": "AIBlueprint",
6
6
  "license": "MIT",