@braingrid/cli 0.2.53 → 0.2.55
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 +33 -0
- package/dist/{chunk-S3D6P3QC.js → chunk-NEDKD2DE.js} +7 -1
- package/dist/{chunk-S3D6P3QC.js.map → chunk-NEDKD2DE.js.map} +1 -1
- package/dist/cli.js +794 -469
- package/dist/cli.js.map +1 -1
- package/dist/{gh-installer-DWTEK33P.js → gh-installer-T7E7SYVI.js} +2 -2
- package/package.json +1 -1
- /package/dist/{gh-installer-DWTEK33P.js.map → gh-installer-T7E7SYVI.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
isGhInstalled,
|
|
12
12
|
isHomebrewInstalled,
|
|
13
13
|
isWingetAvailable
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-NEDKD2DE.js";
|
|
15
15
|
|
|
16
16
|
// src/cli.ts
|
|
17
17
|
import { existsSync } from "fs";
|
|
@@ -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.55" : "0.0.0-test";
|
|
232
232
|
var PRODUCTION_CONFIG = {
|
|
233
233
|
apiUrl: "https://app.braingrid.ai",
|
|
234
234
|
workosAuthUrl: "https://auth.braingrid.ai",
|
|
@@ -312,42 +312,6 @@ function getConfig() {
|
|
|
312
312
|
};
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
// src/utils/jwt.ts
|
|
316
|
-
function decodeJWT(token) {
|
|
317
|
-
try {
|
|
318
|
-
const parts = token.split(".");
|
|
319
|
-
if (parts.length !== 3) {
|
|
320
|
-
return null;
|
|
321
|
-
}
|
|
322
|
-
const payload = parts[1];
|
|
323
|
-
const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
324
|
-
const padded = base64 + "==".substring(0, (4 - base64.length % 4) % 4);
|
|
325
|
-
const decoded = Buffer.from(padded, "base64").toString("utf-8");
|
|
326
|
-
return JSON.parse(decoded);
|
|
327
|
-
} catch {
|
|
328
|
-
return null;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
function isJWTExpired(token) {
|
|
332
|
-
const payload = decodeJWT(token);
|
|
333
|
-
if (!payload || !payload.exp) {
|
|
334
|
-
return true;
|
|
335
|
-
}
|
|
336
|
-
return Date.now() >= payload.exp * 1e3;
|
|
337
|
-
}
|
|
338
|
-
function extractUserFromJWT(payload) {
|
|
339
|
-
return {
|
|
340
|
-
id: payload.sub || "",
|
|
341
|
-
email: payload.email || "",
|
|
342
|
-
// Try different naming conventions for first name
|
|
343
|
-
firstName: payload.firstName || payload.first_name || payload.given_name || (payload.name ? payload.name.split(" ")[0] : ""),
|
|
344
|
-
// Try different naming conventions for last name
|
|
345
|
-
lastName: payload.lastName || payload.last_name || payload.family_name || (payload.name ? payload.name.split(" ").slice(1).join(" ") : ""),
|
|
346
|
-
// Try different naming conventions for organization
|
|
347
|
-
organizationId: payload.organizationId || payload.organization_id || payload.org_id || payload.org || "default"
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
|
|
351
315
|
// src/utils/logger.ts
|
|
352
316
|
import fs from "fs";
|
|
353
317
|
import os from "os";
|
|
@@ -356,7 +320,7 @@ var Logger = class {
|
|
|
356
320
|
constructor(config2 = {}) {
|
|
357
321
|
const isDebugMode = process.env.DEBUG === "true";
|
|
358
322
|
this.config = {
|
|
359
|
-
logToFile:
|
|
323
|
+
logToFile: true,
|
|
360
324
|
logLevel: isDebugMode ? "debug" : "info",
|
|
361
325
|
// Set log level to debug when DEBUG=true
|
|
362
326
|
maxFileSize: 10 * 1024 * 1024,
|
|
@@ -368,7 +332,11 @@ var Logger = class {
|
|
|
368
332
|
};
|
|
369
333
|
this.logFilePath = this.config.logFilePath || path.join(os.homedir(), ".braingrid", "logs", "braingrid-cli.log");
|
|
370
334
|
if (this.config.logToFile) {
|
|
371
|
-
|
|
335
|
+
try {
|
|
336
|
+
this.ensureLogDirectory();
|
|
337
|
+
} catch {
|
|
338
|
+
this.config.logToFile = false;
|
|
339
|
+
}
|
|
372
340
|
}
|
|
373
341
|
}
|
|
374
342
|
ensureLogDirectory() {
|
|
@@ -385,8 +353,9 @@ var Logger = class {
|
|
|
385
353
|
const timestamp = entry.timestamp.toISOString();
|
|
386
354
|
const level = entry.level.toUpperCase().padEnd(5);
|
|
387
355
|
const type = entry.type.toUpperCase().padEnd(7);
|
|
356
|
+
const sessionStr = this.config.sessionId ? ` [${this.config.sessionId}]` : "";
|
|
388
357
|
const contextStr = entry.context ? ` | ${JSON.stringify(entry.context)}` : "";
|
|
389
|
-
return `[${timestamp}] ${level} [${type}] ${entry.message}${contextStr}`;
|
|
358
|
+
return `[${timestamp}] ${level}${sessionStr} [${type}] ${entry.message}${contextStr}`;
|
|
390
359
|
}
|
|
391
360
|
writeToFile(entry) {
|
|
392
361
|
if (!this.config.logToFile) return;
|
|
@@ -508,6 +477,45 @@ function getLogger(config2) {
|
|
|
508
477
|
return loggerInstance;
|
|
509
478
|
}
|
|
510
479
|
|
|
480
|
+
// src/utils/jwt.ts
|
|
481
|
+
function decodeJWT(token) {
|
|
482
|
+
try {
|
|
483
|
+
const parts = token.split(".");
|
|
484
|
+
if (parts.length !== 3) {
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
const payload = parts[1];
|
|
488
|
+
const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
489
|
+
const padded = base64 + "==".substring(0, (4 - base64.length % 4) % 4);
|
|
490
|
+
const decoded = Buffer.from(padded, "base64").toString("utf-8");
|
|
491
|
+
return JSON.parse(decoded);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
getLogger().debug("[JWT] Failed to decode token", {
|
|
494
|
+
error: error instanceof Error ? error.message : String(error)
|
|
495
|
+
});
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
function isJWTExpired(token) {
|
|
500
|
+
const payload = decodeJWT(token);
|
|
501
|
+
if (!payload || !payload.exp) {
|
|
502
|
+
return true;
|
|
503
|
+
}
|
|
504
|
+
return Date.now() >= payload.exp * 1e3;
|
|
505
|
+
}
|
|
506
|
+
function extractUserFromJWT(payload) {
|
|
507
|
+
return {
|
|
508
|
+
id: payload.sub || "",
|
|
509
|
+
email: payload.email || "",
|
|
510
|
+
// Try different naming conventions for first name
|
|
511
|
+
firstName: payload.firstName || payload.first_name || payload.given_name || (payload.name ? payload.name.split(" ")[0] : ""),
|
|
512
|
+
// Try different naming conventions for last name
|
|
513
|
+
lastName: payload.lastName || payload.last_name || payload.family_name || (payload.name ? payload.name.split(" ").slice(1).join(" ") : ""),
|
|
514
|
+
// Try different naming conventions for organization
|
|
515
|
+
organizationId: payload.organizationId || payload.organization_id || payload.org_id || payload.org || "default"
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
|
|
511
519
|
// src/services/credential-store.ts
|
|
512
520
|
import crypto from "crypto";
|
|
513
521
|
import Conf from "conf";
|
|
@@ -1164,11 +1172,17 @@ var BraingridAuth = class {
|
|
|
1164
1172
|
}
|
|
1165
1173
|
}
|
|
1166
1174
|
return true;
|
|
1167
|
-
} catch {
|
|
1175
|
+
} catch (error) {
|
|
1176
|
+
this.logger.debug("[AUTH] isAuthenticated error", {
|
|
1177
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1178
|
+
});
|
|
1168
1179
|
try {
|
|
1169
1180
|
const session = await this.getStoredSession();
|
|
1170
1181
|
return session !== null && !this.isSessionExpired(session);
|
|
1171
|
-
} catch {
|
|
1182
|
+
} catch (error2) {
|
|
1183
|
+
this.logger.debug("[AUTH] isAuthenticated fallback failed", {
|
|
1184
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
1185
|
+
});
|
|
1172
1186
|
return false;
|
|
1173
1187
|
}
|
|
1174
1188
|
}
|
|
@@ -1204,7 +1218,10 @@ var BraingridAuth = class {
|
|
|
1204
1218
|
session.user = user;
|
|
1205
1219
|
await this.storeSession(session);
|
|
1206
1220
|
return user;
|
|
1207
|
-
} catch {
|
|
1221
|
+
} catch (error) {
|
|
1222
|
+
this.logger.debug("[AUTH] getCurrentUser failed", {
|
|
1223
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1224
|
+
});
|
|
1208
1225
|
return null;
|
|
1209
1226
|
}
|
|
1210
1227
|
}
|
|
@@ -1212,7 +1229,10 @@ var BraingridAuth = class {
|
|
|
1212
1229
|
try {
|
|
1213
1230
|
const session = await this.getStoredSession();
|
|
1214
1231
|
return session !== null && !this.isSessionExpired(session);
|
|
1215
|
-
} catch {
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
this.logger.debug("[AUTH] hasStoredSession failed", {
|
|
1234
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1235
|
+
});
|
|
1216
1236
|
return false;
|
|
1217
1237
|
}
|
|
1218
1238
|
}
|
|
@@ -1233,7 +1253,10 @@ var BraingridAuth = class {
|
|
|
1233
1253
|
updated_at: new Date(session.updated_at),
|
|
1234
1254
|
login_time: session.login_time ? new Date(session.login_time) : void 0
|
|
1235
1255
|
};
|
|
1236
|
-
} catch {
|
|
1256
|
+
} catch (error) {
|
|
1257
|
+
this.logger.debug("[AUTH] Failed to parse stored session", {
|
|
1258
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1259
|
+
});
|
|
1237
1260
|
return null;
|
|
1238
1261
|
}
|
|
1239
1262
|
}
|
|
@@ -1576,7 +1599,10 @@ var BraingridAuth = class {
|
|
|
1576
1599
|
async getStoredGitHubToken() {
|
|
1577
1600
|
try {
|
|
1578
1601
|
return await credentialStore.getPassword(KEYCHAIN_SERVICE, GITHUB_KEYCHAIN_ACCOUNT);
|
|
1579
|
-
} catch {
|
|
1602
|
+
} catch (error) {
|
|
1603
|
+
this.logger.debug("[AUTH] Failed to retrieve GitHub token", {
|
|
1604
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1605
|
+
});
|
|
1580
1606
|
return null;
|
|
1581
1607
|
}
|
|
1582
1608
|
}
|
|
@@ -1613,7 +1639,10 @@ var BraingridAuth = class {
|
|
|
1613
1639
|
user,
|
|
1614
1640
|
scopes
|
|
1615
1641
|
};
|
|
1616
|
-
} catch {
|
|
1642
|
+
} catch (error) {
|
|
1643
|
+
this.logger.debug("[AUTH] GitHub token validation failed", {
|
|
1644
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1645
|
+
});
|
|
1617
1646
|
return { valid: false };
|
|
1618
1647
|
}
|
|
1619
1648
|
}
|
|
@@ -1822,9 +1851,25 @@ function formatError(error, context) {
|
|
|
1822
1851
|
return formatAxiosError(error, context);
|
|
1823
1852
|
}
|
|
1824
1853
|
if (error instanceof Error) {
|
|
1825
|
-
|
|
1854
|
+
const logger4 = getLogger();
|
|
1855
|
+
if (error.stack) {
|
|
1856
|
+
logger4.debug("[ERROR] Stack trace", { stack: error.stack });
|
|
1857
|
+
}
|
|
1858
|
+
const prefix2 = context ? `Error ${context}: ` : "";
|
|
1859
|
+
return chalk2.red(`\u274C ${prefix2}${error.message}`);
|
|
1826
1860
|
}
|
|
1827
|
-
|
|
1861
|
+
if (error && typeof error === "object") {
|
|
1862
|
+
try {
|
|
1863
|
+
const serialized = JSON.stringify(error);
|
|
1864
|
+
if (serialized !== "{}") {
|
|
1865
|
+
const prefix2 = context ? `Error ${context}: ` : "";
|
|
1866
|
+
return chalk2.red(`\u274C ${prefix2}${serialized}`);
|
|
1867
|
+
}
|
|
1868
|
+
} catch {
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
const prefix = context ? `Error ${context}: ` : "";
|
|
1872
|
+
return chalk2.red(`\u274C ${prefix}${String(error)}`);
|
|
1828
1873
|
}
|
|
1829
1874
|
function isAxiosError(error) {
|
|
1830
1875
|
return typeof error === "object" && error !== null && "isAxiosError" in error && error.isAxiosError === true;
|
|
@@ -2331,7 +2376,7 @@ async function handleCompletion(shellArg, opts) {
|
|
|
2331
2376
|
// src/handlers/init.handlers.ts
|
|
2332
2377
|
import { access as access3 } from "fs/promises";
|
|
2333
2378
|
import { confirm as confirm2, input, select as select3 } from "@inquirer/prompts";
|
|
2334
|
-
import
|
|
2379
|
+
import chalk12 from "chalk";
|
|
2335
2380
|
|
|
2336
2381
|
// src/utils/axios-with-auth.ts
|
|
2337
2382
|
import axios4 from "axios";
|
|
@@ -2660,6 +2705,23 @@ function closeLogger() {
|
|
|
2660
2705
|
logStream = null;
|
|
2661
2706
|
logFile = null;
|
|
2662
2707
|
}
|
|
2708
|
+
function flushLogger() {
|
|
2709
|
+
return new Promise((resolve2) => {
|
|
2710
|
+
if (!logStream) {
|
|
2711
|
+
resolve2();
|
|
2712
|
+
return;
|
|
2713
|
+
}
|
|
2714
|
+
if (logStream.writableLength === 0) {
|
|
2715
|
+
resolve2();
|
|
2716
|
+
return;
|
|
2717
|
+
}
|
|
2718
|
+
const timeout = setTimeout(resolve2, 1e3);
|
|
2719
|
+
logStream.once("drain", () => {
|
|
2720
|
+
clearTimeout(timeout);
|
|
2721
|
+
resolve2();
|
|
2722
|
+
});
|
|
2723
|
+
});
|
|
2724
|
+
}
|
|
2663
2725
|
|
|
2664
2726
|
// src/services/setup-service.ts
|
|
2665
2727
|
var GITHUB_OWNER = "BrainGridAI";
|
|
@@ -3264,7 +3326,7 @@ async function createGitHubRepoWithGh(name, isPrivate) {
|
|
|
3264
3326
|
}
|
|
3265
3327
|
}
|
|
3266
3328
|
async function canUseGhAutomation() {
|
|
3267
|
-
const { isGhInstalled: isGhInstalled2 } = await import("./gh-installer-
|
|
3329
|
+
const { isGhInstalled: isGhInstalled2 } = await import("./gh-installer-T7E7SYVI.js");
|
|
3268
3330
|
const ghInstalled = await isGhInstalled2();
|
|
3269
3331
|
if (!ghInstalled) {
|
|
3270
3332
|
return false;
|
|
@@ -3296,6 +3358,192 @@ ${entry}
|
|
|
3296
3358
|
await writeFile2(gitignorePath, newContent, "utf8");
|
|
3297
3359
|
}
|
|
3298
3360
|
|
|
3361
|
+
// src/utils/jq-installer.ts
|
|
3362
|
+
import { exec as exec4 } from "child_process";
|
|
3363
|
+
import { promisify as promisify4 } from "util";
|
|
3364
|
+
import chalk7 from "chalk";
|
|
3365
|
+
var execAsync5 = promisify4(exec4);
|
|
3366
|
+
async function isJqInstalled() {
|
|
3367
|
+
return isCliInstalled("jq");
|
|
3368
|
+
}
|
|
3369
|
+
async function getJqVersion() {
|
|
3370
|
+
return getCliVersion("jq", "--version", (output) => {
|
|
3371
|
+
const match = output.match(/jq-([\d.]+)/);
|
|
3372
|
+
return match ? match[1] : output.trim();
|
|
3373
|
+
});
|
|
3374
|
+
}
|
|
3375
|
+
async function installViaHomebrew2() {
|
|
3376
|
+
console.log(chalk7.blue("\u{1F4E6} Installing jq via Homebrew..."));
|
|
3377
|
+
try {
|
|
3378
|
+
await execAsync5("brew install jq", {
|
|
3379
|
+
timeout: 3e5
|
|
3380
|
+
// 5 minutes
|
|
3381
|
+
});
|
|
3382
|
+
const version = await getJqVersion();
|
|
3383
|
+
if (!version) {
|
|
3384
|
+
return {
|
|
3385
|
+
success: false,
|
|
3386
|
+
message: chalk7.red("\u274C jq installation completed but jq command not found")
|
|
3387
|
+
};
|
|
3388
|
+
}
|
|
3389
|
+
return {
|
|
3390
|
+
success: true,
|
|
3391
|
+
message: chalk7.green(`\u2705 jq installed successfully (version ${version})!`),
|
|
3392
|
+
version
|
|
3393
|
+
};
|
|
3394
|
+
} catch (error) {
|
|
3395
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3396
|
+
return {
|
|
3397
|
+
success: false,
|
|
3398
|
+
message: chalk7.red("\u274C Failed to install jq via Homebrew\n\n") + chalk7.dim("Error: ") + errorMsg + "\n\n" + chalk7.dim("Please install jq manually from: ") + chalk7.cyan("https://jqlang.github.io/jq/download/")
|
|
3399
|
+
};
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
async function installViaWebi() {
|
|
3403
|
+
console.log(chalk7.blue("\u{1F4E6} Installing jq via Webi..."));
|
|
3404
|
+
console.log(chalk7.dim("This will install jq to ~/.local/bin/\n"));
|
|
3405
|
+
try {
|
|
3406
|
+
await execAsync5("curl -sS https://webi.sh/jq | sh", {
|
|
3407
|
+
timeout: 3e5
|
|
3408
|
+
// 5 minutes
|
|
3409
|
+
});
|
|
3410
|
+
const version = await getJqVersion();
|
|
3411
|
+
if (!version) {
|
|
3412
|
+
return {
|
|
3413
|
+
success: true,
|
|
3414
|
+
message: chalk7.green("\u2705 jq installed successfully!\n") + chalk7.dim(
|
|
3415
|
+
"Note: You may need to restart your terminal for the jq command to be available."
|
|
3416
|
+
)
|
|
3417
|
+
};
|
|
3418
|
+
}
|
|
3419
|
+
return {
|
|
3420
|
+
success: true,
|
|
3421
|
+
message: chalk7.green(`\u2705 jq installed successfully (version ${version})!`),
|
|
3422
|
+
version
|
|
3423
|
+
};
|
|
3424
|
+
} catch (error) {
|
|
3425
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3426
|
+
return {
|
|
3427
|
+
success: false,
|
|
3428
|
+
message: chalk7.red("\u274C Failed to install jq via Webi\n\n") + chalk7.dim("Error: ") + errorMsg + "\n\n" + chalk7.dim("Please install jq manually from: ") + chalk7.cyan("https://jqlang.github.io/jq/download/")
|
|
3429
|
+
};
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
async function installJqMacOS() {
|
|
3433
|
+
const hasHomebrew = await isHomebrewInstalled();
|
|
3434
|
+
if (hasHomebrew) {
|
|
3435
|
+
return installViaHomebrew2();
|
|
3436
|
+
}
|
|
3437
|
+
return installViaWebi();
|
|
3438
|
+
}
|
|
3439
|
+
async function installJqWindows() {
|
|
3440
|
+
const hasWinget = await isWingetAvailable();
|
|
3441
|
+
if (!hasWinget) {
|
|
3442
|
+
return {
|
|
3443
|
+
success: false,
|
|
3444
|
+
message: chalk7.red("\u274C winget is not available on this system\n\n") + chalk7.dim("winget is included in Windows 10 (version 1809+) and Windows 11.\n") + chalk7.dim("Please install jq manually from: ") + chalk7.cyan("https://jqlang.github.io/jq/download/")
|
|
3445
|
+
};
|
|
3446
|
+
}
|
|
3447
|
+
console.log(chalk7.blue("\u{1F4E6} Installing jq via winget..."));
|
|
3448
|
+
try {
|
|
3449
|
+
await execAsync5("winget install --id jqlang.jq --silent", {
|
|
3450
|
+
timeout: 3e5
|
|
3451
|
+
// 5 minutes
|
|
3452
|
+
});
|
|
3453
|
+
const version = await getJqVersion();
|
|
3454
|
+
if (!version) {
|
|
3455
|
+
return {
|
|
3456
|
+
success: false,
|
|
3457
|
+
message: chalk7.red("\u274C jq installation completed but jq command not found")
|
|
3458
|
+
};
|
|
3459
|
+
}
|
|
3460
|
+
return {
|
|
3461
|
+
success: true,
|
|
3462
|
+
message: chalk7.green(`\u2705 jq installed successfully (version ${version})!`),
|
|
3463
|
+
version
|
|
3464
|
+
};
|
|
3465
|
+
} catch (error) {
|
|
3466
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3467
|
+
return {
|
|
3468
|
+
success: false,
|
|
3469
|
+
message: chalk7.red("\u274C Failed to install jq via winget\n\n") + chalk7.dim("Error: ") + errorMsg + "\n\n" + chalk7.dim("Please install jq manually from: ") + chalk7.cyan("https://jqlang.github.io/jq/download/")
|
|
3470
|
+
};
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
async function installJqLinux() {
|
|
3474
|
+
const packageManager = await detectLinuxPackageManager();
|
|
3475
|
+
if (!packageManager) {
|
|
3476
|
+
return {
|
|
3477
|
+
success: false,
|
|
3478
|
+
message: chalk7.red("\u274C Could not detect a supported package manager\n\n") + chalk7.dim("Supported package managers: apt, dnf, yum, pacman\n") + chalk7.dim("Please install jq manually from: ") + chalk7.cyan("https://jqlang.github.io/jq/download/")
|
|
3479
|
+
};
|
|
3480
|
+
}
|
|
3481
|
+
console.log(chalk7.blue(`\u{1F4E6} Installing jq via ${packageManager.name}...`));
|
|
3482
|
+
console.log(chalk7.dim("This may prompt for your sudo password.\n"));
|
|
3483
|
+
try {
|
|
3484
|
+
let installCommand;
|
|
3485
|
+
switch (packageManager.name) {
|
|
3486
|
+
case "apt":
|
|
3487
|
+
installCommand = "sudo apt update && sudo apt install jq -y";
|
|
3488
|
+
break;
|
|
3489
|
+
case "dnf":
|
|
3490
|
+
installCommand = "sudo dnf install jq -y";
|
|
3491
|
+
break;
|
|
3492
|
+
case "yum":
|
|
3493
|
+
installCommand = "sudo yum install jq -y";
|
|
3494
|
+
break;
|
|
3495
|
+
case "pacman":
|
|
3496
|
+
installCommand = "sudo pacman -S --noconfirm jq";
|
|
3497
|
+
break;
|
|
3498
|
+
default:
|
|
3499
|
+
return {
|
|
3500
|
+
success: false,
|
|
3501
|
+
message: chalk7.red(`\u274C Unsupported package manager: ${packageManager.name}`)
|
|
3502
|
+
};
|
|
3503
|
+
}
|
|
3504
|
+
await execAsync5(installCommand, {
|
|
3505
|
+
timeout: 3e5
|
|
3506
|
+
// 5 minutes
|
|
3507
|
+
});
|
|
3508
|
+
const version = await getJqVersion();
|
|
3509
|
+
if (!version) {
|
|
3510
|
+
return {
|
|
3511
|
+
success: false,
|
|
3512
|
+
message: chalk7.red("\u274C jq installation completed but jq command not found")
|
|
3513
|
+
};
|
|
3514
|
+
}
|
|
3515
|
+
return {
|
|
3516
|
+
success: true,
|
|
3517
|
+
message: chalk7.green(`\u2705 jq installed successfully (version ${version})!`),
|
|
3518
|
+
version
|
|
3519
|
+
};
|
|
3520
|
+
} catch (error) {
|
|
3521
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3522
|
+
return {
|
|
3523
|
+
success: false,
|
|
3524
|
+
message: chalk7.red("\u274C Failed to install jq\n\n") + chalk7.dim("Error: ") + errorMsg + "\n\n" + chalk7.dim("Please install jq manually from: ") + chalk7.cyan("https://jqlang.github.io/jq/download/")
|
|
3525
|
+
};
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3528
|
+
async function installJq() {
|
|
3529
|
+
const platform = process.platform;
|
|
3530
|
+
switch (platform) {
|
|
3531
|
+
case "darwin":
|
|
3532
|
+
return installJqMacOS();
|
|
3533
|
+
case "win32":
|
|
3534
|
+
return installJqWindows();
|
|
3535
|
+
case "linux":
|
|
3536
|
+
return installJqLinux();
|
|
3537
|
+
default:
|
|
3538
|
+
return {
|
|
3539
|
+
success: false,
|
|
3540
|
+
message: chalk7.red(`\u274C Unsupported platform: ${platform}
|
|
3541
|
+
|
|
3542
|
+
`) + chalk7.dim("Please install jq manually from: ") + chalk7.cyan("https://jqlang.github.io/jq/download/")
|
|
3543
|
+
};
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
|
|
3299
3547
|
// src/utils/local-store.ts
|
|
3300
3548
|
import fs4 from "fs";
|
|
3301
3549
|
import path6 from "path";
|
|
@@ -3307,7 +3555,7 @@ var LocalRepositorySchema = z.object({
|
|
|
3307
3555
|
owner: z.string(),
|
|
3308
3556
|
name: z.string(),
|
|
3309
3557
|
full_name: z.string(),
|
|
3310
|
-
url: z.string().
|
|
3558
|
+
url: z.string().optional()
|
|
3311
3559
|
});
|
|
3312
3560
|
var LocalProjectConfigSchema = z.object({
|
|
3313
3561
|
organization_id: z.string(),
|
|
@@ -3402,7 +3650,7 @@ async function getRepositoryId(repositoryService, owner, name) {
|
|
|
3402
3650
|
}
|
|
3403
3651
|
|
|
3404
3652
|
// src/utils/spinner.ts
|
|
3405
|
-
import
|
|
3653
|
+
import chalk8 from "chalk";
|
|
3406
3654
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3407
3655
|
async function waitWithSpinner(message, checkFn, intervalMs = 3e3, maxAttempts = 60) {
|
|
3408
3656
|
let frameIndex = 0;
|
|
@@ -3410,7 +3658,7 @@ async function waitWithSpinner(message, checkFn, intervalMs = 3e3, maxAttempts =
|
|
|
3410
3658
|
const updateSpinner = () => {
|
|
3411
3659
|
const frame = SPINNER_FRAMES[frameIndex];
|
|
3412
3660
|
frameIndex = (frameIndex + 1) % SPINNER_FRAMES.length;
|
|
3413
|
-
process.stdout.write(`\r${
|
|
3661
|
+
process.stdout.write(`\r${chalk8.cyan(frame)} ${message}...`);
|
|
3414
3662
|
};
|
|
3415
3663
|
spinnerInterval = setInterval(updateSpinner, 100);
|
|
3416
3664
|
try {
|
|
@@ -3434,7 +3682,7 @@ async function waitWithSpinner(message, checkFn, intervalMs = 3e3, maxAttempts =
|
|
|
3434
3682
|
throw error;
|
|
3435
3683
|
}
|
|
3436
3684
|
}
|
|
3437
|
-
function showSpinner(message, color =
|
|
3685
|
+
function showSpinner(message, color = chalk8.cyan) {
|
|
3438
3686
|
let frameIndex = 0;
|
|
3439
3687
|
const interval = setInterval(() => {
|
|
3440
3688
|
const frame = SPINNER_FRAMES[frameIndex];
|
|
@@ -3448,7 +3696,7 @@ function showSpinner(message, color = chalk7.cyan) {
|
|
|
3448
3696
|
}
|
|
3449
3697
|
|
|
3450
3698
|
// src/utils/update-checker.ts
|
|
3451
|
-
import
|
|
3699
|
+
import chalk9 from "chalk";
|
|
3452
3700
|
|
|
3453
3701
|
// src/utils/version.ts
|
|
3454
3702
|
import axios6 from "axios";
|
|
@@ -3540,7 +3788,7 @@ async function checkAndShowUpdateWarning() {
|
|
|
3540
3788
|
try {
|
|
3541
3789
|
const { available, currentVersion, latestVersion } = await isUpdateAvailable();
|
|
3542
3790
|
if (available && latestVersion) {
|
|
3543
|
-
const warning = "\n" +
|
|
3791
|
+
const warning = "\n" + chalk9.yellow(`\u26A0\uFE0F Update available: ${currentVersion} \u2192 ${latestVersion}`) + "\n" + chalk9.dim(` Run \`${getUpdateCommand()}\` to update`) + "\n";
|
|
3544
3792
|
console.log(warning);
|
|
3545
3793
|
}
|
|
3546
3794
|
} catch {
|
|
@@ -3551,7 +3799,7 @@ async function checkAndShowUpdateWarning() {
|
|
|
3551
3799
|
import * as fs5 from "fs/promises";
|
|
3552
3800
|
import * as path7 from "path";
|
|
3553
3801
|
import { select } from "@inquirer/prompts";
|
|
3554
|
-
import
|
|
3802
|
+
import chalk10 from "chalk";
|
|
3555
3803
|
async function fileExists(filePath) {
|
|
3556
3804
|
try {
|
|
3557
3805
|
await fs5.access(filePath);
|
|
@@ -3589,7 +3837,7 @@ async function getFileList(sourcePaths, targetPaths) {
|
|
|
3589
3837
|
`source=${sourceDir} error=${error instanceof Error ? error.message : String(error)}`
|
|
3590
3838
|
);
|
|
3591
3839
|
console.warn(
|
|
3592
|
-
|
|
3840
|
+
chalk10.yellow(`\u26A0\uFE0F Could not list directory: ${sourceDir}`),
|
|
3593
3841
|
error instanceof Error ? error.message : String(error)
|
|
3594
3842
|
);
|
|
3595
3843
|
}
|
|
@@ -3600,28 +3848,28 @@ async function getFileList(sourcePaths, targetPaths) {
|
|
|
3600
3848
|
return operations;
|
|
3601
3849
|
}
|
|
3602
3850
|
function displayInstallationPlan(operations, injectionFile) {
|
|
3603
|
-
console.log(
|
|
3604
|
-
console.log(
|
|
3605
|
-
console.log(
|
|
3851
|
+
console.log(chalk10.bold("\n\u{1F4CB} Installation Plan:\n"));
|
|
3852
|
+
console.log(chalk10.cyan(" Content Injection:"));
|
|
3853
|
+
console.log(chalk10.dim(` ${injectionFile}`));
|
|
3606
3854
|
const newFiles = operations.filter((op) => !op.exists);
|
|
3607
3855
|
const existingFiles = operations.filter((op) => op.exists);
|
|
3608
3856
|
if (newFiles.length > 0) {
|
|
3609
|
-
console.log(
|
|
3857
|
+
console.log(chalk10.cyan("\n New Files:"));
|
|
3610
3858
|
for (const op of newFiles) {
|
|
3611
|
-
console.log(
|
|
3859
|
+
console.log(chalk10.dim(` ${op.targetPath}`));
|
|
3612
3860
|
}
|
|
3613
3861
|
}
|
|
3614
3862
|
if (existingFiles.length > 0) {
|
|
3615
|
-
console.log(
|
|
3863
|
+
console.log(chalk10.yellow("\n Existing Files (will prompt):"));
|
|
3616
3864
|
for (const op of existingFiles) {
|
|
3617
|
-
console.log(
|
|
3865
|
+
console.log(chalk10.dim(` ${op.targetPath}`));
|
|
3618
3866
|
}
|
|
3619
3867
|
}
|
|
3620
3868
|
console.log("");
|
|
3621
3869
|
}
|
|
3622
3870
|
async function promptForConflict(filePath) {
|
|
3623
3871
|
const answer = await select({
|
|
3624
|
-
message:
|
|
3872
|
+
message: chalk10.yellow(`File exists: ${filePath}`),
|
|
3625
3873
|
choices: [
|
|
3626
3874
|
{ name: "[A]ll - Overwrite all remaining", value: "all" },
|
|
3627
3875
|
{ name: "[O]verwrite - Replace this file", value: "overwrite" },
|
|
@@ -3662,7 +3910,7 @@ async function installFiles(operations, force, dirCount) {
|
|
|
3662
3910
|
`target=${operation.targetPath} error=${error instanceof Error ? error.message : String(error)}`
|
|
3663
3911
|
);
|
|
3664
3912
|
console.error(
|
|
3665
|
-
|
|
3913
|
+
chalk10.red(`Failed to copy ${operation.targetPath}:`),
|
|
3666
3914
|
error instanceof Error ? error.message : String(error)
|
|
3667
3915
|
);
|
|
3668
3916
|
skipped++;
|
|
@@ -3678,7 +3926,7 @@ async function _handleSetup(config2, opts) {
|
|
|
3678
3926
|
"start",
|
|
3679
3927
|
`integration=${config2.name} force=${opts.force} dry_run=${opts.dryRun}`
|
|
3680
3928
|
);
|
|
3681
|
-
console.log(
|
|
3929
|
+
console.log(chalk10.bold(`\u{1F680} Setting up ${config2.name} integration...
|
|
3682
3930
|
`));
|
|
3683
3931
|
const operations = await getFileList(config2.sourceDirs, config2.targetDirs);
|
|
3684
3932
|
const injectionFileExists = await fileExists(config2.injection.targetFile);
|
|
@@ -3695,7 +3943,7 @@ async function _handleSetup(config2, opts) {
|
|
|
3695
3943
|
if (opts.dryRun) {
|
|
3696
3944
|
return {
|
|
3697
3945
|
success: true,
|
|
3698
|
-
message:
|
|
3946
|
+
message: chalk10.green("\u2705 Dry-run complete. No files were modified.\n\n") + chalk10.dim(`Would install ${operations.length} files.`)
|
|
3699
3947
|
};
|
|
3700
3948
|
}
|
|
3701
3949
|
const copyOps = operations.filter((op) => op.type === "copy");
|
|
@@ -3704,7 +3952,7 @@ async function _handleSetup(config2, opts) {
|
|
|
3704
3952
|
const totalInstalled = result.installedPerDir.reduce((a, b) => a + b, 0);
|
|
3705
3953
|
return {
|
|
3706
3954
|
success: false,
|
|
3707
|
-
message:
|
|
3955
|
+
message: chalk10.yellow("\u26A0\uFE0F Installation cancelled.\n\n") + chalk10.dim(`Installed: ${totalInstalled}, Skipped: ${result.skipped}`),
|
|
3708
3956
|
code: "CANCELLED"
|
|
3709
3957
|
};
|
|
3710
3958
|
}
|
|
@@ -3720,7 +3968,7 @@ async function _handleSetup(config2, opts) {
|
|
|
3720
3968
|
`target=${config2.injection.targetFile} error=${error instanceof Error ? error.message : String(error)}`
|
|
3721
3969
|
);
|
|
3722
3970
|
console.error(
|
|
3723
|
-
|
|
3971
|
+
chalk10.red(`Failed to inject content into ${config2.injection.targetFile}:`),
|
|
3724
3972
|
error instanceof Error ? error.message : String(error)
|
|
3725
3973
|
);
|
|
3726
3974
|
}
|
|
@@ -3742,14 +3990,14 @@ function buildSuccessMessage(config2, installedPerDir, extras) {
|
|
|
3742
3990
|
const count = installedPerDir[i] ?? 0;
|
|
3743
3991
|
if (count === 0) continue;
|
|
3744
3992
|
const { label } = config2.dirLabels[i];
|
|
3745
|
-
dirLines +=
|
|
3993
|
+
dirLines += chalk10.dim(` ${label}: ${count}
|
|
3746
3994
|
`);
|
|
3747
3995
|
}
|
|
3748
|
-
return
|
|
3996
|
+
return chalk10.green(`\u2705 ${config2.name} integration installed successfully!
|
|
3749
3997
|
|
|
3750
|
-
`) +
|
|
3998
|
+
`) + chalk10.dim("Files installed:\n") + dirLines + extras + chalk10.dim(` Content injected into: ${config2.injection.targetFile}
|
|
3751
3999
|
|
|
3752
|
-
`) +
|
|
4000
|
+
`) + chalk10.dim("Next, try:\n") + chalk10.dim(" /build REQ-X \u2192 build a requirement\n") + chalk10.dim(' /specify "add two-factor auth" \u2192 specify a requirement\n') + chalk10.dim(" Learn more: ") + chalk10.cyan(config2.docsUrl);
|
|
3753
4001
|
}
|
|
3754
4002
|
function isSetupResult(result) {
|
|
3755
4003
|
return "data" in result && result.success === true && !("message" in result);
|
|
@@ -3804,7 +4052,7 @@ async function handleSetupClaudeCode(opts) {
|
|
|
3804
4052
|
`error=${error instanceof Error ? error.message : String(error)}`
|
|
3805
4053
|
);
|
|
3806
4054
|
console.error(
|
|
3807
|
-
|
|
4055
|
+
chalk10.yellow("\u26A0\uFE0F Failed to install status line script:"),
|
|
3808
4056
|
error instanceof Error ? error.message : String(error)
|
|
3809
4057
|
);
|
|
3810
4058
|
}
|
|
@@ -3819,7 +4067,7 @@ async function handleSetupClaudeCode(opts) {
|
|
|
3819
4067
|
`error=${error instanceof Error ? error.message : String(error)}`
|
|
3820
4068
|
);
|
|
3821
4069
|
console.error(
|
|
3822
|
-
|
|
4070
|
+
chalk10.yellow("\u26A0\uFE0F Failed to update Claude settings:"),
|
|
3823
4071
|
error instanceof Error ? error.message : String(error)
|
|
3824
4072
|
);
|
|
3825
4073
|
}
|
|
@@ -3844,13 +4092,13 @@ async function handleSetupClaudeCode(opts) {
|
|
|
3844
4092
|
`script=${script} error=${error instanceof Error ? error.message : String(error)}`
|
|
3845
4093
|
);
|
|
3846
4094
|
console.error(
|
|
3847
|
-
|
|
4095
|
+
chalk10.yellow(`\u26A0\uFE0F Failed to install hook ${script}:`),
|
|
3848
4096
|
error instanceof Error ? error.message : String(error)
|
|
3849
4097
|
);
|
|
3850
4098
|
}
|
|
3851
4099
|
}
|
|
3852
|
-
const statusLineMessage = statusLineInstalled ?
|
|
3853
|
-
const hooksMessage = installedHooks.map((s) =>
|
|
4100
|
+
const statusLineMessage = statusLineInstalled ? chalk10.dim(" Status line: .claude/statusline.sh\n") : "";
|
|
4101
|
+
const hooksMessage = installedHooks.map((s) => chalk10.dim(` Hook script: .claude/hooks/${s}
|
|
3854
4102
|
`)).join("");
|
|
3855
4103
|
const totalInstalled = displayPerDir.reduce((a, b) => a + b, 0);
|
|
3856
4104
|
log(
|
|
@@ -3859,6 +4107,7 @@ async function handleSetupClaudeCode(opts) {
|
|
|
3859
4107
|
"complete",
|
|
3860
4108
|
`installed=${totalInstalled} skipped=${setupResult.data.skipped} hooks=${installedHooks.length}`
|
|
3861
4109
|
);
|
|
4110
|
+
await flushLogger();
|
|
3862
4111
|
closeLogger();
|
|
3863
4112
|
return {
|
|
3864
4113
|
success: true,
|
|
@@ -3867,10 +4116,11 @@ async function handleSetupClaudeCode(opts) {
|
|
|
3867
4116
|
} catch (error) {
|
|
3868
4117
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3869
4118
|
log("ERROR", "setup", "fatal", `error=${errorMessage}`);
|
|
4119
|
+
await flushLogger();
|
|
3870
4120
|
closeLogger();
|
|
3871
4121
|
return {
|
|
3872
4122
|
success: false,
|
|
3873
|
-
message:
|
|
4123
|
+
message: chalk10.red(`\u274C Setup failed: ${errorMessage}`)
|
|
3874
4124
|
};
|
|
3875
4125
|
}
|
|
3876
4126
|
}
|
|
@@ -3897,6 +4147,7 @@ async function handleSetupCursor(opts) {
|
|
|
3897
4147
|
const { installedPerDir, skipped } = setupResult.data;
|
|
3898
4148
|
const totalInstalled = installedPerDir.reduce((a, b) => a + b, 0);
|
|
3899
4149
|
log("INFO", "setup", "complete", `installed=${totalInstalled} skipped=${skipped}`);
|
|
4150
|
+
await flushLogger();
|
|
3900
4151
|
closeLogger();
|
|
3901
4152
|
return {
|
|
3902
4153
|
success: true,
|
|
@@ -3905,10 +4156,11 @@ async function handleSetupCursor(opts) {
|
|
|
3905
4156
|
} catch (error) {
|
|
3906
4157
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3907
4158
|
log("ERROR", "setup", "fatal", `error=${errorMessage}`);
|
|
4159
|
+
await flushLogger();
|
|
3908
4160
|
closeLogger();
|
|
3909
4161
|
return {
|
|
3910
4162
|
success: false,
|
|
3911
|
-
message:
|
|
4163
|
+
message: chalk10.red(`\u274C Setup failed: ${errorMessage}`)
|
|
3912
4164
|
};
|
|
3913
4165
|
}
|
|
3914
4166
|
}
|
|
@@ -3916,7 +4168,7 @@ async function handleSetupCursor(opts) {
|
|
|
3916
4168
|
// src/handlers/update.handlers.ts
|
|
3917
4169
|
import { execSync as execSync3 } from "child_process";
|
|
3918
4170
|
import { confirm } from "@inquirer/prompts";
|
|
3919
|
-
import
|
|
4171
|
+
import chalk11 from "chalk";
|
|
3920
4172
|
|
|
3921
4173
|
// src/utils/package-manager.ts
|
|
3922
4174
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -4032,7 +4284,7 @@ function runSetupSubprocess(subcommand) {
|
|
|
4032
4284
|
return output.toString();
|
|
4033
4285
|
} catch (error) {
|
|
4034
4286
|
const msg = error instanceof Error ? error.message : String(error);
|
|
4035
|
-
return
|
|
4287
|
+
return chalk11.yellow(`\u26A0\uFE0F Setup ${subcommand} failed: ${msg}`);
|
|
4036
4288
|
}
|
|
4037
4289
|
}
|
|
4038
4290
|
async function promptForIdeUpdates() {
|
|
@@ -4065,17 +4317,17 @@ ${runSetupSubprocess("cursor")}`;
|
|
|
4065
4317
|
async function handleUpdate(opts) {
|
|
4066
4318
|
try {
|
|
4067
4319
|
const currentVersion = getCurrentVersion();
|
|
4068
|
-
let output =
|
|
4069
|
-
output += `${
|
|
4320
|
+
let output = chalk11.bold.cyan("\n\u{1F504} BrainGrid CLI Update\n\n");
|
|
4321
|
+
output += `${chalk11.bold("Current version:")} ${currentVersion}
|
|
4070
4322
|
`;
|
|
4071
|
-
output +=
|
|
4323
|
+
output += chalk11.dim("Checking for updates...\n");
|
|
4072
4324
|
const latestVersion = await getLatestVersion();
|
|
4073
|
-
output += `${
|
|
4325
|
+
output += `${chalk11.bold("Latest version:")} ${latestVersion}
|
|
4074
4326
|
|
|
4075
4327
|
`;
|
|
4076
4328
|
const comparison = compareVersions(currentVersion, latestVersion);
|
|
4077
4329
|
if (comparison === 0) {
|
|
4078
|
-
output +=
|
|
4330
|
+
output += chalk11.green("\u2705 You are already on the latest version!\n");
|
|
4079
4331
|
console.log(output);
|
|
4080
4332
|
await copyBraingridReadme();
|
|
4081
4333
|
await addBraingridTempToGitignore();
|
|
@@ -4087,32 +4339,32 @@ async function handleUpdate(opts) {
|
|
|
4087
4339
|
};
|
|
4088
4340
|
}
|
|
4089
4341
|
if (comparison > 0) {
|
|
4090
|
-
output +=
|
|
4091
|
-
output +=
|
|
4342
|
+
output += chalk11.yellow("\u26A0\uFE0F You are on a newer version than what is published.\n");
|
|
4343
|
+
output += chalk11.dim(" This is expected if you are developing locally.\n");
|
|
4092
4344
|
return {
|
|
4093
4345
|
success: true,
|
|
4094
4346
|
message: output,
|
|
4095
4347
|
data: { currentVersion, latestVersion, upToDate: false }
|
|
4096
4348
|
};
|
|
4097
4349
|
}
|
|
4098
|
-
output +=
|
|
4350
|
+
output += chalk11.yellow(`\u2B06\uFE0F Update available: ${currentVersion} \u2192 ${latestVersion}
|
|
4099
4351
|
|
|
4100
4352
|
`);
|
|
4101
4353
|
if (opts.check) {
|
|
4102
|
-
output +=
|
|
4354
|
+
output += chalk11.dim("Run ") + chalk11.cyan("braingrid update") + chalk11.dim(" to update\n");
|
|
4103
4355
|
return {
|
|
4104
4356
|
success: true,
|
|
4105
4357
|
message: output,
|
|
4106
4358
|
data: { currentVersion, latestVersion, upToDate: false }
|
|
4107
4359
|
};
|
|
4108
4360
|
}
|
|
4109
|
-
output +=
|
|
4361
|
+
output += chalk11.dim("Detecting package manager...\n");
|
|
4110
4362
|
const packageManager = await detectPackageManager(PACKAGE_NAME);
|
|
4111
|
-
output += `${
|
|
4363
|
+
output += `${chalk11.bold("Package manager:")} ${packageManager}
|
|
4112
4364
|
|
|
4113
4365
|
`;
|
|
4114
4366
|
const updateCommand = getUpdateCommand2(packageManager, PACKAGE_NAME);
|
|
4115
|
-
output += `${
|
|
4367
|
+
output += `${chalk11.dim("Running: ") + chalk11.cyan(updateCommand)}
|
|
4116
4368
|
|
|
4117
4369
|
`;
|
|
4118
4370
|
console.log(output);
|
|
@@ -4122,7 +4374,7 @@ async function handleUpdate(opts) {
|
|
|
4122
4374
|
const setupOutput = await promptForIdeUpdates();
|
|
4123
4375
|
return {
|
|
4124
4376
|
success: true,
|
|
4125
|
-
message:
|
|
4377
|
+
message: chalk11.green("\n\u2705 Successfully updated BrainGrid CLI!\n") + setupOutput,
|
|
4126
4378
|
data: { currentVersion, latestVersion, packageManager }
|
|
4127
4379
|
};
|
|
4128
4380
|
} catch (error) {
|
|
@@ -4160,12 +4412,12 @@ function getServices() {
|
|
|
4160
4412
|
function promptToAddOrganization(owner, webUrl) {
|
|
4161
4413
|
return {
|
|
4162
4414
|
success: false,
|
|
4163
|
-
message:
|
|
4415
|
+
message: chalk12.yellow("\u26A0\uFE0F No projects found for this repository.\n\n") + chalk12.dim(`Repository: ${owner}/*
|
|
4164
4416
|
|
|
4165
|
-
`) +
|
|
4417
|
+
`) + chalk12.dim(`You have GitHub connected, but not for the "${owner}" organization.
|
|
4166
4418
|
|
|
4167
|
-
`) +
|
|
4168
|
-
`) +
|
|
4419
|
+
`) + chalk12.dim("To connect ") + chalk12.cyan(owner) + chalk12.dim(":\n") + chalk12.dim(" 1. Visit: ") + chalk12.cyan(`${webUrl}/integrations`) + chalk12.dim("\n") + chalk12.dim(' 2. Click "Add GitHub Organization"\n') + chalk12.dim(` 3. Select "${owner}"
|
|
4420
|
+
`) + chalk12.dim(" 4. Run ") + chalk12.cyan("braingrid init") + chalk12.dim(" again")
|
|
4169
4421
|
};
|
|
4170
4422
|
}
|
|
4171
4423
|
async function promptToCreateProject(gitInfo, projectService, repositoryService) {
|
|
@@ -4173,20 +4425,20 @@ async function promptToCreateProject(gitInfo, projectService, repositoryService)
|
|
|
4173
4425
|
if (!gitInfo.owner || !gitInfo.name) {
|
|
4174
4426
|
return {
|
|
4175
4427
|
success: false,
|
|
4176
|
-
message:
|
|
4428
|
+
message: chalk12.red("\u274C Repository information is incomplete")
|
|
4177
4429
|
};
|
|
4178
4430
|
}
|
|
4179
4431
|
const repositoryId = await getRepositoryId(repositoryService, gitInfo.owner, gitInfo.name);
|
|
4180
4432
|
if (!repositoryId) {
|
|
4181
4433
|
return {
|
|
4182
4434
|
success: false,
|
|
4183
|
-
message:
|
|
4435
|
+
message: chalk12.yellow("\u26A0\uFE0F Repository accessible but could not retrieve details.\n\n") + chalk12.dim(`Repository: ${gitInfo.owner}/${gitInfo.name}
|
|
4184
4436
|
|
|
4185
|
-
`) +
|
|
4437
|
+
`) + chalk12.dim("Please try again or create a project manually at: ") + chalk12.cyan(webUrl)
|
|
4186
4438
|
};
|
|
4187
4439
|
}
|
|
4188
4440
|
console.log(
|
|
4189
|
-
|
|
4441
|
+
chalk12.yellow("\u26A0\uFE0F Repository accessible but no project exists.\n\n") + chalk12.dim(`Repository: ${gitInfo.owner}/${gitInfo.name}
|
|
4190
4442
|
`)
|
|
4191
4443
|
);
|
|
4192
4444
|
const shouldCreate = await confirm2({
|
|
@@ -4196,7 +4448,7 @@ async function promptToCreateProject(gitInfo, projectService, repositoryService)
|
|
|
4196
4448
|
if (!shouldCreate) {
|
|
4197
4449
|
return {
|
|
4198
4450
|
success: false,
|
|
4199
|
-
message:
|
|
4451
|
+
message: chalk12.dim("\nProject creation cancelled.\n\n") + chalk12.dim("Create a project at ") + chalk12.cyan(webUrl) + chalk12.dim(" and link it to this repository, or use:\n") + chalk12.cyan(
|
|
4200
4452
|
`braingrid project create --name "${gitInfo.name}" --repositories "${gitInfo.owner}/${gitInfo.name}"`
|
|
4201
4453
|
)
|
|
4202
4454
|
};
|
|
@@ -4207,9 +4459,9 @@ async function promptToCreateProject(gitInfo, projectService, repositoryService)
|
|
|
4207
4459
|
description: `Project for ${gitInfo.owner}/${gitInfo.name}`,
|
|
4208
4460
|
repository_id: repositoryId
|
|
4209
4461
|
});
|
|
4210
|
-
console.log(
|
|
4462
|
+
console.log(chalk12.green(`
|
|
4211
4463
|
\u2705 Created project ${project2.short_id}: ${project2.name}`));
|
|
4212
|
-
console.log(
|
|
4464
|
+
console.log(chalk12.green(`\u2705 Linked repository ${gitInfo.owner}/${gitInfo.name}
|
|
4213
4465
|
`));
|
|
4214
4466
|
return { success: true, message: "", data: project2 };
|
|
4215
4467
|
} catch (error) {
|
|
@@ -4223,18 +4475,18 @@ async function promptToGrantRepositoryAccess(gitInfo, webUrl, repositoryService,
|
|
|
4223
4475
|
if (!gitInfo.owner || !gitInfo.name) {
|
|
4224
4476
|
return {
|
|
4225
4477
|
success: false,
|
|
4226
|
-
message:
|
|
4478
|
+
message: chalk12.red("\u274C Repository information is incomplete")
|
|
4227
4479
|
};
|
|
4228
4480
|
}
|
|
4229
4481
|
const owner = gitInfo.owner;
|
|
4230
4482
|
const name = gitInfo.name;
|
|
4231
4483
|
console.log(
|
|
4232
|
-
|
|
4484
|
+
chalk12.yellow("\u26A0\uFE0F Repository found but BrainGrid needs access.\n\n") + chalk12.dim(`Repository: ${owner}/${name}
|
|
4233
4485
|
|
|
4234
|
-
`) +
|
|
4486
|
+
`) + chalk12.dim("Please grant BrainGrid access to this repository:\n") + chalk12.dim(" 1. Visit: ") + chalk12.cyan(`${webUrl}/integrations`) + chalk12.dim("\n") + chalk12.dim(
|
|
4235
4487
|
` 2. Click on your "${owner}" installation "Add/Remove" to grant BrainGrid access to your repository
|
|
4236
4488
|
`
|
|
4237
|
-
) +
|
|
4489
|
+
) + chalk12.dim(` 3. Select "${name}" and save
|
|
4238
4490
|
|
|
4239
4491
|
`)
|
|
4240
4492
|
);
|
|
@@ -4247,10 +4499,10 @@ async function promptToGrantRepositoryAccess(gitInfo, webUrl, repositoryService,
|
|
|
4247
4499
|
if (!accessGranted) {
|
|
4248
4500
|
return {
|
|
4249
4501
|
success: false,
|
|
4250
|
-
message:
|
|
4502
|
+
message: chalk12.yellow("\n\u26A0\uFE0F Repository access not detected within 3 minutes.\n\n") + chalk12.dim("Please grant access at: ") + chalk12.cyan(`${webUrl}/integrations`) + chalk12.dim(" and run ") + chalk12.cyan("braingrid init") + chalk12.dim(" again.")
|
|
4251
4503
|
};
|
|
4252
4504
|
}
|
|
4253
|
-
console.log(
|
|
4505
|
+
console.log(chalk12.green("\u2705 Repository access granted!\n"));
|
|
4254
4506
|
return promptToCreateProject(gitInfo, projectService, repositoryService);
|
|
4255
4507
|
}
|
|
4256
4508
|
async function handleNoProjectForRepository(owner, name, gitInfo, githubService, repositoryService, projectService, config2) {
|
|
@@ -4271,9 +4523,9 @@ async function handleNoProjectForRepository(owner, name, gitInfo, githubService,
|
|
|
4271
4523
|
if (allInstallations.length === 0) {
|
|
4272
4524
|
return {
|
|
4273
4525
|
success: false,
|
|
4274
|
-
message:
|
|
4526
|
+
message: chalk12.yellow("\u26A0\uFE0F No projects found for this repository.\n\n") + chalk12.dim(`Repository: ${owner}/${name}
|
|
4275
4527
|
|
|
4276
|
-
`) +
|
|
4528
|
+
`) + chalk12.dim("It looks like you haven't connected your GitHub account yet.\n") + chalk12.dim("Please connect GitHub at: ") + chalk12.cyan(`${webUrl}/integrations`) + chalk12.dim("\n\nOnce connected, create a project and link it to this repository.")
|
|
4277
4529
|
};
|
|
4278
4530
|
}
|
|
4279
4531
|
const ownerInstallation = findInstallationForOwner(owner, allInstallations);
|
|
@@ -4289,28 +4541,28 @@ async function handleNoProjectForRepository(owner, name, gitInfo, githubService,
|
|
|
4289
4541
|
function showSetupInstructions(scenario) {
|
|
4290
4542
|
let message = "";
|
|
4291
4543
|
if (scenario === "no-git") {
|
|
4292
|
-
message +=
|
|
4293
|
-
message +=
|
|
4294
|
-
message +=
|
|
4544
|
+
message += chalk12.dim("To initialize BrainGrid locally:\n\n");
|
|
4545
|
+
message += chalk12.dim(" 1. Initialize git:\n");
|
|
4546
|
+
message += chalk12.cyan(" git init\n\n");
|
|
4295
4547
|
} else {
|
|
4296
|
-
message +=
|
|
4548
|
+
message += chalk12.dim("To connect to GitHub:\n\n");
|
|
4297
4549
|
}
|
|
4298
|
-
message +=
|
|
4299
|
-
message +=
|
|
4300
|
-
message +=
|
|
4301
|
-
message +=
|
|
4550
|
+
message += chalk12.dim(" 2. Create GitHub repository:\n");
|
|
4551
|
+
message += chalk12.dim(" \u2022 Install GitHub CLI: ") + chalk12.cyan("https://cli.github.com\n");
|
|
4552
|
+
message += chalk12.dim(" Then: ") + chalk12.cyan("gh repo create --private --source=.\n");
|
|
4553
|
+
message += chalk12.dim(" \u2022 Or manually: ") + chalk12.cyan("https://github.com/new\n\n");
|
|
4302
4554
|
if (scenario === "no-git") {
|
|
4303
|
-
message +=
|
|
4555
|
+
message += chalk12.dim(" 3. Run: ") + chalk12.cyan("braingrid init\n\n");
|
|
4304
4556
|
} else {
|
|
4305
|
-
message +=
|
|
4306
|
-
message +=
|
|
4307
|
-
message +=
|
|
4557
|
+
message += chalk12.dim(" 3. Add remote and run init:\n");
|
|
4558
|
+
message += chalk12.cyan(" git remote add origin <url>\n");
|
|
4559
|
+
message += chalk12.cyan(" braingrid init\n\n");
|
|
4308
4560
|
}
|
|
4309
|
-
message +=
|
|
4310
|
-
message +=
|
|
4311
|
-
message +=
|
|
4312
|
-
message +=
|
|
4313
|
-
message += `${
|
|
4561
|
+
message += chalk12.bold("Or use BrainGrid without local initialization:\n\n");
|
|
4562
|
+
message += chalk12.dim(" All commands support the --project flag:\n");
|
|
4563
|
+
message += chalk12.cyan(" braingrid requirement list --project PROJ-123\n");
|
|
4564
|
+
message += chalk12.cyan(' braingrid task create --project PROJ-123 --title "Task"\n\n');
|
|
4565
|
+
message += `${chalk12.dim(" Note: Without local init, you must specify --project for each command.")}
|
|
4314
4566
|
`;
|
|
4315
4567
|
return message;
|
|
4316
4568
|
}
|
|
@@ -4327,10 +4579,10 @@ async function handleNoGitRepository() {
|
|
|
4327
4579
|
if (!gitInitSuccess) {
|
|
4328
4580
|
return {
|
|
4329
4581
|
success: false,
|
|
4330
|
-
message:
|
|
4582
|
+
message: chalk12.red("\u274C Failed to initialize git repository")
|
|
4331
4583
|
};
|
|
4332
4584
|
}
|
|
4333
|
-
console.log(
|
|
4585
|
+
console.log(chalk12.green("\u2705 Initialized git repository"));
|
|
4334
4586
|
const dirName = getCurrentDirectoryName();
|
|
4335
4587
|
const isPrivate = await select3({
|
|
4336
4588
|
message: "Repository visibility:",
|
|
@@ -4344,16 +4596,16 @@ async function handleNoGitRepository() {
|
|
|
4344
4596
|
message: "Repository name:",
|
|
4345
4597
|
default: dirName
|
|
4346
4598
|
});
|
|
4347
|
-
console.log(
|
|
4599
|
+
console.log(chalk12.dim("\nCreating repository...\n"));
|
|
4348
4600
|
const repo = await createGitHubRepoWithGh(repoName, isPrivate);
|
|
4349
4601
|
if (!repo) {
|
|
4350
4602
|
return {
|
|
4351
4603
|
success: false,
|
|
4352
|
-
message:
|
|
4604
|
+
message: chalk12.red("\u274C Failed to create GitHub repository\n\n") + showSetupInstructions("no-git")
|
|
4353
4605
|
};
|
|
4354
4606
|
}
|
|
4355
|
-
console.log(
|
|
4356
|
-
console.log(
|
|
4607
|
+
console.log(chalk12.green(`\u2705 Created repository: ${repo.url}`));
|
|
4608
|
+
console.log(chalk12.green("\u2705 Added remote origin\n"));
|
|
4357
4609
|
return {
|
|
4358
4610
|
success: true,
|
|
4359
4611
|
message: "continue-init",
|
|
@@ -4364,7 +4616,7 @@ async function handleNoGitRepository() {
|
|
|
4364
4616
|
}
|
|
4365
4617
|
return {
|
|
4366
4618
|
success: false,
|
|
4367
|
-
message:
|
|
4619
|
+
message: chalk12.yellow("\u26A0\uFE0F This directory is not a git repository.\n\n") + showSetupInstructions("no-git")
|
|
4368
4620
|
};
|
|
4369
4621
|
}
|
|
4370
4622
|
async function handleNoGitRemote() {
|
|
@@ -4388,16 +4640,16 @@ async function handleNoGitRemote() {
|
|
|
4388
4640
|
message: "Repository name:",
|
|
4389
4641
|
default: dirName
|
|
4390
4642
|
});
|
|
4391
|
-
console.log(
|
|
4643
|
+
console.log(chalk12.dim("\nCreating repository...\n"));
|
|
4392
4644
|
const repo = await createGitHubRepoWithGh(repoName, isPrivate);
|
|
4393
4645
|
if (!repo) {
|
|
4394
4646
|
return {
|
|
4395
4647
|
success: false,
|
|
4396
|
-
message:
|
|
4648
|
+
message: chalk12.red("\u274C Failed to create GitHub repository\n\n") + showSetupInstructions("no-remote")
|
|
4397
4649
|
};
|
|
4398
4650
|
}
|
|
4399
|
-
console.log(
|
|
4400
|
-
console.log(
|
|
4651
|
+
console.log(chalk12.green(`\u2705 Created repository: ${repo.url}`));
|
|
4652
|
+
console.log(chalk12.green("\u2705 Added remote origin\n"));
|
|
4401
4653
|
return {
|
|
4402
4654
|
success: true,
|
|
4403
4655
|
message: "continue-init",
|
|
@@ -4408,7 +4660,7 @@ async function handleNoGitRemote() {
|
|
|
4408
4660
|
}
|
|
4409
4661
|
return {
|
|
4410
4662
|
success: false,
|
|
4411
|
-
message:
|
|
4663
|
+
message: chalk12.yellow("\u26A0\uFE0F Git repository detected but no GitHub remote configured.\n\n") + showSetupInstructions("no-remote")
|
|
4412
4664
|
};
|
|
4413
4665
|
}
|
|
4414
4666
|
async function handleInit(opts) {
|
|
@@ -4419,8 +4671,8 @@ async function handleInit(opts) {
|
|
|
4419
4671
|
const updateInfo = await isUpdateAvailable();
|
|
4420
4672
|
if (updateInfo.available && updateInfo.latestVersion) {
|
|
4421
4673
|
console.log(
|
|
4422
|
-
|
|
4423
|
-
\u26A0\uFE0F A new version of BrainGrid CLI is available: `) +
|
|
4674
|
+
chalk12.yellow(`
|
|
4675
|
+
\u26A0\uFE0F A new version of BrainGrid CLI is available: `) + chalk12.dim(`${updateInfo.currentVersion} \u2192 `) + chalk12.green(updateInfo.latestVersion) + "\n"
|
|
4424
4676
|
);
|
|
4425
4677
|
const shouldUpdate = await confirm2({
|
|
4426
4678
|
message: "Would you like to update now?",
|
|
@@ -4431,7 +4683,7 @@ async function handleInit(opts) {
|
|
|
4431
4683
|
console.log(result.message);
|
|
4432
4684
|
return {
|
|
4433
4685
|
success: true,
|
|
4434
|
-
message:
|
|
4686
|
+
message: chalk12.dim("\nRun `braingrid init` again after the update completes.")
|
|
4435
4687
|
};
|
|
4436
4688
|
}
|
|
4437
4689
|
console.log();
|
|
@@ -4452,7 +4704,7 @@ async function handleInit(opts) {
|
|
|
4452
4704
|
if (!shouldInstall) {
|
|
4453
4705
|
return {
|
|
4454
4706
|
success: false,
|
|
4455
|
-
message:
|
|
4707
|
+
message: chalk12.yellow("\u26A0\uFE0F Git installation cancelled.\n\n") + getManualInstallInstructions()
|
|
4456
4708
|
};
|
|
4457
4709
|
}
|
|
4458
4710
|
console.log();
|
|
@@ -4469,15 +4721,15 @@ async function handleInit(opts) {
|
|
|
4469
4721
|
log("ERROR", "init", "git_check", "installed=false post_install=true");
|
|
4470
4722
|
return {
|
|
4471
4723
|
success: false,
|
|
4472
|
-
message:
|
|
4724
|
+
message: chalk12.red("\u274C Git installation completed but git command not found\n\n") + chalk12.dim("You may need to restart your terminal or add Git to your PATH.\n") + getManualInstallInstructions()
|
|
4473
4725
|
};
|
|
4474
4726
|
}
|
|
4475
4727
|
}
|
|
4476
4728
|
log("INFO", "init", "git_check", "installed=true");
|
|
4477
4729
|
if (!await isGhInstalled()) {
|
|
4478
|
-
console.log(
|
|
4730
|
+
console.log(chalk12.blue("\n\u{1F4A1} GitHub CLI is highly recommended for working with BrainGrid."));
|
|
4479
4731
|
console.log(
|
|
4480
|
-
|
|
4732
|
+
chalk12.dim(" It enables seamless GitHub integration and repository management.\n")
|
|
4481
4733
|
);
|
|
4482
4734
|
const shouldInstallGh = await confirm2({
|
|
4483
4735
|
message: "Would you like to install GitHub CLI now?",
|
|
@@ -4491,22 +4743,44 @@ async function handleInit(opts) {
|
|
|
4491
4743
|
console.log();
|
|
4492
4744
|
} else {
|
|
4493
4745
|
console.log(ghInstallResult.message);
|
|
4494
|
-
console.log(
|
|
4746
|
+
console.log(chalk12.dim("You can install it manually later.\n"));
|
|
4495
4747
|
}
|
|
4496
4748
|
} else {
|
|
4497
|
-
console.log(
|
|
4749
|
+
console.log(chalk12.dim("Skipping GitHub CLI installation.\n"));
|
|
4498
4750
|
}
|
|
4499
4751
|
}
|
|
4500
4752
|
log("INFO", "init", "gh_check", `installed=${await isGhInstalled()}`);
|
|
4753
|
+
if (!await isJqInstalled()) {
|
|
4754
|
+
console.log(chalk12.blue("\n\u{1F4A1} jq is required for BrainGrid hooks to parse JSON data."));
|
|
4755
|
+
console.log(chalk12.dim(" All IDE integrations (Claude Code, Cursor) use jq.\n"));
|
|
4756
|
+
const shouldInstallJq = await confirm2({
|
|
4757
|
+
message: "Would you like to install jq now?",
|
|
4758
|
+
default: true
|
|
4759
|
+
});
|
|
4760
|
+
if (shouldInstallJq) {
|
|
4761
|
+
console.log();
|
|
4762
|
+
const jqInstallResult = await installJq();
|
|
4763
|
+
if (jqInstallResult.success) {
|
|
4764
|
+
console.log(jqInstallResult.message);
|
|
4765
|
+
console.log();
|
|
4766
|
+
} else {
|
|
4767
|
+
console.log(jqInstallResult.message);
|
|
4768
|
+
console.log(chalk12.dim("You can install it manually later.\n"));
|
|
4769
|
+
}
|
|
4770
|
+
} else {
|
|
4771
|
+
console.log(chalk12.dim("Skipping jq installation.\n"));
|
|
4772
|
+
}
|
|
4773
|
+
}
|
|
4774
|
+
log("INFO", "init", "jq_check", `installed=${await isJqInstalled()}`);
|
|
4501
4775
|
if (await projectConfigExists() && !opts.force) {
|
|
4502
4776
|
try {
|
|
4503
4777
|
const existing = await loadProjectConfig();
|
|
4504
4778
|
return {
|
|
4505
4779
|
success: false,
|
|
4506
|
-
message:
|
|
4507
|
-
`) +
|
|
4780
|
+
message: chalk12.yellow("\u26A0\uFE0F Already initialized.\n\n") + chalk12.dim(`Project: ${existing.project_name} (${existing.project_short_id})
|
|
4781
|
+
`) + chalk12.dim(`Repository: ${existing.repository?.full_name || "N/A"}
|
|
4508
4782
|
|
|
4509
|
-
`) +
|
|
4783
|
+
`) + chalk12.dim("Use --force to reinitialize")
|
|
4510
4784
|
};
|
|
4511
4785
|
} catch (error) {
|
|
4512
4786
|
log(
|
|
@@ -4517,7 +4791,7 @@ async function handleInit(opts) {
|
|
|
4517
4791
|
);
|
|
4518
4792
|
return {
|
|
4519
4793
|
success: false,
|
|
4520
|
-
message:
|
|
4794
|
+
message: chalk12.yellow("\u26A0\uFE0F Invalid project configuration found.\n") + chalk12.dim("Use --force to reinitialize")
|
|
4521
4795
|
};
|
|
4522
4796
|
}
|
|
4523
4797
|
}
|
|
@@ -4531,7 +4805,7 @@ async function handleInit(opts) {
|
|
|
4531
4805
|
if (!shouldLogin) {
|
|
4532
4806
|
return {
|
|
4533
4807
|
success: false,
|
|
4534
|
-
message:
|
|
4808
|
+
message: chalk12.yellow("\u26A0\uFE0F Authentication required.\n") + chalk12.dim("Run ") + chalk12.cyan("braingrid login") + chalk12.dim(" when you're ready to authenticate.")
|
|
4535
4809
|
};
|
|
4536
4810
|
}
|
|
4537
4811
|
log("WARN", "init", "login_required", "prompted=true");
|
|
@@ -4541,14 +4815,14 @@ async function handleInit(opts) {
|
|
|
4541
4815
|
log("ERROR", "init", "login_failed", "error=login handler returned failure");
|
|
4542
4816
|
return {
|
|
4543
4817
|
success: false,
|
|
4544
|
-
message:
|
|
4818
|
+
message: chalk12.red("\u274C Login failed.\n") + chalk12.dim("Please try running ") + chalk12.cyan("braingrid login") + chalk12.dim(" again.")
|
|
4545
4819
|
};
|
|
4546
4820
|
}
|
|
4547
4821
|
if (!await auth.isAuthenticated()) {
|
|
4548
4822
|
log("ERROR", "init", "login_failed", "error=login not completed");
|
|
4549
4823
|
return {
|
|
4550
4824
|
success: false,
|
|
4551
|
-
message:
|
|
4825
|
+
message: chalk12.red("\u274C Login was not completed.\n") + chalk12.dim("Please try running ") + chalk12.cyan("braingrid login") + chalk12.dim(" again.")
|
|
4552
4826
|
};
|
|
4553
4827
|
}
|
|
4554
4828
|
console.log();
|
|
@@ -4557,27 +4831,27 @@ async function handleInit(opts) {
|
|
|
4557
4831
|
if (!session) {
|
|
4558
4832
|
return {
|
|
4559
4833
|
success: false,
|
|
4560
|
-
message:
|
|
4834
|
+
message: chalk12.red("\u274C No session found. Please run `braingrid login` first.")
|
|
4561
4835
|
};
|
|
4562
4836
|
}
|
|
4563
4837
|
if (session.organization_id === "default") {
|
|
4564
|
-
console.log(
|
|
4838
|
+
console.log(chalk12.yellow("\u26A0\uFE0F Organization ID not set, validating session...\n"));
|
|
4565
4839
|
const isValid = await auth.isAuthenticated();
|
|
4566
4840
|
if (!isValid) {
|
|
4567
4841
|
return {
|
|
4568
4842
|
success: false,
|
|
4569
|
-
message:
|
|
4843
|
+
message: chalk12.red("\u274C Session validation failed. Please run `braingrid login` again.")
|
|
4570
4844
|
};
|
|
4571
4845
|
}
|
|
4572
4846
|
const updatedSession = await auth.getStoredSession();
|
|
4573
4847
|
if (!updatedSession || updatedSession.organization_id === "default") {
|
|
4574
4848
|
return {
|
|
4575
4849
|
success: false,
|
|
4576
|
-
message:
|
|
4850
|
+
message: chalk12.red("\u274C Unable to retrieve organization information.\n\n") + chalk12.dim("This may indicate an issue with your account setup.\n") + chalk12.dim("Please contact support or try logging in again with ") + chalk12.cyan("braingrid logout") + chalk12.dim(" and ") + chalk12.cyan("braingrid login")
|
|
4577
4851
|
};
|
|
4578
4852
|
}
|
|
4579
4853
|
Object.assign(session, updatedSession);
|
|
4580
|
-
console.log(
|
|
4854
|
+
console.log(chalk12.green("\u2705 Organization ID updated successfully\n"));
|
|
4581
4855
|
}
|
|
4582
4856
|
let gitInfo = await getGitRepositoryInfo();
|
|
4583
4857
|
let project2;
|
|
@@ -4593,9 +4867,9 @@ async function handleInit(opts) {
|
|
|
4593
4867
|
);
|
|
4594
4868
|
return {
|
|
4595
4869
|
success: false,
|
|
4596
|
-
message:
|
|
4870
|
+
message: chalk12.red(`\u274C Project not found: ${opts.project}
|
|
4597
4871
|
|
|
4598
|
-
`) +
|
|
4872
|
+
`) + chalk12.dim("Make sure the project ID is correct and you have access to it.")
|
|
4599
4873
|
};
|
|
4600
4874
|
}
|
|
4601
4875
|
} else {
|
|
@@ -4606,7 +4880,7 @@ async function handleInit(opts) {
|
|
|
4606
4880
|
if (!gitInfo || !gitInfo.owner || !gitInfo.name) {
|
|
4607
4881
|
return {
|
|
4608
4882
|
success: false,
|
|
4609
|
-
message:
|
|
4883
|
+
message: chalk12.red("\u274C Failed to get repository information after setup")
|
|
4610
4884
|
};
|
|
4611
4885
|
}
|
|
4612
4886
|
} else {
|
|
@@ -4620,7 +4894,7 @@ async function handleInit(opts) {
|
|
|
4620
4894
|
if (!gitInfo || !gitInfo.owner || !gitInfo.name) {
|
|
4621
4895
|
return {
|
|
4622
4896
|
success: false,
|
|
4623
|
-
message:
|
|
4897
|
+
message: chalk12.red("\u274C Failed to get repository information after setup")
|
|
4624
4898
|
};
|
|
4625
4899
|
}
|
|
4626
4900
|
} else {
|
|
@@ -4630,7 +4904,7 @@ async function handleInit(opts) {
|
|
|
4630
4904
|
if (!gitInfo) {
|
|
4631
4905
|
return {
|
|
4632
4906
|
success: false,
|
|
4633
|
-
message:
|
|
4907
|
+
message: chalk12.red("\u274C Repository information is missing")
|
|
4634
4908
|
};
|
|
4635
4909
|
}
|
|
4636
4910
|
const owner = gitInfo.owner;
|
|
@@ -4638,7 +4912,7 @@ async function handleInit(opts) {
|
|
|
4638
4912
|
if (!owner || !name) {
|
|
4639
4913
|
return {
|
|
4640
4914
|
success: false,
|
|
4641
|
-
message:
|
|
4915
|
+
message: chalk12.red("\u274C Repository information is incomplete")
|
|
4642
4916
|
};
|
|
4643
4917
|
}
|
|
4644
4918
|
let response;
|
|
@@ -4678,8 +4952,8 @@ async function handleInit(opts) {
|
|
|
4678
4952
|
project2 = response.projects[0];
|
|
4679
4953
|
}
|
|
4680
4954
|
log("INFO", "init", "project_found", `id=${project2.short_id} name=${project2.name}`);
|
|
4681
|
-
const projectInfo =
|
|
4682
|
-
` : "") +
|
|
4955
|
+
const projectInfo = chalk12.bold("\n\u{1F4E6} BrainGrid Project Found\n\n") + chalk12.dim("Project: ") + chalk12.cyan(project2.name) + "\n" + chalk12.dim("ID: ") + chalk12.gray(project2.short_id) + "\n" + (project2.description ? `${chalk12.dim("Description: ") + chalk12.gray(project2.description)}
|
|
4956
|
+
` : "") + chalk12.dim("Repository: ") + chalk12.gray(project2.repository?.full_name || "N/A") + "\n\n";
|
|
4683
4957
|
console.log(projectInfo);
|
|
4684
4958
|
if (!opts.force) {
|
|
4685
4959
|
const shouldInit = await confirm2({
|
|
@@ -4689,7 +4963,7 @@ async function handleInit(opts) {
|
|
|
4689
4963
|
if (!shouldInit) {
|
|
4690
4964
|
return {
|
|
4691
4965
|
success: false,
|
|
4692
|
-
message:
|
|
4966
|
+
message: chalk12.yellow("Initialization cancelled.")
|
|
4693
4967
|
};
|
|
4694
4968
|
}
|
|
4695
4969
|
}
|
|
@@ -4715,7 +4989,7 @@ async function handleInit(opts) {
|
|
|
4715
4989
|
await addBraingridTempToGitignore();
|
|
4716
4990
|
await copyBraingridReadme();
|
|
4717
4991
|
console.log(
|
|
4718
|
-
|
|
4992
|
+
chalk12.green("\u2705 Repository initialized successfully!\n\n") + chalk12.dim("Project: ") + chalk12.cyan(project2.name) + chalk12.dim(` (${project2.short_id})`) + "\n" + chalk12.dim("Config: ") + chalk12.gray(".braingrid/project.json") + "\n"
|
|
4719
4993
|
);
|
|
4720
4994
|
const installedIDEs = await detectInstalledIDEs();
|
|
4721
4995
|
log(
|
|
@@ -4741,9 +5015,9 @@ async function handleInit(opts) {
|
|
|
4741
5015
|
if (result.success) {
|
|
4742
5016
|
console.log(result.message);
|
|
4743
5017
|
} else {
|
|
4744
|
-
console.log(
|
|
5018
|
+
console.log(chalk12.yellow("\u26A0\uFE0F Claude Code setup was not completed."));
|
|
4745
5019
|
console.log(
|
|
4746
|
-
|
|
5020
|
+
chalk12.dim("You can run ") + chalk12.cyan("braingrid setup claude-code") + chalk12.dim(" later.")
|
|
4747
5021
|
);
|
|
4748
5022
|
}
|
|
4749
5023
|
} catch (error) {
|
|
@@ -4753,9 +5027,9 @@ async function handleInit(opts) {
|
|
|
4753
5027
|
"setup_claude_failed",
|
|
4754
5028
|
`error=${error instanceof Error ? error.message : String(error)}`
|
|
4755
5029
|
);
|
|
4756
|
-
console.log(
|
|
5030
|
+
console.log(chalk12.yellow("\u26A0\uFE0F Claude Code setup encountered an error."));
|
|
4757
5031
|
console.log(
|
|
4758
|
-
|
|
5032
|
+
chalk12.dim("You can run ") + chalk12.cyan("braingrid setup claude-code") + chalk12.dim(" later.")
|
|
4759
5033
|
);
|
|
4760
5034
|
}
|
|
4761
5035
|
console.log("");
|
|
@@ -4778,9 +5052,9 @@ async function handleInit(opts) {
|
|
|
4778
5052
|
if (result.success) {
|
|
4779
5053
|
console.log(result.message);
|
|
4780
5054
|
} else {
|
|
4781
|
-
console.log(
|
|
5055
|
+
console.log(chalk12.yellow("\u26A0\uFE0F Cursor setup was not completed."));
|
|
4782
5056
|
console.log(
|
|
4783
|
-
|
|
5057
|
+
chalk12.dim("You can run ") + chalk12.cyan("braingrid setup cursor") + chalk12.dim(" later.")
|
|
4784
5058
|
);
|
|
4785
5059
|
}
|
|
4786
5060
|
} catch (error) {
|
|
@@ -4790,9 +5064,9 @@ async function handleInit(opts) {
|
|
|
4790
5064
|
"setup_cursor_failed",
|
|
4791
5065
|
`error=${error instanceof Error ? error.message : String(error)}`
|
|
4792
5066
|
);
|
|
4793
|
-
console.log(
|
|
5067
|
+
console.log(chalk12.yellow("\u26A0\uFE0F Cursor setup encountered an error."));
|
|
4794
5068
|
console.log(
|
|
4795
|
-
|
|
5069
|
+
chalk12.dim("You can run ") + chalk12.cyan("braingrid setup cursor") + chalk12.dim(" later.")
|
|
4796
5070
|
);
|
|
4797
5071
|
}
|
|
4798
5072
|
console.log("");
|
|
@@ -4800,10 +5074,11 @@ async function handleInit(opts) {
|
|
|
4800
5074
|
}
|
|
4801
5075
|
const initDuration = Math.round((Date.now() - initStartTime) / 1e3);
|
|
4802
5076
|
log("INFO", "init", "complete", `project=${project2.short_id} duration=${initDuration}s`);
|
|
5077
|
+
await flushLogger();
|
|
4803
5078
|
closeLogger();
|
|
4804
5079
|
return {
|
|
4805
5080
|
success: true,
|
|
4806
|
-
message:
|
|
5081
|
+
message: chalk12.dim("You can now use project-scoped commands without specifying a project ID.") + "\n" + chalk12.dim("Debug log: .braingrid/temp/init-debug.log"),
|
|
4807
5082
|
data: localConfig
|
|
4808
5083
|
};
|
|
4809
5084
|
} catch (error) {
|
|
@@ -4813,6 +5088,7 @@ async function handleInit(opts) {
|
|
|
4813
5088
|
"fatal",
|
|
4814
5089
|
`error=${error instanceof Error ? error.message : String(error)}`
|
|
4815
5090
|
);
|
|
5091
|
+
await flushLogger();
|
|
4816
5092
|
closeLogger();
|
|
4817
5093
|
return {
|
|
4818
5094
|
success: false,
|
|
@@ -4822,10 +5098,10 @@ async function handleInit(opts) {
|
|
|
4822
5098
|
}
|
|
4823
5099
|
|
|
4824
5100
|
// src/handlers/project.handlers.ts
|
|
4825
|
-
import
|
|
5101
|
+
import chalk15 from "chalk";
|
|
4826
5102
|
|
|
4827
5103
|
// src/utils/formatting.ts
|
|
4828
|
-
import
|
|
5104
|
+
import chalk13 from "chalk";
|
|
4829
5105
|
|
|
4830
5106
|
// src/utils/id-normalization.ts
|
|
4831
5107
|
function normalizeId(prefix, input2) {
|
|
@@ -4867,7 +5143,7 @@ function getWebUiUrl(apiUrl) {
|
|
|
4867
5143
|
}
|
|
4868
5144
|
function formatTasksListOutput(tasks, format, verbose, options) {
|
|
4869
5145
|
if (tasks.length === 0) {
|
|
4870
|
-
return
|
|
5146
|
+
return chalk13.yellow("No tasks found.");
|
|
4871
5147
|
}
|
|
4872
5148
|
switch (format) {
|
|
4873
5149
|
case "json":
|
|
@@ -4897,7 +5173,7 @@ function formatTasksListOutput(tasks, format, verbose, options) {
|
|
|
4897
5173
|
}
|
|
4898
5174
|
}
|
|
4899
5175
|
function formatTasksListTable(tasks) {
|
|
4900
|
-
let output =
|
|
5176
|
+
let output = chalk13.bold(`\u{1F4CB} Tasks (${tasks.length})
|
|
4901
5177
|
|
|
4902
5178
|
`);
|
|
4903
5179
|
output += "ID Short ID Status Title Assigned To Blocked\n";
|
|
@@ -4917,58 +5193,58 @@ function formatTasksListTable(tasks) {
|
|
|
4917
5193
|
return output;
|
|
4918
5194
|
}
|
|
4919
5195
|
function formatTasksListVerbose(tasks, options) {
|
|
4920
|
-
let output =
|
|
5196
|
+
let output = chalk13.bold(`\u{1F4CB} Tasks (${tasks.length})
|
|
4921
5197
|
|
|
4922
5198
|
`);
|
|
4923
|
-
const divider =
|
|
5199
|
+
const divider = chalk13.gray("\u2500".repeat(50));
|
|
4924
5200
|
for (let i = 0; i < tasks.length; i++) {
|
|
4925
5201
|
const task2 = tasks[i];
|
|
4926
5202
|
const statusEmoji = getTaskStatusEmoji(task2.status);
|
|
4927
|
-
output += `${statusEmoji} ${
|
|
5203
|
+
output += `${statusEmoji} ${chalk13.bold(task2.title)}
|
|
4928
5204
|
`;
|
|
4929
|
-
output += `${
|
|
5205
|
+
output += `${chalk13.bold("Short ID:")} TASK-${task2.number}
|
|
4930
5206
|
`;
|
|
4931
|
-
output += `${
|
|
5207
|
+
output += `${chalk13.bold("ID:")} ${task2.id}
|
|
4932
5208
|
`;
|
|
4933
5209
|
if (options?.apiUrl && options?.requirementId) {
|
|
4934
5210
|
const webUiUrl = getWebUiUrl(options.apiUrl);
|
|
4935
|
-
output += `${
|
|
5211
|
+
output += `${chalk13.bold("URL:")} ${webUiUrl}/requirements/overview?id=${options.requirementId}&tab=tasks
|
|
4936
5212
|
`;
|
|
4937
5213
|
}
|
|
4938
|
-
output += `${
|
|
5214
|
+
output += `${chalk13.bold("Project:")} ${options?.projectShortId || "N/A"}
|
|
4939
5215
|
`;
|
|
4940
|
-
output += `${
|
|
5216
|
+
output += `${chalk13.bold("Requirement:")} ${options?.requirementShortId || "N/A"}
|
|
4941
5217
|
`;
|
|
4942
|
-
output += `${
|
|
5218
|
+
output += `${chalk13.bold("Status:")} ${task2.status}
|
|
4943
5219
|
`;
|
|
4944
5220
|
if (task2.assigned_to) {
|
|
4945
|
-
output += `${
|
|
5221
|
+
output += `${chalk13.bold("Assigned to:")} ${task2.assigned_to}
|
|
4946
5222
|
`;
|
|
4947
5223
|
} else {
|
|
4948
|
-
output += `${
|
|
5224
|
+
output += `${chalk13.bold("Assigned to:")} Unassigned
|
|
4949
5225
|
`;
|
|
4950
5226
|
}
|
|
4951
5227
|
if (task2.created_at) {
|
|
4952
|
-
output += `${
|
|
5228
|
+
output += `${chalk13.bold("Created:")} ${new Date(task2.created_at).toLocaleString()}
|
|
4953
5229
|
`;
|
|
4954
5230
|
}
|
|
4955
5231
|
if (task2.updated_at) {
|
|
4956
|
-
output += `${
|
|
5232
|
+
output += `${chalk13.bold("Updated:")} ${new Date(task2.updated_at).toLocaleString()}
|
|
4957
5233
|
`;
|
|
4958
5234
|
}
|
|
4959
5235
|
if (task2.started_at) {
|
|
4960
|
-
output += `${
|
|
5236
|
+
output += `${chalk13.bold("Started:")} ${new Date(task2.started_at).toLocaleString()}
|
|
4961
5237
|
`;
|
|
4962
5238
|
}
|
|
4963
5239
|
if (task2.finished_at) {
|
|
4964
|
-
output += `${
|
|
5240
|
+
output += `${chalk13.bold("Finished:")} ${new Date(task2.finished_at).toLocaleString()}
|
|
4965
5241
|
`;
|
|
4966
5242
|
}
|
|
4967
5243
|
if (task2.content) {
|
|
4968
5244
|
output += `
|
|
4969
5245
|
${divider}
|
|
4970
5246
|
`;
|
|
4971
|
-
output += `${
|
|
5247
|
+
output += `${chalk13.bold("Content:")}
|
|
4972
5248
|
${task2.content}
|
|
4973
5249
|
`;
|
|
4974
5250
|
output += `${divider}
|
|
@@ -4976,12 +5252,12 @@ ${task2.content}
|
|
|
4976
5252
|
}
|
|
4977
5253
|
if (task2.blocked_by && task2.blocked_by.length > 0) {
|
|
4978
5254
|
output += `
|
|
4979
|
-
${
|
|
5255
|
+
${chalk13.bold("Blocked by:")} ${task2.blocked_by.join(", ")}
|
|
4980
5256
|
`;
|
|
4981
5257
|
}
|
|
4982
5258
|
if (i < tasks.length - 1) {
|
|
4983
5259
|
output += `
|
|
4984
|
-
${
|
|
5260
|
+
${chalk13.gray("\u2550".repeat(50))}
|
|
4985
5261
|
|
|
4986
5262
|
`;
|
|
4987
5263
|
}
|
|
@@ -5194,57 +5470,57 @@ function getRequirementStatusEmoji(status) {
|
|
|
5194
5470
|
}
|
|
5195
5471
|
function formatRequirementOutput(requirement2, options) {
|
|
5196
5472
|
const statusEmoji = getRequirementStatusEmoji(requirement2.status);
|
|
5197
|
-
const divider =
|
|
5473
|
+
const divider = chalk13.gray("\u2500".repeat(50));
|
|
5198
5474
|
let message = "";
|
|
5199
5475
|
if (options?.successMessage) {
|
|
5200
|
-
message +=
|
|
5476
|
+
message += chalk13.green(`\u2705 ${options.successMessage}
|
|
5201
5477
|
|
|
5202
5478
|
`);
|
|
5203
5479
|
}
|
|
5204
|
-
message += `${statusEmoji} ${
|
|
5480
|
+
message += `${statusEmoji} ${chalk13.bold(requirement2.name)}
|
|
5205
5481
|
|
|
5206
5482
|
`;
|
|
5207
|
-
message += `${
|
|
5483
|
+
message += `${chalk13.bold("Short ID:")} ${requirement2.short_id || "N/A"}
|
|
5208
5484
|
`;
|
|
5209
|
-
message += `${
|
|
5485
|
+
message += `${chalk13.bold("ID:")} ${requirement2.id}
|
|
5210
5486
|
`;
|
|
5211
5487
|
if (options?.apiUrl) {
|
|
5212
5488
|
const webUiUrl = getWebUiUrl(options.apiUrl);
|
|
5213
|
-
message += `${
|
|
5489
|
+
message += `${chalk13.bold("URL:")} ${webUiUrl}/requirements/overview?id=${requirement2.id}
|
|
5214
5490
|
`;
|
|
5215
5491
|
}
|
|
5216
|
-
message += `${
|
|
5492
|
+
message += `${chalk13.bold("Project:")} ${options?.projectShortId || "N/A"}
|
|
5217
5493
|
`;
|
|
5218
5494
|
if (requirement2.branch) {
|
|
5219
|
-
message += `${
|
|
5495
|
+
message += `${chalk13.bold("Branch:")} ${requirement2.branch}
|
|
5220
5496
|
`;
|
|
5221
5497
|
}
|
|
5222
|
-
message += `${
|
|
5498
|
+
message += `${chalk13.bold("Status:")} ${requirement2.status}
|
|
5223
5499
|
`;
|
|
5224
5500
|
if (requirement2.tags && requirement2.tags.length > 0) {
|
|
5225
5501
|
const tagNames = requirement2.tags.map((tag) => tag.name).join(", ");
|
|
5226
|
-
message += `${
|
|
5502
|
+
message += `${chalk13.bold("Tags:")} ${tagNames}
|
|
5227
5503
|
`;
|
|
5228
5504
|
}
|
|
5229
5505
|
if (requirement2.assignee) {
|
|
5230
5506
|
const assigneeName = requirement2.assignee.first_name || requirement2.assignee.last_name ? `${requirement2.assignee.first_name || ""} ${requirement2.assignee.last_name || ""}`.trim() : requirement2.assignee.email;
|
|
5231
|
-
message += `${
|
|
5507
|
+
message += `${chalk13.bold("Assigned to:")} ${assigneeName} (${requirement2.assignee.email})
|
|
5232
5508
|
`;
|
|
5233
5509
|
} else {
|
|
5234
|
-
message += `${
|
|
5510
|
+
message += `${chalk13.bold("Assigned to:")} Unassigned
|
|
5235
5511
|
`;
|
|
5236
5512
|
}
|
|
5237
|
-
message += `${
|
|
5513
|
+
message += `${chalk13.bold("Created:")} ${new Date(requirement2.created_at).toLocaleString()}
|
|
5238
5514
|
`;
|
|
5239
5515
|
if (options?.showUpdated) {
|
|
5240
|
-
message += `${
|
|
5516
|
+
message += `${chalk13.bold("Updated:")} ${new Date(requirement2.updated_at).toLocaleString()}
|
|
5241
5517
|
`;
|
|
5242
5518
|
}
|
|
5243
5519
|
if (options?.showDescription && requirement2.description) {
|
|
5244
5520
|
message += `
|
|
5245
5521
|
${divider}
|
|
5246
5522
|
`;
|
|
5247
|
-
message += `${
|
|
5523
|
+
message += `${chalk13.bold("Description:")}
|
|
5248
5524
|
${requirement2.description}
|
|
5249
5525
|
`;
|
|
5250
5526
|
message += `${divider}
|
|
@@ -5254,7 +5530,7 @@ ${requirement2.description}
|
|
|
5254
5530
|
message += `
|
|
5255
5531
|
${divider}
|
|
5256
5532
|
`;
|
|
5257
|
-
message += `${
|
|
5533
|
+
message += `${chalk13.bold("Content:")}
|
|
5258
5534
|
${requirement2.content}
|
|
5259
5535
|
`;
|
|
5260
5536
|
message += `${divider}
|
|
@@ -5262,7 +5538,7 @@ ${requirement2.content}
|
|
|
5262
5538
|
}
|
|
5263
5539
|
if (options?.showTaskList) {
|
|
5264
5540
|
message += `
|
|
5265
|
-
${
|
|
5541
|
+
${chalk13.bold("Tasks:")}
|
|
5266
5542
|
`;
|
|
5267
5543
|
if (requirement2.tasks && requirement2.tasks.length > 0) {
|
|
5268
5544
|
for (const task2 of requirement2.tasks) {
|
|
@@ -5278,7 +5554,7 @@ ${chalk12.bold("Tasks:")}
|
|
|
5278
5554
|
const completedTasks = tasks.filter((task2) => task2.status === "COMPLETED").length;
|
|
5279
5555
|
const totalTasks = tasks.length;
|
|
5280
5556
|
message += `
|
|
5281
|
-
${
|
|
5557
|
+
${chalk13.bold("Tasks:")} ${completedTasks}/${totalTasks} completed
|
|
5282
5558
|
`;
|
|
5283
5559
|
message += `${divider}
|
|
5284
5560
|
`;
|
|
@@ -5301,59 +5577,59 @@ function getTaskStatusEmoji(status) {
|
|
|
5301
5577
|
}
|
|
5302
5578
|
function formatTaskOutput(task2, options) {
|
|
5303
5579
|
const statusEmoji = getTaskStatusEmoji(task2.status);
|
|
5304
|
-
const divider =
|
|
5580
|
+
const divider = chalk13.gray("\u2500".repeat(50));
|
|
5305
5581
|
let message = "";
|
|
5306
5582
|
if (options?.successMessage) {
|
|
5307
|
-
message +=
|
|
5583
|
+
message += chalk13.green(`\u2705 ${options.successMessage}
|
|
5308
5584
|
|
|
5309
5585
|
`);
|
|
5310
5586
|
}
|
|
5311
|
-
message += `${statusEmoji} ${
|
|
5587
|
+
message += `${statusEmoji} ${chalk13.bold(task2.title)}
|
|
5312
5588
|
|
|
5313
5589
|
`;
|
|
5314
|
-
message += `${
|
|
5590
|
+
message += `${chalk13.bold("Short ID:")} TASK-${task2.number}
|
|
5315
5591
|
`;
|
|
5316
|
-
message += `${
|
|
5592
|
+
message += `${chalk13.bold("ID:")} ${task2.id}
|
|
5317
5593
|
`;
|
|
5318
5594
|
if (options?.apiUrl && options?.requirementId) {
|
|
5319
5595
|
const webUiUrl = getWebUiUrl(options.apiUrl);
|
|
5320
|
-
message += `${
|
|
5596
|
+
message += `${chalk13.bold("URL:")} ${webUiUrl}/requirements/overview?id=${options.requirementId}&tab=tasks
|
|
5321
5597
|
`;
|
|
5322
5598
|
}
|
|
5323
|
-
message += `${
|
|
5599
|
+
message += `${chalk13.bold("Project:")} ${options?.projectShortId || "N/A"}
|
|
5324
5600
|
`;
|
|
5325
|
-
message += `${
|
|
5601
|
+
message += `${chalk13.bold("Requirement:")} ${options?.requirementShortId || "N/A"}
|
|
5326
5602
|
`;
|
|
5327
|
-
message += `${
|
|
5603
|
+
message += `${chalk13.bold("Status:")} ${task2.status}
|
|
5328
5604
|
`;
|
|
5329
5605
|
if (task2.assigned_to) {
|
|
5330
|
-
message += `${
|
|
5606
|
+
message += `${chalk13.bold("Assigned to:")} ${task2.assigned_to}
|
|
5331
5607
|
`;
|
|
5332
5608
|
} else {
|
|
5333
|
-
message += `${
|
|
5609
|
+
message += `${chalk13.bold("Assigned to:")} Unassigned
|
|
5334
5610
|
`;
|
|
5335
5611
|
}
|
|
5336
5612
|
if (task2.created_at) {
|
|
5337
|
-
message += `${
|
|
5613
|
+
message += `${chalk13.bold("Created:")} ${new Date(task2.created_at).toLocaleString()}
|
|
5338
5614
|
`;
|
|
5339
5615
|
}
|
|
5340
5616
|
if (task2.updated_at) {
|
|
5341
|
-
message += `${
|
|
5617
|
+
message += `${chalk13.bold("Updated:")} ${new Date(task2.updated_at).toLocaleString()}
|
|
5342
5618
|
`;
|
|
5343
5619
|
}
|
|
5344
5620
|
if (task2.started_at) {
|
|
5345
|
-
message += `${
|
|
5621
|
+
message += `${chalk13.bold("Started:")} ${new Date(task2.started_at).toLocaleString()}
|
|
5346
5622
|
`;
|
|
5347
5623
|
}
|
|
5348
5624
|
if (task2.finished_at) {
|
|
5349
|
-
message += `${
|
|
5625
|
+
message += `${chalk13.bold("Finished:")} ${new Date(task2.finished_at).toLocaleString()}
|
|
5350
5626
|
`;
|
|
5351
5627
|
}
|
|
5352
5628
|
if (options?.showContent && task2.content) {
|
|
5353
5629
|
message += `
|
|
5354
5630
|
${divider}
|
|
5355
5631
|
`;
|
|
5356
|
-
message += `${
|
|
5632
|
+
message += `${chalk13.bold("Content:")}
|
|
5357
5633
|
${task2.content}
|
|
5358
5634
|
`;
|
|
5359
5635
|
message += `${divider}
|
|
@@ -5361,7 +5637,7 @@ ${task2.content}
|
|
|
5361
5637
|
}
|
|
5362
5638
|
if (task2.blocked_by && task2.blocked_by.length > 0) {
|
|
5363
5639
|
message += `
|
|
5364
|
-
${
|
|
5640
|
+
${chalk13.bold("Blocked by:")} ${task2.blocked_by.join(", ")}
|
|
5365
5641
|
`;
|
|
5366
5642
|
}
|
|
5367
5643
|
return message;
|
|
@@ -5944,9 +6220,9 @@ function formatProjectShowXml(project2) {
|
|
|
5944
6220
|
}
|
|
5945
6221
|
function formatRequirementTreeView(requirements, tasksMap) {
|
|
5946
6222
|
if (requirements.length === 0) {
|
|
5947
|
-
return
|
|
6223
|
+
return chalk13.yellow("No requirements found.\n");
|
|
5948
6224
|
}
|
|
5949
|
-
let output =
|
|
6225
|
+
let output = chalk13.bold.cyan(`\u{1F4CB} Requirements (Tree View)
|
|
5950
6226
|
|
|
5951
6227
|
`);
|
|
5952
6228
|
for (let i = 0; i < requirements.length; i++) {
|
|
@@ -5959,12 +6235,12 @@ function formatRequirementTreeView(requirements, tasksMap) {
|
|
|
5959
6235
|
if (shortId.startsWith("REQ-REQ-")) {
|
|
5960
6236
|
shortId = shortId.replace("REQ-REQ-", "REQ-");
|
|
5961
6237
|
}
|
|
5962
|
-
const branchInfo = req.branch ?
|
|
5963
|
-
output += `${reqPrefix}${
|
|
6238
|
+
const branchInfo = req.branch ? chalk13.gray(` (branch: ${req.branch})`) : "";
|
|
6239
|
+
output += `${reqPrefix}${chalk13.bold(shortId)} ${reqStatusEmoji} ${req.name}${branchInfo}
|
|
5964
6240
|
`;
|
|
5965
6241
|
const tasks = tasksMap.get(req.id) || [];
|
|
5966
6242
|
if (tasks.length === 0) {
|
|
5967
|
-
output += `${childPrefix}\u2514\u2500\u2500 ${
|
|
6243
|
+
output += `${childPrefix}\u2514\u2500\u2500 ${chalk13.gray("(no tasks yet)")}
|
|
5968
6244
|
`;
|
|
5969
6245
|
} else {
|
|
5970
6246
|
for (let j = 0; j < tasks.length; j++) {
|
|
@@ -5972,7 +6248,7 @@ function formatRequirementTreeView(requirements, tasksMap) {
|
|
|
5972
6248
|
const isLastTask = j === tasks.length - 1;
|
|
5973
6249
|
const taskPrefix = isLastTask ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
5974
6250
|
const taskStatusEmoji = getRequirementStatusEmoji(task2.status);
|
|
5975
|
-
const blockedInfo = task2.blocked_by && task2.blocked_by.length > 0 ?
|
|
6251
|
+
const blockedInfo = task2.blocked_by && task2.blocked_by.length > 0 ? chalk13.yellow(` [Blocked by: ${task2.blocked_by.length}]`) : "";
|
|
5976
6252
|
output += `${childPrefix}${taskPrefix}${task2.number} ${taskStatusEmoji} ${task2.title}${blockedInfo}
|
|
5977
6253
|
`;
|
|
5978
6254
|
}
|
|
@@ -5987,7 +6263,7 @@ function parseProjectId(input2) {
|
|
|
5987
6263
|
}
|
|
5988
6264
|
|
|
5989
6265
|
// src/utils/workspace-manager.ts
|
|
5990
|
-
import
|
|
6266
|
+
import chalk14 from "chalk";
|
|
5991
6267
|
var WorkspaceManager = class {
|
|
5992
6268
|
constructor() {
|
|
5993
6269
|
this.activeRequirementId = null;
|
|
@@ -6027,13 +6303,13 @@ var WorkspaceManager = class {
|
|
|
6027
6303
|
const msg = error instanceof Error ? error.message : String(error);
|
|
6028
6304
|
return {
|
|
6029
6305
|
success: false,
|
|
6030
|
-
error:
|
|
6306
|
+
error: chalk14.red("\u274C Found .braingrid/project.json but failed to load it:") + "\n" + chalk14.dim(` ${msg}`) + "\n\n" + chalk14.dim("Try re-initializing with:\n") + chalk14.cyan(" braingrid init --force")
|
|
6031
6307
|
};
|
|
6032
6308
|
}
|
|
6033
6309
|
}
|
|
6034
6310
|
return {
|
|
6035
6311
|
success: false,
|
|
6036
|
-
error:
|
|
6312
|
+
error: chalk14.red("\u274C No project specified and no local project found.") + "\n\n" + chalk14.dim("To initialize this workspace, run:\n") + chalk14.cyan(" braingrid init") + "\n\n" + chalk14.dim("Or specify a project explicitly:\n") + chalk14.cyan(" braingrid <command> -p PROJ-123")
|
|
6037
6313
|
};
|
|
6038
6314
|
}
|
|
6039
6315
|
/**
|
|
@@ -6067,9 +6343,9 @@ var WorkspaceManager = class {
|
|
|
6067
6343
|
}
|
|
6068
6344
|
return {
|
|
6069
6345
|
success: false,
|
|
6070
|
-
error:
|
|
6346
|
+
error: chalk14.red("\u274C No requirement specified.") + "\n\n" + chalk14.dim("Unable to auto-detect requirement from branch name.\n") + chalk14.dim("Please provide a requirement ID explicitly:\n") + chalk14.cyan(" braingrid requirement show REQ-123") + "\n" + chalk14.dim(" or\n") + chalk14.cyan(" braingrid task list -r REQ-123") + "\n\n" + chalk14.dim(
|
|
6071
6347
|
"Tip: Name your branch with a requirement ID (e.g., feature/REQ-123-description)\n"
|
|
6072
|
-
) +
|
|
6348
|
+
) + chalk14.dim("to enable auto-detection.")
|
|
6073
6349
|
};
|
|
6074
6350
|
}
|
|
6075
6351
|
/**
|
|
@@ -6128,19 +6404,19 @@ async function handleProjectList(opts) {
|
|
|
6128
6404
|
if (!isAuthenticated) {
|
|
6129
6405
|
return {
|
|
6130
6406
|
success: false,
|
|
6131
|
-
message:
|
|
6407
|
+
message: chalk15.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
6132
6408
|
};
|
|
6133
6409
|
}
|
|
6134
6410
|
const format = opts.format || "table";
|
|
6135
6411
|
if (!["table", "json", "xml", "markdown"].includes(format)) {
|
|
6136
6412
|
return {
|
|
6137
6413
|
success: false,
|
|
6138
|
-
message:
|
|
6414
|
+
message: chalk15.red(
|
|
6139
6415
|
`\u274C Invalid format: ${format}. Supported formats: table, json, xml, markdown`
|
|
6140
6416
|
)
|
|
6141
6417
|
};
|
|
6142
6418
|
}
|
|
6143
|
-
const stop = showSpinner("Loading projects",
|
|
6419
|
+
const stop = showSpinner("Loading projects", chalk15.gray);
|
|
6144
6420
|
try {
|
|
6145
6421
|
const response = await projectService.listProjects({
|
|
6146
6422
|
page: opts.page ? parseInt(opts.page, 10) : 1,
|
|
@@ -6167,11 +6443,11 @@ async function handleProjectList(opts) {
|
|
|
6167
6443
|
if (response.projects.length === 0) {
|
|
6168
6444
|
return {
|
|
6169
6445
|
success: true,
|
|
6170
|
-
message:
|
|
6446
|
+
message: chalk15.yellow("No projects found."),
|
|
6171
6447
|
data: response
|
|
6172
6448
|
};
|
|
6173
6449
|
}
|
|
6174
|
-
output =
|
|
6450
|
+
output = chalk15.bold("\u{1F4CB} Projects\n\n");
|
|
6175
6451
|
output += "ID Short ID Name Created\n";
|
|
6176
6452
|
output += `${"\u2500".repeat(100)}
|
|
6177
6453
|
`;
|
|
@@ -6210,21 +6486,21 @@ async function handleProjectShow(opts) {
|
|
|
6210
6486
|
if (!isAuthenticated) {
|
|
6211
6487
|
return {
|
|
6212
6488
|
success: false,
|
|
6213
|
-
message:
|
|
6489
|
+
message: chalk15.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
6214
6490
|
};
|
|
6215
6491
|
}
|
|
6216
6492
|
const format = opts.format || "table";
|
|
6217
6493
|
if (!["table", "json", "xml", "markdown"].includes(format)) {
|
|
6218
6494
|
return {
|
|
6219
6495
|
success: false,
|
|
6220
|
-
message:
|
|
6496
|
+
message: chalk15.red(
|
|
6221
6497
|
`\u274C Invalid format: ${format}. Supported formats: table, json, xml, markdown`
|
|
6222
6498
|
)
|
|
6223
6499
|
};
|
|
6224
6500
|
}
|
|
6225
6501
|
if (opts.id) {
|
|
6226
6502
|
const normalizedId = parseProjectId(opts.id);
|
|
6227
|
-
const stop2 = showSpinner("Loading project",
|
|
6503
|
+
const stop2 = showSpinner("Loading project", chalk15.gray);
|
|
6228
6504
|
try {
|
|
6229
6505
|
const project2 = await projectService.getProject(normalizedId);
|
|
6230
6506
|
stop2();
|
|
@@ -6243,23 +6519,23 @@ async function handleProjectShow(opts) {
|
|
|
6243
6519
|
break;
|
|
6244
6520
|
}
|
|
6245
6521
|
default: {
|
|
6246
|
-
output =
|
|
6522
|
+
output = chalk15.bold(`
|
|
6247
6523
|
\u{1F4C1} Project: ${project2.name}
|
|
6248
6524
|
|
|
6249
6525
|
`);
|
|
6250
|
-
output += `${
|
|
6526
|
+
output += `${chalk15.bold("ID:")} ${project2.id}
|
|
6251
6527
|
`;
|
|
6252
|
-
output += `${
|
|
6528
|
+
output += `${chalk15.bold("Short ID:")} ${project2.short_id}
|
|
6253
6529
|
`;
|
|
6254
|
-
output += `${
|
|
6530
|
+
output += `${chalk15.bold("Name:")} ${project2.name}
|
|
6255
6531
|
`;
|
|
6256
6532
|
if (project2.description) {
|
|
6257
|
-
output += `${
|
|
6533
|
+
output += `${chalk15.bold("Description:")} ${project2.description}
|
|
6258
6534
|
`;
|
|
6259
6535
|
}
|
|
6260
|
-
output += `${
|
|
6536
|
+
output += `${chalk15.bold("Created:")} ${new Date(project2.created_at).toLocaleString()}
|
|
6261
6537
|
`;
|
|
6262
|
-
output += `${
|
|
6538
|
+
output += `${chalk15.bold("Updated:")} ${new Date(project2.updated_at).toLocaleString()}
|
|
6263
6539
|
`;
|
|
6264
6540
|
break;
|
|
6265
6541
|
}
|
|
@@ -6279,13 +6555,13 @@ async function handleProjectShow(opts) {
|
|
|
6279
6555
|
if (parts.length !== 2) {
|
|
6280
6556
|
return {
|
|
6281
6557
|
success: false,
|
|
6282
|
-
message:
|
|
6558
|
+
message: chalk15.red(
|
|
6283
6559
|
"\u274C Invalid repository format. Use: --repository owner/name (e.g., --repository microsoft/vscode)"
|
|
6284
6560
|
)
|
|
6285
6561
|
};
|
|
6286
6562
|
}
|
|
6287
6563
|
const [repositoryOwner, repositoryName] = parts;
|
|
6288
|
-
const stop2 = showSpinner("Loading projects",
|
|
6564
|
+
const stop2 = showSpinner("Loading projects", chalk15.gray);
|
|
6289
6565
|
try {
|
|
6290
6566
|
const response = await projectService.listProjects({
|
|
6291
6567
|
repository_owner: repositoryOwner,
|
|
@@ -6311,14 +6587,14 @@ async function handleProjectShow(opts) {
|
|
|
6311
6587
|
break;
|
|
6312
6588
|
}
|
|
6313
6589
|
default: {
|
|
6314
|
-
const repoDisplay =
|
|
6590
|
+
const repoDisplay = chalk15.cyan(`${repositoryOwner}/${repositoryName}`);
|
|
6315
6591
|
if (response.projects.length === 0) {
|
|
6316
6592
|
return {
|
|
6317
6593
|
success: true,
|
|
6318
|
-
message:
|
|
6594
|
+
message: chalk15.yellow(`No projects found for repository ${repoDisplay}`)
|
|
6319
6595
|
};
|
|
6320
6596
|
}
|
|
6321
|
-
output =
|
|
6597
|
+
output = chalk15.bold(`\u{1F4CB} Projects for ${repoDisplay}
|
|
6322
6598
|
|
|
6323
6599
|
`);
|
|
6324
6600
|
output += "ID Short ID Name Created\n";
|
|
@@ -6353,7 +6629,7 @@ async function handleProjectShow(opts) {
|
|
|
6353
6629
|
message: workspace.error
|
|
6354
6630
|
};
|
|
6355
6631
|
}
|
|
6356
|
-
const stop = showSpinner("Loading project",
|
|
6632
|
+
const stop = showSpinner("Loading project", chalk15.gray);
|
|
6357
6633
|
try {
|
|
6358
6634
|
const project2 = await projectService.getProject(workspace.projectId);
|
|
6359
6635
|
stop();
|
|
@@ -6372,23 +6648,23 @@ async function handleProjectShow(opts) {
|
|
|
6372
6648
|
break;
|
|
6373
6649
|
}
|
|
6374
6650
|
default: {
|
|
6375
|
-
output =
|
|
6651
|
+
output = chalk15.bold(`
|
|
6376
6652
|
\u{1F4C1} Project: ${project2.name}
|
|
6377
6653
|
|
|
6378
6654
|
`);
|
|
6379
|
-
output += `${
|
|
6655
|
+
output += `${chalk15.bold("ID:")} ${project2.id}
|
|
6380
6656
|
`;
|
|
6381
|
-
output += `${
|
|
6657
|
+
output += `${chalk15.bold("Short ID:")} ${project2.short_id}
|
|
6382
6658
|
`;
|
|
6383
|
-
output += `${
|
|
6659
|
+
output += `${chalk15.bold("Name:")} ${project2.name}
|
|
6384
6660
|
`;
|
|
6385
6661
|
if (project2.description) {
|
|
6386
|
-
output += `${
|
|
6662
|
+
output += `${chalk15.bold("Description:")} ${project2.description}
|
|
6387
6663
|
`;
|
|
6388
6664
|
}
|
|
6389
|
-
output += `${
|
|
6665
|
+
output += `${chalk15.bold("Created:")} ${new Date(project2.created_at).toLocaleString()}
|
|
6390
6666
|
`;
|
|
6391
|
-
output += `${
|
|
6667
|
+
output += `${chalk15.bold("Updated:")} ${new Date(project2.updated_at).toLocaleString()}
|
|
6392
6668
|
`;
|
|
6393
6669
|
break;
|
|
6394
6670
|
}
|
|
@@ -6416,7 +6692,7 @@ async function handleProjectCreate(opts) {
|
|
|
6416
6692
|
if (!isAuthenticated) {
|
|
6417
6693
|
return {
|
|
6418
6694
|
success: false,
|
|
6419
|
-
message:
|
|
6695
|
+
message: chalk15.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
6420
6696
|
};
|
|
6421
6697
|
}
|
|
6422
6698
|
let repositoryId;
|
|
@@ -6427,21 +6703,21 @@ async function handleProjectCreate(opts) {
|
|
|
6427
6703
|
if (parts.length !== 2) {
|
|
6428
6704
|
return {
|
|
6429
6705
|
success: false,
|
|
6430
|
-
message:
|
|
6706
|
+
message: chalk15.red(
|
|
6431
6707
|
"\u274C Invalid repository format. Use: --repository owner/name (e.g., microsoft/vscode)"
|
|
6432
6708
|
)
|
|
6433
6709
|
};
|
|
6434
6710
|
}
|
|
6435
6711
|
const [owner, name] = parts;
|
|
6436
6712
|
const repositoryService = new RepositoryService(config2.apiUrl, auth);
|
|
6437
|
-
const stop2 = showSpinner(`Looking up repository ${opts.repository}`,
|
|
6713
|
+
const stop2 = showSpinner(`Looking up repository ${opts.repository}`, chalk15.gray);
|
|
6438
6714
|
try {
|
|
6439
6715
|
const repoId = await getRepositoryId(repositoryService, owner, name);
|
|
6440
6716
|
stop2();
|
|
6441
6717
|
if (!repoId) {
|
|
6442
6718
|
return {
|
|
6443
6719
|
success: false,
|
|
6444
|
-
message:
|
|
6720
|
+
message: chalk15.red(
|
|
6445
6721
|
`\u274C Repository '${opts.repository}' not found. Please check the name or ensure you have access.`
|
|
6446
6722
|
)
|
|
6447
6723
|
};
|
|
@@ -6451,7 +6727,7 @@ async function handleProjectCreate(opts) {
|
|
|
6451
6727
|
stop2();
|
|
6452
6728
|
}
|
|
6453
6729
|
}
|
|
6454
|
-
const stop = showSpinner("Creating project",
|
|
6730
|
+
const stop = showSpinner("Creating project", chalk15.gray);
|
|
6455
6731
|
try {
|
|
6456
6732
|
const project2 = await projectService.createProject({
|
|
6457
6733
|
name: opts.name,
|
|
@@ -6459,9 +6735,9 @@ async function handleProjectCreate(opts) {
|
|
|
6459
6735
|
repository_id: repositoryId
|
|
6460
6736
|
});
|
|
6461
6737
|
stop();
|
|
6462
|
-
let message =
|
|
6738
|
+
let message = chalk15.green(`\u2705 Created project ${project2.short_id}: ${project2.name}`);
|
|
6463
6739
|
if (opts.repository && repositoryId) {
|
|
6464
|
-
message +=
|
|
6740
|
+
message += chalk15.gray(` (linked to ${opts.repository})`);
|
|
6465
6741
|
}
|
|
6466
6742
|
return {
|
|
6467
6743
|
success: true,
|
|
@@ -6485,19 +6761,19 @@ async function handleProjectUpdate(id, opts) {
|
|
|
6485
6761
|
if (!isAuthenticated) {
|
|
6486
6762
|
return {
|
|
6487
6763
|
success: false,
|
|
6488
|
-
message:
|
|
6764
|
+
message: chalk15.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
6489
6765
|
};
|
|
6490
6766
|
}
|
|
6491
6767
|
if (!opts.name && !opts.description) {
|
|
6492
6768
|
return {
|
|
6493
6769
|
success: false,
|
|
6494
|
-
message:
|
|
6770
|
+
message: chalk15.red(
|
|
6495
6771
|
"\u274C Please provide at least one field to update (--name or --description)"
|
|
6496
6772
|
)
|
|
6497
6773
|
};
|
|
6498
6774
|
}
|
|
6499
6775
|
const normalizedId = parseProjectId(id);
|
|
6500
|
-
const stop = showSpinner("Updating project",
|
|
6776
|
+
const stop = showSpinner("Updating project", chalk15.gray);
|
|
6501
6777
|
try {
|
|
6502
6778
|
const project2 = await projectService.updateProject(normalizedId, {
|
|
6503
6779
|
name: opts.name,
|
|
@@ -6506,7 +6782,7 @@ async function handleProjectUpdate(id, opts) {
|
|
|
6506
6782
|
stop();
|
|
6507
6783
|
return {
|
|
6508
6784
|
success: true,
|
|
6509
|
-
message:
|
|
6785
|
+
message: chalk15.green(`\u2705 Updated project ${project2.short_id}: ${project2.name}`),
|
|
6510
6786
|
data: project2
|
|
6511
6787
|
};
|
|
6512
6788
|
} finally {
|
|
@@ -6526,25 +6802,25 @@ async function handleProjectDelete(id, opts) {
|
|
|
6526
6802
|
if (!isAuthenticated) {
|
|
6527
6803
|
return {
|
|
6528
6804
|
success: false,
|
|
6529
|
-
message:
|
|
6805
|
+
message: chalk15.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
6530
6806
|
};
|
|
6531
6807
|
}
|
|
6532
6808
|
if (!opts.force) {
|
|
6533
6809
|
return {
|
|
6534
6810
|
success: false,
|
|
6535
|
-
message:
|
|
6811
|
+
message: chalk15.yellow(
|
|
6536
6812
|
"\u26A0\uFE0F Deleting a project is permanent. Use --force to confirm deletion."
|
|
6537
6813
|
)
|
|
6538
6814
|
};
|
|
6539
6815
|
}
|
|
6540
6816
|
const normalizedId = parseProjectId(id);
|
|
6541
|
-
const stop = showSpinner("Deleting project",
|
|
6817
|
+
const stop = showSpinner("Deleting project", chalk15.gray);
|
|
6542
6818
|
try {
|
|
6543
6819
|
await projectService.deleteProject(normalizedId);
|
|
6544
6820
|
stop();
|
|
6545
6821
|
return {
|
|
6546
6822
|
success: true,
|
|
6547
|
-
message:
|
|
6823
|
+
message: chalk15.green(`\u2705 Deleted project ${id}`)
|
|
6548
6824
|
};
|
|
6549
6825
|
} finally {
|
|
6550
6826
|
stop();
|
|
@@ -6558,7 +6834,7 @@ async function handleProjectDelete(id, opts) {
|
|
|
6558
6834
|
}
|
|
6559
6835
|
|
|
6560
6836
|
// src/handlers/requirement.handlers.ts
|
|
6561
|
-
import
|
|
6837
|
+
import chalk16 from "chalk";
|
|
6562
6838
|
|
|
6563
6839
|
// src/services/requirement-service.ts
|
|
6564
6840
|
var RequirementService = class {
|
|
@@ -6708,14 +6984,14 @@ async function handleRequirementList(opts) {
|
|
|
6708
6984
|
if (!isAuthenticated) {
|
|
6709
6985
|
return {
|
|
6710
6986
|
success: false,
|
|
6711
|
-
message:
|
|
6987
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
6712
6988
|
};
|
|
6713
6989
|
}
|
|
6714
6990
|
const format = opts.format || "table";
|
|
6715
6991
|
if (!opts.tree && !["table", "json", "xml", "markdown"].includes(format)) {
|
|
6716
6992
|
return {
|
|
6717
6993
|
success: false,
|
|
6718
|
-
message:
|
|
6994
|
+
message: chalk16.red(
|
|
6719
6995
|
`\u274C Invalid format: ${format}. Supported formats: table, json, xml, markdown`
|
|
6720
6996
|
)
|
|
6721
6997
|
};
|
|
@@ -6728,7 +7004,7 @@ async function handleRequirementList(opts) {
|
|
|
6728
7004
|
};
|
|
6729
7005
|
}
|
|
6730
7006
|
const projectId = workspace.projectId;
|
|
6731
|
-
stopSpinner = showSpinner("Loading requirements",
|
|
7007
|
+
stopSpinner = showSpinner("Loading requirements", chalk16.gray);
|
|
6732
7008
|
const response = await requirementService.listProjectRequirements(projectId, {
|
|
6733
7009
|
status: opts.status,
|
|
6734
7010
|
page: opts.page ? parseInt(opts.page, 10) : 1,
|
|
@@ -6740,10 +7016,10 @@ async function handleRequirementList(opts) {
|
|
|
6740
7016
|
if (response.requirements.length === 0) {
|
|
6741
7017
|
return {
|
|
6742
7018
|
success: true,
|
|
6743
|
-
message:
|
|
7019
|
+
message: chalk16.yellow("No requirements found.")
|
|
6744
7020
|
};
|
|
6745
7021
|
}
|
|
6746
|
-
stopSpinner = showSpinner("Loading tasks for tree view",
|
|
7022
|
+
stopSpinner = showSpinner("Loading tasks for tree view", chalk16.gray);
|
|
6747
7023
|
const tasksMap = /* @__PURE__ */ new Map();
|
|
6748
7024
|
const taskPromises = response.requirements.map(async (req) => {
|
|
6749
7025
|
try {
|
|
@@ -6766,7 +7042,7 @@ Page ${response.pagination.page} of ${Math.ceil(response.pagination.total / resp
|
|
|
6766
7042
|
finalOutput += ` (${response.pagination.total} total)`;
|
|
6767
7043
|
if (response.pagination?.has_more) {
|
|
6768
7044
|
finalOutput += `
|
|
6769
|
-
${
|
|
7045
|
+
${chalk16.yellow("\u26A0\uFE0F More requirements exist. Use --limit to see more.")}`;
|
|
6770
7046
|
}
|
|
6771
7047
|
return {
|
|
6772
7048
|
success: true,
|
|
@@ -6792,10 +7068,10 @@ ${chalk15.yellow("\u26A0\uFE0F More requirements exist. Use --limit to see more.
|
|
|
6792
7068
|
if (response.requirements.length === 0) {
|
|
6793
7069
|
return {
|
|
6794
7070
|
success: true,
|
|
6795
|
-
message:
|
|
7071
|
+
message: chalk16.yellow("No requirements found.")
|
|
6796
7072
|
};
|
|
6797
7073
|
}
|
|
6798
|
-
output =
|
|
7074
|
+
output = chalk16.bold("\u{1F4CB} Requirements\n\n");
|
|
6799
7075
|
output += "Short ID Status Name Branch Progress\n";
|
|
6800
7076
|
output += `${"\u2500".repeat(90)}
|
|
6801
7077
|
`;
|
|
@@ -6817,7 +7093,7 @@ ${chalk15.yellow("\u26A0\uFE0F More requirements exist. Use --limit to see more.
|
|
|
6817
7093
|
}
|
|
6818
7094
|
if (response.pagination?.has_more) {
|
|
6819
7095
|
output += `
|
|
6820
|
-
${
|
|
7096
|
+
${chalk16.yellow("\u26A0\uFE0F More requirements exist. Use --limit to see more.")}`;
|
|
6821
7097
|
}
|
|
6822
7098
|
return {
|
|
6823
7099
|
success: true,
|
|
@@ -6842,14 +7118,14 @@ async function handleRequirementShow(opts) {
|
|
|
6842
7118
|
if (!isAuthenticated) {
|
|
6843
7119
|
return {
|
|
6844
7120
|
success: false,
|
|
6845
|
-
message:
|
|
7121
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
6846
7122
|
};
|
|
6847
7123
|
}
|
|
6848
7124
|
const format = opts?.format || "table";
|
|
6849
7125
|
if (!["table", "json", "xml", "markdown"].includes(format)) {
|
|
6850
7126
|
return {
|
|
6851
7127
|
success: false,
|
|
6852
|
-
message:
|
|
7128
|
+
message: chalk16.red(
|
|
6853
7129
|
`\u274C Invalid format: ${format}. Supported formats: table, json, xml, markdown`
|
|
6854
7130
|
)
|
|
6855
7131
|
};
|
|
@@ -6871,7 +7147,7 @@ async function handleRequirementShow(opts) {
|
|
|
6871
7147
|
}
|
|
6872
7148
|
const projectId = workspace.projectId;
|
|
6873
7149
|
const normalizedId = normalizeRequirementId(requirementId);
|
|
6874
|
-
stopSpinner = showSpinner("Loading requirement",
|
|
7150
|
+
stopSpinner = showSpinner("Loading requirement", chalk16.gray);
|
|
6875
7151
|
const requirement2 = await requirementService.getProjectRequirement(projectId, normalizedId);
|
|
6876
7152
|
stopSpinner();
|
|
6877
7153
|
stopSpinner = null;
|
|
@@ -6927,7 +7203,7 @@ async function handleRequirementCreate(opts) {
|
|
|
6927
7203
|
if (!isAuthenticated) {
|
|
6928
7204
|
return {
|
|
6929
7205
|
success: false,
|
|
6930
|
-
message:
|
|
7206
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
6931
7207
|
};
|
|
6932
7208
|
}
|
|
6933
7209
|
const workspace = await workspaceManager.getProject(opts.project);
|
|
@@ -6944,7 +7220,7 @@ async function handleRequirementCreate(opts) {
|
|
|
6944
7220
|
if (emailRegex.test(opts.assignedTo)) {
|
|
6945
7221
|
return {
|
|
6946
7222
|
success: false,
|
|
6947
|
-
message:
|
|
7223
|
+
message: chalk16.red(
|
|
6948
7224
|
"\u274C Email addresses are not supported for --assigned-to yet.\nPlease use the user UUID instead.\nEmail lookup will be supported when the API provides a user lookup endpoint."
|
|
6949
7225
|
)
|
|
6950
7226
|
};
|
|
@@ -6952,7 +7228,7 @@ async function handleRequirementCreate(opts) {
|
|
|
6952
7228
|
if (!uuidRegex.test(opts.assignedTo)) {
|
|
6953
7229
|
return {
|
|
6954
7230
|
success: false,
|
|
6955
|
-
message:
|
|
7231
|
+
message: chalk16.red(
|
|
6956
7232
|
'\u274C Invalid UUID format for --assigned-to.\nPlease provide a valid user UUID (e.g., "550e8400-e29b-41d4-a716-446655440000")'
|
|
6957
7233
|
)
|
|
6958
7234
|
};
|
|
@@ -6964,12 +7240,12 @@ async function handleRequirementCreate(opts) {
|
|
|
6964
7240
|
if (!tagResult.valid) {
|
|
6965
7241
|
return {
|
|
6966
7242
|
success: false,
|
|
6967
|
-
message:
|
|
7243
|
+
message: chalk16.red(`\u274C ${tagResult.error}`)
|
|
6968
7244
|
};
|
|
6969
7245
|
}
|
|
6970
7246
|
validatedTags = tagResult.tags;
|
|
6971
7247
|
}
|
|
6972
|
-
stopSpinner = showSpinner("Creating requirement",
|
|
7248
|
+
stopSpinner = showSpinner("Creating requirement", chalk16.gray);
|
|
6973
7249
|
const requirement2 = await requirementService.createProjectRequirement(projectId, {
|
|
6974
7250
|
name: opts.name,
|
|
6975
7251
|
content: opts.content || null,
|
|
@@ -7003,7 +7279,7 @@ async function handleRequirementCreate(opts) {
|
|
|
7003
7279
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
7004
7280
|
return {
|
|
7005
7281
|
success: false,
|
|
7006
|
-
message:
|
|
7282
|
+
message: chalk16.red(`\u274C Error creating requirement: ${errorMessage}`)
|
|
7007
7283
|
};
|
|
7008
7284
|
}
|
|
7009
7285
|
}
|
|
@@ -7015,14 +7291,14 @@ async function handleRequirementSpecify(opts) {
|
|
|
7015
7291
|
if (!isAuthenticated) {
|
|
7016
7292
|
return {
|
|
7017
7293
|
success: false,
|
|
7018
|
-
message:
|
|
7294
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
7019
7295
|
};
|
|
7020
7296
|
}
|
|
7021
7297
|
const format = opts.format || "table";
|
|
7022
7298
|
if (!["table", "json", "xml", "markdown"].includes(format)) {
|
|
7023
7299
|
return {
|
|
7024
7300
|
success: false,
|
|
7025
|
-
message:
|
|
7301
|
+
message: chalk16.red(
|
|
7026
7302
|
`\u274C Invalid format: ${format}. Supported formats: table, json, xml, markdown`
|
|
7027
7303
|
)
|
|
7028
7304
|
};
|
|
@@ -7038,13 +7314,13 @@ async function handleRequirementSpecify(opts) {
|
|
|
7038
7314
|
if (opts.prompt.length < 10) {
|
|
7039
7315
|
return {
|
|
7040
7316
|
success: false,
|
|
7041
|
-
message:
|
|
7317
|
+
message: chalk16.red("\u274C Prompt must be at least 10 characters long")
|
|
7042
7318
|
};
|
|
7043
7319
|
}
|
|
7044
7320
|
if (opts.prompt.length > 5e3) {
|
|
7045
7321
|
return {
|
|
7046
7322
|
success: false,
|
|
7047
|
-
message:
|
|
7323
|
+
message: chalk16.red("\u274C Prompt must be no more than 5000 characters long")
|
|
7048
7324
|
};
|
|
7049
7325
|
}
|
|
7050
7326
|
let validatedTags;
|
|
@@ -7053,7 +7329,7 @@ async function handleRequirementSpecify(opts) {
|
|
|
7053
7329
|
if (!tagResult.valid) {
|
|
7054
7330
|
return {
|
|
7055
7331
|
success: false,
|
|
7056
|
-
message:
|
|
7332
|
+
message: chalk16.red(`\u274C ${tagResult.error}`)
|
|
7057
7333
|
};
|
|
7058
7334
|
}
|
|
7059
7335
|
validatedTags = tagResult.tags;
|
|
@@ -7116,13 +7392,13 @@ async function handleRequirementUpdate(opts) {
|
|
|
7116
7392
|
if (!isAuthenticated) {
|
|
7117
7393
|
return {
|
|
7118
7394
|
success: false,
|
|
7119
|
-
message:
|
|
7395
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
7120
7396
|
};
|
|
7121
7397
|
}
|
|
7122
7398
|
if (!opts.status && !opts.name && !opts.content) {
|
|
7123
7399
|
return {
|
|
7124
7400
|
success: false,
|
|
7125
|
-
message:
|
|
7401
|
+
message: chalk16.red(
|
|
7126
7402
|
"\u274C Please provide at least one field to update (--status, --name, or --content)"
|
|
7127
7403
|
)
|
|
7128
7404
|
};
|
|
@@ -7144,7 +7420,7 @@ async function handleRequirementUpdate(opts) {
|
|
|
7144
7420
|
}
|
|
7145
7421
|
const projectId = workspace.projectId;
|
|
7146
7422
|
const normalizedId = normalizeRequirementId(requirementId);
|
|
7147
|
-
stopSpinner = showSpinner("Updating requirement",
|
|
7423
|
+
stopSpinner = showSpinner("Updating requirement", chalk16.gray);
|
|
7148
7424
|
const requirement2 = await requirementService.updateProjectRequirement(projectId, normalizedId, {
|
|
7149
7425
|
status: opts.status,
|
|
7150
7426
|
name: opts.name,
|
|
@@ -7154,7 +7430,7 @@ async function handleRequirementUpdate(opts) {
|
|
|
7154
7430
|
stopSpinner = null;
|
|
7155
7431
|
return {
|
|
7156
7432
|
success: true,
|
|
7157
|
-
message:
|
|
7433
|
+
message: chalk16.green(`\u2705 Updated requirement ${requirement2.short_id}: ${requirement2.name}`),
|
|
7158
7434
|
data: requirement2
|
|
7159
7435
|
};
|
|
7160
7436
|
} catch (error) {
|
|
@@ -7175,13 +7451,13 @@ async function handleRequirementDelete(opts) {
|
|
|
7175
7451
|
if (!isAuthenticated) {
|
|
7176
7452
|
return {
|
|
7177
7453
|
success: false,
|
|
7178
|
-
message:
|
|
7454
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
7179
7455
|
};
|
|
7180
7456
|
}
|
|
7181
7457
|
if (!opts.force) {
|
|
7182
7458
|
return {
|
|
7183
7459
|
success: false,
|
|
7184
|
-
message:
|
|
7460
|
+
message: chalk16.yellow(
|
|
7185
7461
|
"\u26A0\uFE0F Deleting a requirement is permanent. Use --force to confirm deletion."
|
|
7186
7462
|
)
|
|
7187
7463
|
};
|
|
@@ -7203,13 +7479,13 @@ async function handleRequirementDelete(opts) {
|
|
|
7203
7479
|
}
|
|
7204
7480
|
const projectId = workspace.projectId;
|
|
7205
7481
|
const normalizedId = normalizeRequirementId(requirementId);
|
|
7206
|
-
stopSpinner = showSpinner("Deleting requirement",
|
|
7482
|
+
stopSpinner = showSpinner("Deleting requirement", chalk16.gray);
|
|
7207
7483
|
await requirementService.deleteProjectRequirement(projectId, normalizedId);
|
|
7208
7484
|
stopSpinner();
|
|
7209
7485
|
stopSpinner = null;
|
|
7210
7486
|
return {
|
|
7211
7487
|
success: true,
|
|
7212
|
-
message:
|
|
7488
|
+
message: chalk16.green(`\u2705 Deleted requirement ${requirementId}`)
|
|
7213
7489
|
};
|
|
7214
7490
|
} catch (error) {
|
|
7215
7491
|
if (stopSpinner) {
|
|
@@ -7229,14 +7505,14 @@ async function handleRequirementBreakdown(opts) {
|
|
|
7229
7505
|
if (!isAuthenticated) {
|
|
7230
7506
|
return {
|
|
7231
7507
|
success: false,
|
|
7232
|
-
message:
|
|
7508
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
7233
7509
|
};
|
|
7234
7510
|
}
|
|
7235
7511
|
const format = opts.format || "table";
|
|
7236
7512
|
if (!["table", "json", "xml", "markdown"].includes(format)) {
|
|
7237
7513
|
return {
|
|
7238
7514
|
success: false,
|
|
7239
|
-
message:
|
|
7515
|
+
message: chalk16.red(
|
|
7240
7516
|
`\u274C Invalid format: ${format}. Supported formats: table, json, xml, markdown`
|
|
7241
7517
|
)
|
|
7242
7518
|
};
|
|
@@ -7258,7 +7534,7 @@ async function handleRequirementBreakdown(opts) {
|
|
|
7258
7534
|
}
|
|
7259
7535
|
const projectId = workspace.projectId;
|
|
7260
7536
|
const normalizedId = normalizeRequirementId(requirementId);
|
|
7261
|
-
stop = showSpinner("Checking requirement...",
|
|
7537
|
+
stop = showSpinner("Checking requirement...", chalk16.gray);
|
|
7262
7538
|
const requirement2 = await requirementService.getProjectRequirement(projectId, normalizedId);
|
|
7263
7539
|
stop();
|
|
7264
7540
|
const taskCount = requirement2.tasks?.length ?? requirement2.task_progress?.total ?? 0;
|
|
@@ -7266,13 +7542,13 @@ async function handleRequirementBreakdown(opts) {
|
|
|
7266
7542
|
const shortId = requirement2.short_id || normalizedId;
|
|
7267
7543
|
return {
|
|
7268
7544
|
success: false,
|
|
7269
|
-
message:
|
|
7545
|
+
message: chalk16.red(
|
|
7270
7546
|
`\u274C Cannot breakdown requirement ${shortId} - it already has ${taskCount} task(s)
|
|
7271
7547
|
|
|
7272
7548
|
`
|
|
7273
|
-
) + "The breakdown command is only for initial task generation from requirements.\nOnce tasks exist, you should manage them individually.\n\n" +
|
|
7549
|
+
) + "The breakdown command is only for initial task generation from requirements.\nOnce tasks exist, you should manage them individually.\n\n" + chalk16.bold("To add more tasks to this requirement:\n") + chalk16.cyan(` braingrid task create -r ${shortId} --title "Task title"
|
|
7274
7550
|
|
|
7275
|
-
`) +
|
|
7551
|
+
`) + chalk16.bold("To view existing tasks:\n") + chalk16.cyan(` braingrid task list -r ${shortId}`)
|
|
7276
7552
|
};
|
|
7277
7553
|
}
|
|
7278
7554
|
stop = showSpinner("Breaking down requirement into tasks...");
|
|
@@ -7293,7 +7569,7 @@ async function handleRequirementBreakdown(opts) {
|
|
|
7293
7569
|
break;
|
|
7294
7570
|
}
|
|
7295
7571
|
default: {
|
|
7296
|
-
output =
|
|
7572
|
+
output = chalk16.green(
|
|
7297
7573
|
`\u2705 Generated ${response.tasks.length} tasks for ${response.requirement_short_id}
|
|
7298
7574
|
|
|
7299
7575
|
`
|
|
@@ -7331,7 +7607,7 @@ async function handleRequirementBreakdown(opts) {
|
|
|
7331
7607
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
7332
7608
|
return {
|
|
7333
7609
|
success: false,
|
|
7334
|
-
message:
|
|
7610
|
+
message: chalk16.red(`\u274C Error breaking down requirement: ${errorMessage}`)
|
|
7335
7611
|
};
|
|
7336
7612
|
}
|
|
7337
7613
|
}
|
|
@@ -7343,14 +7619,14 @@ async function handleRequirementBuild(opts) {
|
|
|
7343
7619
|
if (!isAuthenticated) {
|
|
7344
7620
|
return {
|
|
7345
7621
|
success: false,
|
|
7346
|
-
message:
|
|
7622
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
7347
7623
|
};
|
|
7348
7624
|
}
|
|
7349
7625
|
const format = opts.format || "markdown";
|
|
7350
7626
|
if (!["markdown", "json", "xml"].includes(format)) {
|
|
7351
7627
|
return {
|
|
7352
7628
|
success: false,
|
|
7353
|
-
message:
|
|
7629
|
+
message: chalk16.red("\u274C Invalid format. Must be one of: markdown, json, xml")
|
|
7354
7630
|
};
|
|
7355
7631
|
}
|
|
7356
7632
|
const requirementResult = await workspaceManager.getRequirement(opts.id);
|
|
@@ -7370,7 +7646,7 @@ async function handleRequirementBuild(opts) {
|
|
|
7370
7646
|
}
|
|
7371
7647
|
const projectId = workspace.projectId;
|
|
7372
7648
|
const normalizedId = normalizeRequirementId(requirementId);
|
|
7373
|
-
stopSpinner = showSpinner("Building requirement with tasks",
|
|
7649
|
+
stopSpinner = showSpinner("Building requirement with tasks", chalk16.gray);
|
|
7374
7650
|
const requirement2 = await requirementService.getProjectRequirement(projectId, normalizedId);
|
|
7375
7651
|
stopSpinner();
|
|
7376
7652
|
stopSpinner = null;
|
|
@@ -7418,14 +7694,14 @@ async function handleCreateGitBranch(opts) {
|
|
|
7418
7694
|
if (!isAuthenticated) {
|
|
7419
7695
|
return {
|
|
7420
7696
|
success: false,
|
|
7421
|
-
message:
|
|
7697
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
7422
7698
|
};
|
|
7423
7699
|
}
|
|
7424
7700
|
const format = opts.format || "table";
|
|
7425
7701
|
if (!["table", "json", "markdown"].includes(format)) {
|
|
7426
7702
|
return {
|
|
7427
7703
|
success: false,
|
|
7428
|
-
message:
|
|
7704
|
+
message: chalk16.red(
|
|
7429
7705
|
`\u274C Invalid format: ${format}. Supported formats: table, json, markdown`
|
|
7430
7706
|
)
|
|
7431
7707
|
};
|
|
@@ -7453,7 +7729,7 @@ async function handleCreateGitBranch(opts) {
|
|
|
7453
7729
|
if (!user) {
|
|
7454
7730
|
return {
|
|
7455
7731
|
success: false,
|
|
7456
|
-
message:
|
|
7732
|
+
message: chalk16.red("\u274C Could not get current user for branch name generation")
|
|
7457
7733
|
};
|
|
7458
7734
|
}
|
|
7459
7735
|
const requirement2 = await requirementService.getProjectRequirement(projectId, normalizedId);
|
|
@@ -7462,7 +7738,7 @@ async function handleCreateGitBranch(opts) {
|
|
|
7462
7738
|
const sluggedName = slugify(requirement2.name);
|
|
7463
7739
|
branchName = `${username}/${reqShortId}-${sluggedName}`;
|
|
7464
7740
|
}
|
|
7465
|
-
stopSpinner = showSpinner("Creating GitHub branch...",
|
|
7741
|
+
stopSpinner = showSpinner("Creating GitHub branch...", chalk16.gray);
|
|
7466
7742
|
const response = await requirementService.createGitBranch(projectId, normalizedId, {
|
|
7467
7743
|
branchName,
|
|
7468
7744
|
baseBranch: opts.base
|
|
@@ -7494,13 +7770,13 @@ git fetch origin && git checkout ${response.branch.name}
|
|
|
7494
7770
|
break;
|
|
7495
7771
|
}
|
|
7496
7772
|
default: {
|
|
7497
|
-
output =
|
|
7773
|
+
output = chalk16.green(`\u2705 Created branch: ${response.branch.name}
|
|
7498
7774
|
|
|
7499
7775
|
`);
|
|
7500
|
-
output += `${
|
|
7776
|
+
output += `${chalk16.bold("SHA:")} ${response.branch.sha.substring(0, 7)}
|
|
7501
7777
|
`;
|
|
7502
7778
|
output += `
|
|
7503
|
-
${
|
|
7779
|
+
${chalk16.dim("To checkout:")} git fetch origin && git checkout ${response.branch.name}`;
|
|
7504
7780
|
break;
|
|
7505
7781
|
}
|
|
7506
7782
|
}
|
|
@@ -7526,7 +7802,7 @@ async function handleReviewAcceptance(opts) {
|
|
|
7526
7802
|
if (!isAuthenticated) {
|
|
7527
7803
|
return {
|
|
7528
7804
|
success: false,
|
|
7529
|
-
message:
|
|
7805
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
7530
7806
|
};
|
|
7531
7807
|
}
|
|
7532
7808
|
const requirementResult = await workspaceManager.getRequirement(opts.id);
|
|
@@ -7548,9 +7824,9 @@ async function handleReviewAcceptance(opts) {
|
|
|
7548
7824
|
const normalizedId = normalizeRequirementId(requirementId);
|
|
7549
7825
|
let prNumber = opts.pr;
|
|
7550
7826
|
if (!prNumber) {
|
|
7551
|
-
const { execAsync:
|
|
7827
|
+
const { execAsync: execAsync6 } = await import("./command-execution-HEGDCOLO.js");
|
|
7552
7828
|
try {
|
|
7553
|
-
const { stdout } = await
|
|
7829
|
+
const { stdout } = await execAsync6("gh pr view --json number -q .number");
|
|
7554
7830
|
const detectedPrNumber = stdout.trim();
|
|
7555
7831
|
if (!detectedPrNumber) {
|
|
7556
7832
|
throw new Error("No PR number returned from gh CLI");
|
|
@@ -7559,13 +7835,13 @@ async function handleReviewAcceptance(opts) {
|
|
|
7559
7835
|
} catch {
|
|
7560
7836
|
return {
|
|
7561
7837
|
success: false,
|
|
7562
|
-
message:
|
|
7838
|
+
message: chalk16.red(
|
|
7563
7839
|
"\u274C No PR specified and could not detect PR for current branch.\n Use --pr <number> or ensure you have an open PR for this branch."
|
|
7564
7840
|
)
|
|
7565
7841
|
};
|
|
7566
7842
|
}
|
|
7567
7843
|
}
|
|
7568
|
-
console.log(
|
|
7844
|
+
console.log(chalk16.bold("\n\u{1F50D} AI Code Review\n"));
|
|
7569
7845
|
let fullOutput = "";
|
|
7570
7846
|
await requirementService.reviewAcceptance(
|
|
7571
7847
|
projectId,
|
|
@@ -7598,14 +7874,14 @@ async function handleRequirementTagList(opts) {
|
|
|
7598
7874
|
if (!isAuthenticated) {
|
|
7599
7875
|
return {
|
|
7600
7876
|
success: false,
|
|
7601
|
-
message:
|
|
7877
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
7602
7878
|
};
|
|
7603
7879
|
}
|
|
7604
7880
|
const format = opts.format || "table";
|
|
7605
7881
|
if (!["table", "json", "xml", "markdown"].includes(format)) {
|
|
7606
7882
|
return {
|
|
7607
7883
|
success: false,
|
|
7608
|
-
message:
|
|
7884
|
+
message: chalk16.red(
|
|
7609
7885
|
`\u274C Invalid format: ${format}. Supported formats: table, json, xml, markdown`
|
|
7610
7886
|
)
|
|
7611
7887
|
};
|
|
@@ -7627,7 +7903,7 @@ async function handleRequirementTagList(opts) {
|
|
|
7627
7903
|
}
|
|
7628
7904
|
const projectId = workspace.projectId;
|
|
7629
7905
|
const normalizedId = normalizeRequirementId(requirementId);
|
|
7630
|
-
stopSpinner = showSpinner("Loading tags",
|
|
7906
|
+
stopSpinner = showSpinner("Loading tags", chalk16.gray);
|
|
7631
7907
|
const tags = await requirementService.listRequirementTags(projectId, normalizedId);
|
|
7632
7908
|
stopSpinner();
|
|
7633
7909
|
stopSpinner = null;
|
|
@@ -7674,11 +7950,11 @@ async function handleRequirementTagList(opts) {
|
|
|
7674
7950
|
if (tags.length === 0) {
|
|
7675
7951
|
return {
|
|
7676
7952
|
success: true,
|
|
7677
|
-
message:
|
|
7953
|
+
message: chalk16.yellow(`No tags found for ${normalizedId}.`),
|
|
7678
7954
|
data: tags
|
|
7679
7955
|
};
|
|
7680
7956
|
}
|
|
7681
|
-
output =
|
|
7957
|
+
output = chalk16.bold(`\u{1F3F7}\uFE0F Tags for ${normalizedId}
|
|
7682
7958
|
|
|
7683
7959
|
`);
|
|
7684
7960
|
output += "Name Color\n";
|
|
@@ -7719,20 +7995,20 @@ async function handleRequirementTagAdd(opts) {
|
|
|
7719
7995
|
if (!isAuthenticated) {
|
|
7720
7996
|
return {
|
|
7721
7997
|
success: false,
|
|
7722
|
-
message:
|
|
7998
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
7723
7999
|
};
|
|
7724
8000
|
}
|
|
7725
8001
|
if (!opts.name || opts.name.trim().length === 0) {
|
|
7726
8002
|
return {
|
|
7727
8003
|
success: false,
|
|
7728
|
-
message:
|
|
8004
|
+
message: chalk16.red("\u274C Tag name is required")
|
|
7729
8005
|
};
|
|
7730
8006
|
}
|
|
7731
8007
|
const colorResult = validateHexColor(opts.color);
|
|
7732
8008
|
if (!colorResult.valid) {
|
|
7733
8009
|
return {
|
|
7734
8010
|
success: false,
|
|
7735
|
-
message:
|
|
8011
|
+
message: chalk16.red(`\u274C ${colorResult.error}`)
|
|
7736
8012
|
};
|
|
7737
8013
|
}
|
|
7738
8014
|
const requirementResult = await workspaceManager.getRequirement(opts.requirementId);
|
|
@@ -7752,7 +8028,7 @@ async function handleRequirementTagAdd(opts) {
|
|
|
7752
8028
|
}
|
|
7753
8029
|
const projectId = workspace.projectId;
|
|
7754
8030
|
const normalizedId = normalizeRequirementId(requirementId);
|
|
7755
|
-
stopSpinner = showSpinner("Adding tag",
|
|
8031
|
+
stopSpinner = showSpinner("Adding tag", chalk16.gray);
|
|
7756
8032
|
const response = await requirementService.addRequirementTag(projectId, normalizedId, {
|
|
7757
8033
|
name: opts.name.trim(),
|
|
7758
8034
|
color: opts.color
|
|
@@ -7761,7 +8037,7 @@ async function handleRequirementTagAdd(opts) {
|
|
|
7761
8037
|
stopSpinner = null;
|
|
7762
8038
|
return {
|
|
7763
8039
|
success: true,
|
|
7764
|
-
message:
|
|
8040
|
+
message: chalk16.green(
|
|
7765
8041
|
`\u2705 Added tag "${response.tag.name}" (${response.tag.color}) to ${normalizedId}`
|
|
7766
8042
|
),
|
|
7767
8043
|
data: response
|
|
@@ -7777,13 +8053,13 @@ async function handleRequirementTagAdd(opts) {
|
|
|
7777
8053
|
if (errorData?.code === "MAX_TAGS_EXCEEDED") {
|
|
7778
8054
|
return {
|
|
7779
8055
|
success: false,
|
|
7780
|
-
message:
|
|
8056
|
+
message: chalk16.red("\u274C Maximum 5 tags allowed per requirement")
|
|
7781
8057
|
};
|
|
7782
8058
|
}
|
|
7783
8059
|
if (errorData?.code === "TAG_ALREADY_ASSOCIATED") {
|
|
7784
8060
|
return {
|
|
7785
8061
|
success: false,
|
|
7786
|
-
message:
|
|
8062
|
+
message: chalk16.red(`\u274C Tag "${opts.name}" is already associated with this requirement`)
|
|
7787
8063
|
};
|
|
7788
8064
|
}
|
|
7789
8065
|
}
|
|
@@ -7805,13 +8081,13 @@ async function handleRequirementTagRemove(opts) {
|
|
|
7805
8081
|
if (!isAuthenticated) {
|
|
7806
8082
|
return {
|
|
7807
8083
|
success: false,
|
|
7808
|
-
message:
|
|
8084
|
+
message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
7809
8085
|
};
|
|
7810
8086
|
}
|
|
7811
8087
|
if (!opts.name || opts.name.trim().length === 0) {
|
|
7812
8088
|
return {
|
|
7813
8089
|
success: false,
|
|
7814
|
-
message:
|
|
8090
|
+
message: chalk16.red("\u274C Tag name is required")
|
|
7815
8091
|
};
|
|
7816
8092
|
}
|
|
7817
8093
|
const requirementResult = await workspaceManager.getRequirement(opts.requirementId);
|
|
@@ -7831,13 +8107,13 @@ async function handleRequirementTagRemove(opts) {
|
|
|
7831
8107
|
}
|
|
7832
8108
|
const projectId = workspace.projectId;
|
|
7833
8109
|
const normalizedId = normalizeRequirementId(requirementId);
|
|
7834
|
-
stopSpinner = showSpinner("Removing tag",
|
|
8110
|
+
stopSpinner = showSpinner("Removing tag", chalk16.gray);
|
|
7835
8111
|
await requirementService.removeRequirementTag(projectId, normalizedId, opts.name.trim());
|
|
7836
8112
|
stopSpinner();
|
|
7837
8113
|
stopSpinner = null;
|
|
7838
8114
|
return {
|
|
7839
8115
|
success: true,
|
|
7840
|
-
message:
|
|
8116
|
+
message: chalk16.green(`\u2705 Removed tag "${opts.name}" from ${normalizedId}`)
|
|
7841
8117
|
};
|
|
7842
8118
|
} catch (error) {
|
|
7843
8119
|
if (stopSpinner) {
|
|
@@ -7850,13 +8126,13 @@ async function handleRequirementTagRemove(opts) {
|
|
|
7850
8126
|
if (errorData?.code === "TAG_NOT_FOUND") {
|
|
7851
8127
|
return {
|
|
7852
8128
|
success: false,
|
|
7853
|
-
message:
|
|
8129
|
+
message: chalk16.red(`\u274C Tag "${opts.name}" not found`)
|
|
7854
8130
|
};
|
|
7855
8131
|
}
|
|
7856
8132
|
if (errorData?.code === "ASSOCIATION_NOT_FOUND") {
|
|
7857
8133
|
return {
|
|
7858
8134
|
success: false,
|
|
7859
|
-
message:
|
|
8135
|
+
message: chalk16.red(`\u274C Tag "${opts.name}" is not associated with this requirement`)
|
|
7860
8136
|
};
|
|
7861
8137
|
}
|
|
7862
8138
|
}
|
|
@@ -7872,88 +8148,136 @@ async function handleRequirementTagRemove(opts) {
|
|
|
7872
8148
|
}
|
|
7873
8149
|
|
|
7874
8150
|
// src/handlers/status.handlers.ts
|
|
7875
|
-
import
|
|
8151
|
+
import fs6 from "fs";
|
|
8152
|
+
import path8 from "path";
|
|
8153
|
+
import chalk17 from "chalk";
|
|
7876
8154
|
function getAuth2() {
|
|
7877
8155
|
const config2 = getConfig();
|
|
7878
8156
|
return new BraingridAuth(config2.apiUrl);
|
|
7879
8157
|
}
|
|
8158
|
+
function formatFileSize(bytes) {
|
|
8159
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
8160
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
8161
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
8162
|
+
}
|
|
8163
|
+
function getDebugLogsSection() {
|
|
8164
|
+
let section = chalk17.bold("Debug Logs\n");
|
|
8165
|
+
section += `${chalk17.dim("\u2500".repeat(50))}
|
|
8166
|
+
`;
|
|
8167
|
+
const logger4 = getLogger();
|
|
8168
|
+
const cliLogPath = logger4.getLogFilePath();
|
|
8169
|
+
const cliLogSize = logger4.getLogFileSize();
|
|
8170
|
+
if (cliLogSize > 0) {
|
|
8171
|
+
section += `${chalk17.bold("CLI Log:")} ${cliLogPath} (${formatFileSize(cliLogSize * 1024 * 1024)})
|
|
8172
|
+
`;
|
|
8173
|
+
} else {
|
|
8174
|
+
section += `${chalk17.bold("CLI Log:")} ${chalk17.dim("none")}
|
|
8175
|
+
`;
|
|
8176
|
+
}
|
|
8177
|
+
try {
|
|
8178
|
+
const tempDir = ".braingrid/temp";
|
|
8179
|
+
if (fs6.existsSync(tempDir)) {
|
|
8180
|
+
const hookLogFiles = fs6.readdirSync(tempDir).filter((f) => f.endsWith("-debug.log") || f === "build-debug.log");
|
|
8181
|
+
if (hookLogFiles.length > 0) {
|
|
8182
|
+
for (const file of hookLogFiles) {
|
|
8183
|
+
const filePath = path8.join(tempDir, file);
|
|
8184
|
+
const stats = fs6.statSync(filePath);
|
|
8185
|
+
section += `${chalk17.bold("Hook Log:")} ${filePath} (${formatFileSize(stats.size)})
|
|
8186
|
+
`;
|
|
8187
|
+
}
|
|
8188
|
+
} else {
|
|
8189
|
+
section += `${chalk17.bold("Hook Logs:")} ${chalk17.dim("none")}
|
|
8190
|
+
`;
|
|
8191
|
+
}
|
|
8192
|
+
} else {
|
|
8193
|
+
section += `${chalk17.bold("Hook Logs:")} ${chalk17.dim("none")}
|
|
8194
|
+
`;
|
|
8195
|
+
}
|
|
8196
|
+
} catch {
|
|
8197
|
+
section += `${chalk17.bold("Hook Logs:")} ${chalk17.dim("unable to check")}
|
|
8198
|
+
`;
|
|
8199
|
+
}
|
|
8200
|
+
section += "\n";
|
|
8201
|
+
return section;
|
|
8202
|
+
}
|
|
7880
8203
|
async function handleStatus() {
|
|
7881
8204
|
try {
|
|
7882
8205
|
const config2 = getConfig();
|
|
7883
8206
|
const auth = getAuth2();
|
|
7884
|
-
const stop = showSpinner("Checking status",
|
|
8207
|
+
const stop = showSpinner("Checking status", chalk17.gray);
|
|
7885
8208
|
const isAuthenticated = await auth.isAuthenticated(true);
|
|
7886
8209
|
stop();
|
|
7887
|
-
let output =
|
|
7888
|
-
output +=
|
|
7889
|
-
output += `${
|
|
8210
|
+
let output = chalk17.bold.cyan("\n\u{1F9E0} BrainGrid CLI Status\n\n");
|
|
8211
|
+
output += chalk17.bold("Authentication\n");
|
|
8212
|
+
output += `${chalk17.dim("\u2500".repeat(50))}
|
|
7890
8213
|
`;
|
|
7891
8214
|
if (!isAuthenticated) {
|
|
7892
|
-
output +=
|
|
7893
|
-
output +=
|
|
7894
|
-
output +=
|
|
7895
|
-
output += `${
|
|
8215
|
+
output += chalk17.red("\u274C Not authenticated\n");
|
|
8216
|
+
output += chalk17.dim(" Run ") + chalk17.cyan("braingrid login") + chalk17.dim(" to sign in\n\n");
|
|
8217
|
+
output += chalk17.bold("Git Repository\n");
|
|
8218
|
+
output += `${chalk17.dim("\u2500".repeat(50))}
|
|
7896
8219
|
`;
|
|
7897
8220
|
const gitInfo2 = await getGitRepositoryInfo();
|
|
7898
8221
|
if (!gitInfo2 || !gitInfo2.isRepo) {
|
|
7899
|
-
output +=
|
|
8222
|
+
output += chalk17.yellow("\u26A0\uFE0F Not in a git repository\n\n");
|
|
7900
8223
|
} else {
|
|
7901
|
-
output +=
|
|
8224
|
+
output += chalk17.green("\u2705 Repository detected!\n");
|
|
7902
8225
|
if (gitInfo2.owner && gitInfo2.name) {
|
|
7903
|
-
output += `${
|
|
8226
|
+
output += `${chalk17.bold("Owner:")} ${gitInfo2.owner}
|
|
7904
8227
|
`;
|
|
7905
|
-
output += `${
|
|
8228
|
+
output += `${chalk17.bold("Name:")} ${gitInfo2.name}
|
|
7906
8229
|
`;
|
|
7907
8230
|
} else if (gitInfo2.remoteUrl) {
|
|
7908
|
-
output += `${
|
|
8231
|
+
output += `${chalk17.bold("Remote:")} ${gitInfo2.remoteUrl}
|
|
7909
8232
|
`;
|
|
7910
8233
|
} else {
|
|
7911
|
-
output +=
|
|
8234
|
+
output += chalk17.yellow("\u26A0\uFE0F Local repository (no remote)\n");
|
|
7912
8235
|
}
|
|
7913
8236
|
if (gitInfo2.branch) {
|
|
7914
|
-
output += `${
|
|
8237
|
+
output += `${chalk17.bold("Branch:")} ${gitInfo2.branch}
|
|
7915
8238
|
`;
|
|
7916
8239
|
}
|
|
7917
8240
|
if (gitInfo2.userName || gitInfo2.userEmail) {
|
|
7918
8241
|
const userDisplay = gitInfo2.userName && gitInfo2.userEmail ? `${gitInfo2.userName} <${gitInfo2.userEmail}>` : gitInfo2.userName || gitInfo2.userEmail;
|
|
7919
|
-
output += `${
|
|
8242
|
+
output += `${chalk17.bold("Git User:")} ${userDisplay}
|
|
7920
8243
|
`;
|
|
7921
8244
|
} else {
|
|
7922
|
-
output += `${
|
|
8245
|
+
output += `${chalk17.bold("Git User:")} ` + chalk17.yellow("\u26A0\uFE0F Not configured (run git config --global user.name/email)\n");
|
|
7923
8246
|
}
|
|
7924
8247
|
output += "\n";
|
|
7925
8248
|
}
|
|
7926
|
-
output +=
|
|
7927
|
-
output += `${
|
|
8249
|
+
output += chalk17.bold("Installed Coding Tools\n");
|
|
8250
|
+
output += `${chalk17.dim("\u2500".repeat(50))}
|
|
7928
8251
|
`;
|
|
7929
8252
|
const cliToolsUnauthenticated = await checkInstalledCliTools();
|
|
7930
8253
|
const installedTools2 = cliToolsUnauthenticated.filter((tool) => tool.installed);
|
|
7931
8254
|
if (installedTools2.length === 0) {
|
|
7932
|
-
output +=
|
|
8255
|
+
output += chalk17.yellow("\u26A0\uFE0F No coding tools detected\n\n");
|
|
7933
8256
|
} else {
|
|
7934
8257
|
installedTools2.forEach((tool) => {
|
|
7935
|
-
const versionInfo = tool.version ?
|
|
7936
|
-
output += `${
|
|
8258
|
+
const versionInfo = tool.version ? chalk17.dim(` (${tool.version})`) : "";
|
|
8259
|
+
output += `${chalk17.green("\u2705")} ${tool.name}${versionInfo}
|
|
7937
8260
|
`;
|
|
7938
8261
|
});
|
|
7939
8262
|
output += "\n";
|
|
7940
8263
|
}
|
|
7941
|
-
output +=
|
|
7942
|
-
output += `${
|
|
8264
|
+
output += chalk17.bold("Configuration\n");
|
|
8265
|
+
output += `${chalk17.dim("\u2500".repeat(50))}
|
|
7943
8266
|
`;
|
|
7944
|
-
output += `${
|
|
8267
|
+
output += `${chalk17.bold("API URL:")} ${config2.apiUrl}
|
|
7945
8268
|
`;
|
|
7946
|
-
output += `${
|
|
8269
|
+
output += `${chalk17.bold("OAuth Client:")} ${config2.oauthClientId}
|
|
7947
8270
|
`;
|
|
7948
|
-
output += `${
|
|
8271
|
+
output += `${chalk17.bold("Redirect URI:")} http://127.0.0.1:34536/callback
|
|
7949
8272
|
`;
|
|
7950
|
-
output += `${
|
|
8273
|
+
output += `${chalk17.bold("Config Path:")} ${credentialStore.getStoragePath()}
|
|
7951
8274
|
|
|
7952
8275
|
`;
|
|
7953
|
-
output +=
|
|
7954
|
-
output +=
|
|
8276
|
+
output += getDebugLogsSection();
|
|
8277
|
+
output += chalk17.bold("Overall Status\n");
|
|
8278
|
+
output += `${chalk17.dim("\u2500".repeat(50))}
|
|
7955
8279
|
`;
|
|
7956
|
-
output +=
|
|
8280
|
+
output += chalk17.yellow("\u26A0\uFE0F Setup required - please authenticate\n");
|
|
7957
8281
|
return {
|
|
7958
8282
|
success: true,
|
|
7959
8283
|
message: output,
|
|
@@ -7962,94 +8286,95 @@ async function handleStatus() {
|
|
|
7962
8286
|
}
|
|
7963
8287
|
const session = await auth.getStoredSession();
|
|
7964
8288
|
if (!session) {
|
|
7965
|
-
output +=
|
|
8289
|
+
output += chalk17.red("\u274C Session not found\n\n");
|
|
7966
8290
|
return {
|
|
7967
8291
|
success: true,
|
|
7968
8292
|
message: output,
|
|
7969
8293
|
data: { authenticated: false }
|
|
7970
8294
|
};
|
|
7971
8295
|
}
|
|
7972
|
-
output +=
|
|
8296
|
+
output += chalk17.green("\u2705 Authenticated\n");
|
|
7973
8297
|
const userName = `${session.user.firstName || ""} ${session.user.lastName || ""}`.trim();
|
|
7974
8298
|
if (userName) {
|
|
7975
|
-
output += `${
|
|
8299
|
+
output += `${chalk17.bold("Name:")} ${userName}
|
|
7976
8300
|
`;
|
|
7977
8301
|
}
|
|
7978
|
-
output += `${
|
|
8302
|
+
output += `${chalk17.bold("Email:")} ${session.user.email}
|
|
7979
8303
|
`;
|
|
7980
|
-
output += `${
|
|
8304
|
+
output += `${chalk17.bold("User ID:")} ${session.user.id}
|
|
7981
8305
|
`;
|
|
7982
|
-
output += `${
|
|
8306
|
+
output += `${chalk17.bold("Organization:")} ${session.organization_id}
|
|
7983
8307
|
`;
|
|
7984
8308
|
const sessionAge = Math.floor((Date.now() - session.created_at.getTime()) / 1e3 / 60);
|
|
7985
|
-
output += `${
|
|
8309
|
+
output += `${chalk17.bold("Session Age:")} ${sessionAge} minutes
|
|
7986
8310
|
`;
|
|
7987
|
-
output += `${
|
|
8311
|
+
output += `${chalk17.bold("API URL:")} ${config2.apiUrl}
|
|
7988
8312
|
`;
|
|
7989
|
-
output += `${
|
|
8313
|
+
output += `${chalk17.bold("Config Path:")} ${credentialStore.getStoragePath()}
|
|
7990
8314
|
|
|
7991
8315
|
`;
|
|
7992
|
-
output +=
|
|
7993
|
-
output += `${
|
|
8316
|
+
output += chalk17.bold("Git Repository\n");
|
|
8317
|
+
output += `${chalk17.dim("\u2500".repeat(50))}
|
|
7994
8318
|
`;
|
|
7995
8319
|
const gitInfo = await getGitRepositoryInfo();
|
|
7996
8320
|
if (!gitInfo || !gitInfo.isRepo) {
|
|
7997
|
-
output +=
|
|
8321
|
+
output += chalk17.yellow("\u26A0\uFE0F Not in a git repository\n\n");
|
|
7998
8322
|
} else {
|
|
7999
|
-
output +=
|
|
8323
|
+
output += chalk17.green("\u2705 Repository detected!\n");
|
|
8000
8324
|
if (gitInfo.owner && gitInfo.name) {
|
|
8001
|
-
output += `${
|
|
8325
|
+
output += `${chalk17.bold("Owner:")} ${gitInfo.owner}
|
|
8002
8326
|
`;
|
|
8003
|
-
output += `${
|
|
8327
|
+
output += `${chalk17.bold("Name:")} ${gitInfo.name}
|
|
8004
8328
|
`;
|
|
8005
8329
|
} else if (gitInfo.remoteUrl) {
|
|
8006
|
-
output += `${
|
|
8330
|
+
output += `${chalk17.bold("Remote:")} ${gitInfo.remoteUrl}
|
|
8007
8331
|
`;
|
|
8008
8332
|
} else {
|
|
8009
|
-
output +=
|
|
8333
|
+
output += chalk17.yellow("\u26A0\uFE0F Local repository (no remote)\n");
|
|
8010
8334
|
}
|
|
8011
8335
|
if (gitInfo.branch) {
|
|
8012
|
-
output += `${
|
|
8336
|
+
output += `${chalk17.bold("Branch:")} ${gitInfo.branch}
|
|
8013
8337
|
`;
|
|
8014
8338
|
}
|
|
8015
8339
|
if (gitInfo.userName || gitInfo.userEmail) {
|
|
8016
8340
|
const userDisplay = gitInfo.userName && gitInfo.userEmail ? `${gitInfo.userName} <${gitInfo.userEmail}>` : gitInfo.userName || gitInfo.userEmail;
|
|
8017
|
-
output += `${
|
|
8341
|
+
output += `${chalk17.bold("Git User:")} ${userDisplay}
|
|
8018
8342
|
`;
|
|
8019
8343
|
} else {
|
|
8020
|
-
output += `${
|
|
8344
|
+
output += `${chalk17.bold("Git User:")} ` + chalk17.yellow("\u26A0\uFE0F Not configured (run git config --global user.name/email)\n");
|
|
8021
8345
|
}
|
|
8022
8346
|
output += "\n";
|
|
8023
8347
|
}
|
|
8024
|
-
output +=
|
|
8025
|
-
output += `${
|
|
8348
|
+
output += chalk17.bold("Installed Coding Tools\n");
|
|
8349
|
+
output += `${chalk17.dim("\u2500".repeat(50))}
|
|
8026
8350
|
`;
|
|
8027
8351
|
const cliTools = await checkInstalledCliTools();
|
|
8028
8352
|
const installedTools = cliTools.filter((tool) => tool.installed);
|
|
8029
8353
|
if (installedTools.length === 0) {
|
|
8030
|
-
output +=
|
|
8354
|
+
output += chalk17.yellow("\u26A0\uFE0F No coding tools detected\n\n");
|
|
8031
8355
|
} else {
|
|
8032
8356
|
installedTools.forEach((tool) => {
|
|
8033
|
-
const versionInfo = tool.version ?
|
|
8034
|
-
output += `${
|
|
8357
|
+
const versionInfo = tool.version ? chalk17.dim(` (${tool.version})`) : "";
|
|
8358
|
+
output += `${chalk17.green("\u2705")} ${tool.name}${versionInfo}
|
|
8035
8359
|
`;
|
|
8036
8360
|
});
|
|
8037
8361
|
output += "\n";
|
|
8038
8362
|
}
|
|
8039
|
-
output +=
|
|
8040
|
-
output += `${
|
|
8363
|
+
output += chalk17.bold("Configuration\n");
|
|
8364
|
+
output += `${chalk17.dim("\u2500".repeat(50))}
|
|
8041
8365
|
`;
|
|
8042
|
-
output += `${
|
|
8366
|
+
output += `${chalk17.bold("OAuth Client:")} ${config2.oauthClientId}
|
|
8043
8367
|
`;
|
|
8044
|
-
output += `${
|
|
8368
|
+
output += `${chalk17.bold("Redirect URI:")} http://127.0.0.1:34536/callback
|
|
8045
8369
|
`;
|
|
8046
|
-
output += `${
|
|
8370
|
+
output += `${chalk17.bold("Auth Server:")} ${config2.getWorkOSAuthUrl()}
|
|
8047
8371
|
|
|
8048
8372
|
`;
|
|
8049
|
-
output +=
|
|
8050
|
-
output +=
|
|
8373
|
+
output += getDebugLogsSection();
|
|
8374
|
+
output += chalk17.bold("Overall Status\n");
|
|
8375
|
+
output += `${chalk17.dim("\u2500".repeat(50))}
|
|
8051
8376
|
`;
|
|
8052
|
-
output +=
|
|
8377
|
+
output += chalk17.green("\u2705 Ready to use BrainGrid CLI\n");
|
|
8053
8378
|
return {
|
|
8054
8379
|
success: true,
|
|
8055
8380
|
message: output,
|
|
@@ -8064,7 +8389,7 @@ async function handleStatus() {
|
|
|
8064
8389
|
}
|
|
8065
8390
|
|
|
8066
8391
|
// src/handlers/task.handlers.ts
|
|
8067
|
-
import
|
|
8392
|
+
import chalk18 from "chalk";
|
|
8068
8393
|
|
|
8069
8394
|
// src/services/task-service.ts
|
|
8070
8395
|
var TaskService = class {
|
|
@@ -8168,7 +8493,7 @@ async function handleTaskList(opts) {
|
|
|
8168
8493
|
if (!isAuthenticated) {
|
|
8169
8494
|
return {
|
|
8170
8495
|
success: false,
|
|
8171
|
-
message:
|
|
8496
|
+
message: chalk18.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
8172
8497
|
};
|
|
8173
8498
|
}
|
|
8174
8499
|
const workspace = await workspaceManager.getProject(opts.project);
|
|
@@ -8188,7 +8513,7 @@ async function handleTaskList(opts) {
|
|
|
8188
8513
|
}
|
|
8189
8514
|
const requirementId = requirementResult.requirementId;
|
|
8190
8515
|
if (opts.format !== "json" && opts.format !== "xml") {
|
|
8191
|
-
stopSpinner = showSpinner("Loading tasks",
|
|
8516
|
+
stopSpinner = showSpinner("Loading tasks", chalk18.gray);
|
|
8192
8517
|
}
|
|
8193
8518
|
const response = await taskService.listTasks(projectId, requirementId, {
|
|
8194
8519
|
page: opts.page ? parseInt(opts.page, 10) : 1,
|
|
@@ -8201,7 +8526,7 @@ async function handleTaskList(opts) {
|
|
|
8201
8526
|
if (response.tasks.length === 0) {
|
|
8202
8527
|
return {
|
|
8203
8528
|
success: true,
|
|
8204
|
-
message:
|
|
8529
|
+
message: chalk18.yellow("No tasks found."),
|
|
8205
8530
|
data: response
|
|
8206
8531
|
};
|
|
8207
8532
|
}
|
|
@@ -8217,7 +8542,7 @@ async function handleTaskList(opts) {
|
|
|
8217
8542
|
});
|
|
8218
8543
|
if (response.pagination?.has_more) {
|
|
8219
8544
|
output += `
|
|
8220
|
-
${
|
|
8545
|
+
${chalk18.yellow("\u26A0\uFE0F More tasks exist. Use --limit to see more.")}`;
|
|
8221
8546
|
}
|
|
8222
8547
|
return {
|
|
8223
8548
|
success: true,
|
|
@@ -8242,7 +8567,7 @@ async function handleTaskSummary(opts) {
|
|
|
8242
8567
|
if (!isAuthenticated) {
|
|
8243
8568
|
return {
|
|
8244
8569
|
success: false,
|
|
8245
|
-
message:
|
|
8570
|
+
message: chalk18.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
8246
8571
|
};
|
|
8247
8572
|
}
|
|
8248
8573
|
const workspace = await workspaceManager.getProject(opts.project);
|
|
@@ -8261,7 +8586,7 @@ async function handleTaskSummary(opts) {
|
|
|
8261
8586
|
};
|
|
8262
8587
|
}
|
|
8263
8588
|
const requirementId = requirementResult.requirementId;
|
|
8264
|
-
stopSpinner = showSpinner("Loading tasks",
|
|
8589
|
+
stopSpinner = showSpinner("Loading tasks", chalk18.gray);
|
|
8265
8590
|
const response = await taskService.listTasks(projectId, requirementId, {
|
|
8266
8591
|
page: opts.page ? parseInt(opts.page, 10) : 1,
|
|
8267
8592
|
limit: opts.limit ? parseInt(opts.limit, 10) : 20
|
|
@@ -8271,7 +8596,7 @@ async function handleTaskSummary(opts) {
|
|
|
8271
8596
|
if (response.tasks.length === 0) {
|
|
8272
8597
|
return {
|
|
8273
8598
|
success: true,
|
|
8274
|
-
message:
|
|
8599
|
+
message: chalk18.yellow("No tasks found."),
|
|
8275
8600
|
data: response
|
|
8276
8601
|
};
|
|
8277
8602
|
}
|
|
@@ -8286,7 +8611,7 @@ async function handleTaskSummary(opts) {
|
|
|
8286
8611
|
});
|
|
8287
8612
|
if (response.pagination?.has_more) {
|
|
8288
8613
|
output += `
|
|
8289
|
-
${
|
|
8614
|
+
${chalk18.yellow("\u26A0\uFE0F More tasks exist. Use --limit to see more.")}`;
|
|
8290
8615
|
}
|
|
8291
8616
|
return {
|
|
8292
8617
|
success: true,
|
|
@@ -8311,14 +8636,14 @@ async function handleTaskShow(id, opts) {
|
|
|
8311
8636
|
if (!isAuthenticated) {
|
|
8312
8637
|
return {
|
|
8313
8638
|
success: false,
|
|
8314
|
-
message:
|
|
8639
|
+
message: chalk18.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
8315
8640
|
};
|
|
8316
8641
|
}
|
|
8317
8642
|
const format = opts?.format || "markdown";
|
|
8318
8643
|
if (!["markdown", "json", "xml", "table"].includes(format)) {
|
|
8319
8644
|
return {
|
|
8320
8645
|
success: false,
|
|
8321
|
-
message:
|
|
8646
|
+
message: chalk18.red(
|
|
8322
8647
|
`\u274C Invalid format: ${format}. Supported formats: markdown, json, xml, table`
|
|
8323
8648
|
)
|
|
8324
8649
|
};
|
|
@@ -8348,14 +8673,14 @@ async function handleTaskShow(id, opts) {
|
|
|
8348
8673
|
if (!currentTask.success) {
|
|
8349
8674
|
return {
|
|
8350
8675
|
success: false,
|
|
8351
|
-
message:
|
|
8676
|
+
message: chalk18.red(`\u274C ${currentTask.error}`)
|
|
8352
8677
|
};
|
|
8353
8678
|
}
|
|
8354
8679
|
taskId = currentTask.taskId;
|
|
8355
8680
|
taskWarning = currentTask.warning;
|
|
8356
8681
|
}
|
|
8357
8682
|
const config2 = getConfig();
|
|
8358
|
-
stopSpinner = showSpinner("Loading task",
|
|
8683
|
+
stopSpinner = showSpinner("Loading task", chalk18.gray);
|
|
8359
8684
|
const task2 = await taskService.getTask(projectId, requirementId, taskId);
|
|
8360
8685
|
stopSpinner();
|
|
8361
8686
|
stopSpinner = null;
|
|
@@ -8388,7 +8713,7 @@ async function handleTaskShow(id, opts) {
|
|
|
8388
8713
|
}
|
|
8389
8714
|
if (taskWarning) {
|
|
8390
8715
|
output += `
|
|
8391
|
-
${
|
|
8716
|
+
${chalk18.yellow(`\u26A0\uFE0F ${taskWarning}`)}`;
|
|
8392
8717
|
}
|
|
8393
8718
|
return {
|
|
8394
8719
|
success: true,
|
|
@@ -8413,7 +8738,7 @@ async function handleTaskCreate(opts) {
|
|
|
8413
8738
|
if (!isAuthenticated) {
|
|
8414
8739
|
return {
|
|
8415
8740
|
success: false,
|
|
8416
|
-
message:
|
|
8741
|
+
message: chalk18.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
8417
8742
|
};
|
|
8418
8743
|
}
|
|
8419
8744
|
const workspace = await workspaceManager.getProject(opts.project);
|
|
@@ -8435,7 +8760,7 @@ async function handleTaskCreate(opts) {
|
|
|
8435
8760
|
const projectShortId = projectId;
|
|
8436
8761
|
const requirementShortId = opts.requirement || requirementId;
|
|
8437
8762
|
const config2 = getConfig();
|
|
8438
|
-
stopSpinner = showSpinner("Creating task",
|
|
8763
|
+
stopSpinner = showSpinner("Creating task", chalk18.gray);
|
|
8439
8764
|
const task2 = await taskService.createTask(projectId, requirementId, {
|
|
8440
8765
|
title: opts.title,
|
|
8441
8766
|
content: opts.content,
|
|
@@ -8474,13 +8799,13 @@ async function handleTaskUpdate(id, opts) {
|
|
|
8474
8799
|
if (!isAuthenticated) {
|
|
8475
8800
|
return {
|
|
8476
8801
|
success: false,
|
|
8477
|
-
message:
|
|
8802
|
+
message: chalk18.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
8478
8803
|
};
|
|
8479
8804
|
}
|
|
8480
8805
|
if (!opts?.status && !opts?.title && !opts?.externalId) {
|
|
8481
8806
|
return {
|
|
8482
8807
|
success: false,
|
|
8483
|
-
message:
|
|
8808
|
+
message: chalk18.red(
|
|
8484
8809
|
"\u274C Please provide at least one field to update (--status, --title, or --external-id)"
|
|
8485
8810
|
)
|
|
8486
8811
|
};
|
|
@@ -8510,14 +8835,14 @@ async function handleTaskUpdate(id, opts) {
|
|
|
8510
8835
|
if (!currentTask.success) {
|
|
8511
8836
|
return {
|
|
8512
8837
|
success: false,
|
|
8513
|
-
message:
|
|
8838
|
+
message: chalk18.red(`\u274C ${currentTask.error}`)
|
|
8514
8839
|
};
|
|
8515
8840
|
}
|
|
8516
8841
|
taskId = currentTask.taskId;
|
|
8517
8842
|
taskWarning = currentTask.warning;
|
|
8518
8843
|
}
|
|
8519
8844
|
const config2 = getConfig();
|
|
8520
|
-
stopSpinner = showSpinner("Updating task",
|
|
8845
|
+
stopSpinner = showSpinner("Updating task", chalk18.gray);
|
|
8521
8846
|
const task2 = await taskService.updateTask(projectId, requirementId, taskId, {
|
|
8522
8847
|
status: opts?.status,
|
|
8523
8848
|
title: opts?.title,
|
|
@@ -8535,7 +8860,7 @@ async function handleTaskUpdate(id, opts) {
|
|
|
8535
8860
|
});
|
|
8536
8861
|
if (taskWarning) {
|
|
8537
8862
|
output += `
|
|
8538
|
-
${
|
|
8863
|
+
${chalk18.yellow(`\u26A0\uFE0F ${taskWarning}`)}`;
|
|
8539
8864
|
}
|
|
8540
8865
|
return {
|
|
8541
8866
|
success: true,
|
|
@@ -8560,13 +8885,13 @@ async function handleTaskDelete(id, opts) {
|
|
|
8560
8885
|
if (!isAuthenticated) {
|
|
8561
8886
|
return {
|
|
8562
8887
|
success: false,
|
|
8563
|
-
message:
|
|
8888
|
+
message: chalk18.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
8564
8889
|
};
|
|
8565
8890
|
}
|
|
8566
8891
|
if (!opts.force) {
|
|
8567
8892
|
return {
|
|
8568
8893
|
success: false,
|
|
8569
|
-
message:
|
|
8894
|
+
message: chalk18.yellow("\u26A0\uFE0F Deleting a task is permanent. Use --force to confirm deletion.")
|
|
8570
8895
|
};
|
|
8571
8896
|
}
|
|
8572
8897
|
const workspace = await workspaceManager.getProject(opts.project);
|
|
@@ -8586,13 +8911,13 @@ async function handleTaskDelete(id, opts) {
|
|
|
8586
8911
|
}
|
|
8587
8912
|
const requirementId = requirementResult.requirementId;
|
|
8588
8913
|
const taskId = normalizeTaskId(id);
|
|
8589
|
-
stopSpinner = showSpinner("Deleting task",
|
|
8914
|
+
stopSpinner = showSpinner("Deleting task", chalk18.gray);
|
|
8590
8915
|
await taskService.deleteTask(projectId, requirementId, taskId);
|
|
8591
8916
|
stopSpinner();
|
|
8592
8917
|
stopSpinner = null;
|
|
8593
8918
|
return {
|
|
8594
8919
|
success: true,
|
|
8595
|
-
message:
|
|
8920
|
+
message: chalk18.green(`\u2705 Deleted task ${id}`)
|
|
8596
8921
|
};
|
|
8597
8922
|
} catch (error) {
|
|
8598
8923
|
if (stopSpinner) {
|
|
@@ -8612,14 +8937,14 @@ async function handleTaskSpecify(opts) {
|
|
|
8612
8937
|
if (!isAuthenticated) {
|
|
8613
8938
|
return {
|
|
8614
8939
|
success: false,
|
|
8615
|
-
message:
|
|
8940
|
+
message: chalk18.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
8616
8941
|
};
|
|
8617
8942
|
}
|
|
8618
8943
|
const format = opts.format || "table";
|
|
8619
8944
|
if (!["table", "json", "markdown"].includes(format)) {
|
|
8620
8945
|
return {
|
|
8621
8946
|
success: false,
|
|
8622
|
-
message:
|
|
8947
|
+
message: chalk18.red(
|
|
8623
8948
|
`\u274C Invalid format: ${format}. Supported formats: table, json, markdown`
|
|
8624
8949
|
)
|
|
8625
8950
|
};
|
|
@@ -8643,16 +8968,16 @@ async function handleTaskSpecify(opts) {
|
|
|
8643
8968
|
if (opts.prompt.length < 10) {
|
|
8644
8969
|
return {
|
|
8645
8970
|
success: false,
|
|
8646
|
-
message:
|
|
8971
|
+
message: chalk18.red("\u274C Prompt must be at least 10 characters long")
|
|
8647
8972
|
};
|
|
8648
8973
|
}
|
|
8649
8974
|
if (opts.prompt.length > 5e3) {
|
|
8650
8975
|
return {
|
|
8651
8976
|
success: false,
|
|
8652
|
-
message:
|
|
8977
|
+
message: chalk18.red("\u274C Prompt must be no more than 5000 characters long")
|
|
8653
8978
|
};
|
|
8654
8979
|
}
|
|
8655
|
-
stopSpinner = showSpinner("Creating task from prompt...",
|
|
8980
|
+
stopSpinner = showSpinner("Creating task from prompt...", chalk18.gray);
|
|
8656
8981
|
const response = await taskService.specifyTask(projectId, requirementId, {
|
|
8657
8982
|
prompt: opts.prompt
|
|
8658
8983
|
});
|
|
@@ -8692,10 +9017,10 @@ async function handleTaskSpecify(opts) {
|
|
|
8692
9017
|
function formatTaskSpecifyTable(response) {
|
|
8693
9018
|
const task2 = response.task;
|
|
8694
9019
|
const lines = [];
|
|
8695
|
-
lines.push(
|
|
9020
|
+
lines.push(chalk18.green(`\u2705 Created task ${response.requirement_short_id}/TASK-${task2.number}`));
|
|
8696
9021
|
lines.push("");
|
|
8697
|
-
lines.push(`${
|
|
8698
|
-
lines.push(`${
|
|
9022
|
+
lines.push(`${chalk18.bold("Title:")} ${task2.title}`);
|
|
9023
|
+
lines.push(`${chalk18.bold("Status:")} ${task2.status}`);
|
|
8699
9024
|
return lines.join("\n");
|
|
8700
9025
|
}
|
|
8701
9026
|
function formatTaskSpecifyMarkdown(response, _apiUrl) {
|