@braingrid/cli 0.2.45 → 0.2.47

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/CHANGELOG.md CHANGED
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.47] - 2026-02-20
11
+
12
+ ### Fixed
13
+
14
+ - **Build hooks** — enforce git push before build session exit, source shared log-helper instead of duplicating logging setup
15
+
16
+ ## [0.2.46] - 2026-02-20
17
+
18
+ ### Fixed
19
+
20
+ - **Build sync errors** — log sync errors and add bulk status fallback
21
+ - **Cut-release command** — restore `/cut-release` slash command lost during previous refactor
22
+
10
23
  ## [0.2.45] - 2026-02-20
11
24
 
12
25
  ### Fixed
package/dist/cli.js CHANGED
@@ -228,7 +228,7 @@ async function axiosWithRetry(config2, options) {
228
228
 
229
229
  // src/build-config.ts
230
230
  var BUILD_ENV = true ? "production" : process.env.NODE_ENV === "test" ? "development" : "production";
231
- var CLI_VERSION = true ? "0.2.45" : "0.0.0-test";
231
+ var CLI_VERSION = true ? "0.2.47" : "0.0.0-test";
232
232
  var PRODUCTION_CONFIG = {
233
233
  apiUrl: "https://app.braingrid.ai",
234
234
  workosAuthUrl: "https://auth.braingrid.ai",
@@ -2631,10 +2631,33 @@ var ProjectService = class {
2631
2631
  // src/services/setup-service.ts
2632
2632
  import * as fs2 from "fs/promises";
2633
2633
  import * as path2 from "path";
2634
+ import axios5 from "axios";
2634
2635
  var GITHUB_OWNER = "BrainGridAI";
2635
2636
  var GITHUB_REPO = "braingrid";
2637
+ var GITHUB_API_BASE = `https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents`;
2636
2638
  var MAX_RETRIES = 3;
2637
2639
  var INITIAL_RETRY_DELAY = 100;
2640
+ async function getGitHubToken() {
2641
+ try {
2642
+ const { stdout } = await execAsync("gh auth token");
2643
+ return stdout.trim() || null;
2644
+ } catch {
2645
+ return null;
2646
+ }
2647
+ }
2648
+ var cachedHeaders = null;
2649
+ async function getGitHubHeaders() {
2650
+ if (cachedHeaders) return cachedHeaders;
2651
+ const headers = {
2652
+ Accept: "application/vnd.github.v3+json"
2653
+ };
2654
+ const token = await getGitHubToken();
2655
+ if (token) {
2656
+ headers.Authorization = `token ${token}`;
2657
+ }
2658
+ cachedHeaders = headers;
2659
+ return headers;
2660
+ }
2638
2661
  var BEGIN_MARKER = "<!-- BEGIN BRAINGRID INTEGRATION -->";
2639
2662
  var END_MARKER = "<!-- END BRAINGRID INTEGRATION -->";
2640
2663
  async function withRetry(fn, retries = MAX_RETRIES, delay = INITIAL_RETRY_DELAY) {
@@ -2644,8 +2667,7 @@ async function withRetry(fn, retries = MAX_RETRIES, delay = INITIAL_RETRY_DELAY)
2644
2667
  if (retries === 0) {
2645
2668
  throw error;
2646
2669
  }
2647
- const errorMessage = error instanceof Error ? error.message : String(error);
2648
- const isNetworkError = errorMessage.includes("ECONNRESET") || errorMessage.includes("ETIMEDOUT") || errorMessage.includes("ENOTFOUND") || errorMessage.includes("network");
2670
+ const isNetworkError = axios5.isAxiosError(error) && !error.response;
2649
2671
  if (!isNetworkError) {
2650
2672
  throw error;
2651
2673
  }
@@ -2654,37 +2676,41 @@ async function withRetry(fn, retries = MAX_RETRIES, delay = INITIAL_RETRY_DELAY)
2654
2676
  }
2655
2677
  }
2656
2678
  function parseGitHubError(error) {
2657
- const errorMessage = error instanceof Error ? error.message : String(error);
2658
- if (errorMessage.includes("404") || errorMessage.includes("Not Found")) {
2659
- return "File or directory not found in BrainGrid repository";
2660
- }
2661
- if (errorMessage.includes("403") || errorMessage.includes("rate limit")) {
2662
- return "GitHub API rate limit exceeded. Please wait a few minutes and try again.\nCheck rate limit status: gh api rate_limit";
2663
- }
2664
- if (errorMessage.includes("401") || errorMessage.includes("Unauthorized")) {
2665
- return "GitHub CLI is not authenticated. Run: gh auth login";
2666
- }
2667
- try {
2668
- const match = errorMessage.match(/\{.*\}/s);
2669
- if (match) {
2670
- const errorData = JSON.parse(match[0]);
2671
- return errorData.message || errorMessage;
2679
+ if (axios5.isAxiosError(error)) {
2680
+ const status = error.response?.status;
2681
+ const data = error.response?.data;
2682
+ if (status === 404) {
2683
+ return "File or directory not found in BrainGrid repository";
2672
2684
  }
2673
- } catch {
2685
+ if (status === 403) {
2686
+ return "GitHub API rate limit exceeded. Please wait a few minutes and try again.\nTip: Install GitHub CLI (gh) for higher rate limits: https://cli.github.com";
2687
+ }
2688
+ if (status === 401) {
2689
+ return "GitHub API authentication failed. Your gh auth token may be expired.";
2690
+ }
2691
+ if (data?.message) {
2692
+ return data.message;
2693
+ }
2694
+ if (!error.response) {
2695
+ return `Network error: ${error.message}`;
2696
+ }
2697
+ return error.message;
2674
2698
  }
2675
- return errorMessage;
2699
+ return error instanceof Error ? error.message : String(error);
2676
2700
  }
2677
- async function fetchFileFromGitHub(path7) {
2701
+ async function fetchFileFromGitHub(filePath) {
2678
2702
  return withRetry(async () => {
2679
2703
  try {
2680
- const command = `gh api repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${path7}`;
2681
- const { stdout } = await execAsync(command);
2682
- const response = JSON.parse(stdout);
2704
+ const headers = await getGitHubHeaders();
2705
+ const { data: response } = await axios5.get(
2706
+ `${GITHUB_API_BASE}/${filePath}`,
2707
+ { headers }
2708
+ );
2683
2709
  if (response.type !== "file") {
2684
- throw new Error(`Path ${path7} is not a file`);
2710
+ throw new Error(`Path ${filePath} is not a file`);
2685
2711
  }
2686
2712
  if (!response.content || !response.encoding) {
2687
- throw new Error(`No content found for file ${path7}`);
2713
+ throw new Error(`No content found for file ${filePath}`);
2688
2714
  }
2689
2715
  if (response.encoding !== "base64") {
2690
2716
  throw new Error(`Unexpected encoding: ${response.encoding}`);
@@ -2692,19 +2718,27 @@ async function fetchFileFromGitHub(path7) {
2692
2718
  const content = Buffer.from(response.content, "base64").toString("utf8");
2693
2719
  return content;
2694
2720
  } catch (error) {
2721
+ if (axios5.isAxiosError(error) && !error.response) {
2722
+ throw error;
2723
+ }
2724
+ if (error instanceof Error && error.message.startsWith("Failed to fetch file")) {
2725
+ throw error;
2726
+ }
2695
2727
  const parsedError = parseGitHubError(error);
2696
- throw new Error(`Failed to fetch file ${path7}: ${parsedError}`);
2728
+ throw new Error(`Failed to fetch file ${filePath}: ${parsedError}`);
2697
2729
  }
2698
2730
  });
2699
2731
  }
2700
- async function listGitHubDirectory(path7) {
2732
+ async function listGitHubDirectory(dirPath) {
2701
2733
  return withRetry(async () => {
2702
2734
  try {
2703
- const command = `gh api repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${path7}`;
2704
- const { stdout } = await execAsync(command);
2705
- const response = JSON.parse(stdout);
2735
+ const headers = await getGitHubHeaders();
2736
+ const { data: response } = await axios5.get(
2737
+ `${GITHUB_API_BASE}/${dirPath}`,
2738
+ { headers }
2739
+ );
2706
2740
  if (!Array.isArray(response)) {
2707
- throw new Error(`Path ${path7} is not a directory`);
2741
+ throw new Error(`Path ${dirPath} is not a directory`);
2708
2742
  }
2709
2743
  return response.map((item) => ({
2710
2744
  name: item.name,
@@ -2712,8 +2746,14 @@ async function listGitHubDirectory(path7) {
2712
2746
  path: item.path
2713
2747
  }));
2714
2748
  } catch (error) {
2749
+ if (axios5.isAxiosError(error) && !error.response) {
2750
+ throw error;
2751
+ }
2752
+ if (error instanceof Error && error.message.startsWith("Failed to list directory")) {
2753
+ throw error;
2754
+ }
2715
2755
  const parsedError = parseGitHubError(error);
2716
- throw new Error(`Failed to list directory ${path7}: ${parsedError}`);
2756
+ throw new Error(`Failed to list directory ${dirPath}: ${parsedError}`);
2717
2757
  }
2718
2758
  });
2719
2759
  }
@@ -3358,7 +3398,7 @@ function showSpinner(message, color = chalk7.cyan) {
3358
3398
  import chalk8 from "chalk";
3359
3399
 
3360
3400
  // src/utils/version.ts
3361
- import axios5 from "axios";
3401
+ import axios6 from "axios";
3362
3402
  var PACKAGE_NAME = "@braingrid/cli";
3363
3403
  var NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}`;
3364
3404
  function getCurrentVersion() {
@@ -3366,7 +3406,7 @@ function getCurrentVersion() {
3366
3406
  }
3367
3407
  async function getLatestVersion(timeout = 1e4) {
3368
3408
  try {
3369
- const response = await axios5.get(NPM_REGISTRY_URL, {
3409
+ const response = await axios6.get(NPM_REGISTRY_URL, {
3370
3410
  timeout
3371
3411
  });
3372
3412
  return response.data["dist-tags"].latest;
@@ -3467,25 +3507,6 @@ async function fileExists(filePath) {
3467
3507
  return false;
3468
3508
  }
3469
3509
  }
3470
- async function checkPrerequisites() {
3471
- try {
3472
- await execAsync("gh --version");
3473
- } catch {
3474
- return {
3475
- success: false,
3476
- message: chalk9.red("\u274C GitHub CLI is not installed.\n\n") + chalk9.dim("Install instructions:\n") + chalk9.dim(" macOS: ") + chalk9.cyan("brew install gh") + chalk9.dim("\n") + chalk9.dim(" Windows: ") + chalk9.cyan("winget install GitHub.CLI") + chalk9.dim("\n") + chalk9.dim(" Linux: See ") + chalk9.cyan("https://cli.github.com/manual/installation") + chalk9.dim("\n\n") + chalk9.dim("After installing, run: ") + chalk9.cyan("gh auth login")
3477
- };
3478
- }
3479
- try {
3480
- await execAsync("gh auth status");
3481
- } catch {
3482
- return {
3483
- success: false,
3484
- message: chalk9.red("\u274C Not authenticated with GitHub CLI.\n\n") + chalk9.dim("Please run: ") + chalk9.cyan("gh auth login")
3485
- };
3486
- }
3487
- return null;
3488
- }
3489
3510
  async function getFileList(sourcePaths, targetPaths) {
3490
3511
  const operations = [];
3491
3512
  async function processDirectory(sourceDir, targetDir, dirIndex) {
@@ -3583,10 +3604,6 @@ async function installFiles(operations, force, dirCount) {
3583
3604
  return { installedPerDir, skipped, cancelled: false };
3584
3605
  }
3585
3606
  async function _handleSetup(config2, opts) {
3586
- const prerequisiteError = await checkPrerequisites();
3587
- if (prerequisiteError) {
3588
- return prerequisiteError;
3589
- }
3590
3607
  console.log(chalk9.bold(`\u{1F680} Setting up ${config2.name} integration...
3591
3608
  `));
3592
3609
  const operations = await getFileList(config2.sourceDirs, config2.targetDirs);