@braingrid/cli 0.2.25 → 0.2.26
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 +15 -0
- package/README.md +7 -1
- package/dist/cli.js +220 -77
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.26] - 2025-01-20
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **BRAINGRID_API_TOKEN environment variable support**
|
|
15
|
+
- Enables authentication via JWT token for sandbox/CI environments
|
|
16
|
+
- Allows CLI usage without interactive OAuth login flow
|
|
17
|
+
- Useful for automated pipelines and testing scenarios
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **README documentation updates**
|
|
22
|
+
- Added `requirement create-branch` and `requirement review` commands to docs
|
|
23
|
+
- Updated shell completion subcommands list
|
|
24
|
+
|
|
10
25
|
## [0.2.25] - 2025-12-22
|
|
11
26
|
|
|
12
27
|
### Added
|
package/README.md
CHANGED
|
@@ -213,6 +213,8 @@ braingrid requirement update [id] [--status IDEA|PLANNED|IN_PROGRESS|REVIEW|COMP
|
|
|
213
213
|
braingrid requirement delete [id] [--force]
|
|
214
214
|
braingrid requirement breakdown [id]
|
|
215
215
|
braingrid requirement build [id] [--format markdown|json|xml]
|
|
216
|
+
braingrid requirement create-branch [id] [--name <branch-name>] [--base <branch>]
|
|
217
|
+
braingrid requirement review [id] [--pr <number>]
|
|
216
218
|
|
|
217
219
|
# Working with a different project:
|
|
218
220
|
braingrid requirement list -p PROJ-456 [--status PLANNED]
|
|
@@ -226,6 +228,10 @@ braingrid requirement create -p PROJ-456 --name "Description"
|
|
|
226
228
|
> **Note:** The `-r`/`--requirement` parameter is optional and accepts formats like `REQ-456`, `req-456`, or `456`. The CLI will automatically detect the requirement ID from your git branch name (e.g., `feature/REQ-123-description` or `REQ-123-fix-bug`) if it is not provided.
|
|
227
229
|
>
|
|
228
230
|
> **Note:** The `requirement list` command displays requirements with their status, name, branch (if assigned), and progress percentage.
|
|
231
|
+
>
|
|
232
|
+
> **Note:** The `create-branch` command creates a GitHub branch for a requirement. It auto-generates a branch name in the format `{username}/REQ-123-slug` if not provided.
|
|
233
|
+
>
|
|
234
|
+
> **Note:** The `review` command runs an AI-powered acceptance review on a pull request, validating it against the requirement's acceptance criteria. It auto-detects the PR number from the current branch if not provided.
|
|
229
235
|
|
|
230
236
|
### Task Commands
|
|
231
237
|
|
|
@@ -309,7 +315,7 @@ eval "$(braingrid completion zsh)"
|
|
|
309
315
|
### What Gets Completed
|
|
310
316
|
|
|
311
317
|
- **Commands**: `login`, `logout`, `project`, `requirement`, `task`, etc.
|
|
312
|
-
- **Subcommands**: `list`, `show`, `create`, `update`, `delete`, `breakdown`, `build`
|
|
318
|
+
- **Subcommands**: `list`, `show`, `create`, `update`, `delete`, `breakdown`, `build`, `create-branch`, `review`
|
|
313
319
|
- **Options**: `--help`, `--format`, `--status`, `--project`, `--requirement`
|
|
314
320
|
- **Values**: Status values (`IDEA`, `PLANNED`, `IN_PROGRESS`, etc.), format options (`table`, `json`, `xml`, `markdown`)
|
|
315
321
|
|
package/dist/cli.js
CHANGED
|
@@ -23,6 +23,81 @@ import chalk6 from "chalk";
|
|
|
23
23
|
// src/utils/axios-with-auth.ts
|
|
24
24
|
import axios from "axios";
|
|
25
25
|
|
|
26
|
+
// src/build-config.ts
|
|
27
|
+
var BUILD_ENV = true ? "production" : process.env.NODE_ENV === "test" ? "development" : "production";
|
|
28
|
+
var CLI_VERSION = true ? "0.2.26" : "0.0.0-test";
|
|
29
|
+
var PRODUCTION_CONFIG = {
|
|
30
|
+
apiUrl: "https://app.braingrid.ai",
|
|
31
|
+
workosAuthUrl: "https://auth.braingrid.ai",
|
|
32
|
+
workosClientId: "client_01K6H010C9K69HSDPM9CQM85S7"
|
|
33
|
+
};
|
|
34
|
+
var DEVELOPMENT_CONFIG = {
|
|
35
|
+
apiUrl: "https://app.dev.braingrid.ai",
|
|
36
|
+
workosAuthUrl: "https://balanced-celebration-78-staging.authkit.app",
|
|
37
|
+
workosClientId: "client_01K6H04GF21T4JXNS3JDQM3YNE"
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// src/utils/config.ts
|
|
41
|
+
var BRAINGRID_API_TOKEN = process.env.BRAINGRID_API_TOKEN;
|
|
42
|
+
function getConfig() {
|
|
43
|
+
const baseConfig = BUILD_ENV === "production" ? PRODUCTION_CONFIG : DEVELOPMENT_CONFIG;
|
|
44
|
+
let apiUrl = baseConfig.apiUrl;
|
|
45
|
+
if (BUILD_ENV === "development") {
|
|
46
|
+
if (process.env.NODE_ENV === "local" || process.env.NODE_ENV === "test") {
|
|
47
|
+
apiUrl = "http://localhost:3377";
|
|
48
|
+
} else if (process.env.NODE_ENV === "development") {
|
|
49
|
+
apiUrl = DEVELOPMENT_CONFIG.apiUrl;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const getWorkOSAuthUrl = () => {
|
|
53
|
+
if (process.env.WORKOS_AUTH_URL) {
|
|
54
|
+
return process.env.WORKOS_AUTH_URL;
|
|
55
|
+
}
|
|
56
|
+
if (BUILD_ENV === "production") {
|
|
57
|
+
return PRODUCTION_CONFIG.workosAuthUrl;
|
|
58
|
+
}
|
|
59
|
+
const env = process.env.NODE_ENV || "development";
|
|
60
|
+
if (env === "local" || env === "test" || env === "development" || env === "staging") {
|
|
61
|
+
return DEVELOPMENT_CONFIG.workosAuthUrl;
|
|
62
|
+
}
|
|
63
|
+
return PRODUCTION_CONFIG.workosAuthUrl;
|
|
64
|
+
};
|
|
65
|
+
const getOAuthClientId = () => {
|
|
66
|
+
if (process.env.WORKOS_CLIENT_ID) {
|
|
67
|
+
return process.env.WORKOS_CLIENT_ID;
|
|
68
|
+
}
|
|
69
|
+
if (BUILD_ENV === "production") {
|
|
70
|
+
return PRODUCTION_CONFIG.workosClientId;
|
|
71
|
+
}
|
|
72
|
+
const env = process.env.NODE_ENV || "development";
|
|
73
|
+
if (env === "local" || env === "test" || env === "development" || env === "staging") {
|
|
74
|
+
return DEVELOPMENT_CONFIG.workosClientId;
|
|
75
|
+
}
|
|
76
|
+
return PRODUCTION_CONFIG.workosClientId;
|
|
77
|
+
};
|
|
78
|
+
const getWebAppUrl = () => {
|
|
79
|
+
if (process.env.BRAINGRID_WEB_URL) {
|
|
80
|
+
return process.env.BRAINGRID_WEB_URL;
|
|
81
|
+
}
|
|
82
|
+
if (BUILD_ENV === "production") {
|
|
83
|
+
return PRODUCTION_CONFIG.apiUrl;
|
|
84
|
+
}
|
|
85
|
+
const env = process.env.NODE_ENV || "development";
|
|
86
|
+
if (env === "local" || env === "test") {
|
|
87
|
+
return "http://localhost:3377";
|
|
88
|
+
}
|
|
89
|
+
return DEVELOPMENT_CONFIG.apiUrl;
|
|
90
|
+
};
|
|
91
|
+
return {
|
|
92
|
+
apiUrl: process.env.BRAINGRID_API_URL || apiUrl,
|
|
93
|
+
organizationId: process.env.BRAINGRID_ORG_ID,
|
|
94
|
+
clientId: process.env.BRAINGRID_CLIENT_ID || "braingrid-cli",
|
|
95
|
+
oauthClientId: getOAuthClientId(),
|
|
96
|
+
getWorkOSAuthUrl,
|
|
97
|
+
getWebAppUrl
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
26
101
|
// src/utils/logger.ts
|
|
27
102
|
import fs from "fs";
|
|
28
103
|
import path from "path";
|
|
@@ -211,6 +286,10 @@ function createAuthenticatedAxios(auth) {
|
|
|
211
286
|
});
|
|
212
287
|
instance.interceptors.request.use(
|
|
213
288
|
async (config) => {
|
|
289
|
+
if (BRAINGRID_API_TOKEN) {
|
|
290
|
+
config.headers.Authorization = `Bearer ${BRAINGRID_API_TOKEN}`;
|
|
291
|
+
return config;
|
|
292
|
+
}
|
|
214
293
|
const session = await auth.getStoredSession();
|
|
215
294
|
if (session) {
|
|
216
295
|
config.headers.Authorization = `Bearer ${session.sealed_session}`;
|
|
@@ -251,6 +330,11 @@ function createAuthenticatedAxios(auth) {
|
|
|
251
330
|
const isRedirectToAuth = isAuthRedirect(error);
|
|
252
331
|
if ((is401 || isRedirectToAuth) && !originalRequest._retry) {
|
|
253
332
|
originalRequest._retry = true;
|
|
333
|
+
if (BRAINGRID_API_TOKEN) {
|
|
334
|
+
logger.warn("[AUTH] Sandbox token expired or invalid");
|
|
335
|
+
const sandboxError = new Error(auth.getSandboxExpiredMessage());
|
|
336
|
+
return Promise.reject(sandboxError);
|
|
337
|
+
}
|
|
254
338
|
if (isRedirectToAuth) {
|
|
255
339
|
logger.debug("[AUTH] Received redirect to auth endpoint - token likely expired");
|
|
256
340
|
} else {
|
|
@@ -422,82 +506,6 @@ import { createHash, randomBytes } from "crypto";
|
|
|
422
506
|
import { createServer } from "http";
|
|
423
507
|
import open from "open";
|
|
424
508
|
import axios3, { AxiosError as AxiosError2 } from "axios";
|
|
425
|
-
|
|
426
|
-
// src/build-config.ts
|
|
427
|
-
var BUILD_ENV = true ? "production" : process.env.NODE_ENV === "test" ? "development" : "production";
|
|
428
|
-
var CLI_VERSION = true ? "0.2.25" : "0.0.0-test";
|
|
429
|
-
var PRODUCTION_CONFIG = {
|
|
430
|
-
apiUrl: "https://app.braingrid.ai",
|
|
431
|
-
workosAuthUrl: "https://auth.braingrid.ai",
|
|
432
|
-
workosClientId: "client_01K6H010C9K69HSDPM9CQM85S7"
|
|
433
|
-
};
|
|
434
|
-
var DEVELOPMENT_CONFIG = {
|
|
435
|
-
apiUrl: "https://app.dev.braingrid.ai",
|
|
436
|
-
workosAuthUrl: "https://balanced-celebration-78-staging.authkit.app",
|
|
437
|
-
workosClientId: "client_01K6H04GF21T4JXNS3JDQM3YNE"
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
// src/utils/config.ts
|
|
441
|
-
function getConfig() {
|
|
442
|
-
const baseConfig = BUILD_ENV === "production" ? PRODUCTION_CONFIG : DEVELOPMENT_CONFIG;
|
|
443
|
-
let apiUrl = baseConfig.apiUrl;
|
|
444
|
-
if (BUILD_ENV === "development") {
|
|
445
|
-
if (process.env.NODE_ENV === "local" || process.env.NODE_ENV === "test") {
|
|
446
|
-
apiUrl = "http://localhost:3377";
|
|
447
|
-
} else if (process.env.NODE_ENV === "development") {
|
|
448
|
-
apiUrl = DEVELOPMENT_CONFIG.apiUrl;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
const getWorkOSAuthUrl = () => {
|
|
452
|
-
if (process.env.WORKOS_AUTH_URL) {
|
|
453
|
-
return process.env.WORKOS_AUTH_URL;
|
|
454
|
-
}
|
|
455
|
-
if (BUILD_ENV === "production") {
|
|
456
|
-
return PRODUCTION_CONFIG.workosAuthUrl;
|
|
457
|
-
}
|
|
458
|
-
const env = process.env.NODE_ENV || "development";
|
|
459
|
-
if (env === "local" || env === "test" || env === "development" || env === "staging") {
|
|
460
|
-
return DEVELOPMENT_CONFIG.workosAuthUrl;
|
|
461
|
-
}
|
|
462
|
-
return PRODUCTION_CONFIG.workosAuthUrl;
|
|
463
|
-
};
|
|
464
|
-
const getOAuthClientId = () => {
|
|
465
|
-
if (process.env.WORKOS_CLIENT_ID) {
|
|
466
|
-
return process.env.WORKOS_CLIENT_ID;
|
|
467
|
-
}
|
|
468
|
-
if (BUILD_ENV === "production") {
|
|
469
|
-
return PRODUCTION_CONFIG.workosClientId;
|
|
470
|
-
}
|
|
471
|
-
const env = process.env.NODE_ENV || "development";
|
|
472
|
-
if (env === "local" || env === "test" || env === "development" || env === "staging") {
|
|
473
|
-
return DEVELOPMENT_CONFIG.workosClientId;
|
|
474
|
-
}
|
|
475
|
-
return PRODUCTION_CONFIG.workosClientId;
|
|
476
|
-
};
|
|
477
|
-
const getWebAppUrl = () => {
|
|
478
|
-
if (process.env.BRAINGRID_WEB_URL) {
|
|
479
|
-
return process.env.BRAINGRID_WEB_URL;
|
|
480
|
-
}
|
|
481
|
-
if (BUILD_ENV === "production") {
|
|
482
|
-
return PRODUCTION_CONFIG.apiUrl;
|
|
483
|
-
}
|
|
484
|
-
const env = process.env.NODE_ENV || "development";
|
|
485
|
-
if (env === "local" || env === "test") {
|
|
486
|
-
return "http://localhost:3377";
|
|
487
|
-
}
|
|
488
|
-
return DEVELOPMENT_CONFIG.apiUrl;
|
|
489
|
-
};
|
|
490
|
-
return {
|
|
491
|
-
apiUrl: process.env.BRAINGRID_API_URL || apiUrl,
|
|
492
|
-
organizationId: process.env.BRAINGRID_ORG_ID,
|
|
493
|
-
clientId: process.env.BRAINGRID_CLIENT_ID || "braingrid-cli",
|
|
494
|
-
oauthClientId: getOAuthClientId(),
|
|
495
|
-
getWorkOSAuthUrl,
|
|
496
|
-
getWebAppUrl
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// src/services/oauth2-auth.ts
|
|
501
509
|
var logger2 = getLogger();
|
|
502
510
|
var OAuth2Handler = class {
|
|
503
511
|
/**
|
|
@@ -1000,6 +1008,7 @@ var KEYCHAIN_SERVICE = "braingrid-cli";
|
|
|
1000
1008
|
var KEYCHAIN_ACCOUNT = "session";
|
|
1001
1009
|
var GITHUB_KEYCHAIN_ACCOUNT = "github-token";
|
|
1002
1010
|
var BraingridAuth = class {
|
|
1011
|
+
// Cached session from env token
|
|
1003
1012
|
constructor(baseUrl) {
|
|
1004
1013
|
this.lastValidationTime = 0;
|
|
1005
1014
|
this.lastValidationResult = false;
|
|
@@ -1011,11 +1020,103 @@ var BraingridAuth = class {
|
|
|
1011
1020
|
this.oauthHandler = null;
|
|
1012
1021
|
// Store refresh token separately
|
|
1013
1022
|
this.logger = getLogger();
|
|
1023
|
+
this.envTokenSession = null;
|
|
1014
1024
|
const config = getConfig();
|
|
1015
1025
|
this.baseUrl = baseUrl || config.apiUrl || "https://app.braingrid.ai";
|
|
1016
1026
|
}
|
|
1027
|
+
/**
|
|
1028
|
+
* Check if CLI is using BRAINGRID_API_TOKEN environment variable
|
|
1029
|
+
* This is used in sandbox environments where tokens are injected
|
|
1030
|
+
*/
|
|
1031
|
+
isUsingEnvToken() {
|
|
1032
|
+
return Boolean(BRAINGRID_API_TOKEN);
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Get the env token value (for use in axios interceptor)
|
|
1036
|
+
*/
|
|
1037
|
+
getEnvToken() {
|
|
1038
|
+
return BRAINGRID_API_TOKEN;
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Fetch user profile from server using the env token
|
|
1042
|
+
* This is used to populate session data when using BRAINGRID_API_TOKEN
|
|
1043
|
+
*/
|
|
1044
|
+
async fetchProfileFromServer() {
|
|
1045
|
+
if (!BRAINGRID_API_TOKEN) {
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
1048
|
+
try {
|
|
1049
|
+
this.logger.debug("[AUTH] Fetching profile using BRAINGRID_API_TOKEN");
|
|
1050
|
+
const response = await axiosWithRetry(
|
|
1051
|
+
{
|
|
1052
|
+
url: `${this.baseUrl}/api/v1/profile`,
|
|
1053
|
+
method: "POST",
|
|
1054
|
+
headers: {
|
|
1055
|
+
"Content-Type": "application/json",
|
|
1056
|
+
Authorization: `Bearer ${BRAINGRID_API_TOKEN}`
|
|
1057
|
+
},
|
|
1058
|
+
maxRedirects: 0,
|
|
1059
|
+
validateStatus: (status) => status < 500
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
maxRetries: 2,
|
|
1063
|
+
initialDelay: 500
|
|
1064
|
+
}
|
|
1065
|
+
);
|
|
1066
|
+
if (response.status !== 200) {
|
|
1067
|
+
this.logger.warn(`[AUTH] Profile fetch failed with status ${response.status}`);
|
|
1068
|
+
return null;
|
|
1069
|
+
}
|
|
1070
|
+
const profileData = response.data;
|
|
1071
|
+
if (profileData.error || !profileData.user || !profileData.organization) {
|
|
1072
|
+
this.logger.warn("[AUTH] Profile response missing user or organization data");
|
|
1073
|
+
return null;
|
|
1074
|
+
}
|
|
1075
|
+
const user = {
|
|
1076
|
+
object: "user",
|
|
1077
|
+
id: profileData.user.id,
|
|
1078
|
+
email: profileData.user.email,
|
|
1079
|
+
emailVerified: true,
|
|
1080
|
+
firstName: profileData.user.firstName || "",
|
|
1081
|
+
lastName: profileData.user.lastName || "",
|
|
1082
|
+
profilePictureUrl: profileData.user.avatar || "",
|
|
1083
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1084
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1085
|
+
lastSignInAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1086
|
+
externalId: null,
|
|
1087
|
+
metadata: {
|
|
1088
|
+
username: profileData.user.username,
|
|
1089
|
+
organizationId: profileData.organization.id,
|
|
1090
|
+
organizationName: profileData.organization.name
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
const session = {
|
|
1094
|
+
user,
|
|
1095
|
+
sealed_session: BRAINGRID_API_TOKEN,
|
|
1096
|
+
organization_id: profileData.organization.id,
|
|
1097
|
+
created_at: /* @__PURE__ */ new Date(),
|
|
1098
|
+
updated_at: /* @__PURE__ */ new Date(),
|
|
1099
|
+
login_time: /* @__PURE__ */ new Date()
|
|
1100
|
+
};
|
|
1101
|
+
this.envTokenSession = session;
|
|
1102
|
+
this.logger.debug("[AUTH] Successfully fetched profile from env token");
|
|
1103
|
+
return session;
|
|
1104
|
+
} catch (error) {
|
|
1105
|
+
this.logger.error("[AUTH] Error fetching profile with env token:", { error });
|
|
1106
|
+
return null;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1017
1109
|
async isAuthenticated(forceValidation = false) {
|
|
1018
1110
|
try {
|
|
1111
|
+
if (BRAINGRID_API_TOKEN) {
|
|
1112
|
+
this.logger.debug("[AUTH] Using BRAINGRID_API_TOKEN (sandbox mode)");
|
|
1113
|
+
if (isJWTExpired(BRAINGRID_API_TOKEN)) {
|
|
1114
|
+
this.logger.warn("[AUTH] Sandbox session expired");
|
|
1115
|
+
return false;
|
|
1116
|
+
}
|
|
1117
|
+
const session2 = await this.getStoredSession();
|
|
1118
|
+
return session2 !== null;
|
|
1119
|
+
}
|
|
1019
1120
|
const session = await this.getStoredSession();
|
|
1020
1121
|
if (!session) {
|
|
1021
1122
|
this.logger.debug("[AUTH] No stored session found");
|
|
@@ -1149,6 +1250,12 @@ var BraingridAuth = class {
|
|
|
1149
1250
|
}
|
|
1150
1251
|
}
|
|
1151
1252
|
async getStoredSession() {
|
|
1253
|
+
if (BRAINGRID_API_TOKEN) {
|
|
1254
|
+
if (this.envTokenSession) {
|
|
1255
|
+
return this.envTokenSession;
|
|
1256
|
+
}
|
|
1257
|
+
return await this.fetchProfileFromServer();
|
|
1258
|
+
}
|
|
1152
1259
|
try {
|
|
1153
1260
|
const sessionData = await credentialStore.getPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
|
|
1154
1261
|
if (!sessionData) return null;
|
|
@@ -1177,12 +1284,23 @@ var BraingridAuth = class {
|
|
|
1177
1284
|
this.loginTime = nowMs;
|
|
1178
1285
|
}
|
|
1179
1286
|
async clearSession() {
|
|
1287
|
+
if (BRAINGRID_API_TOKEN) {
|
|
1288
|
+
this.logger.debug("[AUTH] Session managed by sandbox environment - clear is no-op");
|
|
1289
|
+
this.envTokenSession = null;
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1180
1292
|
await credentialStore.deletePassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
|
|
1181
1293
|
await credentialStore.deletePassword(KEYCHAIN_SERVICE, "refresh-token");
|
|
1182
1294
|
this.refreshTokenValue = void 0;
|
|
1183
1295
|
this.lastValidationTime = 0;
|
|
1184
1296
|
this.lastValidationResult = false;
|
|
1185
1297
|
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Get sandbox-specific error message for expired/invalid tokens
|
|
1300
|
+
*/
|
|
1301
|
+
getSandboxExpiredMessage() {
|
|
1302
|
+
return "Sandbox session expired. Your sandbox environment has a 5-hour limit.\nPlease create a new sandbox to continue.";
|
|
1303
|
+
}
|
|
1186
1304
|
async handleAuthenticationError() {
|
|
1187
1305
|
this.lastValidationTime = 0;
|
|
1188
1306
|
this.lastValidationResult = false;
|
|
@@ -5317,6 +5435,14 @@ function getAuth() {
|
|
|
5317
5435
|
async function handleLogin() {
|
|
5318
5436
|
try {
|
|
5319
5437
|
const auth = getAuth();
|
|
5438
|
+
if (BRAINGRID_API_TOKEN) {
|
|
5439
|
+
return {
|
|
5440
|
+
success: true,
|
|
5441
|
+
message: chalk9.blue(
|
|
5442
|
+
"\u2139\uFE0F Using BRAINGRID_API_TOKEN - already authenticated via sandbox environment."
|
|
5443
|
+
)
|
|
5444
|
+
};
|
|
5445
|
+
}
|
|
5320
5446
|
console.log(chalk9.blue("\u{1F510} Starting OAuth2 authentication flow..."));
|
|
5321
5447
|
console.log(chalk9.dim("Your browser will open to complete authentication.\n"));
|
|
5322
5448
|
const gitUser = await getGitUser();
|
|
@@ -5350,6 +5476,12 @@ async function handleLogin() {
|
|
|
5350
5476
|
async function handleLogout() {
|
|
5351
5477
|
try {
|
|
5352
5478
|
const auth = getAuth();
|
|
5479
|
+
if (BRAINGRID_API_TOKEN) {
|
|
5480
|
+
return {
|
|
5481
|
+
success: true,
|
|
5482
|
+
message: chalk9.blue("\u2139\uFE0F Session managed by sandbox environment - logout not required.")
|
|
5483
|
+
};
|
|
5484
|
+
}
|
|
5353
5485
|
await auth.clearSession();
|
|
5354
5486
|
return {
|
|
5355
5487
|
success: true,
|
|
@@ -5367,6 +5499,12 @@ async function handleWhoami() {
|
|
|
5367
5499
|
const auth = getAuth();
|
|
5368
5500
|
const isAuthenticated = await auth.isAuthenticated();
|
|
5369
5501
|
if (!isAuthenticated) {
|
|
5502
|
+
if (BRAINGRID_API_TOKEN) {
|
|
5503
|
+
return {
|
|
5504
|
+
success: false,
|
|
5505
|
+
message: chalk9.red(auth.getSandboxExpiredMessage())
|
|
5506
|
+
};
|
|
5507
|
+
}
|
|
5370
5508
|
return {
|
|
5371
5509
|
success: false,
|
|
5372
5510
|
message: chalk9.yellow("\u26A0\uFE0F Not logged in. Run `braingrid login` to authenticate.")
|
|
@@ -5389,8 +5527,13 @@ async function handleWhoami() {
|
|
|
5389
5527
|
`;
|
|
5390
5528
|
output += `${chalk9.bold("Org ID:")} ${session.organization_id}
|
|
5391
5529
|
`;
|
|
5392
|
-
|
|
5530
|
+
if (BRAINGRID_API_TOKEN) {
|
|
5531
|
+
output += `${chalk9.bold("Auth:")} ${chalk9.cyan("Sandbox API Token")}
|
|
5393
5532
|
`;
|
|
5533
|
+
} else {
|
|
5534
|
+
output += `${chalk9.bold("Session:")} ${new Date(session.created_at).toLocaleString()}
|
|
5535
|
+
`;
|
|
5536
|
+
}
|
|
5394
5537
|
return {
|
|
5395
5538
|
success: true,
|
|
5396
5539
|
message: output,
|