@braingrid/cli 0.2.51 → 0.2.53
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 +32 -0
- package/dist/cli.js +242 -55
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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.
|
|
231
|
+
var CLI_VERSION = true ? "0.2.53" : "0.0.0-test";
|
|
232
232
|
var PRODUCTION_CONFIG = {
|
|
233
233
|
apiUrl: "https://app.braingrid.ai",
|
|
234
234
|
workosAuthUrl: "https://auth.braingrid.ai",
|
|
@@ -2629,9 +2629,39 @@ var ProjectService = class {
|
|
|
2629
2629
|
};
|
|
2630
2630
|
|
|
2631
2631
|
// src/services/setup-service.ts
|
|
2632
|
-
import * as
|
|
2633
|
-
import * as
|
|
2632
|
+
import * as fs3 from "fs/promises";
|
|
2633
|
+
import * as path3 from "path";
|
|
2634
2634
|
import axios5 from "axios";
|
|
2635
|
+
|
|
2636
|
+
// src/utils/cli-logger.ts
|
|
2637
|
+
import * as fs2 from "fs";
|
|
2638
|
+
import * as path2 from "path";
|
|
2639
|
+
var logFile = null;
|
|
2640
|
+
var logStream = null;
|
|
2641
|
+
function initLogger(logPath) {
|
|
2642
|
+
if (logStream) {
|
|
2643
|
+
logStream.end();
|
|
2644
|
+
}
|
|
2645
|
+
const dir = path2.dirname(logPath);
|
|
2646
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
2647
|
+
logFile = logPath;
|
|
2648
|
+
logStream = fs2.createWriteStream(logPath, { flags: "a" });
|
|
2649
|
+
}
|
|
2650
|
+
function log(level, component, event, details = "") {
|
|
2651
|
+
if (!logStream) return;
|
|
2652
|
+
const now = /* @__PURE__ */ new Date();
|
|
2653
|
+
const ts = now.toLocaleTimeString("en-US", { hour12: false });
|
|
2654
|
+
const line = `${ts} [${level.padEnd(5)}] ${component} | ${event} | ${details}
|
|
2655
|
+
`;
|
|
2656
|
+
logStream.write(line);
|
|
2657
|
+
}
|
|
2658
|
+
function closeLogger() {
|
|
2659
|
+
logStream?.end();
|
|
2660
|
+
logStream = null;
|
|
2661
|
+
logFile = null;
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
// src/services/setup-service.ts
|
|
2635
2665
|
var GITHUB_OWNER = "BrainGridAI";
|
|
2636
2666
|
var GITHUB_REPO = "braingrid";
|
|
2637
2667
|
var GITHUB_API_BASE = `https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents`;
|
|
@@ -2664,6 +2694,12 @@ async function githubGet(url) {
|
|
|
2664
2694
|
return await axios5.get(url, { headers });
|
|
2665
2695
|
} catch (error) {
|
|
2666
2696
|
if (axios5.isAxiosError(error) && error.response?.status === 401 && cachedHeaders?.Authorization) {
|
|
2697
|
+
log(
|
|
2698
|
+
"WARN",
|
|
2699
|
+
"github-api",
|
|
2700
|
+
"auth_fallback",
|
|
2701
|
+
"dropping expired token, retrying unauthenticated"
|
|
2702
|
+
);
|
|
2667
2703
|
delete cachedHeaders.Authorization;
|
|
2668
2704
|
return axios5.get(url, { headers: cachedHeaders });
|
|
2669
2705
|
}
|
|
@@ -2683,6 +2719,7 @@ async function withRetry(fn, retries = MAX_RETRIES, delay = INITIAL_RETRY_DELAY)
|
|
|
2683
2719
|
if (!isNetworkError) {
|
|
2684
2720
|
throw error;
|
|
2685
2721
|
}
|
|
2722
|
+
log("WARN", "github-api", "retry", `attempt=${MAX_RETRIES - retries + 1} delay=${delay}ms`);
|
|
2686
2723
|
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
2687
2724
|
return withRetry(fn, retries - 1, delay * 2);
|
|
2688
2725
|
}
|
|
@@ -2712,6 +2749,7 @@ function parseGitHubError(error) {
|
|
|
2712
2749
|
}
|
|
2713
2750
|
async function fetchFileFromGitHub(filePath) {
|
|
2714
2751
|
return withRetry(async () => {
|
|
2752
|
+
log("INFO", "github-api", "fetch", `path=${filePath}`);
|
|
2715
2753
|
try {
|
|
2716
2754
|
const { data: response } = await githubGet(
|
|
2717
2755
|
`${GITHUB_API_BASE}/${filePath}`
|
|
@@ -2768,9 +2806,9 @@ async function listGitHubDirectory(dirPath) {
|
|
|
2768
2806
|
async function copyFileFromGitHub(sourcePath, targetPath) {
|
|
2769
2807
|
try {
|
|
2770
2808
|
const content = await fetchFileFromGitHub(sourcePath);
|
|
2771
|
-
const parentDir =
|
|
2772
|
-
await
|
|
2773
|
-
await
|
|
2809
|
+
const parentDir = path3.dirname(targetPath);
|
|
2810
|
+
await fs3.mkdir(parentDir, { recursive: true });
|
|
2811
|
+
await fs3.writeFile(targetPath, content, { encoding: "utf8", mode: 420 });
|
|
2774
2812
|
} catch (error) {
|
|
2775
2813
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2776
2814
|
throw new Error(`Failed to copy file ${sourcePath} to ${targetPath}: ${errorMessage}`);
|
|
@@ -2781,7 +2819,7 @@ async function injectContentIntoFile(targetPath, content) {
|
|
|
2781
2819
|
let fileContent;
|
|
2782
2820
|
let fileExists3 = false;
|
|
2783
2821
|
try {
|
|
2784
|
-
fileContent = await
|
|
2822
|
+
fileContent = await fs3.readFile(targetPath, "utf8");
|
|
2785
2823
|
fileExists3 = true;
|
|
2786
2824
|
} catch {
|
|
2787
2825
|
fileContent = "";
|
|
@@ -2803,7 +2841,7 @@ async function injectContentIntoFile(targetPath, content) {
|
|
|
2803
2841
|
const newContent = `${before}${BEGIN_MARKER}
|
|
2804
2842
|
${cleanContent}
|
|
2805
2843
|
${END_MARKER}${after}`;
|
|
2806
|
-
await
|
|
2844
|
+
await fs3.writeFile(targetPath, newContent, { encoding: "utf8" });
|
|
2807
2845
|
} else {
|
|
2808
2846
|
const newContent = `${fileContent}
|
|
2809
2847
|
|
|
@@ -2811,16 +2849,16 @@ ${BEGIN_MARKER}
|
|
|
2811
2849
|
${cleanContent}
|
|
2812
2850
|
${END_MARKER}
|
|
2813
2851
|
`;
|
|
2814
|
-
await
|
|
2852
|
+
await fs3.writeFile(targetPath, newContent, { encoding: "utf8" });
|
|
2815
2853
|
}
|
|
2816
2854
|
} else {
|
|
2817
|
-
const parentDir =
|
|
2818
|
-
await
|
|
2855
|
+
const parentDir = path3.dirname(targetPath);
|
|
2856
|
+
await fs3.mkdir(parentDir, { recursive: true });
|
|
2819
2857
|
const newContent = `${BEGIN_MARKER}
|
|
2820
2858
|
${cleanContent}
|
|
2821
2859
|
${END_MARKER}
|
|
2822
2860
|
`;
|
|
2823
|
-
await
|
|
2861
|
+
await fs3.writeFile(targetPath, newContent, { encoding: "utf8", mode: 420 });
|
|
2824
2862
|
}
|
|
2825
2863
|
} catch (error) {
|
|
2826
2864
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -2829,9 +2867,9 @@ ${END_MARKER}
|
|
|
2829
2867
|
}
|
|
2830
2868
|
async function installStatusLineScript(scriptContent, targetPath = ".claude/statusline.sh") {
|
|
2831
2869
|
try {
|
|
2832
|
-
const parentDir =
|
|
2833
|
-
await
|
|
2834
|
-
await
|
|
2870
|
+
const parentDir = path3.dirname(targetPath);
|
|
2871
|
+
await fs3.mkdir(parentDir, { recursive: true });
|
|
2872
|
+
await fs3.writeFile(targetPath, scriptContent, { encoding: "utf8", mode: 493 });
|
|
2835
2873
|
} catch (error) {
|
|
2836
2874
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2837
2875
|
throw new Error(`Failed to install status line script to ${targetPath}: ${errorMessage}`);
|
|
@@ -2839,9 +2877,9 @@ async function installStatusLineScript(scriptContent, targetPath = ".claude/stat
|
|
|
2839
2877
|
}
|
|
2840
2878
|
async function installHookScript(scriptContent, targetPath) {
|
|
2841
2879
|
try {
|
|
2842
|
-
const parentDir =
|
|
2843
|
-
await
|
|
2844
|
-
await
|
|
2880
|
+
const parentDir = path3.dirname(targetPath);
|
|
2881
|
+
await fs3.mkdir(parentDir, { recursive: true });
|
|
2882
|
+
await fs3.writeFile(targetPath, scriptContent, { encoding: "utf8", mode: 493 });
|
|
2845
2883
|
} catch (error) {
|
|
2846
2884
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2847
2885
|
throw new Error(`Failed to install hook script to ${targetPath}: ${errorMessage}`);
|
|
@@ -2850,11 +2888,17 @@ async function installHookScript(scriptContent, targetPath) {
|
|
|
2850
2888
|
async function copyBraingridReadme(targetPath = ".braingrid/README.md") {
|
|
2851
2889
|
try {
|
|
2852
2890
|
const content = await fetchFileFromGitHub("claude-code/README.md");
|
|
2853
|
-
const parentDir =
|
|
2854
|
-
await
|
|
2855
|
-
await
|
|
2891
|
+
const parentDir = path3.dirname(targetPath);
|
|
2892
|
+
await fs3.mkdir(parentDir, { recursive: true });
|
|
2893
|
+
await fs3.writeFile(targetPath, content, { encoding: "utf8", mode: 420 });
|
|
2856
2894
|
return true;
|
|
2857
|
-
} catch {
|
|
2895
|
+
} catch (error) {
|
|
2896
|
+
log(
|
|
2897
|
+
"WARN",
|
|
2898
|
+
"setup",
|
|
2899
|
+
"readme_failed",
|
|
2900
|
+
`error=${error instanceof Error ? error.message : String(error)}`
|
|
2901
|
+
);
|
|
2858
2902
|
return false;
|
|
2859
2903
|
}
|
|
2860
2904
|
}
|
|
@@ -2920,7 +2964,7 @@ async function updateClaudeSettings(settingsPath = ".claude/settings.json", stat
|
|
|
2920
2964
|
try {
|
|
2921
2965
|
let settings = {};
|
|
2922
2966
|
try {
|
|
2923
|
-
const content2 = await
|
|
2967
|
+
const content2 = await fs3.readFile(settingsPath, "utf8");
|
|
2924
2968
|
settings = JSON.parse(content2);
|
|
2925
2969
|
} catch {
|
|
2926
2970
|
}
|
|
@@ -2966,10 +3010,10 @@ async function updateClaudeSettings(settingsPath = ".claude/settings.json", stat
|
|
|
2966
3010
|
...existingHooks,
|
|
2967
3011
|
...mergedByType
|
|
2968
3012
|
};
|
|
2969
|
-
const parentDir =
|
|
2970
|
-
await
|
|
3013
|
+
const parentDir = path3.dirname(settingsPath);
|
|
3014
|
+
await fs3.mkdir(parentDir, { recursive: true });
|
|
2971
3015
|
const content = JSON.stringify(settings, null, " ");
|
|
2972
|
-
await
|
|
3016
|
+
await fs3.writeFile(settingsPath, content, { encoding: "utf8" });
|
|
2973
3017
|
} catch (error) {
|
|
2974
3018
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2975
3019
|
throw new Error(`Failed to update Claude settings at ${settingsPath}: ${errorMessage}`);
|
|
@@ -3177,7 +3221,7 @@ function getManualInstallInstructions() {
|
|
|
3177
3221
|
|
|
3178
3222
|
// src/utils/github-repo.ts
|
|
3179
3223
|
import { exec as exec3 } from "child_process";
|
|
3180
|
-
import
|
|
3224
|
+
import path4 from "path";
|
|
3181
3225
|
import { promisify as promisify3 } from "util";
|
|
3182
3226
|
var execAsync4 = promisify3(exec3);
|
|
3183
3227
|
async function initGitRepo() {
|
|
@@ -3197,7 +3241,7 @@ async function isGhAuthenticated() {
|
|
|
3197
3241
|
}
|
|
3198
3242
|
}
|
|
3199
3243
|
function getCurrentDirectoryName() {
|
|
3200
|
-
return
|
|
3244
|
+
return path4.basename(process.cwd());
|
|
3201
3245
|
}
|
|
3202
3246
|
async function createGitHubRepoWithGh(name, isPrivate) {
|
|
3203
3247
|
try {
|
|
@@ -3230,11 +3274,11 @@ async function canUseGhAutomation() {
|
|
|
3230
3274
|
|
|
3231
3275
|
// src/utils/gitignore.ts
|
|
3232
3276
|
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
3233
|
-
import
|
|
3277
|
+
import path5 from "path";
|
|
3234
3278
|
async function addBraingridTempToGitignore() {
|
|
3235
3279
|
const gitRoot = await getGitRoot();
|
|
3236
3280
|
if (!gitRoot) return;
|
|
3237
|
-
const gitignorePath =
|
|
3281
|
+
const gitignorePath = path5.join(gitRoot, ".gitignore");
|
|
3238
3282
|
const entry = ".braingrid/temp/";
|
|
3239
3283
|
let content = "";
|
|
3240
3284
|
try {
|
|
@@ -3253,8 +3297,8 @@ ${entry}
|
|
|
3253
3297
|
}
|
|
3254
3298
|
|
|
3255
3299
|
// src/utils/local-store.ts
|
|
3256
|
-
import
|
|
3257
|
-
import
|
|
3300
|
+
import fs4 from "fs";
|
|
3301
|
+
import path6 from "path";
|
|
3258
3302
|
|
|
3259
3303
|
// src/types/local-project.ts
|
|
3260
3304
|
import { z } from "zod";
|
|
@@ -3284,28 +3328,28 @@ async function getDefaultCwd() {
|
|
|
3284
3328
|
}
|
|
3285
3329
|
async function getBraingridDir(cwd) {
|
|
3286
3330
|
const dir = cwd ?? await getDefaultCwd();
|
|
3287
|
-
return
|
|
3331
|
+
return path6.join(dir, BRAINGRID_DIR);
|
|
3288
3332
|
}
|
|
3289
3333
|
async function getProjectConfigPath(cwd) {
|
|
3290
3334
|
const braingridDir = await getBraingridDir(cwd);
|
|
3291
|
-
return
|
|
3335
|
+
return path6.join(braingridDir, PROJECT_CONFIG_FILE);
|
|
3292
3336
|
}
|
|
3293
3337
|
async function projectConfigExists(cwd) {
|
|
3294
3338
|
const configPath = await getProjectConfigPath(cwd);
|
|
3295
|
-
return
|
|
3339
|
+
return fs4.existsSync(configPath);
|
|
3296
3340
|
}
|
|
3297
3341
|
async function ensureBraingridDir(cwd) {
|
|
3298
3342
|
const dir = await getBraingridDir(cwd);
|
|
3299
|
-
if (!
|
|
3300
|
-
|
|
3343
|
+
if (!fs4.existsSync(dir)) {
|
|
3344
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
3301
3345
|
}
|
|
3302
3346
|
}
|
|
3303
3347
|
async function loadProjectConfig(cwd) {
|
|
3304
3348
|
const configPath = await getProjectConfigPath(cwd);
|
|
3305
|
-
if (!
|
|
3349
|
+
if (!fs4.existsSync(configPath)) {
|
|
3306
3350
|
throw new Error(`Project not initialized. Run 'braingrid init' to initialize this repository.`);
|
|
3307
3351
|
}
|
|
3308
|
-
const content =
|
|
3352
|
+
const content = fs4.readFileSync(configPath, "utf8");
|
|
3309
3353
|
const data = JSON.parse(content);
|
|
3310
3354
|
return LocalProjectConfigSchema.parse(data);
|
|
3311
3355
|
}
|
|
@@ -3313,7 +3357,7 @@ async function saveProjectConfig(config2, cwd) {
|
|
|
3313
3357
|
await ensureBraingridDir(cwd);
|
|
3314
3358
|
const configPath = await getProjectConfigPath(cwd);
|
|
3315
3359
|
const content = JSON.stringify(config2, null, 2);
|
|
3316
|
-
|
|
3360
|
+
fs4.writeFileSync(configPath, content, "utf8");
|
|
3317
3361
|
}
|
|
3318
3362
|
async function getLocalProjectId(cwd) {
|
|
3319
3363
|
try {
|
|
@@ -3504,13 +3548,13 @@ async function checkAndShowUpdateWarning() {
|
|
|
3504
3548
|
}
|
|
3505
3549
|
|
|
3506
3550
|
// src/handlers/setup.handlers.ts
|
|
3507
|
-
import * as
|
|
3508
|
-
import * as
|
|
3551
|
+
import * as fs5 from "fs/promises";
|
|
3552
|
+
import * as path7 from "path";
|
|
3509
3553
|
import { select } from "@inquirer/prompts";
|
|
3510
3554
|
import chalk9 from "chalk";
|
|
3511
3555
|
async function fileExists(filePath) {
|
|
3512
3556
|
try {
|
|
3513
|
-
await
|
|
3557
|
+
await fs5.access(filePath);
|
|
3514
3558
|
return true;
|
|
3515
3559
|
} catch {
|
|
3516
3560
|
return false;
|
|
@@ -3523,7 +3567,7 @@ async function getFileList(sourcePaths, targetPaths) {
|
|
|
3523
3567
|
const items = await listGitHubDirectory(sourceDir);
|
|
3524
3568
|
for (const item of items) {
|
|
3525
3569
|
if (item.type === "file") {
|
|
3526
|
-
const itemTargetPath =
|
|
3570
|
+
const itemTargetPath = path7.join(targetDir, item.name);
|
|
3527
3571
|
const exists = await fileExists(itemTargetPath);
|
|
3528
3572
|
operations.push({
|
|
3529
3573
|
type: "copy",
|
|
@@ -3533,11 +3577,17 @@ async function getFileList(sourcePaths, targetPaths) {
|
|
|
3533
3577
|
dirIndex
|
|
3534
3578
|
});
|
|
3535
3579
|
} else if (item.type === "dir") {
|
|
3536
|
-
const itemTargetPath =
|
|
3580
|
+
const itemTargetPath = path7.join(targetDir, item.name);
|
|
3537
3581
|
await processDirectory(item.path, itemTargetPath, dirIndex);
|
|
3538
3582
|
}
|
|
3539
3583
|
}
|
|
3540
3584
|
} catch (error) {
|
|
3585
|
+
log(
|
|
3586
|
+
"WARN",
|
|
3587
|
+
"setup",
|
|
3588
|
+
"list_dir_failed",
|
|
3589
|
+
`source=${sourceDir} error=${error instanceof Error ? error.message : String(error)}`
|
|
3590
|
+
);
|
|
3541
3591
|
console.warn(
|
|
3542
3592
|
chalk9.yellow(`\u26A0\uFE0F Could not list directory: ${sourceDir}`),
|
|
3543
3593
|
error instanceof Error ? error.message : String(error)
|
|
@@ -3591,6 +3641,7 @@ async function installFiles(operations, force, dirCount) {
|
|
|
3591
3641
|
if (response === "quit") {
|
|
3592
3642
|
return { installedPerDir, skipped, cancelled: true };
|
|
3593
3643
|
} else if (response === "skip") {
|
|
3644
|
+
log("INFO", "setup", "skip_file", `target=${operation.targetPath} reason=user_skip`);
|
|
3594
3645
|
skipped++;
|
|
3595
3646
|
continue;
|
|
3596
3647
|
} else if (response === "all") {
|
|
@@ -3599,10 +3650,17 @@ async function installFiles(operations, force, dirCount) {
|
|
|
3599
3650
|
}
|
|
3600
3651
|
try {
|
|
3601
3652
|
await copyFileFromGitHub(operation.sourcePath, operation.targetPath);
|
|
3653
|
+
log("INFO", "setup", "copy_file", `target=${operation.targetPath}`);
|
|
3602
3654
|
if (operation.dirIndex !== void 0) {
|
|
3603
3655
|
installedPerDir[operation.dirIndex]++;
|
|
3604
3656
|
}
|
|
3605
3657
|
} catch (error) {
|
|
3658
|
+
log(
|
|
3659
|
+
"ERROR",
|
|
3660
|
+
"setup",
|
|
3661
|
+
"copy_file_failed",
|
|
3662
|
+
`target=${operation.targetPath} error=${error instanceof Error ? error.message : String(error)}`
|
|
3663
|
+
);
|
|
3606
3664
|
console.error(
|
|
3607
3665
|
chalk9.red(`Failed to copy ${operation.targetPath}:`),
|
|
3608
3666
|
error instanceof Error ? error.message : String(error)
|
|
@@ -3613,6 +3671,13 @@ async function installFiles(operations, force, dirCount) {
|
|
|
3613
3671
|
return { installedPerDir, skipped, cancelled: false };
|
|
3614
3672
|
}
|
|
3615
3673
|
async function _handleSetup(config2, opts) {
|
|
3674
|
+
initLogger(".braingrid/temp/setup-debug.log");
|
|
3675
|
+
log(
|
|
3676
|
+
"INFO",
|
|
3677
|
+
"setup",
|
|
3678
|
+
"start",
|
|
3679
|
+
`integration=${config2.name} force=${opts.force} dry_run=${opts.dryRun}`
|
|
3680
|
+
);
|
|
3616
3681
|
console.log(chalk9.bold(`\u{1F680} Setting up ${config2.name} integration...
|
|
3617
3682
|
`));
|
|
3618
3683
|
const operations = await getFileList(config2.sourceDirs, config2.targetDirs);
|
|
@@ -3646,13 +3711,23 @@ async function _handleSetup(config2, opts) {
|
|
|
3646
3711
|
try {
|
|
3647
3712
|
const content = await fetchFileFromGitHub(config2.injection.sourceFile);
|
|
3648
3713
|
await injectContentIntoFile(config2.injection.targetFile, content);
|
|
3714
|
+
log("INFO", "setup", "inject", `target=${config2.injection.targetFile}`);
|
|
3649
3715
|
} catch (error) {
|
|
3716
|
+
log(
|
|
3717
|
+
"ERROR",
|
|
3718
|
+
"setup",
|
|
3719
|
+
"inject_failed",
|
|
3720
|
+
`target=${config2.injection.targetFile} error=${error instanceof Error ? error.message : String(error)}`
|
|
3721
|
+
);
|
|
3650
3722
|
console.error(
|
|
3651
3723
|
chalk9.red(`Failed to inject content into ${config2.injection.targetFile}:`),
|
|
3652
3724
|
error instanceof Error ? error.message : String(error)
|
|
3653
3725
|
);
|
|
3654
3726
|
}
|
|
3655
|
-
await copyBraingridReadme();
|
|
3727
|
+
const readmeCopied = await copyBraingridReadme();
|
|
3728
|
+
if (readmeCopied) {
|
|
3729
|
+
log("INFO", "setup", "readme", "path=.braingrid/README.md");
|
|
3730
|
+
}
|
|
3656
3731
|
return {
|
|
3657
3732
|
success: true,
|
|
3658
3733
|
data: {
|
|
@@ -3720,7 +3795,14 @@ async function handleSetupClaudeCode(opts) {
|
|
|
3720
3795
|
const scriptContent = await fetchFileFromGitHub("claude-code/statusline.sh");
|
|
3721
3796
|
await installStatusLineScript(scriptContent);
|
|
3722
3797
|
statusLineInstalled = true;
|
|
3798
|
+
log("INFO", "setup", "statusline", "path=.claude/statusline.sh");
|
|
3723
3799
|
} catch (error) {
|
|
3800
|
+
log(
|
|
3801
|
+
"ERROR",
|
|
3802
|
+
"setup",
|
|
3803
|
+
"statusline_failed",
|
|
3804
|
+
`error=${error instanceof Error ? error.message : String(error)}`
|
|
3805
|
+
);
|
|
3724
3806
|
console.error(
|
|
3725
3807
|
chalk9.yellow("\u26A0\uFE0F Failed to install status line script:"),
|
|
3726
3808
|
error instanceof Error ? error.message : String(error)
|
|
@@ -3728,7 +3810,14 @@ async function handleSetupClaudeCode(opts) {
|
|
|
3728
3810
|
}
|
|
3729
3811
|
try {
|
|
3730
3812
|
await updateClaudeSettings();
|
|
3813
|
+
log("INFO", "setup", "settings", "path=.claude/settings.json");
|
|
3731
3814
|
} catch (error) {
|
|
3815
|
+
log(
|
|
3816
|
+
"ERROR",
|
|
3817
|
+
"setup",
|
|
3818
|
+
"settings_failed",
|
|
3819
|
+
`error=${error instanceof Error ? error.message : String(error)}`
|
|
3820
|
+
);
|
|
3732
3821
|
console.error(
|
|
3733
3822
|
chalk9.yellow("\u26A0\uFE0F Failed to update Claude settings:"),
|
|
3734
3823
|
error instanceof Error ? error.message : String(error)
|
|
@@ -3746,7 +3835,14 @@ async function handleSetupClaudeCode(opts) {
|
|
|
3746
3835
|
const content = await fetchFileFromGitHub(`claude-code/hooks/${script}`);
|
|
3747
3836
|
await installHookScript(content, `.claude/hooks/${script}`);
|
|
3748
3837
|
installedHooks.push(script);
|
|
3838
|
+
log("INFO", "setup", "hook", `script=${script}`);
|
|
3749
3839
|
} catch (error) {
|
|
3840
|
+
log(
|
|
3841
|
+
"ERROR",
|
|
3842
|
+
"setup",
|
|
3843
|
+
"hook_failed",
|
|
3844
|
+
`script=${script} error=${error instanceof Error ? error.message : String(error)}`
|
|
3845
|
+
);
|
|
3750
3846
|
console.error(
|
|
3751
3847
|
chalk9.yellow(`\u26A0\uFE0F Failed to install hook ${script}:`),
|
|
3752
3848
|
error instanceof Error ? error.message : String(error)
|
|
@@ -3756,12 +3852,22 @@ async function handleSetupClaudeCode(opts) {
|
|
|
3756
3852
|
const statusLineMessage = statusLineInstalled ? chalk9.dim(" Status line: .claude/statusline.sh\n") : "";
|
|
3757
3853
|
const hooksMessage = installedHooks.map((s) => chalk9.dim(` Hook script: .claude/hooks/${s}
|
|
3758
3854
|
`)).join("");
|
|
3855
|
+
const totalInstalled = displayPerDir.reduce((a, b) => a + b, 0);
|
|
3856
|
+
log(
|
|
3857
|
+
"INFO",
|
|
3858
|
+
"setup",
|
|
3859
|
+
"complete",
|
|
3860
|
+
`installed=${totalInstalled} skipped=${setupResult.data.skipped} hooks=${installedHooks.length}`
|
|
3861
|
+
);
|
|
3862
|
+
closeLogger();
|
|
3759
3863
|
return {
|
|
3760
3864
|
success: true,
|
|
3761
3865
|
message: buildSuccessMessage(config2, displayPerDir, statusLineMessage + hooksMessage)
|
|
3762
3866
|
};
|
|
3763
3867
|
} catch (error) {
|
|
3764
3868
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3869
|
+
log("ERROR", "setup", "fatal", `error=${errorMessage}`);
|
|
3870
|
+
closeLogger();
|
|
3765
3871
|
return {
|
|
3766
3872
|
success: false,
|
|
3767
3873
|
message: chalk9.red(`\u274C Setup failed: ${errorMessage}`)
|
|
@@ -3788,13 +3894,18 @@ async function handleSetupCursor(opts) {
|
|
|
3788
3894
|
if (!isSetupResult(setupResult)) {
|
|
3789
3895
|
return setupResult;
|
|
3790
3896
|
}
|
|
3791
|
-
const { installedPerDir } = setupResult.data;
|
|
3897
|
+
const { installedPerDir, skipped } = setupResult.data;
|
|
3898
|
+
const totalInstalled = installedPerDir.reduce((a, b) => a + b, 0);
|
|
3899
|
+
log("INFO", "setup", "complete", `installed=${totalInstalled} skipped=${skipped}`);
|
|
3900
|
+
closeLogger();
|
|
3792
3901
|
return {
|
|
3793
3902
|
success: true,
|
|
3794
3903
|
message: buildSuccessMessage(config2, installedPerDir, "")
|
|
3795
3904
|
};
|
|
3796
3905
|
} catch (error) {
|
|
3797
3906
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3907
|
+
log("ERROR", "setup", "fatal", `error=${errorMessage}`);
|
|
3908
|
+
closeLogger();
|
|
3798
3909
|
return {
|
|
3799
3910
|
success: false,
|
|
3800
3911
|
message: chalk9.red(`\u274C Setup failed: ${errorMessage}`)
|
|
@@ -4147,7 +4258,13 @@ async function handleNoProjectForRepository(owner, name, gitInfo, githubService,
|
|
|
4147
4258
|
try {
|
|
4148
4259
|
const installationsResponse = await githubService.listInstallations({ limit: 100 });
|
|
4149
4260
|
allInstallations = installationsResponse.installations;
|
|
4150
|
-
} catch {
|
|
4261
|
+
} catch (error) {
|
|
4262
|
+
log(
|
|
4263
|
+
"WARN",
|
|
4264
|
+
"init",
|
|
4265
|
+
"list_installations_failed",
|
|
4266
|
+
`error=${error instanceof Error ? error.message : String(error)}`
|
|
4267
|
+
);
|
|
4151
4268
|
allInstallations = [];
|
|
4152
4269
|
}
|
|
4153
4270
|
const webUrl = config2.getWebAppUrl();
|
|
@@ -4296,6 +4413,9 @@ async function handleNoGitRemote() {
|
|
|
4296
4413
|
}
|
|
4297
4414
|
async function handleInit(opts) {
|
|
4298
4415
|
try {
|
|
4416
|
+
const initStartTime = Date.now();
|
|
4417
|
+
initLogger(".braingrid/temp/init-debug.log");
|
|
4418
|
+
log("INFO", "init", "start", `force=${opts.force} project=${opts.project || "auto-detect"}`);
|
|
4299
4419
|
const updateInfo = await isUpdateAvailable();
|
|
4300
4420
|
if (updateInfo.available && updateInfo.latestVersion) {
|
|
4301
4421
|
console.log(
|
|
@@ -4316,6 +4436,12 @@ async function handleInit(opts) {
|
|
|
4316
4436
|
}
|
|
4317
4437
|
console.log();
|
|
4318
4438
|
}
|
|
4439
|
+
log(
|
|
4440
|
+
"INFO",
|
|
4441
|
+
"init",
|
|
4442
|
+
"update_check",
|
|
4443
|
+
`available=${updateInfo.available} current=${updateInfo.currentVersion}${updateInfo.latestVersion ? ` latest=${updateInfo.latestVersion}` : ""}`
|
|
4444
|
+
);
|
|
4319
4445
|
const config2 = getConfig();
|
|
4320
4446
|
const { projectService, githubService, repositoryService, auth } = getServices();
|
|
4321
4447
|
if (!await isGitInstalled()) {
|
|
@@ -4340,12 +4466,14 @@ async function handleInit(opts) {
|
|
|
4340
4466
|
console.log(installResult.message);
|
|
4341
4467
|
console.log();
|
|
4342
4468
|
if (!await isGitInstalled()) {
|
|
4469
|
+
log("ERROR", "init", "git_check", "installed=false post_install=true");
|
|
4343
4470
|
return {
|
|
4344
4471
|
success: false,
|
|
4345
4472
|
message: chalk11.red("\u274C Git installation completed but git command not found\n\n") + chalk11.dim("You may need to restart your terminal or add Git to your PATH.\n") + getManualInstallInstructions()
|
|
4346
4473
|
};
|
|
4347
4474
|
}
|
|
4348
4475
|
}
|
|
4476
|
+
log("INFO", "init", "git_check", "installed=true");
|
|
4349
4477
|
if (!await isGhInstalled()) {
|
|
4350
4478
|
console.log(chalk11.blue("\n\u{1F4A1} GitHub CLI is highly recommended for working with BrainGrid."));
|
|
4351
4479
|
console.log(
|
|
@@ -4369,6 +4497,7 @@ async function handleInit(opts) {
|
|
|
4369
4497
|
console.log(chalk11.dim("Skipping GitHub CLI installation.\n"));
|
|
4370
4498
|
}
|
|
4371
4499
|
}
|
|
4500
|
+
log("INFO", "init", "gh_check", `installed=${await isGhInstalled()}`);
|
|
4372
4501
|
if (await projectConfigExists() && !opts.force) {
|
|
4373
4502
|
try {
|
|
4374
4503
|
const existing = await loadProjectConfig();
|
|
@@ -4379,7 +4508,13 @@ async function handleInit(opts) {
|
|
|
4379
4508
|
|
|
4380
4509
|
`) + chalk11.dim("Use --force to reinitialize")
|
|
4381
4510
|
};
|
|
4382
|
-
} catch {
|
|
4511
|
+
} catch (error) {
|
|
4512
|
+
log(
|
|
4513
|
+
"ERROR",
|
|
4514
|
+
"init",
|
|
4515
|
+
"config_load",
|
|
4516
|
+
`error=${error instanceof Error ? error.message : String(error)}`
|
|
4517
|
+
);
|
|
4383
4518
|
return {
|
|
4384
4519
|
success: false,
|
|
4385
4520
|
message: chalk11.yellow("\u26A0\uFE0F Invalid project configuration found.\n") + chalk11.dim("Use --force to reinitialize")
|
|
@@ -4387,6 +4522,7 @@ async function handleInit(opts) {
|
|
|
4387
4522
|
}
|
|
4388
4523
|
}
|
|
4389
4524
|
const isAuthenticated = await auth.isAuthenticated();
|
|
4525
|
+
log("INFO", "init", "auth_check", `authenticated=${isAuthenticated}`);
|
|
4390
4526
|
if (!isAuthenticated) {
|
|
4391
4527
|
const shouldLogin = await confirm2({
|
|
4392
4528
|
message: "You need to be authenticated. Would you like to log in / sign up now?",
|
|
@@ -4398,15 +4534,18 @@ async function handleInit(opts) {
|
|
|
4398
4534
|
message: chalk11.yellow("\u26A0\uFE0F Authentication required.\n") + chalk11.dim("Run ") + chalk11.cyan("braingrid login") + chalk11.dim(" when you're ready to authenticate.")
|
|
4399
4535
|
};
|
|
4400
4536
|
}
|
|
4537
|
+
log("WARN", "init", "login_required", "prompted=true");
|
|
4401
4538
|
console.log();
|
|
4402
4539
|
const loginResult = await handleLogin();
|
|
4403
4540
|
if (!loginResult.success) {
|
|
4541
|
+
log("ERROR", "init", "login_failed", "error=login handler returned failure");
|
|
4404
4542
|
return {
|
|
4405
4543
|
success: false,
|
|
4406
4544
|
message: chalk11.red("\u274C Login failed.\n") + chalk11.dim("Please try running ") + chalk11.cyan("braingrid login") + chalk11.dim(" again.")
|
|
4407
4545
|
};
|
|
4408
4546
|
}
|
|
4409
4547
|
if (!await auth.isAuthenticated()) {
|
|
4548
|
+
log("ERROR", "init", "login_failed", "error=login not completed");
|
|
4410
4549
|
return {
|
|
4411
4550
|
success: false,
|
|
4412
4551
|
message: chalk11.red("\u274C Login was not completed.\n") + chalk11.dim("Please try running ") + chalk11.cyan("braingrid login") + chalk11.dim(" again.")
|
|
@@ -4445,7 +4584,13 @@ async function handleInit(opts) {
|
|
|
4445
4584
|
if (opts.project) {
|
|
4446
4585
|
try {
|
|
4447
4586
|
project2 = await projectService.getProject(opts.project);
|
|
4448
|
-
} catch {
|
|
4587
|
+
} catch (error) {
|
|
4588
|
+
log(
|
|
4589
|
+
"ERROR",
|
|
4590
|
+
"init",
|
|
4591
|
+
"project_fetch",
|
|
4592
|
+
`project=${opts.project} error=${error instanceof Error ? error.message : String(error)}`
|
|
4593
|
+
);
|
|
4449
4594
|
return {
|
|
4450
4595
|
success: false,
|
|
4451
4596
|
message: chalk11.red(`\u274C Project not found: ${opts.project}
|
|
@@ -4532,6 +4677,7 @@ async function handleInit(opts) {
|
|
|
4532
4677
|
}
|
|
4533
4678
|
project2 = response.projects[0];
|
|
4534
4679
|
}
|
|
4680
|
+
log("INFO", "init", "project_found", `id=${project2.short_id} name=${project2.name}`);
|
|
4535
4681
|
const projectInfo = chalk11.bold("\n\u{1F4E6} BrainGrid Project Found\n\n") + chalk11.dim("Project: ") + chalk11.cyan(project2.name) + "\n" + chalk11.dim("ID: ") + chalk11.gray(project2.short_id) + "\n" + (project2.description ? `${chalk11.dim("Description: ") + chalk11.gray(project2.description)}
|
|
4536
4682
|
` : "") + chalk11.dim("Repository: ") + chalk11.gray(project2.repository?.full_name || "N/A") + "\n\n";
|
|
4537
4683
|
console.log(projectInfo);
|
|
@@ -4565,12 +4711,19 @@ async function handleInit(opts) {
|
|
|
4565
4711
|
created_at: project2.created_at
|
|
4566
4712
|
};
|
|
4567
4713
|
await saveProjectConfig(localConfig);
|
|
4714
|
+
log("INFO", "init", "config_saved", "path=.braingrid/project.json");
|
|
4568
4715
|
await addBraingridTempToGitignore();
|
|
4569
4716
|
await copyBraingridReadme();
|
|
4570
4717
|
console.log(
|
|
4571
4718
|
chalk11.green("\u2705 Repository initialized successfully!\n\n") + chalk11.dim("Project: ") + chalk11.cyan(project2.name) + chalk11.dim(` (${project2.short_id})`) + "\n" + chalk11.dim("Config: ") + chalk11.gray(".braingrid/project.json") + "\n"
|
|
4572
4719
|
);
|
|
4573
4720
|
const installedIDEs = await detectInstalledIDEs();
|
|
4721
|
+
log(
|
|
4722
|
+
"INFO",
|
|
4723
|
+
"init",
|
|
4724
|
+
"ide_detect",
|
|
4725
|
+
`claude_code=${installedIDEs.claudeCode} cursor=${installedIDEs.cursor}`
|
|
4726
|
+
);
|
|
4574
4727
|
if (installedIDEs.claudeCode) {
|
|
4575
4728
|
const claudeSetupExists = await fileExists2(".claude/commands/specify.md");
|
|
4576
4729
|
console.log("");
|
|
@@ -4579,6 +4732,7 @@ async function handleInit(opts) {
|
|
|
4579
4732
|
default: true
|
|
4580
4733
|
});
|
|
4581
4734
|
if (setupClaude) {
|
|
4735
|
+
log("INFO", "init", "setup_claude", `force=${claudeSetupExists}`);
|
|
4582
4736
|
console.log("");
|
|
4583
4737
|
try {
|
|
4584
4738
|
const result = await handleSetupClaudeCode({
|
|
@@ -4592,7 +4746,13 @@ async function handleInit(opts) {
|
|
|
4592
4746
|
chalk11.dim("You can run ") + chalk11.cyan("braingrid setup claude-code") + chalk11.dim(" later.")
|
|
4593
4747
|
);
|
|
4594
4748
|
}
|
|
4595
|
-
} catch {
|
|
4749
|
+
} catch (error) {
|
|
4750
|
+
log(
|
|
4751
|
+
"ERROR",
|
|
4752
|
+
"init",
|
|
4753
|
+
"setup_claude_failed",
|
|
4754
|
+
`error=${error instanceof Error ? error.message : String(error)}`
|
|
4755
|
+
);
|
|
4596
4756
|
console.log(chalk11.yellow("\u26A0\uFE0F Claude Code setup encountered an error."));
|
|
4597
4757
|
console.log(
|
|
4598
4758
|
chalk11.dim("You can run ") + chalk11.cyan("braingrid setup claude-code") + chalk11.dim(" later.")
|
|
@@ -4609,6 +4769,7 @@ async function handleInit(opts) {
|
|
|
4609
4769
|
default: true
|
|
4610
4770
|
});
|
|
4611
4771
|
if (setupCursor) {
|
|
4772
|
+
log("INFO", "init", "setup_cursor", `force=${cursorSetupExists}`);
|
|
4612
4773
|
console.log("");
|
|
4613
4774
|
try {
|
|
4614
4775
|
const result = await handleSetupCursor({
|
|
@@ -4622,7 +4783,13 @@ async function handleInit(opts) {
|
|
|
4622
4783
|
chalk11.dim("You can run ") + chalk11.cyan("braingrid setup cursor") + chalk11.dim(" later.")
|
|
4623
4784
|
);
|
|
4624
4785
|
}
|
|
4625
|
-
} catch {
|
|
4786
|
+
} catch (error) {
|
|
4787
|
+
log(
|
|
4788
|
+
"ERROR",
|
|
4789
|
+
"init",
|
|
4790
|
+
"setup_cursor_failed",
|
|
4791
|
+
`error=${error instanceof Error ? error.message : String(error)}`
|
|
4792
|
+
);
|
|
4626
4793
|
console.log(chalk11.yellow("\u26A0\uFE0F Cursor setup encountered an error."));
|
|
4627
4794
|
console.log(
|
|
4628
4795
|
chalk11.dim("You can run ") + chalk11.cyan("braingrid setup cursor") + chalk11.dim(" later.")
|
|
@@ -4631,14 +4798,22 @@ async function handleInit(opts) {
|
|
|
4631
4798
|
console.log("");
|
|
4632
4799
|
}
|
|
4633
4800
|
}
|
|
4801
|
+
const initDuration = Math.round((Date.now() - initStartTime) / 1e3);
|
|
4802
|
+
log("INFO", "init", "complete", `project=${project2.short_id} duration=${initDuration}s`);
|
|
4803
|
+
closeLogger();
|
|
4634
4804
|
return {
|
|
4635
4805
|
success: true,
|
|
4636
|
-
message: chalk11.dim(
|
|
4637
|
-
"You can now use project-scoped commands without specifying a project ID."
|
|
4638
|
-
),
|
|
4806
|
+
message: chalk11.dim("You can now use project-scoped commands without specifying a project ID.") + "\n" + chalk11.dim("Debug log: .braingrid/temp/init-debug.log"),
|
|
4639
4807
|
data: localConfig
|
|
4640
4808
|
};
|
|
4641
4809
|
} catch (error) {
|
|
4810
|
+
log(
|
|
4811
|
+
"ERROR",
|
|
4812
|
+
"init",
|
|
4813
|
+
"fatal",
|
|
4814
|
+
`error=${error instanceof Error ? error.message : String(error)}`
|
|
4815
|
+
);
|
|
4816
|
+
closeLogger();
|
|
4642
4817
|
return {
|
|
4643
4818
|
success: false,
|
|
4644
4819
|
message: formatError(error, "initializing repository")
|
|
@@ -5844,6 +6019,18 @@ var WorkspaceManager = class {
|
|
|
5844
6019
|
projectId: normalized
|
|
5845
6020
|
};
|
|
5846
6021
|
}
|
|
6022
|
+
const configExists = await projectConfigExists();
|
|
6023
|
+
if (configExists) {
|
|
6024
|
+
try {
|
|
6025
|
+
await loadProjectConfig();
|
|
6026
|
+
} catch (error) {
|
|
6027
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
6028
|
+
return {
|
|
6029
|
+
success: false,
|
|
6030
|
+
error: chalk13.red("\u274C Found .braingrid/project.json but failed to load it:") + "\n" + chalk13.dim(` ${msg}`) + "\n\n" + chalk13.dim("Try re-initializing with:\n") + chalk13.cyan(" braingrid init --force")
|
|
6031
|
+
};
|
|
6032
|
+
}
|
|
6033
|
+
}
|
|
5847
6034
|
return {
|
|
5848
6035
|
success: false,
|
|
5849
6036
|
error: chalk13.red("\u274C No project specified and no local project found.") + "\n\n" + chalk13.dim("To initialize this workspace, run:\n") + chalk13.cyan(" braingrid init") + "\n\n" + chalk13.dim("Or specify a project explicitly:\n") + chalk13.cyan(" braingrid <command> -p PROJ-123")
|