@great-arrow/cli 0.1.53 → 0.1.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/dist/index.js +352 -63
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9402,7 +9402,7 @@ function isNodeError(value) {
|
|
|
9402
9402
|
|
|
9403
9403
|
// src/lib/version.ts
|
|
9404
9404
|
var CLI_PACKAGE_NAME = "@great-arrow/cli";
|
|
9405
|
-
var CLI_VERSION = "0.1.
|
|
9405
|
+
var CLI_VERSION = "0.1.55";
|
|
9406
9406
|
var GAD_INSTALL_VERSION = "2026.08.08";
|
|
9407
9407
|
var GAD_INSTALL_MIN_VERSION = "2026.06.22";
|
|
9408
9408
|
var GAD_INSTALL_HEADER = "X-GAD-Install-Version";
|
|
@@ -9411,6 +9411,9 @@ var GAD_CLI_VERSION_HEADER = "X-GAD-CLI-Version";
|
|
|
9411
9411
|
// src/commands/login.ts
|
|
9412
9412
|
import { execFile } from "node:child_process";
|
|
9413
9413
|
|
|
9414
|
+
// src/lib/credentials.ts
|
|
9415
|
+
import { randomUUID } from "node:crypto";
|
|
9416
|
+
|
|
9414
9417
|
// src/lib/keychain.ts
|
|
9415
9418
|
import { mkdir, writeFile, readFile, unlink } from "node:fs/promises";
|
|
9416
9419
|
import { homedir } from "node:os";
|
|
@@ -9532,7 +9535,12 @@ async function loadStoredCredential() {
|
|
|
9532
9535
|
return parseStoredValue(await getToken());
|
|
9533
9536
|
}
|
|
9534
9537
|
async function saveOAuthCredential(credential) {
|
|
9535
|
-
return setToken(
|
|
9538
|
+
return setToken(
|
|
9539
|
+
JSON.stringify({
|
|
9540
|
+
...credential,
|
|
9541
|
+
localSessionId: credential.localSessionId || randomUUID()
|
|
9542
|
+
})
|
|
9543
|
+
);
|
|
9536
9544
|
}
|
|
9537
9545
|
async function savePatToken(token) {
|
|
9538
9546
|
return setToken(token);
|
|
@@ -9903,14 +9911,33 @@ function toCredential(env4, apiUrl, clientId, now) {
|
|
|
9903
9911
|
}
|
|
9904
9912
|
var TOKEN_POST_TIMEOUT_MS = 8e3;
|
|
9905
9913
|
async function postToken(apiUrl, form, fetchImpl, timeoutMs = TOKEN_POST_TIMEOUT_MS) {
|
|
9906
|
-
const
|
|
9907
|
-
|
|
9908
|
-
|
|
9909
|
-
|
|
9910
|
-
|
|
9914
|
+
const controller = new AbortController();
|
|
9915
|
+
let timer;
|
|
9916
|
+
const deadline = new Promise((_resolve, reject) => {
|
|
9917
|
+
timer = setTimeout(() => {
|
|
9918
|
+
const error = new DOMException(
|
|
9919
|
+
"Token exchange timed out.",
|
|
9920
|
+
"TimeoutError"
|
|
9921
|
+
);
|
|
9922
|
+
controller.abort(error);
|
|
9923
|
+
reject(error);
|
|
9924
|
+
}, timeoutMs);
|
|
9911
9925
|
});
|
|
9912
|
-
const
|
|
9913
|
-
|
|
9926
|
+
const request = async () => {
|
|
9927
|
+
const res = await fetchImpl(`${trimSlash2(apiUrl)}/api/oauth/token`, {
|
|
9928
|
+
method: "POST",
|
|
9929
|
+
headers: TOKEN_HEADERS,
|
|
9930
|
+
body: new URLSearchParams(form).toString(),
|
|
9931
|
+
signal: controller.signal
|
|
9932
|
+
});
|
|
9933
|
+
const json = await res.json().catch(() => ({}));
|
|
9934
|
+
return { ok: res.ok, status: res.status, json };
|
|
9935
|
+
};
|
|
9936
|
+
try {
|
|
9937
|
+
return await Promise.race([request(), deadline]);
|
|
9938
|
+
} finally {
|
|
9939
|
+
if (timer) clearTimeout(timer);
|
|
9940
|
+
}
|
|
9914
9941
|
}
|
|
9915
9942
|
async function exchangeCode(opts) {
|
|
9916
9943
|
const now = opts.now ?? Date.now();
|
|
@@ -10364,6 +10391,20 @@ var login_default = loginCommand;
|
|
|
10364
10391
|
import { mkdir as mkdir3, open, rm, stat } from "node:fs/promises";
|
|
10365
10392
|
import { homedir as homedir4 } from "node:os";
|
|
10366
10393
|
import { join as join4 } from "node:path";
|
|
10394
|
+
|
|
10395
|
+
// src/lib/oauth/session-identity.ts
|
|
10396
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
10397
|
+
function credentialSessionId(credential) {
|
|
10398
|
+
return credential.localSessionId || createHash2("sha256").update(
|
|
10399
|
+
JSON.stringify([
|
|
10400
|
+
credential.clientId,
|
|
10401
|
+
credential.apiUrl,
|
|
10402
|
+
credential.refreshToken
|
|
10403
|
+
])
|
|
10404
|
+
).digest("hex");
|
|
10405
|
+
}
|
|
10406
|
+
|
|
10407
|
+
// src/lib/auth.ts
|
|
10367
10408
|
var REFRESH_SKEW_MS = 12e4;
|
|
10368
10409
|
var inflightRefresh = null;
|
|
10369
10410
|
var REFRESH_LOCK_STALE_MS = 15e3;
|
|
@@ -10387,7 +10428,12 @@ async function acquireRefreshLock() {
|
|
|
10387
10428
|
await handle.close();
|
|
10388
10429
|
return true;
|
|
10389
10430
|
} catch (err) {
|
|
10390
|
-
if (err.code !== "EEXIST")
|
|
10431
|
+
if (err.code !== "EEXIST") {
|
|
10432
|
+
throw networkError(
|
|
10433
|
+
"Could not lock session renewal.",
|
|
10434
|
+
"Check local credential storage and retry; your session has been kept."
|
|
10435
|
+
);
|
|
10436
|
+
}
|
|
10391
10437
|
}
|
|
10392
10438
|
const age = await stat(path10).then((st) => Date.now() - st.mtimeMs).catch(() => Number.POSITIVE_INFINITY);
|
|
10393
10439
|
if (age > REFRESH_LOCK_STALE_MS) {
|
|
@@ -10416,8 +10462,13 @@ async function storedPairOtherThan(ours) {
|
|
|
10416
10462
|
} catch (err) {
|
|
10417
10463
|
debugSwallow("refresh.reread", err);
|
|
10418
10464
|
}
|
|
10419
|
-
if (stored?.kind !== "oauth")
|
|
10420
|
-
|
|
10465
|
+
if (stored?.kind !== "oauth") {
|
|
10466
|
+
throw authError(
|
|
10467
|
+
"The original session changed or ended during renewal.",
|
|
10468
|
+
"Restart this command with your current connection."
|
|
10469
|
+
);
|
|
10470
|
+
}
|
|
10471
|
+
if (ours.localSessionId && credentialSessionId(stored.credential) !== credentialSessionId(ours) || stored.credential.clientId !== ours.clientId || stored.credential.apiUrl.replace(/\/$/, "") !== ours.apiUrl.replace(/\/$/, "")) {
|
|
10421
10472
|
throw networkError(
|
|
10422
10473
|
"The stored session changed while renewing it.",
|
|
10423
10474
|
"Retry the command with the current session."
|
|
@@ -10443,11 +10494,32 @@ async function resolveAuth() {
|
|
|
10443
10494
|
if (stored?.kind === "oauth") {
|
|
10444
10495
|
const fresh = await ensureFreshAccessToken(stored.credential);
|
|
10445
10496
|
warnLegacyApiUrl(fresh.apiUrl);
|
|
10497
|
+
const originalSessionId = credentialSessionId(fresh);
|
|
10498
|
+
const originalApiUrl = fresh.apiUrl;
|
|
10499
|
+
const originalClientId = fresh.clientId;
|
|
10446
10500
|
return withWorkspace({
|
|
10447
10501
|
token: fresh.accessToken,
|
|
10448
10502
|
apiUrl: fresh.apiUrl,
|
|
10449
10503
|
tokenType: "oauth",
|
|
10450
|
-
expiresAt: fresh.accessExpiresAt
|
|
10504
|
+
expiresAt: fresh.accessExpiresAt,
|
|
10505
|
+
getToken: async () => {
|
|
10506
|
+
const latestConfig = await loadConfig();
|
|
10507
|
+
const latest = await loadStoredCredential();
|
|
10508
|
+
if ((latestConfig.api_url || DEFAULT_API_URL) !== configApiUrl || (latestConfig.default_workspace || void 0) !== activeWorkspace || process.env.GAD_TOKEN || latest?.kind !== "oauth" || credentialSessionId(latest.credential) !== originalSessionId || latest.credential.apiUrl !== originalApiUrl || latest.credential.clientId !== originalClientId) {
|
|
10509
|
+
throw authError(
|
|
10510
|
+
"The original session or workspace changed or ended.",
|
|
10511
|
+
"Restart this command with your current connection."
|
|
10512
|
+
);
|
|
10513
|
+
}
|
|
10514
|
+
const renewed = await ensureFreshAccessToken(latest.credential);
|
|
10515
|
+
if (credentialSessionId(renewed) !== originalSessionId) {
|
|
10516
|
+
throw authError(
|
|
10517
|
+
"The original session changed.",
|
|
10518
|
+
"Restart this command with your current connection."
|
|
10519
|
+
);
|
|
10520
|
+
}
|
|
10521
|
+
return renewed.accessToken;
|
|
10522
|
+
}
|
|
10451
10523
|
});
|
|
10452
10524
|
}
|
|
10453
10525
|
if (stored?.kind === "pat") {
|
|
@@ -10502,10 +10574,6 @@ async function ensureFreshAccessToken(credential) {
|
|
|
10502
10574
|
if (Date.now() < credential.accessExpiresAt - REFRESH_SKEW_MS) {
|
|
10503
10575
|
return credential;
|
|
10504
10576
|
}
|
|
10505
|
-
if (Date.now() >= credential.refreshExpiresAt) {
|
|
10506
|
-
await clearStoredCredential();
|
|
10507
|
-
throw sessionExpired();
|
|
10508
|
-
}
|
|
10509
10577
|
inflightRefresh ??= doRefresh(credential);
|
|
10510
10578
|
try {
|
|
10511
10579
|
return await inflightRefresh;
|
|
@@ -10529,12 +10597,32 @@ async function doRefresh(credential) {
|
|
|
10529
10597
|
"Retry shortly; your saved session has been kept."
|
|
10530
10598
|
);
|
|
10531
10599
|
}
|
|
10532
|
-
|
|
10600
|
+
if (Date.now() >= current.refreshExpiresAt) {
|
|
10601
|
+
await clearStoredCredential();
|
|
10602
|
+
throw sessionExpired();
|
|
10603
|
+
}
|
|
10604
|
+
const rotated = await refreshTokens({
|
|
10533
10605
|
apiUrl: current.apiUrl,
|
|
10534
10606
|
clientId: current.clientId,
|
|
10535
10607
|
refreshToken: current.refreshToken
|
|
10536
10608
|
});
|
|
10537
|
-
|
|
10609
|
+
const refreshed = {
|
|
10610
|
+
...rotated,
|
|
10611
|
+
localSessionId: credentialSessionId(current)
|
|
10612
|
+
};
|
|
10613
|
+
const saved = await loadStoredCredential();
|
|
10614
|
+
if (saved?.kind !== "oauth" || credentialSessionId(saved.credential) !== credentialSessionId(current)) {
|
|
10615
|
+
throw authError(
|
|
10616
|
+
"The original session changed or ended during renewal.",
|
|
10617
|
+
"Restart this command with your current connection."
|
|
10618
|
+
);
|
|
10619
|
+
}
|
|
10620
|
+
if (!await saveOAuthCredential(refreshed)) {
|
|
10621
|
+
throw networkError(
|
|
10622
|
+
"Could not persist the renewed session.",
|
|
10623
|
+
"Check your credential storage before retrying."
|
|
10624
|
+
);
|
|
10625
|
+
}
|
|
10538
10626
|
return refreshed;
|
|
10539
10627
|
} catch (err) {
|
|
10540
10628
|
if (err instanceof RefreshRejected) {
|
|
@@ -10890,12 +10978,14 @@ function sleep(ms) {
|
|
|
10890
10978
|
}
|
|
10891
10979
|
var GadClient = class {
|
|
10892
10980
|
token;
|
|
10981
|
+
getToken;
|
|
10893
10982
|
apiUrl;
|
|
10894
10983
|
repoUrl;
|
|
10895
10984
|
workspaceId;
|
|
10896
10985
|
timeout;
|
|
10897
10986
|
constructor(options) {
|
|
10898
10987
|
this.token = options.token;
|
|
10988
|
+
this.getToken = options.getToken;
|
|
10899
10989
|
this.apiUrl = options.apiUrl.replace(/\/$/, "");
|
|
10900
10990
|
this.repoUrl = options.repoUrl ?? detectGitOrigin();
|
|
10901
10991
|
this.workspaceId = options.workspaceId?.trim() || getCommandWorkspaceTarget({ hasRepo: Boolean(this.repoUrl) }) || null;
|
|
@@ -10931,8 +11021,28 @@ var GadClient = class {
|
|
|
10931
11021
|
const controller = new AbortController();
|
|
10932
11022
|
const timer = setTimeout(() => controller.abort(), effectiveTimeout);
|
|
10933
11023
|
try {
|
|
11024
|
+
const headers = this.getToken ? new Headers(init.headers) : void 0;
|
|
11025
|
+
if (headers && this.getToken) {
|
|
11026
|
+
const token = await Promise.race([
|
|
11027
|
+
this.getToken(),
|
|
11028
|
+
new Promise((_resolve, reject) => {
|
|
11029
|
+
controller.signal.addEventListener(
|
|
11030
|
+
"abort",
|
|
11031
|
+
() => reject(
|
|
11032
|
+
networkError(
|
|
11033
|
+
"Session renewal timed out.",
|
|
11034
|
+
"Retry shortly; your saved session has been kept."
|
|
11035
|
+
)
|
|
11036
|
+
),
|
|
11037
|
+
{ once: true }
|
|
11038
|
+
);
|
|
11039
|
+
})
|
|
11040
|
+
]);
|
|
11041
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
11042
|
+
}
|
|
10934
11043
|
const response = await fetch(url, {
|
|
10935
11044
|
...init,
|
|
11045
|
+
...headers ? { headers: Object.fromEntries(headers) } : {},
|
|
10936
11046
|
signal: controller.signal
|
|
10937
11047
|
});
|
|
10938
11048
|
clearTimeout(timer);
|
|
@@ -11070,6 +11180,68 @@ var GadClient = class {
|
|
|
11070
11180
|
}
|
|
11071
11181
|
return payload;
|
|
11072
11182
|
}
|
|
11183
|
+
/**
|
|
11184
|
+
* Own one chat response through body consumption, with the normal workspace
|
|
11185
|
+
* attribution. A received turn is never replayed. The consumer handles either
|
|
11186
|
+
* the versioned local handoff or the actual frontier stream inside this scope.
|
|
11187
|
+
*/
|
|
11188
|
+
async withChatResponse(body, consume, options = {}) {
|
|
11189
|
+
const deadlineMs = options.deadlineMs ?? 3e5;
|
|
11190
|
+
if (!Number.isInteger(deadlineMs) || deadlineMs < 1 || deadlineMs > 3e5) {
|
|
11191
|
+
throw new CliError(
|
|
11192
|
+
"Chat deadline must be between 1 and 300000 milliseconds.",
|
|
11193
|
+
3 /* VALIDATION_ERROR */
|
|
11194
|
+
);
|
|
11195
|
+
}
|
|
11196
|
+
const controller = new AbortController();
|
|
11197
|
+
const signal = options.signal ? AbortSignal.any([controller.signal, options.signal]) : controller.signal;
|
|
11198
|
+
const timer = setTimeout(
|
|
11199
|
+
() => controller.abort(new Error("Chat response deadline exceeded.")),
|
|
11200
|
+
deadlineMs
|
|
11201
|
+
);
|
|
11202
|
+
let rejectAbort;
|
|
11203
|
+
let response;
|
|
11204
|
+
const aborted = new Promise((_, reject) => {
|
|
11205
|
+
rejectAbort = () => reject(signal.reason ?? new Error("Chat stopped."));
|
|
11206
|
+
if (signal.aborted) rejectAbort();
|
|
11207
|
+
else signal.addEventListener("abort", rejectAbort, { once: true });
|
|
11208
|
+
});
|
|
11209
|
+
try {
|
|
11210
|
+
return await Promise.race([
|
|
11211
|
+
(async () => {
|
|
11212
|
+
signal.throwIfAborted();
|
|
11213
|
+
response = await fetch(`${this.apiUrl}/api/chat`, {
|
|
11214
|
+
method: "POST",
|
|
11215
|
+
headers: {
|
|
11216
|
+
...this.buildHeaders(),
|
|
11217
|
+
Accept: "text/event-stream, application/json"
|
|
11218
|
+
},
|
|
11219
|
+
body: JSON.stringify(body),
|
|
11220
|
+
redirect: "error",
|
|
11221
|
+
cache: "no-store",
|
|
11222
|
+
signal
|
|
11223
|
+
});
|
|
11224
|
+
signal.throwIfAborted();
|
|
11225
|
+
if (!response.ok) await this.handleResponse(response);
|
|
11226
|
+
return consume(response, signal);
|
|
11227
|
+
})(),
|
|
11228
|
+
aborted
|
|
11229
|
+
]);
|
|
11230
|
+
} finally {
|
|
11231
|
+
clearTimeout(timer);
|
|
11232
|
+
if (rejectAbort) signal.removeEventListener("abort", rejectAbort);
|
|
11233
|
+
controller.abort();
|
|
11234
|
+
const body2 = response?.body;
|
|
11235
|
+
if (body2 && !body2.locked)
|
|
11236
|
+
void (async () => {
|
|
11237
|
+
try {
|
|
11238
|
+
await body2.cancel();
|
|
11239
|
+
} catch (error) {
|
|
11240
|
+
debugSwallow("chat.response.cancel", error);
|
|
11241
|
+
}
|
|
11242
|
+
})();
|
|
11243
|
+
}
|
|
11244
|
+
}
|
|
11073
11245
|
/**
|
|
11074
11246
|
* Make a GET request to a REST API endpoint.
|
|
11075
11247
|
*
|
|
@@ -11181,6 +11353,7 @@ function whoamiCommand() {
|
|
|
11181
11353
|
const auth = await resolveAuth();
|
|
11182
11354
|
const client = new GadClient({
|
|
11183
11355
|
token: auth.token,
|
|
11356
|
+
getToken: auth.getToken,
|
|
11184
11357
|
apiUrl: auth.apiUrl
|
|
11185
11358
|
});
|
|
11186
11359
|
let result;
|
|
@@ -11291,7 +11464,11 @@ var detailFields = [
|
|
|
11291
11464
|
];
|
|
11292
11465
|
async function buildClient() {
|
|
11293
11466
|
const auth = await resolveAuth();
|
|
11294
|
-
return new GadClient({
|
|
11467
|
+
return new GadClient({
|
|
11468
|
+
token: auth.token,
|
|
11469
|
+
getToken: auth.getToken,
|
|
11470
|
+
apiUrl: auth.apiUrl
|
|
11471
|
+
});
|
|
11295
11472
|
}
|
|
11296
11473
|
function extractPreview(item) {
|
|
11297
11474
|
if (typeof item.content === "string") {
|
|
@@ -11469,7 +11646,11 @@ var memberColumns = [
|
|
|
11469
11646
|
];
|
|
11470
11647
|
async function createClient() {
|
|
11471
11648
|
const auth = await resolveAuth();
|
|
11472
|
-
return new GadClient({
|
|
11649
|
+
return new GadClient({
|
|
11650
|
+
token: auth.token,
|
|
11651
|
+
getToken: auth.getToken,
|
|
11652
|
+
apiUrl: auth.apiUrl
|
|
11653
|
+
});
|
|
11473
11654
|
}
|
|
11474
11655
|
var listCommand = new Command("list").description("List all accessible workspaces").option("--json", "Output as JSON").action(async (options) => {
|
|
11475
11656
|
const jsonFlag = Boolean(
|
|
@@ -11663,7 +11844,11 @@ var listCommand2 = new Command("list").description("List open todos sorted by pr
|
|
|
11663
11844
|
noColor: parentOpts.noColor || false
|
|
11664
11845
|
});
|
|
11665
11846
|
const auth = await resolveAuth();
|
|
11666
|
-
const client = new GadClient({
|
|
11847
|
+
const client = new GadClient({
|
|
11848
|
+
token: auth.token,
|
|
11849
|
+
getToken: auth.getToken,
|
|
11850
|
+
apiUrl: auth.apiUrl
|
|
11851
|
+
});
|
|
11667
11852
|
const args = {
|
|
11668
11853
|
status: options.status ?? "open"
|
|
11669
11854
|
};
|
|
@@ -11689,7 +11874,11 @@ var createCommand = new Command("create").description("Create a new todo card").
|
|
|
11689
11874
|
noColor: false
|
|
11690
11875
|
});
|
|
11691
11876
|
const auth = await resolveAuth();
|
|
11692
|
-
const client = new GadClient({
|
|
11877
|
+
const client = new GadClient({
|
|
11878
|
+
token: auth.token,
|
|
11879
|
+
getToken: auth.getToken,
|
|
11880
|
+
apiUrl: auth.apiUrl
|
|
11881
|
+
});
|
|
11693
11882
|
const args = { title };
|
|
11694
11883
|
if (options.priority) {
|
|
11695
11884
|
args.priority = options.priority;
|
|
@@ -11717,7 +11906,11 @@ var doneCommand = new Command("done").description("Mark a todo as done").argumen
|
|
|
11717
11906
|
noColor: false
|
|
11718
11907
|
});
|
|
11719
11908
|
const auth = await resolveAuth();
|
|
11720
|
-
const client = new GadClient({
|
|
11909
|
+
const client = new GadClient({
|
|
11910
|
+
token: auth.token,
|
|
11911
|
+
getToken: auth.getToken,
|
|
11912
|
+
apiUrl: auth.apiUrl
|
|
11913
|
+
});
|
|
11721
11914
|
await client.mcpCall("todo_update", { id, status: "done" });
|
|
11722
11915
|
fmt.success(`Todo ${id} marked as done.`);
|
|
11723
11916
|
});
|
|
@@ -11736,7 +11929,11 @@ var updateCommand = new Command("update").description("Update a todo's status").
|
|
|
11736
11929
|
process.exit(3);
|
|
11737
11930
|
}
|
|
11738
11931
|
const auth = await resolveAuth();
|
|
11739
|
-
const client = new GadClient({
|
|
11932
|
+
const client = new GadClient({
|
|
11933
|
+
token: auth.token,
|
|
11934
|
+
getToken: auth.getToken,
|
|
11935
|
+
apiUrl: auth.apiUrl
|
|
11936
|
+
});
|
|
11740
11937
|
await client.mcpCall("todo_update", { id, status: options.status });
|
|
11741
11938
|
fmt.success(`Todo ${id} updated to status: ${options.status}`);
|
|
11742
11939
|
});
|
|
@@ -11778,7 +11975,11 @@ var getCommand = new Command("get").description("Show one card's full state (ass
|
|
|
11778
11975
|
noColor: parentOpts.noColor || false
|
|
11779
11976
|
});
|
|
11780
11977
|
const auth = await resolveAuth();
|
|
11781
|
-
const client = new GadClient({
|
|
11978
|
+
const client = new GadClient({
|
|
11979
|
+
token: auth.token,
|
|
11980
|
+
getToken: auth.getToken,
|
|
11981
|
+
apiUrl: auth.apiUrl
|
|
11982
|
+
});
|
|
11782
11983
|
const result = await client.mcpCall("todo_get", { id });
|
|
11783
11984
|
if (!result || typeof result !== "object" || result.error) {
|
|
11784
11985
|
fmt.error(`Todo ${id} not found in this workspace.`);
|
|
@@ -11838,7 +12039,11 @@ var assignCommand = new Command("assign").description("Assign a card to a specia
|
|
|
11838
12039
|
process.exit(3);
|
|
11839
12040
|
}
|
|
11840
12041
|
const auth = await resolveAuth();
|
|
11841
|
-
const client = new GadClient({
|
|
12042
|
+
const client = new GadClient({
|
|
12043
|
+
token: auth.token,
|
|
12044
|
+
getToken: auth.getToken,
|
|
12045
|
+
apiUrl: auth.apiUrl
|
|
12046
|
+
});
|
|
11842
12047
|
const result = await client.mcpCall("todo_assign", built.args);
|
|
11843
12048
|
if (isToolError(result)) {
|
|
11844
12049
|
fmt.error(toolErrorMessage(result));
|
|
@@ -11866,7 +12071,11 @@ var runCommand = new Command("run").description("Start the agent already queued
|
|
|
11866
12071
|
noColor: false
|
|
11867
12072
|
});
|
|
11868
12073
|
const auth = await resolveAuth();
|
|
11869
|
-
const client = new GadClient({
|
|
12074
|
+
const client = new GadClient({
|
|
12075
|
+
token: auth.token,
|
|
12076
|
+
getToken: auth.getToken,
|
|
12077
|
+
apiUrl: auth.apiUrl
|
|
12078
|
+
});
|
|
11870
12079
|
const result = await client.post(
|
|
11871
12080
|
`/api/todos/${encodeURIComponent(id)}/run`,
|
|
11872
12081
|
{}
|
|
@@ -11954,7 +12163,11 @@ var claimCommand = new Command("claim").description("Preflight + atomically clai
|
|
|
11954
12163
|
noColor: parentOpts.noColor || false
|
|
11955
12164
|
});
|
|
11956
12165
|
const auth = await resolveAuth();
|
|
11957
|
-
const client = new GadClient({
|
|
12166
|
+
const client = new GadClient({
|
|
12167
|
+
token: auth.token,
|
|
12168
|
+
getToken: auth.getToken,
|
|
12169
|
+
apiUrl: auth.apiUrl
|
|
12170
|
+
});
|
|
11958
12171
|
if (!options.force) {
|
|
11959
12172
|
tryGit(["fetch", "--quiet", "origin", "main"]);
|
|
11960
12173
|
const log = tryGit(["log", "--format=%s", "-n", "10", "origin/main"]) ?? tryGit(["log", "--format=%s", "-n", "10", "FETCH_HEAD"]) ?? "";
|
|
@@ -12532,6 +12745,7 @@ function workCommand() {
|
|
|
12532
12745
|
}
|
|
12533
12746
|
const client = new GadClient({
|
|
12534
12747
|
token: auth.token,
|
|
12748
|
+
getToken: auth.getToken,
|
|
12535
12749
|
apiUrl: auth.apiUrl
|
|
12536
12750
|
});
|
|
12537
12751
|
const data = await client.get("/api/work/status", {
|
|
@@ -12556,6 +12770,7 @@ function workCommand() {
|
|
|
12556
12770
|
const auth = await resolveAuth();
|
|
12557
12771
|
const client = new GadClient({
|
|
12558
12772
|
token: auth.token,
|
|
12773
|
+
getToken: auth.getToken,
|
|
12559
12774
|
apiUrl: auth.apiUrl
|
|
12560
12775
|
});
|
|
12561
12776
|
const report = options.file ? JSON.parse(readFileSync(options.file, "utf8")) : await collectWorkStatus({
|
|
@@ -13089,7 +13304,11 @@ function normalizeResponse(value) {
|
|
|
13089
13304
|
}
|
|
13090
13305
|
async function createClient2() {
|
|
13091
13306
|
const auth = await resolveAuth();
|
|
13092
|
-
return new GadClient({
|
|
13307
|
+
return new GadClient({
|
|
13308
|
+
token: auth.token,
|
|
13309
|
+
getToken: auth.getToken,
|
|
13310
|
+
apiUrl: auth.apiUrl
|
|
13311
|
+
});
|
|
13093
13312
|
}
|
|
13094
13313
|
function renderGuardrails(data, cmd) {
|
|
13095
13314
|
const output = globalOutputOpts(cmd);
|
|
@@ -14216,7 +14435,7 @@ async function ensureHookCredential(opts) {
|
|
|
14216
14435
|
}
|
|
14217
14436
|
|
|
14218
14437
|
// src/lib/mcp-doctor.ts
|
|
14219
|
-
import { createHash as
|
|
14438
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
14220
14439
|
|
|
14221
14440
|
// src/lib/mcp-target.ts
|
|
14222
14441
|
var GREAT_ARROW_HOSTS = /* @__PURE__ */ new Set([
|
|
@@ -14555,7 +14774,7 @@ function connectorGuidance(entries) {
|
|
|
14555
14774
|
return 'If you ALSO installed the Great Arrow connector on claude.ai, Claude Code counts it as a second server and nags "needs authentication" forever. Silence the duplicate by adding its name to "deniedMcpServers" in ~/.claude/settings.json ("disabledMcpServers" is not a valid key; "disabledMcpjsonServers" only covers .mcp.json servers).';
|
|
14556
14775
|
}
|
|
14557
14776
|
function fingerprint(value) {
|
|
14558
|
-
return
|
|
14777
|
+
return createHash3("sha256").update(value).digest("hex").slice(0, 12);
|
|
14559
14778
|
}
|
|
14560
14779
|
function describeStoredCredential(raw) {
|
|
14561
14780
|
const trimmed = raw?.trim();
|
|
@@ -14829,7 +15048,11 @@ async function checkApi(auth) {
|
|
|
14829
15048
|
hint: "Fix authentication first."
|
|
14830
15049
|
};
|
|
14831
15050
|
}
|
|
14832
|
-
const client = new GadClient({
|
|
15051
|
+
const client = new GadClient({
|
|
15052
|
+
token: auth.token,
|
|
15053
|
+
getToken: auth.getToken,
|
|
15054
|
+
apiUrl: auth.apiUrl
|
|
15055
|
+
});
|
|
14833
15056
|
try {
|
|
14834
15057
|
await client.get("/api/health");
|
|
14835
15058
|
return {
|
|
@@ -14855,7 +15078,11 @@ async function checkCliVersion(auth) {
|
|
|
14855
15078
|
hint: "Fix authentication first, then run 'gad doctor' again."
|
|
14856
15079
|
};
|
|
14857
15080
|
}
|
|
14858
|
-
const client = new GadClient({
|
|
15081
|
+
const client = new GadClient({
|
|
15082
|
+
token: auth.token,
|
|
15083
|
+
getToken: auth.getToken,
|
|
15084
|
+
apiUrl: auth.apiUrl
|
|
15085
|
+
});
|
|
14859
15086
|
try {
|
|
14860
15087
|
const result = await client.get("/api/mcp/version");
|
|
14861
15088
|
const cli = result.updates?.cli ?? result.cli ?? {};
|
|
@@ -14901,7 +15128,11 @@ async function checkIntegrations(auth) {
|
|
|
14901
15128
|
hint: "Fix authentication first."
|
|
14902
15129
|
};
|
|
14903
15130
|
}
|
|
14904
|
-
const client = new GadClient({
|
|
15131
|
+
const client = new GadClient({
|
|
15132
|
+
token: auth.token,
|
|
15133
|
+
getToken: auth.getToken,
|
|
15134
|
+
apiUrl: auth.apiUrl
|
|
15135
|
+
});
|
|
14905
15136
|
try {
|
|
14906
15137
|
const result = await client.mcpCall("integrations_list", {});
|
|
14907
15138
|
const data = result ?? {};
|
|
@@ -14942,7 +15173,11 @@ async function checkMcp(auth) {
|
|
|
14942
15173
|
hint: "Fix authentication first."
|
|
14943
15174
|
};
|
|
14944
15175
|
}
|
|
14945
|
-
const client = new GadClient({
|
|
15176
|
+
const client = new GadClient({
|
|
15177
|
+
token: auth.token,
|
|
15178
|
+
getToken: auth.getToken,
|
|
15179
|
+
apiUrl: auth.apiUrl
|
|
15180
|
+
});
|
|
14946
15181
|
try {
|
|
14947
15182
|
await client.mcpCall("workspace_introspect", {});
|
|
14948
15183
|
return {
|
|
@@ -15550,7 +15785,11 @@ var integrationListColumns = [
|
|
|
15550
15785
|
];
|
|
15551
15786
|
async function createClient3() {
|
|
15552
15787
|
const auth = await resolveAuth();
|
|
15553
|
-
return new GadClient({
|
|
15788
|
+
return new GadClient({
|
|
15789
|
+
token: auth.token,
|
|
15790
|
+
getToken: auth.getToken,
|
|
15791
|
+
apiUrl: auth.apiUrl
|
|
15792
|
+
});
|
|
15554
15793
|
}
|
|
15555
15794
|
function formatErrorDetail(rawError) {
|
|
15556
15795
|
if (rawError === null || rawError === void 0) return null;
|
|
@@ -15661,13 +15900,13 @@ var integrationsCommand = new Command("integrations").description("Manage connec
|
|
|
15661
15900
|
var integrations_default = integrationsCommand;
|
|
15662
15901
|
|
|
15663
15902
|
// src/commands/mcp.ts
|
|
15664
|
-
import { createHash as
|
|
15903
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
15665
15904
|
import { hostname } from "node:os";
|
|
15666
15905
|
|
|
15667
15906
|
// src/lib/mcp-bridge.ts
|
|
15668
15907
|
import { createInterface as createInterface2 } from "node:readline";
|
|
15669
15908
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
15670
|
-
import { randomUUID } from "node:crypto";
|
|
15909
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
15671
15910
|
var BRIDGE_CLIENT_ID = "gad-cli";
|
|
15672
15911
|
var DEFAULT_API_URL2 = "https://www.greatarrow.ai";
|
|
15673
15912
|
var DEFAULT_TIMEOUT_MS3 = 9e4;
|
|
@@ -15830,7 +16069,7 @@ async function runStdioBridge(options) {
|
|
|
15830
16069
|
`));
|
|
15831
16070
|
const endpoint = `${options.auth.apiUrl}/api/mcp`;
|
|
15832
16071
|
const timeoutMs = Number(env4.MEMORY_TIMEOUT_MS ?? DEFAULT_TIMEOUT_MS3);
|
|
15833
|
-
const sessionId = (env4.GAD_SESSION_ID ?? env4.MEMORY_SESSION_ID)?.trim() || `${BRIDGE_CLIENT_ID}:${Date.now()}-${
|
|
16072
|
+
const sessionId = (env4.GAD_SESSION_ID ?? env4.MEMORY_SESSION_ID)?.trim() || `${BRIDGE_CLIENT_ID}:${Date.now()}-${randomUUID2().slice(0, 8)}`;
|
|
15834
16073
|
const repoUrl = (env4.GAD_REPO_URL ?? env4.MEMORY_REPO_URL)?.trim() || detectGitOrigin3();
|
|
15835
16074
|
const workspaceId = (env4.GAD_WORKSPACE_ID ?? env4.GAD_WORKSPACE)?.trim() || getCommandWorkspaceTarget({ hasRepo: Boolean(repoUrl) });
|
|
15836
16075
|
const headers = buildBridgeHeaders({
|
|
@@ -15994,7 +16233,11 @@ async function mcpJsonAtRiskOfCommit(dir) {
|
|
|
15994
16233
|
}
|
|
15995
16234
|
async function createClient4() {
|
|
15996
16235
|
const auth = await resolveAuth();
|
|
15997
|
-
const client = new GadClient({
|
|
16236
|
+
const client = new GadClient({
|
|
16237
|
+
token: auth.token,
|
|
16238
|
+
getToken: auth.getToken,
|
|
16239
|
+
apiUrl: auth.apiUrl
|
|
16240
|
+
});
|
|
15998
16241
|
return { client, apiUrl: auth.apiUrl };
|
|
15999
16242
|
}
|
|
16000
16243
|
function generateMcpConfig(client, apiUrl, token, repoUrl) {
|
|
@@ -16029,7 +16272,7 @@ function generateMcpConfig(client, apiUrl, token, repoUrl) {
|
|
|
16029
16272
|
Authorization: `Bearer ${token}`,
|
|
16030
16273
|
"X-MCP-Client": CLIENT_IDS[client],
|
|
16031
16274
|
"X-Device-Name": deviceName,
|
|
16032
|
-
"X-Machine-Id":
|
|
16275
|
+
"X-Machine-Id": createHash4("sha256").update(rawHost).digest("hex"),
|
|
16033
16276
|
[GAD_INSTALL_HEADER]: GAD_INSTALL_VERSION,
|
|
16034
16277
|
...repoUrl ? { "X-Repo-URL": repoUrl } : {}
|
|
16035
16278
|
};
|
|
@@ -16294,7 +16537,11 @@ var testCommand = new Command("test").description(
|
|
|
16294
16537
|
const c = createColor(false);
|
|
16295
16538
|
const auth = await resolveAuth();
|
|
16296
16539
|
const apiUrl = auth.apiUrl;
|
|
16297
|
-
const client = new GadClient({
|
|
16540
|
+
const client = new GadClient({
|
|
16541
|
+
token: auth.token,
|
|
16542
|
+
getToken: auth.getToken,
|
|
16543
|
+
apiUrl
|
|
16544
|
+
});
|
|
16298
16545
|
const verbose = !jsonFlag;
|
|
16299
16546
|
const checks = [
|
|
16300
16547
|
await checkDns(apiUrl, verbose, c),
|
|
@@ -16833,6 +17080,7 @@ function smokeCommand() {
|
|
|
16833
17080
|
const auth = await resolveAuth();
|
|
16834
17081
|
const client = new GadClient({
|
|
16835
17082
|
token: auth.token,
|
|
17083
|
+
getToken: auth.getToken,
|
|
16836
17084
|
apiUrl: auth.apiUrl
|
|
16837
17085
|
});
|
|
16838
17086
|
if (!isJson && !isQuiet) {
|
|
@@ -16880,7 +17128,11 @@ var agentListColumns = [
|
|
|
16880
17128
|
];
|
|
16881
17129
|
async function buildClient2() {
|
|
16882
17130
|
const auth = await resolveAuth();
|
|
16883
|
-
return new GadClient({
|
|
17131
|
+
return new GadClient({
|
|
17132
|
+
token: auth.token,
|
|
17133
|
+
getToken: auth.getToken,
|
|
17134
|
+
apiUrl: auth.apiUrl
|
|
17135
|
+
});
|
|
16884
17136
|
}
|
|
16885
17137
|
function invokeOutcome(data) {
|
|
16886
17138
|
if (typeof data === "string") {
|
|
@@ -17030,6 +17282,7 @@ function askCommand() {
|
|
|
17030
17282
|
const auth = await resolveAuth();
|
|
17031
17283
|
const client = new GadClient({
|
|
17032
17284
|
token: auth.token,
|
|
17285
|
+
getToken: auth.getToken,
|
|
17033
17286
|
apiUrl: auth.apiUrl
|
|
17034
17287
|
});
|
|
17035
17288
|
const fmt = createFormatter({
|
|
@@ -18022,26 +18275,36 @@ function authHeaders(token) {
|
|
|
18022
18275
|
function origin(apiUrl) {
|
|
18023
18276
|
return apiUrl.replace(/\/+$/, "");
|
|
18024
18277
|
}
|
|
18025
|
-
function appAwareFetch(apiUrl, token, base) {
|
|
18026
|
-
return (input, init) => {
|
|
18278
|
+
function appAwareFetch(apiUrl, token, base, getToken2) {
|
|
18279
|
+
return async (input, init) => {
|
|
18027
18280
|
const target = typeof input === "string" ? input : String(input);
|
|
18028
|
-
|
|
18029
|
-
|
|
18281
|
+
const relative = target.startsWith("/") && !target.startsWith("//");
|
|
18282
|
+
if (!relative && !target.startsWith(`${origin(apiUrl)}/`))
|
|
18283
|
+
return base(input, init);
|
|
18284
|
+
const currentToken = getToken2 ? await withTimeout(15e3, () => getToken2()) : token;
|
|
18285
|
+
return base(relative ? `${origin(apiUrl)}${target}` : target, {
|
|
18030
18286
|
...init,
|
|
18031
18287
|
headers: {
|
|
18032
18288
|
...init?.headers,
|
|
18033
|
-
...authHeaders(
|
|
18289
|
+
...authHeaders(currentToken)
|
|
18034
18290
|
}
|
|
18035
18291
|
});
|
|
18036
18292
|
};
|
|
18037
18293
|
}
|
|
18038
18294
|
async function withTimeout(ms, run2) {
|
|
18039
18295
|
const controller = new AbortController();
|
|
18040
|
-
|
|
18296
|
+
let timer;
|
|
18297
|
+
const deadline = new Promise((_resolve, reject) => {
|
|
18298
|
+
timer = setTimeout(() => {
|
|
18299
|
+
const error = new DOMException("Request timed out", "AbortError");
|
|
18300
|
+
controller.abort(error);
|
|
18301
|
+
reject(error);
|
|
18302
|
+
}, ms);
|
|
18303
|
+
});
|
|
18041
18304
|
try {
|
|
18042
|
-
return await run2(controller.signal);
|
|
18305
|
+
return await Promise.race([run2(controller.signal), deadline]);
|
|
18043
18306
|
} finally {
|
|
18044
|
-
clearTimeout(timer);
|
|
18307
|
+
if (timer) clearTimeout(timer);
|
|
18045
18308
|
}
|
|
18046
18309
|
}
|
|
18047
18310
|
function readHandoff(payload) {
|
|
@@ -18106,7 +18369,7 @@ async function askForTheTurn(opts) {
|
|
|
18106
18369
|
if (!response.ok) {
|
|
18107
18370
|
throw new LocalTurnFailed(
|
|
18108
18371
|
"handoff",
|
|
18109
|
-
response.status === 401
|
|
18372
|
+
response.status === 401 ? "Sign in again \u2014 this computer is not allowed to ask for work." : response.status === 403 ? "This connection needs permission. Review its scopes and workspace access at /account/connections." : `Great Arrow refused that (${response.status}).`,
|
|
18110
18373
|
true
|
|
18111
18374
|
);
|
|
18112
18375
|
}
|
|
@@ -18168,14 +18431,14 @@ async function handBack(opts) {
|
|
|
18168
18431
|
}
|
|
18169
18432
|
async function answerOnThisComputer(opts) {
|
|
18170
18433
|
const base = opts.fetchImpl ?? fetch;
|
|
18171
|
-
const doFetch = appAwareFetch(opts.apiUrl, opts.token, base);
|
|
18434
|
+
const doFetch = appAwareFetch(opts.apiUrl, opts.token, base, opts.getToken);
|
|
18172
18435
|
const handoff = await askForTheTurn({
|
|
18173
18436
|
apiUrl: opts.apiUrl,
|
|
18174
18437
|
token: opts.token,
|
|
18175
18438
|
question: opts.question,
|
|
18176
18439
|
sessionId: opts.sessionId ?? null,
|
|
18177
18440
|
timezone: opts.timezone,
|
|
18178
|
-
doFetch
|
|
18441
|
+
doFetch
|
|
18179
18442
|
});
|
|
18180
18443
|
if (!handoff) {
|
|
18181
18444
|
return { answeredHere: false, reason: "answered_by_great_arrow" };
|
|
@@ -18217,7 +18480,7 @@ async function answerOnThisComputer(opts) {
|
|
|
18217
18480
|
outputTokens: result.outputTokens,
|
|
18218
18481
|
promptCharacters: result.promptCharacters,
|
|
18219
18482
|
latencyMs: Date.now() - startedAt,
|
|
18220
|
-
doFetch
|
|
18483
|
+
doFetch
|
|
18221
18484
|
});
|
|
18222
18485
|
return {
|
|
18223
18486
|
answeredHere: true,
|
|
@@ -18237,7 +18500,7 @@ async function answerOnThisComputer(opts) {
|
|
|
18237
18500
|
outputTokens: void 0,
|
|
18238
18501
|
promptCharacters: 0,
|
|
18239
18502
|
latencyMs: Date.now() - startedAt,
|
|
18240
|
-
doFetch
|
|
18503
|
+
doFetch
|
|
18241
18504
|
});
|
|
18242
18505
|
throw new LocalTurnFailed(
|
|
18243
18506
|
"writing",
|
|
@@ -18470,7 +18733,11 @@ function checkCommand() {
|
|
|
18470
18733
|
const provider = readProvider(options.app);
|
|
18471
18734
|
const baseUrl = typeof options.url === "string" && options.url ? options.url : LOCAL_PROVIDER_PRESETS[provider].baseUrl;
|
|
18472
18735
|
const auth = await resolveAuth();
|
|
18473
|
-
const client = new GadClient({
|
|
18736
|
+
const client = new GadClient({
|
|
18737
|
+
token: auth.token,
|
|
18738
|
+
getToken: auth.getToken,
|
|
18739
|
+
apiUrl: auth.apiUrl
|
|
18740
|
+
});
|
|
18474
18741
|
const fmt = createFormatter({
|
|
18475
18742
|
json: g.json,
|
|
18476
18743
|
quiet: g.quiet,
|
|
@@ -18545,7 +18812,11 @@ function statusCommand2() {
|
|
|
18545
18812
|
return new Command("status").description("Show what is set up for models on this computer").action(async (_options, command) => {
|
|
18546
18813
|
const g = globalOutputOpts(command);
|
|
18547
18814
|
const auth = await resolveAuth();
|
|
18548
|
-
const client = new GadClient({
|
|
18815
|
+
const client = new GadClient({
|
|
18816
|
+
token: auth.token,
|
|
18817
|
+
getToken: auth.getToken,
|
|
18818
|
+
apiUrl: auth.apiUrl
|
|
18819
|
+
});
|
|
18549
18820
|
const payload = await client.mcpCall(
|
|
18550
18821
|
"model_local_get",
|
|
18551
18822
|
{},
|
|
@@ -18613,7 +18884,11 @@ function offCommand() {
|
|
|
18613
18884
|
return new Command("off").description("Stop answering with a model on this computer").action(async (_options, command) => {
|
|
18614
18885
|
const g = globalOutputOpts(command);
|
|
18615
18886
|
const auth = await resolveAuth();
|
|
18616
|
-
const client = new GadClient({
|
|
18887
|
+
const client = new GadClient({
|
|
18888
|
+
token: auth.token,
|
|
18889
|
+
getToken: auth.getToken,
|
|
18890
|
+
apiUrl: auth.apiUrl
|
|
18891
|
+
});
|
|
18617
18892
|
const fmt = createFormatter({
|
|
18618
18893
|
json: g.json,
|
|
18619
18894
|
quiet: g.quiet,
|
|
@@ -18644,6 +18919,7 @@ function askHereCommand() {
|
|
|
18644
18919
|
report = await answerOnThisComputer({
|
|
18645
18920
|
apiUrl: auth.apiUrl,
|
|
18646
18921
|
token: auth.token,
|
|
18922
|
+
getToken: auth.getToken,
|
|
18647
18923
|
question,
|
|
18648
18924
|
sessionId: typeof options.session === "string" ? options.session : null,
|
|
18649
18925
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
@@ -18757,6 +19033,7 @@ function statusCommand3() {
|
|
|
18757
19033
|
const auth = await resolveAuth();
|
|
18758
19034
|
const client = new GadClient({
|
|
18759
19035
|
token: auth.token,
|
|
19036
|
+
getToken: auth.getToken,
|
|
18760
19037
|
apiUrl: auth.apiUrl
|
|
18761
19038
|
});
|
|
18762
19039
|
const fmt = createFormatter({
|
|
@@ -18934,7 +19211,11 @@ function openCommand() {
|
|
|
18934
19211
|
).option("--print", "Print the URL instead of opening a browser").option("--json", "Output the resolved surface as JSON").action(async (surface, options, command) => {
|
|
18935
19212
|
const g = globalOutputOpts(command);
|
|
18936
19213
|
const auth = await resolveAuth();
|
|
18937
|
-
const client = new GadClient({
|
|
19214
|
+
const client = new GadClient({
|
|
19215
|
+
token: auth.token,
|
|
19216
|
+
getToken: auth.getToken,
|
|
19217
|
+
apiUrl: auth.apiUrl
|
|
19218
|
+
});
|
|
18938
19219
|
const result = await client.mcpCall("surfaces_list", {
|
|
18939
19220
|
query: surface
|
|
18940
19221
|
});
|
|
@@ -19022,7 +19303,11 @@ function nextCommand() {
|
|
|
19022
19303
|
noColor: g.noColor
|
|
19023
19304
|
});
|
|
19024
19305
|
const auth = await resolveAuth();
|
|
19025
|
-
const client = new GadClient({
|
|
19306
|
+
const client = new GadClient({
|
|
19307
|
+
token: auth.token,
|
|
19308
|
+
getToken: auth.getToken,
|
|
19309
|
+
apiUrl: auth.apiUrl
|
|
19310
|
+
});
|
|
19026
19311
|
let identityStatus = null;
|
|
19027
19312
|
try {
|
|
19028
19313
|
const who = await client.mcpCall("workspace_introspect", {});
|
|
@@ -19085,7 +19370,11 @@ function discoverCommand() {
|
|
|
19085
19370
|
noColor: g.noColor
|
|
19086
19371
|
});
|
|
19087
19372
|
const auth = await resolveAuth();
|
|
19088
|
-
const client = new GadClient({
|
|
19373
|
+
const client = new GadClient({
|
|
19374
|
+
token: auth.token,
|
|
19375
|
+
getToken: auth.getToken,
|
|
19376
|
+
apiUrl: auth.apiUrl
|
|
19377
|
+
});
|
|
19089
19378
|
const parsed = opts.limit ? Number.parseInt(opts.limit, 10) : NaN;
|
|
19090
19379
|
const args = Number.isFinite(parsed) && parsed > 0 ? { limit: parsed } : {};
|
|
19091
19380
|
const result = await client.mcpCall("did_you_know", args);
|