aiblueprint-cli 1.3.0 → 1.3.2

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
@@ -33191,20 +33191,23 @@ async function checkAndInstallDependencies() {
33191
33191
  }
33192
33192
  }
33193
33193
  }
33194
- async function installStatuslineDependencies(claudeDir) {
33195
- const statuslineDir = path4.join(claudeDir, "scripts/statusline");
33194
+ async function installScriptsDependencies(claudeDir) {
33195
+ const scriptsDir = path4.join(claudeDir, "scripts");
33196
33196
  console.log(source_default.yellow(`
33197
- Installing statusline dependencies...`));
33197
+ Installing scripts dependencies...`));
33198
33198
  try {
33199
33199
  execSync("bun install", {
33200
- cwd: statuslineDir,
33200
+ cwd: scriptsDir,
33201
33201
  stdio: "inherit"
33202
33202
  });
33203
- console.log(source_default.green(" ✓ Statusline dependencies installed"));
33203
+ console.log(source_default.green(" ✓ Scripts dependencies installed"));
33204
33204
  } catch (error) {
33205
- console.log(source_default.red(" Failed to install statusline dependencies. Please run 'bun install' manually in ~/.claude/scripts/statusline"));
33205
+ console.log(source_default.red(" Failed to install scripts dependencies. Please run 'bun install' manually in ~/.claude/scripts"));
33206
33206
  }
33207
33207
  }
33208
+ async function installStatuslineDependencies(claudeDir) {
33209
+ await installScriptsDependencies(claudeDir);
33210
+ }
33208
33211
 
33209
33212
  // src/commands/setup/settings.ts
33210
33213
  var import_fs_extra3 = __toESM(require_lib4(), 1);
@@ -33765,15 +33768,24 @@ async function listFilesFromGitHub(dirPath) {
33765
33768
  if (!response.ok) {
33766
33769
  return [];
33767
33770
  }
33768
- const files = await response.json();
33769
- return files.filter((file) => file.type === "file").map((file) => file.name);
33771
+ const items = await response.json();
33772
+ const files = [];
33773
+ for (const item of items) {
33774
+ if (item.type === "file") {
33775
+ files.push(item.name);
33776
+ } else if (item.type === "dir") {
33777
+ const subFiles = await listFilesFromGitHub(`${dirPath}/${item.name}`);
33778
+ files.push(...subFiles.map((f) => `${item.name}/${f}`));
33779
+ }
33780
+ }
33781
+ return files;
33770
33782
  } catch (error) {
33771
33783
  return [];
33772
33784
  }
33773
33785
  }
33774
33786
  async function isGitHubAvailable() {
33775
33787
  try {
33776
- const testUrl = `${GITHUB_RAW_BASE3}/commands/commit.md`;
33788
+ const testUrl = `${GITHUB_RAW_BASE3}/commands/apex.md`;
33777
33789
  const testResponse = await fetch(testUrl);
33778
33790
  return testResponse.ok;
33779
33791
  } catch {
@@ -33967,6 +33979,20 @@ class SimpleSpinner3 {
33967
33979
  console.log(source_default.green(`✓ ${message}`));
33968
33980
  }
33969
33981
  }
33982
+ async function getLocalMdFilesRecursively(dir, basePath = "") {
33983
+ const files = [];
33984
+ const entries = await import_fs_extra10.default.readdir(dir, { withFileTypes: true });
33985
+ for (const entry of entries) {
33986
+ const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
33987
+ if (entry.isDirectory()) {
33988
+ const subFiles = await getLocalMdFilesRecursively(path12.join(dir, entry.name), relativePath);
33989
+ files.push(...subFiles);
33990
+ } else if (entry.name.endsWith(".md")) {
33991
+ files.push(relativePath);
33992
+ }
33993
+ }
33994
+ return files;
33995
+ }
33970
33996
  async function discoverAvailableCommands() {
33971
33997
  const commands = {};
33972
33998
  const useGitHub = await isGitHubAvailable();
@@ -33979,8 +34005,7 @@ async function discoverAvailableCommands() {
33979
34005
  if (!commandsDir) {
33980
34006
  throw new Error("Commands directory not found");
33981
34007
  }
33982
- const files = await import_fs_extra10.default.readdir(commandsDir);
33983
- mdFiles = files.filter((file) => file.endsWith(".md"));
34008
+ mdFiles = await getLocalMdFilesRecursively(commandsDir);
33984
34009
  }
33985
34010
  for (const file of mdFiles) {
33986
34011
  const commandName = file.replace(".md", "");
@@ -33988,7 +34013,7 @@ async function discoverAvailableCommands() {
33988
34013
  const content = await getFileContentWithGitHubFallback("commands", file);
33989
34014
  const { metadata } = parseYamlFrontmatter(content);
33990
34015
  commands[commandName] = {
33991
- name: commandName.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
34016
+ name: commandName.split("/").map((part) => part.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase())).join("/"),
33992
34017
  description: metadata.description || "No description available",
33993
34018
  allowedTools: metadata["allowed-tools"],
33994
34019
  argumentHint: metadata["argument-hint"],
@@ -34608,6 +34633,59 @@ class x {
34608
34633
  }
34609
34634
  }
34610
34635
  }
34636
+
34637
+ class BD extends x {
34638
+ get cursor() {
34639
+ return this.value ? 0 : 1;
34640
+ }
34641
+ get _value() {
34642
+ return this.cursor === 0;
34643
+ }
34644
+ constructor(u) {
34645
+ super(u, false), this.value = !!u.initialValue, this.on("value", () => {
34646
+ this.value = this._value;
34647
+ }), this.on("confirm", (F) => {
34648
+ this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = F, this.state = "submit", this.close();
34649
+ }), this.on("cursor", () => {
34650
+ this.value = !this.value;
34651
+ });
34652
+ }
34653
+ }
34654
+ var fD = Object.defineProperty;
34655
+ var gD = (e, u, F) => (u in e) ? fD(e, u, { enumerable: true, configurable: true, writable: true, value: F }) : e[u] = F;
34656
+ var K = (e, u, F) => (gD(e, typeof u != "symbol" ? u + "" : u, F), F);
34657
+ var vD = class extends x {
34658
+ constructor(u) {
34659
+ 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) => {
34660
+ F === "a" && this.toggleAll();
34661
+ }), this.on("cursor", (F) => {
34662
+ switch (F) {
34663
+ case "left":
34664
+ case "up":
34665
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
34666
+ break;
34667
+ case "down":
34668
+ case "right":
34669
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
34670
+ break;
34671
+ case "space":
34672
+ this.toggleValue();
34673
+ break;
34674
+ }
34675
+ });
34676
+ }
34677
+ get _value() {
34678
+ return this.options[this.cursor].value;
34679
+ }
34680
+ toggleAll() {
34681
+ const u = this.value.length === this.options.length;
34682
+ this.value = u ? [] : this.options.map((F) => F.value);
34683
+ }
34684
+ toggleValue() {
34685
+ const u = this.value.includes(this._value);
34686
+ this.value = u ? this.value.filter((F) => F !== this._value) : [...this.value, this._value];
34687
+ }
34688
+ };
34611
34689
  var TD = Object.defineProperty;
34612
34690
  var jD = (e, u, F) => (u in e) ? TD(e, u, { enumerable: true, configurable: true, writable: true, value: F }) : e[u] = F;
34613
34691
  var MD = (e, u, F) => (jD(e, typeof u != "symbol" ? u + "" : u, F), F);
@@ -34665,7 +34743,7 @@ var H = o("◆", "*");
34665
34743
  var I2 = o("■", "x");
34666
34744
  var x2 = o("▲", "x");
34667
34745
  var S2 = o("◇", "o");
34668
- var K = o("┌", "T");
34746
+ var K2 = o("┌", "T");
34669
34747
  var a2 = o("│", "|");
34670
34748
  var d2 = o("└", "—");
34671
34749
  var b2 = o("●", ">");
@@ -34716,13 +34794,76 @@ ${import_picocolors2.default.cyan(d2)}
34716
34794
  `;
34717
34795
  }
34718
34796
  } }).prompt();
34797
+ var se = (r2) => {
34798
+ const n = r2.active ?? "Yes", i = r2.inactive ?? "No";
34799
+ return new BD({ active: n, inactive: i, initialValue: r2.initialValue ?? true, render() {
34800
+ const t = `${import_picocolors2.default.gray(a2)}
34801
+ ${y2(this.state)} ${r2.message}
34802
+ `, s = this.value ? n : i;
34803
+ switch (this.state) {
34804
+ case "submit":
34805
+ return `${t}${import_picocolors2.default.gray(a2)} ${import_picocolors2.default.dim(s)}`;
34806
+ case "cancel":
34807
+ return `${t}${import_picocolors2.default.gray(a2)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
34808
+ ${import_picocolors2.default.gray(a2)}`;
34809
+ default:
34810
+ 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}`}
34811
+ ${import_picocolors2.default.cyan(d2)}
34812
+ `;
34813
+ }
34814
+ } }).prompt();
34815
+ };
34816
+ var ae = (r2) => {
34817
+ const n = (i, t) => {
34818
+ const s = i.label ?? String(i.value);
34819
+ 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)}`;
34820
+ };
34821
+ return new vD({ options: r2.options, initialValues: r2.initialValues, required: r2.required ?? true, cursorAt: r2.cursorAt, validate(i) {
34822
+ if (this.required && i.length === 0)
34823
+ return `Please select at least one option.
34824
+ ${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`))}`;
34825
+ }, render() {
34826
+ let i = `${import_picocolors2.default.gray(a2)}
34827
+ ${y2(this.state)} ${r2.message}
34828
+ `;
34829
+ switch (this.state) {
34830
+ case "submit":
34831
+ 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")}`;
34832
+ case "cancel": {
34833
+ const t = this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "cancelled")).join(import_picocolors2.default.dim(", "));
34834
+ return `${i}${import_picocolors2.default.gray(a2)} ${t.trim() ? `${t}
34835
+ ${import_picocolors2.default.gray(a2)}` : ""}`;
34836
+ }
34837
+ case "error": {
34838
+ const t = this.error.split(`
34839
+ `).map((s, c2) => c2 === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(s)}` : ` ${s}`).join(`
34840
+ `);
34841
+ return i + import_picocolors2.default.yellow(a2) + " " + this.options.map((s, c2) => {
34842
+ const l2 = this.value.includes(s.value), u = c2 === this.cursor;
34843
+ return u && l2 ? n(s, "active-selected") : l2 ? n(s, "selected") : n(s, u ? "active" : "inactive");
34844
+ }).join(`
34845
+ ${import_picocolors2.default.yellow(a2)} `) + `
34846
+ ` + t + `
34847
+ `;
34848
+ }
34849
+ default:
34850
+ return `${i}${import_picocolors2.default.cyan(a2)} ${this.options.map((t, s) => {
34851
+ const c2 = this.value.includes(t.value), l2 = s === this.cursor;
34852
+ return l2 && c2 ? n(t, "active-selected") : c2 ? n(t, "selected") : n(t, l2 ? "active" : "inactive");
34853
+ }).join(`
34854
+ ${import_picocolors2.default.cyan(a2)} `)}
34855
+ ${import_picocolors2.default.cyan(d2)}
34856
+ `;
34857
+ }
34858
+ } }).prompt();
34859
+ };
34719
34860
  var ue = (r2 = "") => {
34720
34861
  process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(r2)}
34721
34862
 
34722
34863
  `);
34723
34864
  };
34724
34865
  var oe = (r2 = "") => {
34725
- process.stdout.write(`${import_picocolors2.default.gray(K)} ${r2}
34866
+ process.stdout.write(`${import_picocolors2.default.gray(K2)} ${r2}
34726
34867
  `);
34727
34868
  };
34728
34869
  var $e = (r2 = "") => {
@@ -34779,6 +34920,10 @@ var de = () => {
34779
34920
  return process.on("uncaughtExceptionMonitor", () => $2(2)), process.on("unhandledRejection", () => $2(2)), process.on("SIGINT", () => $2(1)), process.on("SIGTERM", () => $2(1)), process.on("exit", $2), { start: l2, stop: u, message: m2 };
34780
34921
  };
34781
34922
 
34923
+ // src/commands/pro.ts
34924
+ import os10 from "os";
34925
+ import path16 from "path";
34926
+
34782
34927
  // src/lib/pro-installer.ts
34783
34928
  var import_fs_extra12 = __toESM(require_lib4(), 1);
34784
34929
  import os8 from "os";
@@ -34807,7 +34952,7 @@ async function downloadFromPrivateGitHub(repo, branch, relativePath, targetPath,
34807
34952
  return false;
34808
34953
  }
34809
34954
  }
34810
- async function downloadDirectoryFromPrivateGitHub(repo, branch, dirPath, targetDir, githubToken) {
34955
+ async function downloadDirectoryFromPrivateGitHub(repo, branch, dirPath, targetDir, githubToken, onProgress) {
34811
34956
  try {
34812
34957
  const apiUrl = `https://api.github.com/repos/${repo}/contents/${dirPath}?ref=${branch}`;
34813
34958
  const response = await fetch(apiUrl, {
@@ -34829,10 +34974,12 @@ async function downloadDirectoryFromPrivateGitHub(repo, branch, dirPath, targetD
34829
34974
  for (const file of files) {
34830
34975
  const relativePath = dirPath ? `${dirPath}/${file.name}` : file.name;
34831
34976
  const targetPath = path14.join(targetDir, file.name);
34977
+ const displayPath = relativePath.replace("claude-code-config/", "");
34832
34978
  if (file.type === "file") {
34979
+ onProgress?.(displayPath, "file");
34833
34980
  await downloadFromPrivateGitHub(repo, branch, relativePath, targetPath, githubToken);
34834
34981
  } else if (file.type === "dir") {
34835
- await downloadDirectoryFromPrivateGitHub(repo, branch, relativePath, targetPath, githubToken);
34982
+ await downloadDirectoryFromPrivateGitHub(repo, branch, relativePath, targetPath, githubToken, onProgress);
34836
34983
  }
34837
34984
  }
34838
34985
  return true;
@@ -34842,11 +34989,11 @@ async function downloadDirectoryFromPrivateGitHub(repo, branch, dirPath, targetD
34842
34989
  }
34843
34990
  }
34844
34991
  async function installProConfigs(options) {
34845
- const { githubToken, claudeCodeFolder } = options;
34992
+ const { githubToken, claudeCodeFolder, onProgress } = options;
34846
34993
  const claudeFolder = claudeCodeFolder || path14.join(os8.homedir(), ".claude");
34847
34994
  const tempDir = path14.join(os8.tmpdir(), `aiblueprint-premium-${Date.now()}`);
34848
34995
  try {
34849
- const success = await downloadDirectoryFromPrivateGitHub(PREMIUM_REPO, PREMIUM_BRANCH, "claude-code-config", tempDir, githubToken);
34996
+ const success = await downloadDirectoryFromPrivateGitHub(PREMIUM_REPO, PREMIUM_BRANCH, "claude-code-config", tempDir, githubToken, onProgress);
34850
34997
  if (!success) {
34851
34998
  throw new Error("Failed to download premium configurations");
34852
34999
  }
@@ -34854,66 +35001,45 @@ async function installProConfigs(options) {
34854
35001
  overwrite: true,
34855
35002
  recursive: true
34856
35003
  });
34857
- console.log(`✓ Premium configurations installed to ${claudeFolder}`);
34858
35004
  } catch (error) {
34859
35005
  throw new Error(`Failed to install premium configs: ${error instanceof Error ? error.message : "Unknown error"}`);
34860
35006
  } finally {
34861
35007
  try {
34862
35008
  await import_fs_extra12.default.remove(tempDir);
34863
- } catch (error) {
35009
+ } catch {
34864
35010
  }
34865
35011
  }
34866
35012
  }
34867
35013
 
34868
- // src/lib/setup-helper.ts
35014
+ // src/lib/token-storage.ts
34869
35015
  var import_fs_extra13 = __toESM(require_lib4(), 1);
34870
- import path15 from "path";
34871
35016
  import os9 from "os";
34872
- async function installBasicConfigs(options = {}, skipStatusline = false) {
34873
- const claudeDir = options.claudeCodeFolder || path15.join(os9.homedir(), ".claude");
34874
- await import_fs_extra13.default.ensureDir(claudeDir);
34875
- console.log(source_default.gray("\uD83D\uDCE6 Installing free configurations..."));
34876
- console.log(source_default.gray(" • Commands..."));
34877
- await downloadDirectoryFromGitHub("commands", path15.join(claudeDir, "commands"));
34878
- console.log(source_default.gray(" • Agents..."));
34879
- await downloadDirectoryFromGitHub("agents", path15.join(claudeDir, "agents"));
34880
- if (!skipStatusline) {
34881
- console.log(source_default.gray(" • Statusline (basic)..."));
34882
- await downloadDirectoryFromGitHub("scripts/statusline", path15.join(claudeDir, "scripts", "statusline"));
34883
- }
34884
- console.log(source_default.green("✓ Free configurations installed"));
34885
- return claudeDir;
34886
- }
34887
-
34888
- // src/lib/token-storage.ts
34889
- var import_fs_extra14 = __toESM(require_lib4(), 1);
34890
- import os10 from "os";
34891
- import path16 from "path";
35017
+ import path15 from "path";
34892
35018
  function getConfigDir() {
34893
- const platform = os10.platform();
35019
+ const platform = os9.platform();
34894
35020
  if (platform === "win32") {
34895
- const appData = process.env.APPDATA || path16.join(os10.homedir(), "AppData", "Roaming");
34896
- return path16.join(appData, "aiblueprint");
35021
+ const appData = process.env.APPDATA || path15.join(os9.homedir(), "AppData", "Roaming");
35022
+ return path15.join(appData, "aiblueprint");
34897
35023
  } else {
34898
- const configHome = process.env.XDG_CONFIG_HOME || path16.join(os10.homedir(), ".config");
34899
- return path16.join(configHome, "aiblueprint");
35024
+ const configHome = process.env.XDG_CONFIG_HOME || path15.join(os9.homedir(), ".config");
35025
+ return path15.join(configHome, "aiblueprint");
34900
35026
  }
34901
35027
  }
34902
35028
  function getTokenFilePath() {
34903
- return path16.join(getConfigDir(), "token.txt");
35029
+ return path15.join(getConfigDir(), "token.txt");
34904
35030
  }
34905
35031
  async function saveToken(githubToken) {
34906
35032
  const tokenFile = getTokenFilePath();
34907
- await import_fs_extra14.default.ensureDir(path16.dirname(tokenFile));
34908
- await import_fs_extra14.default.writeFile(tokenFile, githubToken, { mode: 384 });
35033
+ await import_fs_extra13.default.ensureDir(path15.dirname(tokenFile));
35034
+ await import_fs_extra13.default.writeFile(tokenFile, githubToken, { mode: 384 });
34909
35035
  }
34910
35036
  async function getToken() {
34911
35037
  const tokenFile = getTokenFilePath();
34912
- if (!await import_fs_extra14.default.pathExists(tokenFile)) {
35038
+ if (!await import_fs_extra13.default.pathExists(tokenFile)) {
34913
35039
  return null;
34914
35040
  }
34915
35041
  try {
34916
- const token = await import_fs_extra14.default.readFile(tokenFile, "utf-8");
35042
+ const token = await import_fs_extra13.default.readFile(tokenFile, "utf-8");
34917
35043
  return token.trim();
34918
35044
  } catch (error) {
34919
35045
  return null;
@@ -34922,13 +35048,12 @@ async function getToken() {
34922
35048
  function getTokenInfo() {
34923
35049
  return {
34924
35050
  path: getTokenFilePath(),
34925
- platform: os10.platform()
35051
+ platform: os9.platform()
34926
35052
  };
34927
35053
  }
34928
35054
 
34929
35055
  // src/commands/pro.ts
34930
- var import_fs_extra15 = __toESM(require_lib4(), 1);
34931
- import path17 from "path";
35056
+ var import_fs_extra14 = __toESM(require_lib4(), 1);
34932
35057
  var API_URL = "https://codeline.app/api/products";
34933
35058
  var PRODUCT_ID = "prd_XJVgxVPbGG";
34934
35059
  async function countInstalledItems(claudeDir) {
@@ -34938,27 +35063,27 @@ async function countInstalledItems(claudeDir) {
34938
35063
  skills: 0
34939
35064
  };
34940
35065
  try {
34941
- const commandsDir = path17.join(claudeDir, "commands");
34942
- if (await import_fs_extra15.default.pathExists(commandsDir)) {
34943
- const files = await import_fs_extra15.default.readdir(commandsDir);
35066
+ const commandsDir = path16.join(claudeDir, "commands");
35067
+ if (await import_fs_extra14.default.pathExists(commandsDir)) {
35068
+ const files = await import_fs_extra14.default.readdir(commandsDir);
34944
35069
  counts.commands = files.filter((f3) => f3.endsWith(".md")).length;
34945
35070
  }
34946
35071
  } catch {
34947
35072
  }
34948
35073
  try {
34949
- const agentsDir = path17.join(claudeDir, "agents");
34950
- if (await import_fs_extra15.default.pathExists(agentsDir)) {
34951
- const files = await import_fs_extra15.default.readdir(agentsDir);
35074
+ const agentsDir = path16.join(claudeDir, "agents");
35075
+ if (await import_fs_extra14.default.pathExists(agentsDir)) {
35076
+ const files = await import_fs_extra14.default.readdir(agentsDir);
34952
35077
  counts.agents = files.filter((f3) => f3.endsWith(".md")).length;
34953
35078
  }
34954
35079
  } catch {
34955
35080
  }
34956
35081
  try {
34957
- const skillsDir = path17.join(claudeDir, "skills");
34958
- if (await import_fs_extra15.default.pathExists(skillsDir)) {
34959
- const items = await import_fs_extra15.default.readdir(skillsDir);
35082
+ const skillsDir = path16.join(claudeDir, "skills");
35083
+ if (await import_fs_extra14.default.pathExists(skillsDir)) {
35084
+ const items = await import_fs_extra14.default.readdir(skillsDir);
34960
35085
  const dirs = await Promise.all(items.map(async (item) => {
34961
- const stat = await import_fs_extra15.default.stat(path17.join(skillsDir, item));
35086
+ const stat = await import_fs_extra14.default.stat(path16.join(skillsDir, item));
34962
35087
  return stat.isDirectory();
34963
35088
  }));
34964
35089
  counts.skills = dirs.filter(Boolean).length;
@@ -35065,16 +35190,24 @@ async function proSetupCommand(options = {}) {
35065
35190
  $e(source_default.red("❌ Not activated"));
35066
35191
  process.exit(1);
35067
35192
  }
35193
+ const claudeDir = options.folder ? path16.resolve(options.folder) : path16.join(os10.homedir(), ".claude");
35068
35194
  const spinner = de();
35069
- spinner.start("Installing free configurations...");
35070
- const claudeDir = await installBasicConfigs({ claudeCodeFolder: options.folder }, true);
35071
- spinner.stop("Free configurations installed");
35195
+ const onProgress = (file, type) => {
35196
+ spinner.message(`Installing: ${source_default.cyan(file)} ${source_default.gray(`(${type})`)}`);
35197
+ };
35072
35198
  spinner.start("Installing premium configurations...");
35073
35199
  await installProConfigs({
35074
35200
  githubToken,
35075
- claudeCodeFolder: claudeDir
35201
+ claudeCodeFolder: claudeDir,
35202
+ onProgress
35076
35203
  });
35077
35204
  spinner.stop("Premium configurations installed");
35205
+ spinner.start("Checking global dependencies...");
35206
+ await checkAndInstallDependencies();
35207
+ spinner.stop("Global dependencies ready");
35208
+ spinner.start("Installing scripts dependencies...");
35209
+ await installScriptsDependencies(claudeDir);
35210
+ spinner.stop("Scripts dependencies installed");
35078
35211
  spinner.start("Setting up shell shortcuts...");
35079
35212
  await setupShellShortcuts();
35080
35213
  spinner.stop("Shell shortcuts configured");
@@ -35133,6 +35266,354 @@ async function proUpdateCommand(options = {}) {
35133
35266
  }
35134
35267
  }
35135
35268
 
35269
+ // src/commands/sync.ts
35270
+ import os11 from "os";
35271
+ import path18 from "path";
35272
+
35273
+ // src/lib/sync-utils.ts
35274
+ var import_fs_extra15 = __toESM(require_lib4(), 1);
35275
+ import path17 from "path";
35276
+ import crypto from "crypto";
35277
+ var PREMIUM_REPO2 = "Melvynx/aiblueprint-cli-premium";
35278
+ var PREMIUM_BRANCH2 = "main";
35279
+ function computeFileSha(content) {
35280
+ const size = content.length;
35281
+ const header = `blob ${size}\x00`;
35282
+ const fullContent = Buffer.concat([Buffer.from(header), content]);
35283
+ return crypto.createHash("sha1").update(fullContent).digest("hex");
35284
+ }
35285
+ async function listRemoteDirectory(dirPath, githubToken) {
35286
+ const apiUrl = `https://api.github.com/repos/${PREMIUM_REPO2}/contents/claude-code-config/${dirPath}?ref=${PREMIUM_BRANCH2}`;
35287
+ const response = await fetch(apiUrl, {
35288
+ headers: {
35289
+ Authorization: `token ${githubToken}`,
35290
+ Accept: "application/vnd.github.v3+json"
35291
+ }
35292
+ });
35293
+ if (!response.ok) {
35294
+ if (response.status === 404) {
35295
+ return [];
35296
+ }
35297
+ throw new Error(`Failed to list directory ${dirPath}: ${response.status}`);
35298
+ }
35299
+ const files = await response.json();
35300
+ if (!Array.isArray(files)) {
35301
+ return [];
35302
+ }
35303
+ return files;
35304
+ }
35305
+ async function listRemoteFilesRecursive(dirPath, githubToken, basePath = "") {
35306
+ const results = [];
35307
+ const files = await listRemoteDirectory(dirPath, githubToken);
35308
+ for (const file of files) {
35309
+ const relativePath = basePath ? `${basePath}/${file.name}` : file.name;
35310
+ if (file.type === "file") {
35311
+ results.push({ path: relativePath, sha: file.sha, isFolder: false });
35312
+ } else if (file.type === "dir") {
35313
+ results.push({ path: relativePath, sha: "", isFolder: true });
35314
+ const subFiles = await listRemoteFilesRecursive(`${dirPath}/${file.name}`, githubToken, relativePath);
35315
+ results.push(...subFiles);
35316
+ }
35317
+ }
35318
+ return results;
35319
+ }
35320
+ async function computeLocalFileSha(filePath) {
35321
+ try {
35322
+ const content = await import_fs_extra15.default.readFile(filePath);
35323
+ return computeFileSha(content);
35324
+ } catch {
35325
+ return null;
35326
+ }
35327
+ }
35328
+ async function listLocalFiles(dir) {
35329
+ const files = [];
35330
+ if (!await import_fs_extra15.default.pathExists(dir)) {
35331
+ return files;
35332
+ }
35333
+ const items = await import_fs_extra15.default.readdir(dir);
35334
+ for (const item of items) {
35335
+ const fullPath = path17.join(dir, item);
35336
+ const stat = await import_fs_extra15.default.stat(fullPath);
35337
+ if (stat.isDirectory()) {
35338
+ files.push(item);
35339
+ const subFiles = await listLocalFilesRecursive(fullPath, item);
35340
+ files.push(...subFiles);
35341
+ } else {
35342
+ files.push(item);
35343
+ }
35344
+ }
35345
+ return files;
35346
+ }
35347
+ async function listLocalFilesRecursive(dir, basePath) {
35348
+ const files = [];
35349
+ const items = await import_fs_extra15.default.readdir(dir);
35350
+ for (const item of items) {
35351
+ const fullPath = path17.join(dir, item);
35352
+ const relativePath = `${basePath}/${item}`;
35353
+ const stat = await import_fs_extra15.default.stat(fullPath);
35354
+ if (stat.isDirectory()) {
35355
+ files.push(relativePath);
35356
+ const subFiles = await listLocalFilesRecursive(fullPath, relativePath);
35357
+ files.push(...subFiles);
35358
+ } else {
35359
+ files.push(relativePath);
35360
+ }
35361
+ }
35362
+ return files;
35363
+ }
35364
+ async function analyzeCategory(category, claudeDir, githubToken) {
35365
+ const items = [];
35366
+ const localDir = path17.join(claudeDir, category);
35367
+ const remoteFiles = await listRemoteFilesRecursive(category, githubToken);
35368
+ const localFiles = await listLocalFiles(localDir);
35369
+ const remoteSet = new Map;
35370
+ for (const rf of remoteFiles) {
35371
+ remoteSet.set(rf.path, { sha: rf.sha, isFolder: rf.isFolder });
35372
+ }
35373
+ const localSet = new Set(localFiles);
35374
+ for (const [remotePath, { sha, isFolder }] of remoteSet) {
35375
+ const localPath = path17.join(localDir, remotePath);
35376
+ if (isFolder) {
35377
+ continue;
35378
+ }
35379
+ if (!localSet.has(remotePath)) {
35380
+ items.push({
35381
+ name: remotePath,
35382
+ relativePath: `${category}/${remotePath}`,
35383
+ status: "new",
35384
+ category
35385
+ });
35386
+ } else {
35387
+ const localSha = await computeLocalFileSha(localPath);
35388
+ if (localSha !== sha) {
35389
+ items.push({
35390
+ name: remotePath,
35391
+ relativePath: `${category}/${remotePath}`,
35392
+ status: "modified",
35393
+ category
35394
+ });
35395
+ } else {
35396
+ items.push({
35397
+ name: remotePath,
35398
+ relativePath: `${category}/${remotePath}`,
35399
+ status: "unchanged",
35400
+ category
35401
+ });
35402
+ }
35403
+ }
35404
+ }
35405
+ for (const localPath of localSet) {
35406
+ if (!remoteSet.has(localPath)) {
35407
+ const fullPath = path17.join(localDir, localPath);
35408
+ const stat = await import_fs_extra15.default.stat(fullPath).catch(() => null);
35409
+ if (stat && !stat.isDirectory()) {
35410
+ items.push({
35411
+ name: localPath,
35412
+ relativePath: `${category}/${localPath}`,
35413
+ status: "deleted",
35414
+ category
35415
+ });
35416
+ }
35417
+ }
35418
+ }
35419
+ return items;
35420
+ }
35421
+ async function analyzeSyncChanges(claudeDir, githubToken) {
35422
+ const allItems = [];
35423
+ const categories = [
35424
+ "commands",
35425
+ "agents",
35426
+ "skills",
35427
+ "scripts"
35428
+ ];
35429
+ for (const category of categories) {
35430
+ const items = await analyzeCategory(category, claudeDir, githubToken);
35431
+ allItems.push(...items);
35432
+ }
35433
+ return {
35434
+ items: allItems,
35435
+ newCount: allItems.filter((i) => i.status === "new").length,
35436
+ modifiedCount: allItems.filter((i) => i.status === "modified").length,
35437
+ deletedCount: allItems.filter((i) => i.status === "deleted").length,
35438
+ unchangedCount: allItems.filter((i) => i.status === "unchanged").length
35439
+ };
35440
+ }
35441
+ async function downloadFromPrivateGitHub2(relativePath, targetPath, githubToken) {
35442
+ try {
35443
+ const url = `https://raw.githubusercontent.com/${PREMIUM_REPO2}/${PREMIUM_BRANCH2}/claude-code-config/${relativePath}`;
35444
+ const response = await fetch(url, {
35445
+ headers: {
35446
+ Authorization: `token ${githubToken}`,
35447
+ Accept: "application/vnd.github.v3.raw"
35448
+ }
35449
+ });
35450
+ if (!response.ok) {
35451
+ return false;
35452
+ }
35453
+ const content = await response.arrayBuffer();
35454
+ await import_fs_extra15.default.ensureDir(path17.dirname(targetPath));
35455
+ await import_fs_extra15.default.writeFile(targetPath, Buffer.from(content));
35456
+ return true;
35457
+ } catch {
35458
+ return false;
35459
+ }
35460
+ }
35461
+ async function syncSelectedItems(claudeDir, items, githubToken, onProgress) {
35462
+ let success = 0;
35463
+ let failed = 0;
35464
+ let deleted = 0;
35465
+ for (const item of items) {
35466
+ const targetPath = path17.join(claudeDir, item.relativePath);
35467
+ if (item.status === "deleted") {
35468
+ onProgress?.(item.relativePath, "deleting");
35469
+ try {
35470
+ await import_fs_extra15.default.remove(targetPath);
35471
+ deleted++;
35472
+ } catch {
35473
+ failed++;
35474
+ }
35475
+ } else {
35476
+ onProgress?.(item.relativePath, item.status === "new" ? "adding" : "updating");
35477
+ const ok = await downloadFromPrivateGitHub2(item.relativePath, targetPath, githubToken);
35478
+ if (ok) {
35479
+ success++;
35480
+ } else {
35481
+ failed++;
35482
+ }
35483
+ }
35484
+ }
35485
+ return { success, failed, deleted };
35486
+ }
35487
+
35488
+ // src/commands/sync.ts
35489
+ function formatItem(item) {
35490
+ const icons = {
35491
+ new: "\uD83C\uDD95",
35492
+ modified: "\uD83D\uDCDD",
35493
+ deleted: "\uD83D\uDDD1️",
35494
+ unchanged: "✅"
35495
+ };
35496
+ const colors12 = {
35497
+ new: source_default.green,
35498
+ modified: source_default.yellow,
35499
+ deleted: source_default.red,
35500
+ unchanged: source_default.gray
35501
+ };
35502
+ return `${icons[item.status]} ${colors12[item.status](item.relativePath)}`;
35503
+ }
35504
+ function groupByCategory(items) {
35505
+ const grouped = new Map;
35506
+ for (const item of items) {
35507
+ const existing = grouped.get(item.category) || [];
35508
+ existing.push(item);
35509
+ grouped.set(item.category, existing);
35510
+ }
35511
+ return grouped;
35512
+ }
35513
+ async function proSyncCommand(options = {}) {
35514
+ oe(source_default.blue("\uD83D\uDD04 Sync Premium Configurations"));
35515
+ try {
35516
+ const githubToken = await getToken();
35517
+ if (!githubToken) {
35518
+ f2.error("No token found");
35519
+ f2.info("Run: aiblueprint claude-code pro activate <token>");
35520
+ $e(source_default.red("❌ Not activated"));
35521
+ process.exit(1);
35522
+ }
35523
+ const claudeDir = options.folder ? path18.resolve(options.folder) : path18.join(os11.homedir(), ".claude");
35524
+ const spinner = de();
35525
+ spinner.start("Analyzing changes...");
35526
+ const result = await analyzeSyncChanges(claudeDir, githubToken);
35527
+ spinner.stop("Analysis complete");
35528
+ const changedItems = result.items.filter((i) => i.status !== "unchanged");
35529
+ if (changedItems.length === 0) {
35530
+ f2.success("Everything is up to date!");
35531
+ $e(source_default.green("✅ No changes needed"));
35532
+ return;
35533
+ }
35534
+ f2.info(`Found: ${source_default.green(`${result.newCount} new`)}, ${source_default.yellow(`${result.modifiedCount} modified`)}, ${source_default.red(`${result.deletedCount} to remove`)}, ${source_default.gray(`${result.unchangedCount} unchanged`)}`);
35535
+ f2.message("");
35536
+ f2.message(source_default.bold("Changes by category:"));
35537
+ const grouped = groupByCategory(changedItems);
35538
+ for (const [category, items] of grouped) {
35539
+ f2.message("");
35540
+ f2.message(source_default.cyan.bold(` ${category.toUpperCase()}`));
35541
+ for (const item of items) {
35542
+ f2.message(` ${formatItem(item)}`);
35543
+ }
35544
+ }
35545
+ f2.message("");
35546
+ const choices = [];
35547
+ for (const item of changedItems) {
35548
+ const icons = { new: "\uD83C\uDD95", modified: "\uD83D\uDCDD", deleted: "\uD83D\uDDD1️", unchanged: "" };
35549
+ const actions = { new: "add", modified: "update", deleted: "remove", unchanged: "" };
35550
+ choices.push({
35551
+ value: item,
35552
+ label: `${icons[item.status]} ${item.relativePath}`,
35553
+ hint: actions[item.status]
35554
+ });
35555
+ }
35556
+ const selected = await ae({
35557
+ message: "Select items to sync:",
35558
+ options: choices,
35559
+ initialValues: choices.map((c2) => c2.value),
35560
+ required: false
35561
+ });
35562
+ if (lD(selected)) {
35563
+ ue("Sync cancelled");
35564
+ process.exit(0);
35565
+ }
35566
+ const selectedItems = selected;
35567
+ if (selectedItems.length === 0) {
35568
+ f2.warn("No items selected");
35569
+ $e(source_default.yellow("⚠️ Nothing to sync"));
35570
+ return;
35571
+ }
35572
+ const toAdd = selectedItems.filter((i) => i.status === "new").length;
35573
+ const toUpdate = selectedItems.filter((i) => i.status === "modified").length;
35574
+ const toRemove = selectedItems.filter((i) => i.status === "deleted").length;
35575
+ const summary = [
35576
+ toAdd > 0 ? `add ${toAdd}` : "",
35577
+ toUpdate > 0 ? `update ${toUpdate}` : "",
35578
+ toRemove > 0 ? `remove ${toRemove}` : ""
35579
+ ].filter(Boolean).join(", ");
35580
+ const confirmResult = await se({
35581
+ message: `Proceed? (${summary})`,
35582
+ initialValue: true
35583
+ });
35584
+ if (lD(confirmResult) || !confirmResult) {
35585
+ ue("Sync cancelled");
35586
+ process.exit(0);
35587
+ }
35588
+ spinner.start("Syncing...");
35589
+ const syncResult = await syncSelectedItems(claudeDir, selectedItems, githubToken, (file, action) => {
35590
+ spinner.message(`${action}: ${source_default.cyan(file)}`);
35591
+ });
35592
+ spinner.stop("Sync complete");
35593
+ const results = [];
35594
+ if (syncResult.success > 0)
35595
+ results.push(source_default.green(`${syncResult.success} added/updated`));
35596
+ if (syncResult.deleted > 0)
35597
+ results.push(source_default.red(`${syncResult.deleted} removed`));
35598
+ if (syncResult.failed > 0)
35599
+ results.push(source_default.yellow(`${syncResult.failed} failed`));
35600
+ f2.success(results.join(", "));
35601
+ const scriptsWereSynced = selectedItems.some((i) => i.category === "scripts");
35602
+ if (scriptsWereSynced) {
35603
+ spinner.start("Installing scripts dependencies...");
35604
+ await installScriptsDependencies(claudeDir);
35605
+ spinner.stop("Scripts dependencies installed");
35606
+ }
35607
+ $e(source_default.green("✅ Sync completed"));
35608
+ } catch (error) {
35609
+ if (error instanceof Error) {
35610
+ f2.error(error.message);
35611
+ }
35612
+ $e(source_default.red("❌ Sync failed"));
35613
+ process.exit(1);
35614
+ }
35615
+ }
35616
+
35136
35617
  // src/cli.ts
35137
35618
  import { readFileSync as readFileSync2 } from "fs";
35138
35619
  import { dirname as dirname4, join } from "path";
@@ -35197,6 +35678,11 @@ proCmd.command("update").description("Update premium configurations").action((op
35197
35678
  const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
35198
35679
  proUpdateCommand({ folder: claudeCodeFolder });
35199
35680
  });
35681
+ proCmd.command("sync").description("Sync premium configurations with selective update").action((options, command) => {
35682
+ const parentOptions = command.parent.parent.opts();
35683
+ const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
35684
+ proSyncCommand({ folder: claudeCodeFolder });
35685
+ });
35200
35686
  program2.parse(process.argv);
35201
35687
  if (!process.argv.slice(2).length) {
35202
35688
  console.log(source_default.blue("\uD83D\uDE80 AIBlueprint CLI"));