@great-arrow/cli 0.1.38 → 0.1.40
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 +225 -121
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -706,7 +706,7 @@ var require_graceful_fs = __commonJS({
|
|
|
706
706
|
}
|
|
707
707
|
function ReadStream$open() {
|
|
708
708
|
var that = this;
|
|
709
|
-
|
|
709
|
+
open2(that.path, that.flags, that.mode, function(err, fd) {
|
|
710
710
|
if (err) {
|
|
711
711
|
if (that.autoClose)
|
|
712
712
|
that.destroy();
|
|
@@ -726,7 +726,7 @@ var require_graceful_fs = __commonJS({
|
|
|
726
726
|
}
|
|
727
727
|
function WriteStream$open() {
|
|
728
728
|
var that = this;
|
|
729
|
-
|
|
729
|
+
open2(that.path, that.flags, that.mode, function(err, fd) {
|
|
730
730
|
if (err) {
|
|
731
731
|
that.destroy();
|
|
732
732
|
that.emit("error", err);
|
|
@@ -743,8 +743,8 @@ var require_graceful_fs = __commonJS({
|
|
|
743
743
|
return new fs7.WriteStream(path10, options);
|
|
744
744
|
}
|
|
745
745
|
var fs$open = fs7.open;
|
|
746
|
-
fs7.open =
|
|
747
|
-
function
|
|
746
|
+
fs7.open = open2;
|
|
747
|
+
function open2(path10, flags, mode, cb) {
|
|
748
748
|
if (typeof mode === "function")
|
|
749
749
|
cb = mode, mode = null;
|
|
750
750
|
return go$open(path10, flags, mode, cb);
|
|
@@ -1964,7 +1964,7 @@ var require_minimist = __commonJS({
|
|
|
1964
1964
|
var require_rc = __commonJS({
|
|
1965
1965
|
"node_modules/.pnpm/rc@1.2.8/node_modules/rc/index.js"(exports, module) {
|
|
1966
1966
|
var cc = require_utils();
|
|
1967
|
-
var
|
|
1967
|
+
var join8 = __require("path").join;
|
|
1968
1968
|
var deepExtend = require_deep_extend();
|
|
1969
1969
|
var etc = "/etc";
|
|
1970
1970
|
var win = process.platform === "win32";
|
|
@@ -1989,15 +1989,15 @@ var require_rc = __commonJS({
|
|
|
1989
1989
|
}
|
|
1990
1990
|
if (!win)
|
|
1991
1991
|
[
|
|
1992
|
-
|
|
1993
|
-
|
|
1992
|
+
join8(etc, name, "config"),
|
|
1993
|
+
join8(etc, name + "rc")
|
|
1994
1994
|
].forEach(addConfigFile);
|
|
1995
1995
|
if (home)
|
|
1996
1996
|
[
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
1997
|
+
join8(home, ".config", name, "config"),
|
|
1998
|
+
join8(home, ".config", name),
|
|
1999
|
+
join8(home, "." + name, "config"),
|
|
2000
|
+
join8(home, "." + name + "rc")
|
|
2001
2001
|
].forEach(addConfigFile);
|
|
2002
2002
|
addConfigFile(cc.find("." + name + "rc"));
|
|
2003
2003
|
if (env4.config) addConfigFile(env4.config);
|
|
@@ -2680,7 +2680,7 @@ var require_graceful_fs2 = __commonJS({
|
|
|
2680
2680
|
}
|
|
2681
2681
|
function ReadStream$open() {
|
|
2682
2682
|
var that = this;
|
|
2683
|
-
|
|
2683
|
+
open2(that.path, that.flags, that.mode, function(err, fd) {
|
|
2684
2684
|
if (err) {
|
|
2685
2685
|
if (that.autoClose)
|
|
2686
2686
|
that.destroy();
|
|
@@ -2700,7 +2700,7 @@ var require_graceful_fs2 = __commonJS({
|
|
|
2700
2700
|
}
|
|
2701
2701
|
function WriteStream$open() {
|
|
2702
2702
|
var that = this;
|
|
2703
|
-
|
|
2703
|
+
open2(that.path, that.flags, that.mode, function(err, fd) {
|
|
2704
2704
|
if (err) {
|
|
2705
2705
|
that.destroy();
|
|
2706
2706
|
that.emit("error", err);
|
|
@@ -2717,8 +2717,8 @@ var require_graceful_fs2 = __commonJS({
|
|
|
2717
2717
|
return new fs7.WriteStream(path10, options);
|
|
2718
2718
|
}
|
|
2719
2719
|
var fs$open = fs7.open;
|
|
2720
|
-
fs7.open =
|
|
2721
|
-
function
|
|
2720
|
+
fs7.open = open2;
|
|
2721
|
+
function open2(path10, flags, mode, cb) {
|
|
2722
2722
|
if (typeof mode === "function")
|
|
2723
2723
|
cb = mode, mode = null;
|
|
2724
2724
|
return go$open(path10, flags, mode, cb);
|
|
@@ -9399,7 +9399,7 @@ function isNodeError(value) {
|
|
|
9399
9399
|
|
|
9400
9400
|
// src/lib/version.ts
|
|
9401
9401
|
var CLI_PACKAGE_NAME = "@great-arrow/cli";
|
|
9402
|
-
var CLI_VERSION = "0.1.
|
|
9402
|
+
var CLI_VERSION = "0.1.40";
|
|
9403
9403
|
var GAD_INSTALL_VERSION = "2026.08.08";
|
|
9404
9404
|
var GAD_INSTALL_MIN_VERSION = "2026.06.22";
|
|
9405
9405
|
var GAD_INSTALL_HEADER = "X-GAD-Install-Version";
|
|
@@ -10000,10 +10000,10 @@ function isColorEnabled(noColorFlag) {
|
|
|
10000
10000
|
}
|
|
10001
10001
|
function createColor(noColorFlag) {
|
|
10002
10002
|
const enabled2 = isColorEnabled(noColorFlag);
|
|
10003
|
-
const wrap = (
|
|
10003
|
+
const wrap = (open2, close) => {
|
|
10004
10004
|
return (text2) => {
|
|
10005
10005
|
if (!enabled2) return text2;
|
|
10006
|
-
return `\x1B[${
|
|
10006
|
+
return `\x1B[${open2}m${text2}\x1B[${close}m`;
|
|
10007
10007
|
};
|
|
10008
10008
|
};
|
|
10009
10009
|
return {
|
|
@@ -10306,9 +10306,68 @@ var logoutCommand = new Command("logout").description("Remove stored authenticat
|
|
|
10306
10306
|
});
|
|
10307
10307
|
|
|
10308
10308
|
// src/lib/auth.ts
|
|
10309
|
+
import { mkdir as mkdir3, open, rm, stat } from "node:fs/promises";
|
|
10310
|
+
import { homedir as homedir3 } from "node:os";
|
|
10311
|
+
import { join as join3 } from "node:path";
|
|
10309
10312
|
var DEFAULT_API_URL2 = "https://www.greatarrow.ai";
|
|
10310
10313
|
var REFRESH_SKEW_MS = 12e4;
|
|
10311
10314
|
var inflightRefresh = null;
|
|
10315
|
+
var REFRESH_LOCK_STALE_MS = 15e3;
|
|
10316
|
+
var REFRESH_LOCK_WAIT_MS = 5e3;
|
|
10317
|
+
var REFRESH_LOCK_POLL_MS = 100;
|
|
10318
|
+
function refreshLockPath() {
|
|
10319
|
+
return join3(homedir3(), ".great-arrow", "refresh.lock");
|
|
10320
|
+
}
|
|
10321
|
+
async function acquireRefreshLock() {
|
|
10322
|
+
const path10 = refreshLockPath();
|
|
10323
|
+
try {
|
|
10324
|
+
await mkdir3(join3(homedir3(), ".great-arrow"), { recursive: true });
|
|
10325
|
+
} catch (err) {
|
|
10326
|
+
debugSwallow("refresh-lock.mkdir", err);
|
|
10327
|
+
}
|
|
10328
|
+
const deadline = Date.now() + REFRESH_LOCK_WAIT_MS;
|
|
10329
|
+
for (; ; ) {
|
|
10330
|
+
try {
|
|
10331
|
+
const handle = await open(path10, "wx");
|
|
10332
|
+
await handle.writeFile(String(process.pid));
|
|
10333
|
+
await handle.close();
|
|
10334
|
+
return true;
|
|
10335
|
+
} catch (err) {
|
|
10336
|
+
if (err.code !== "EEXIST") return true;
|
|
10337
|
+
}
|
|
10338
|
+
const age = await stat(path10).then((st) => Date.now() - st.mtimeMs).catch(() => Number.POSITIVE_INFINITY);
|
|
10339
|
+
if (age > REFRESH_LOCK_STALE_MS) {
|
|
10340
|
+
try {
|
|
10341
|
+
await rm(path10, { force: true });
|
|
10342
|
+
} catch (err) {
|
|
10343
|
+
debugSwallow("refresh-lock.stale-rm", err);
|
|
10344
|
+
}
|
|
10345
|
+
continue;
|
|
10346
|
+
}
|
|
10347
|
+
if (Date.now() >= deadline) return false;
|
|
10348
|
+
await new Promise((r) => setTimeout(r, REFRESH_LOCK_POLL_MS));
|
|
10349
|
+
}
|
|
10350
|
+
}
|
|
10351
|
+
async function releaseRefreshLock() {
|
|
10352
|
+
try {
|
|
10353
|
+
await rm(refreshLockPath(), { force: true });
|
|
10354
|
+
} catch (err) {
|
|
10355
|
+
debugSwallow("refresh-lock.release", err);
|
|
10356
|
+
}
|
|
10357
|
+
}
|
|
10358
|
+
async function rotatedByAnotherProcess(ours) {
|
|
10359
|
+
let stored = null;
|
|
10360
|
+
try {
|
|
10361
|
+
stored = await loadStoredCredential();
|
|
10362
|
+
} catch (err) {
|
|
10363
|
+
debugSwallow("refresh.reread", err);
|
|
10364
|
+
}
|
|
10365
|
+
if (stored?.kind !== "oauth") return null;
|
|
10366
|
+
const theirs = stored.credential;
|
|
10367
|
+
if (theirs.refreshToken === ours.refreshToken) return null;
|
|
10368
|
+
if (Date.now() >= theirs.accessExpiresAt - REFRESH_SKEW_MS) return null;
|
|
10369
|
+
return theirs;
|
|
10370
|
+
}
|
|
10312
10371
|
async function resolveAuth() {
|
|
10313
10372
|
const config = await loadConfig();
|
|
10314
10373
|
const configApiUrl = config.api_url || DEFAULT_API_URL2;
|
|
@@ -10367,7 +10426,10 @@ async function ensureFreshAccessToken(credential) {
|
|
|
10367
10426
|
}
|
|
10368
10427
|
}
|
|
10369
10428
|
async function doRefresh(credential) {
|
|
10429
|
+
const held = await acquireRefreshLock();
|
|
10370
10430
|
try {
|
|
10431
|
+
const theirs = await rotatedByAnotherProcess(credential);
|
|
10432
|
+
if (theirs) return theirs;
|
|
10371
10433
|
const refreshed = await refreshTokens({
|
|
10372
10434
|
apiUrl: credential.apiUrl,
|
|
10373
10435
|
clientId: credential.clientId,
|
|
@@ -10381,6 +10443,8 @@ async function doRefresh(credential) {
|
|
|
10381
10443
|
throw sessionExpired();
|
|
10382
10444
|
}
|
|
10383
10445
|
throw err;
|
|
10446
|
+
} finally {
|
|
10447
|
+
if (held) await releaseRefreshLock();
|
|
10384
10448
|
}
|
|
10385
10449
|
}
|
|
10386
10450
|
function sessionExpired() {
|
|
@@ -12198,7 +12262,7 @@ var work_default = workCommand;
|
|
|
12198
12262
|
// src/commands/worktree.ts
|
|
12199
12263
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
12200
12264
|
import { existsSync, readFileSync as readFileSync2, statSync, writeFileSync } from "node:fs";
|
|
12201
|
-
import { basename, dirname as dirname3, isAbsolute, join as
|
|
12265
|
+
import { basename, dirname as dirname3, isAbsolute, join as join4, resolve } from "node:path";
|
|
12202
12266
|
var realExec = (cmd, args, opts) => {
|
|
12203
12267
|
const out = execFileSync3(cmd, args, {
|
|
12204
12268
|
cwd: opts?.cwd,
|
|
@@ -12220,9 +12284,9 @@ function parseDefaultBranch(symbolicRef) {
|
|
|
12220
12284
|
return match ? match[1] : null;
|
|
12221
12285
|
}
|
|
12222
12286
|
function detectPackageManager(repoRoot) {
|
|
12223
|
-
if (existsSync(
|
|
12224
|
-
if (existsSync(
|
|
12225
|
-
if (existsSync(
|
|
12287
|
+
if (existsSync(join4(repoRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
12288
|
+
if (existsSync(join4(repoRoot, "bun.lockb"))) return "bun";
|
|
12289
|
+
if (existsSync(join4(repoRoot, "yarn.lock"))) return "yarn";
|
|
12226
12290
|
return "npm";
|
|
12227
12291
|
}
|
|
12228
12292
|
function defaultWorktreeDir(repoRoot, branch) {
|
|
@@ -12230,7 +12294,7 @@ function defaultWorktreeDir(repoRoot, branch) {
|
|
|
12230
12294
|
/[^A-Za-z0-9._-]+/g,
|
|
12231
12295
|
"-"
|
|
12232
12296
|
);
|
|
12233
|
-
return
|
|
12297
|
+
return join4(dirname3(repoRoot), `${basename(repoRoot)}-${slug}`);
|
|
12234
12298
|
}
|
|
12235
12299
|
var AGENT_PROCESS_RE = /(^|\/)(claude|kiro|cursor|codex)/i;
|
|
12236
12300
|
function psField(pid, field) {
|
|
@@ -12253,7 +12317,7 @@ function findAgentPid(startPid) {
|
|
|
12253
12317
|
return null;
|
|
12254
12318
|
}
|
|
12255
12319
|
function ownGitDir(worktreeDir) {
|
|
12256
|
-
const dotGit =
|
|
12320
|
+
const dotGit = join4(worktreeDir, ".git");
|
|
12257
12321
|
if (!existsSync(dotGit)) return null;
|
|
12258
12322
|
if (statSync(dotGit).isDirectory()) return dotGit;
|
|
12259
12323
|
const match = readFileSync2(dotGit, "utf8").trim().match(/^gitdir:\s*(.+)$/m);
|
|
@@ -12268,7 +12332,7 @@ function stampWorktreeOwner(worktreeDir) {
|
|
|
12268
12332
|
const ownerPid = findAgentPid(process.ppid);
|
|
12269
12333
|
if (!ownerPid) return null;
|
|
12270
12334
|
writeFileSync(
|
|
12271
|
-
|
|
12335
|
+
join4(gitDir, "agent-owner.json"),
|
|
12272
12336
|
JSON.stringify(
|
|
12273
12337
|
{
|
|
12274
12338
|
ownerPid,
|
|
@@ -12362,7 +12426,7 @@ function createTaskWorktree(opts) {
|
|
|
12362
12426
|
const stampedPid = opts.stamp === false ? null : stampWorktreeOwner(dir);
|
|
12363
12427
|
const packageManager = detectPackageManager(repoRoot);
|
|
12364
12428
|
let installed = false;
|
|
12365
|
-
if (opts.install !== false && existsSync(
|
|
12429
|
+
if (opts.install !== false && existsSync(join4(repoRoot, "package.json"))) {
|
|
12366
12430
|
exec2(packageManager, ["install"], { cwd: dir, inherit: true });
|
|
12367
12431
|
installed = true;
|
|
12368
12432
|
}
|
|
@@ -12431,7 +12495,7 @@ import {
|
|
|
12431
12495
|
readFileSync as readFileSync3,
|
|
12432
12496
|
writeFileSync as writeFileSync2
|
|
12433
12497
|
} from "node:fs";
|
|
12434
|
-
import { isAbsolute as isAbsolute2, join as
|
|
12498
|
+
import { isAbsolute as isAbsolute2, join as join5, resolve as resolve2 } from "node:path";
|
|
12435
12499
|
var GUARD_MARKER = "# gad-agent-guard v1";
|
|
12436
12500
|
var SCHEMA_AUDIT_MARKER = "# gad-schema-audit v1";
|
|
12437
12501
|
var GUARD_FILE = "gad-commit-guard.mjs";
|
|
@@ -12614,22 +12678,22 @@ function installCommitGuard(opts) {
|
|
|
12614
12678
|
);
|
|
12615
12679
|
}
|
|
12616
12680
|
if (!isAbsolute2(commonDir)) commonDir = resolve2(repoRoot, commonDir);
|
|
12617
|
-
const hooksDir =
|
|
12681
|
+
const hooksDir = join5(commonDir, "hooks");
|
|
12618
12682
|
mkdirSync(hooksDir, { recursive: true });
|
|
12619
|
-
const guardPath =
|
|
12683
|
+
const guardPath = join5(hooksDir, GUARD_FILE);
|
|
12620
12684
|
writeFileSync2(guardPath, buildGuardScript());
|
|
12621
12685
|
chmodSync(guardPath, 493);
|
|
12622
|
-
const huskyHook =
|
|
12623
|
-
const hookPath = existsSync2(huskyHook) ? huskyHook :
|
|
12686
|
+
const huskyHook = join5(repoRoot, ".husky", "pre-commit");
|
|
12687
|
+
const hookPath = existsSync2(huskyHook) ? huskyHook : join5(hooksDir, "pre-commit");
|
|
12624
12688
|
const existing = existsSync2(hookPath) ? readFileSync3(hookPath, "utf8") : null;
|
|
12625
12689
|
const plan = planHookInstall(existing);
|
|
12626
12690
|
if (plan.action !== "noop") {
|
|
12627
12691
|
writeFileSync2(hookPath, plan.content);
|
|
12628
12692
|
}
|
|
12629
12693
|
chmodSync(hookPath, 493);
|
|
12630
|
-
const huskyDir =
|
|
12631
|
-
const huskyPrePush =
|
|
12632
|
-
const schemaAuditHookPath = existsSync2(huskyPrePush) || existsSync2(huskyDir) ? huskyPrePush :
|
|
12694
|
+
const huskyDir = join5(repoRoot, ".husky");
|
|
12695
|
+
const huskyPrePush = join5(huskyDir, "pre-push");
|
|
12696
|
+
const schemaAuditHookPath = existsSync2(huskyPrePush) || existsSync2(huskyDir) ? huskyPrePush : join5(hooksDir, "pre-push");
|
|
12633
12697
|
const existingSchemaAuditHook = existsSync2(schemaAuditHookPath) ? readFileSync3(schemaAuditHookPath, "utf8") : null;
|
|
12634
12698
|
const schemaAuditPlan = planSchemaAuditHookInstall(existingSchemaAuditHook);
|
|
12635
12699
|
if (schemaAuditPlan.action !== "noop") {
|
|
@@ -12752,9 +12816,9 @@ function guardrailsCommand() {
|
|
|
12752
12816
|
|
|
12753
12817
|
// src/commands/doctor.ts
|
|
12754
12818
|
import { existsSync as existsSync3 } from "node:fs";
|
|
12755
|
-
import { copyFile, mkdir as
|
|
12756
|
-
import { homedir as
|
|
12757
|
-
import { dirname as dirname4, join as
|
|
12819
|
+
import { copyFile, mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
12820
|
+
import { homedir as homedir4 } from "node:os";
|
|
12821
|
+
import { dirname as dirname4, join as join6 } from "node:path";
|
|
12758
12822
|
|
|
12759
12823
|
// src/lib/codex-config.ts
|
|
12760
12824
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
@@ -14239,7 +14303,7 @@ async function checkMcp(auth) {
|
|
|
14239
14303
|
}
|
|
14240
14304
|
}
|
|
14241
14305
|
function defaultCodexConfigPath() {
|
|
14242
|
-
return
|
|
14306
|
+
return join6(homedir4(), ".codex", "config.toml");
|
|
14243
14307
|
}
|
|
14244
14308
|
function codexIssuesToChecks(issues) {
|
|
14245
14309
|
return issues.map((issue) => {
|
|
@@ -14283,7 +14347,7 @@ function codexCommand() {
|
|
|
14283
14347
|
if (options.enforce) {
|
|
14284
14348
|
const apiUrl = extractCodexGreatArrowApiUrl(content) ?? (await resolveAuth()).apiUrl;
|
|
14285
14349
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
14286
|
-
await
|
|
14350
|
+
await mkdir4(dirname4(configPath), { recursive: true });
|
|
14287
14351
|
if (content.trim()) {
|
|
14288
14352
|
backupPath = `${configPath}.bak.${timestamp}`;
|
|
14289
14353
|
await copyFile(configPath, backupPath);
|
|
@@ -14377,12 +14441,12 @@ function claudeCommand() {
|
|
|
14377
14441
|
isTTY: isTTY(),
|
|
14378
14442
|
noColor: g.noColor
|
|
14379
14443
|
});
|
|
14380
|
-
const home =
|
|
14381
|
-
const gaDir =
|
|
14382
|
-
const userConfigPath =
|
|
14383
|
-
const settingsPath =
|
|
14384
|
-
const hookConfigPath =
|
|
14385
|
-
const glanceHookPath =
|
|
14444
|
+
const home = homedir4();
|
|
14445
|
+
const gaDir = join6(home, ".great-arrow");
|
|
14446
|
+
const userConfigPath = join6(home, ".claude.json");
|
|
14447
|
+
const settingsPath = join6(home, ".claude", "settings.json");
|
|
14448
|
+
const hookConfigPath = join6(gaDir, "hook-config.json");
|
|
14449
|
+
const glanceHookPath = join6(gaDir, "claude-glance-hook.mjs");
|
|
14386
14450
|
const checks = [];
|
|
14387
14451
|
const repairs = [];
|
|
14388
14452
|
const backups = [];
|
|
@@ -14404,7 +14468,7 @@ function claudeCommand() {
|
|
|
14404
14468
|
await copyFile(path10, backupPath);
|
|
14405
14469
|
backups.push(backupPath);
|
|
14406
14470
|
}
|
|
14407
|
-
await
|
|
14471
|
+
await mkdir4(dirname4(path10), { recursive: true });
|
|
14408
14472
|
await writeFile3(path10, content, "utf8");
|
|
14409
14473
|
};
|
|
14410
14474
|
let auth = null;
|
|
@@ -14451,7 +14515,7 @@ function claudeCommand() {
|
|
|
14451
14515
|
{ signal: AbortSignal.timeout(1e4) }
|
|
14452
14516
|
);
|
|
14453
14517
|
if (res.ok) {
|
|
14454
|
-
await
|
|
14518
|
+
await mkdir4(gaDir, { recursive: true });
|
|
14455
14519
|
await writeFile3(glanceHookPath, await res.text(), {
|
|
14456
14520
|
mode: 493
|
|
14457
14521
|
});
|
|
@@ -14590,8 +14654,8 @@ function claudeCommand() {
|
|
|
14590
14654
|
file: "/Library/Application Support/ClaudeCode/managed-settings.json"
|
|
14591
14655
|
},
|
|
14592
14656
|
{ scope: "user", file: settingsPath },
|
|
14593
|
-
{ scope: "project", file:
|
|
14594
|
-
{ scope: "local", file:
|
|
14657
|
+
{ scope: "project", file: join6(cwd, ".claude", "settings.json") },
|
|
14658
|
+
{ scope: "local", file: join6(cwd, ".claude", "settings.local.json") }
|
|
14595
14659
|
];
|
|
14596
14660
|
const configured = [];
|
|
14597
14661
|
for (const { scope, file } of scopes) {
|
|
@@ -14660,12 +14724,12 @@ function claudeCommand() {
|
|
|
14660
14724
|
});
|
|
14661
14725
|
}
|
|
14662
14726
|
function defaultJsonClientConfigs() {
|
|
14663
|
-
const home =
|
|
14727
|
+
const home = homedir4();
|
|
14664
14728
|
return [
|
|
14665
|
-
{ name: "Claude Code", path:
|
|
14666
|
-
{ name: "Cursor", path:
|
|
14667
|
-
{ name: "Kiro", path:
|
|
14668
|
-
{ name: "Gemini CLI", path:
|
|
14729
|
+
{ name: "Claude Code", path: join6(home, ".claude.json") },
|
|
14730
|
+
{ name: "Cursor", path: join6(home, ".cursor", "mcp.json") },
|
|
14731
|
+
{ name: "Kiro", path: join6(home, ".kiro", "settings", "mcp.json") },
|
|
14732
|
+
{ name: "Gemini CLI", path: join6(home, ".gemini", "settings.json") }
|
|
14669
14733
|
];
|
|
14670
14734
|
}
|
|
14671
14735
|
function clientsCommand() {
|
|
@@ -15311,14 +15375,14 @@ async function pathExists(path10) {
|
|
|
15311
15375
|
}
|
|
15312
15376
|
}
|
|
15313
15377
|
async function installCodexConfig(apiUrl, token, repoUrl) {
|
|
15314
|
-
const { homedir:
|
|
15315
|
-
const { join:
|
|
15316
|
-
const { chmod, copyFile: copyFile2, mkdir:
|
|
15317
|
-
const codexDir =
|
|
15318
|
-
const configPath =
|
|
15319
|
-
const envPath =
|
|
15378
|
+
const { homedir: homedir6 } = await import("node:os");
|
|
15379
|
+
const { join: join8 } = await import("node:path");
|
|
15380
|
+
const { chmod, copyFile: copyFile2, mkdir: mkdir6, readFile: readFile5, writeFile: writeFile5 } = await import("node:fs/promises");
|
|
15381
|
+
const codexDir = join8(homedir6(), ".codex");
|
|
15382
|
+
const configPath = join8(codexDir, "config.toml");
|
|
15383
|
+
const envPath = join8(codexDir, ".env");
|
|
15320
15384
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
15321
|
-
await
|
|
15385
|
+
await mkdir6(codexDir, { recursive: true });
|
|
15322
15386
|
const existingConfig = await pathExists(configPath) ? await readFile5(configPath, "utf8") : "";
|
|
15323
15387
|
if (existingConfig.trim()) {
|
|
15324
15388
|
await copyFile2(configPath, `${configPath}.bak.${timestamp}`);
|
|
@@ -15614,12 +15678,12 @@ var installCommand = new Command("install").description("Generate MCP configurat
|
|
|
15614
15678
|
process.stdout.write(configJson2 + "\n");
|
|
15615
15679
|
return;
|
|
15616
15680
|
}
|
|
15617
|
-
const { homedir:
|
|
15618
|
-
const { join:
|
|
15619
|
-
const { mkdir:
|
|
15620
|
-
const geminiDir =
|
|
15621
|
-
const mcpPath =
|
|
15622
|
-
await
|
|
15681
|
+
const { homedir: homedir6 } = await import("node:os");
|
|
15682
|
+
const { join: join9 } = await import("node:path");
|
|
15683
|
+
const { mkdir: mkdir6, readFile: readFile5, writeFile: writeFile6 } = await import("node:fs/promises");
|
|
15684
|
+
const geminiDir = join9(homedir6(), ".gemini");
|
|
15685
|
+
const mcpPath = join9(geminiDir, "settings.json");
|
|
15686
|
+
await mkdir6(geminiDir, { recursive: true });
|
|
15623
15687
|
let existingConfig = {};
|
|
15624
15688
|
try {
|
|
15625
15689
|
const content = await readFile5(mcpPath, "utf-8");
|
|
@@ -15640,14 +15704,14 @@ var installCommand = new Command("install").description("Generate MCP configurat
|
|
|
15640
15704
|
"utf-8"
|
|
15641
15705
|
);
|
|
15642
15706
|
fmt.success(`Wrote gemini MCP config to ${mcpPath}`);
|
|
15643
|
-
const agyMcpDir =
|
|
15707
|
+
const agyMcpDir = join9(
|
|
15644
15708
|
geminiDir,
|
|
15645
15709
|
"antigravity-cli",
|
|
15646
15710
|
"mcp",
|
|
15647
15711
|
MCP_SERVER_NAME
|
|
15648
15712
|
);
|
|
15649
|
-
await
|
|
15650
|
-
const instructionsPath =
|
|
15713
|
+
await mkdir6(agyMcpDir, { recursive: true });
|
|
15714
|
+
const instructionsPath = join9(agyMcpDir, "instructions.md");
|
|
15651
15715
|
const instructionsContent = `You are connected to greatarrow.ai - the user's private workspace memory + integrations brain.
|
|
15652
15716
|
|
|
15653
15717
|
CRITICAL DIRECTIVE (MANDATORY STANDARD):
|
|
@@ -15679,8 +15743,8 @@ Always assume full autonomy to leverage these tools to their maximum extent.`;
|
|
|
15679
15743
|
return;
|
|
15680
15744
|
}
|
|
15681
15745
|
const { writeFile: writeFile5 } = await import("node:fs/promises");
|
|
15682
|
-
const { join:
|
|
15683
|
-
const outputPath =
|
|
15746
|
+
const { join: join8 } = await import("node:path");
|
|
15747
|
+
const outputPath = join8(process.cwd(), ".mcp.json");
|
|
15684
15748
|
await writeFile5(outputPath, configJson + "\n", { mode: 384 });
|
|
15685
15749
|
fmt.success(`Wrote ${clientName} MCP config to .mcp.json`);
|
|
15686
15750
|
if (await mcpJsonAtRiskOfCommit(process.cwd())) {
|
|
@@ -15711,13 +15775,13 @@ async function readKeychainOnly() {
|
|
|
15711
15775
|
}
|
|
15712
15776
|
}
|
|
15713
15777
|
async function resolveProxyScript(override) {
|
|
15714
|
-
const { homedir:
|
|
15715
|
-
const { join:
|
|
15778
|
+
const { homedir: homedir6 } = await import("node:os");
|
|
15779
|
+
const { join: join8 } = await import("node:path");
|
|
15716
15780
|
const candidates = [
|
|
15717
15781
|
override,
|
|
15718
15782
|
process.env.GAD_PROXY_SCRIPT,
|
|
15719
|
-
|
|
15720
|
-
|
|
15783
|
+
join8(homedir6(), ".great-arrow", "mcp-server.mjs"),
|
|
15784
|
+
join8(process.cwd(), "scripts", "mcp-server.mjs")
|
|
15721
15785
|
].filter((c) => Boolean(c));
|
|
15722
15786
|
for (const candidate of candidates) {
|
|
15723
15787
|
if (await pathExists(candidate)) return candidate;
|
|
@@ -15741,13 +15805,13 @@ async function runProxyDiagnostics(scriptPath) {
|
|
|
15741
15805
|
}
|
|
15742
15806
|
}
|
|
15743
15807
|
async function findLegacyStores(cwd) {
|
|
15744
|
-
const { join:
|
|
15808
|
+
const { join: join8 } = await import("node:path");
|
|
15745
15809
|
const { readdir } = await import("node:fs/promises");
|
|
15746
15810
|
const dirs = /* @__PURE__ */ new Set([cwd]);
|
|
15747
15811
|
try {
|
|
15748
|
-
const worktreeRoot =
|
|
15812
|
+
const worktreeRoot = join8(cwd, ".claude", "worktrees");
|
|
15749
15813
|
for (const entry of await readdir(worktreeRoot, { withFileTypes: true })) {
|
|
15750
|
-
if (entry.isDirectory()) dirs.add(
|
|
15814
|
+
if (entry.isDirectory()) dirs.add(join8(worktreeRoot, entry.name));
|
|
15751
15815
|
}
|
|
15752
15816
|
} catch (err) {
|
|
15753
15817
|
debugSwallow("mcp.findLegacyStores(worktrees)", err);
|
|
@@ -15769,18 +15833,18 @@ async function findLegacyStores(cwd) {
|
|
|
15769
15833
|
}
|
|
15770
15834
|
const stores = [];
|
|
15771
15835
|
for (const dir of dirs) {
|
|
15772
|
-
const path10 =
|
|
15836
|
+
const path10 = join8(dir, ".mcp", OAUTH_CRED_FILENAME);
|
|
15773
15837
|
const raw = await readIfExists(path10);
|
|
15774
15838
|
if (raw !== null) stores.push({ path: path10, raw });
|
|
15775
15839
|
}
|
|
15776
15840
|
return stores;
|
|
15777
15841
|
}
|
|
15778
15842
|
async function scanConnections() {
|
|
15779
|
-
const { homedir:
|
|
15780
|
-
const { join:
|
|
15781
|
-
const home =
|
|
15843
|
+
const { homedir: homedir6 } = await import("node:os");
|
|
15844
|
+
const { join: join8 } = await import("node:path");
|
|
15845
|
+
const home = homedir6();
|
|
15782
15846
|
const hookSettings = await readIfExists(
|
|
15783
|
-
|
|
15847
|
+
join8(home, ".claude", "settings.json")
|
|
15784
15848
|
);
|
|
15785
15849
|
const hooksInstalled = hookSettings ? hasGreatArrowHooks(hookSettings) : false;
|
|
15786
15850
|
const entries = [];
|
|
@@ -15813,16 +15877,16 @@ async function probeEndpoint() {
|
|
|
15813
15877
|
}
|
|
15814
15878
|
}
|
|
15815
15879
|
async function applyMigration(plan) {
|
|
15816
|
-
const { homedir:
|
|
15817
|
-
const { join:
|
|
15818
|
-
const { mkdir:
|
|
15880
|
+
const { homedir: homedir6 } = await import("node:os");
|
|
15881
|
+
const { join: join8 } = await import("node:path");
|
|
15882
|
+
const { mkdir: mkdir6, rename, writeFile: writeFile5 } = await import("node:fs/promises");
|
|
15819
15883
|
const applied = [];
|
|
15820
|
-
const dir =
|
|
15821
|
-
await
|
|
15884
|
+
const dir = join8(homedir6(), ".great-arrow");
|
|
15885
|
+
await mkdir6(dir, { recursive: true, mode: 448 });
|
|
15822
15886
|
if (plan.seedFrom) {
|
|
15823
15887
|
const raw = await readIfExists(plan.seedFrom);
|
|
15824
15888
|
if (raw !== null) {
|
|
15825
|
-
const target =
|
|
15889
|
+
const target = join8(dir, OAUTH_CRED_FILENAME);
|
|
15826
15890
|
const tmp = `${target}.tmp`;
|
|
15827
15891
|
await writeFile5(tmp, raw, { mode: 384 });
|
|
15828
15892
|
await rename(tmp, target);
|
|
@@ -15832,7 +15896,7 @@ async function applyMigration(plan) {
|
|
|
15832
15896
|
if (plan.syncKeychainToFile) {
|
|
15833
15897
|
const raw = await readKeychainOnly();
|
|
15834
15898
|
if (raw) {
|
|
15835
|
-
const target =
|
|
15899
|
+
const target = join8(dir, "credential");
|
|
15836
15900
|
const tmp = `${target}.tmp`;
|
|
15837
15901
|
await writeFile5(tmp, raw, { mode: 384 });
|
|
15838
15902
|
await rename(tmp, target);
|
|
@@ -15858,19 +15922,19 @@ var doctorSubcommand = new Command("doctor").description(
|
|
|
15858
15922
|
noColor: false
|
|
15859
15923
|
});
|
|
15860
15924
|
const c = createColor(jsonFlag);
|
|
15861
|
-
const { homedir:
|
|
15862
|
-
const { join:
|
|
15863
|
-
const home =
|
|
15925
|
+
const { homedir: homedir6 } = await import("node:os");
|
|
15926
|
+
const { join: join8 } = await import("node:path");
|
|
15927
|
+
const home = homedir6();
|
|
15864
15928
|
const proxyPath = await resolveProxyScript(options.proxy);
|
|
15865
15929
|
const diagnostics = proxyPath ? await runProxyDiagnostics(proxyPath) : null;
|
|
15866
15930
|
const entries = await scanConnections();
|
|
15867
15931
|
const duplicates = detectDuplicates(entries);
|
|
15868
15932
|
const keychain = await readKeychainOnly();
|
|
15869
15933
|
const credentialFile = await readIfExists(
|
|
15870
|
-
|
|
15934
|
+
join8(home, ".great-arrow", "credential")
|
|
15871
15935
|
);
|
|
15872
15936
|
const userStore = await readIfExists(
|
|
15873
|
-
|
|
15937
|
+
join8(home, ".great-arrow", OAUTH_CRED_FILENAME)
|
|
15874
15938
|
);
|
|
15875
15939
|
const legacyStores = await findLegacyStores(process.cwd());
|
|
15876
15940
|
const findings = [
|
|
@@ -16287,9 +16351,9 @@ function askCommand() {
|
|
|
16287
16351
|
}
|
|
16288
16352
|
|
|
16289
16353
|
// src/lib/glance-footer.ts
|
|
16290
|
-
import { readFile as readFile4, writeFile as writeFile4, mkdir as
|
|
16291
|
-
import { homedir as
|
|
16292
|
-
import { join as
|
|
16354
|
+
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir5 } from "node:fs/promises";
|
|
16355
|
+
import { homedir as homedir5 } from "node:os";
|
|
16356
|
+
import { join as join7, dirname as dirname5 } from "node:path";
|
|
16293
16357
|
|
|
16294
16358
|
// src/lib/seen.ts
|
|
16295
16359
|
var SEEN_TIMEOUT_MS = 1e3;
|
|
@@ -16327,7 +16391,11 @@ async function reportSeen(opts) {
|
|
|
16327
16391
|
}
|
|
16328
16392
|
|
|
16329
16393
|
// src/lib/glance-footer.ts
|
|
16330
|
-
var
|
|
16394
|
+
var BASE_FETCH_TIMEOUT_MS = 1500;
|
|
16395
|
+
var TIP_FETCH_TIMEOUT_MS = 6e3;
|
|
16396
|
+
function fetchBudgetMs(askForTip) {
|
|
16397
|
+
return askForTip ? TIP_FETCH_TIMEOUT_MS : BASE_FETCH_TIMEOUT_MS;
|
|
16398
|
+
}
|
|
16331
16399
|
var THROTTLE_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
16332
16400
|
var TIP_THROTTLE_INTERVAL_MS = 20 * 60 * 60 * 1e3;
|
|
16333
16401
|
var URGENT_THRESHOLD = 15;
|
|
@@ -16341,8 +16409,20 @@ async function maybeShowGlanceFooter(argv) {
|
|
|
16341
16409
|
const entry = state[workspaceKey] ?? {};
|
|
16342
16410
|
const now = Date.now();
|
|
16343
16411
|
const askForTip = shouldRequestTip({ state: entry, now });
|
|
16344
|
-
const
|
|
16345
|
-
|
|
16412
|
+
const fetched = await fetchGlance(auth.apiUrl, auth.token, askForTip);
|
|
16413
|
+
const payload = fetched.payload;
|
|
16414
|
+
if (!payload) {
|
|
16415
|
+
if (fetched.tipMaybeSpent) {
|
|
16416
|
+
state[workspaceKey] = nextGlanceState(entry, {
|
|
16417
|
+
now,
|
|
16418
|
+
tipMaybeSpent: true,
|
|
16419
|
+
showNeedsYou: false,
|
|
16420
|
+
topItemId: null
|
|
16421
|
+
});
|
|
16422
|
+
await saveGlanceState(state);
|
|
16423
|
+
}
|
|
16424
|
+
return;
|
|
16425
|
+
}
|
|
16346
16426
|
const showNeedsYou = payload.urgency !== null && shouldShowGlance({
|
|
16347
16427
|
urgency: payload.urgency,
|
|
16348
16428
|
topItemId: topSignature(payload),
|
|
@@ -16350,14 +16430,22 @@ async function maybeShowGlanceFooter(argv) {
|
|
|
16350
16430
|
now
|
|
16351
16431
|
});
|
|
16352
16432
|
const tip = payload.tip;
|
|
16353
|
-
|
|
16433
|
+
const nextEntry = nextGlanceState(entry, {
|
|
16434
|
+
now,
|
|
16435
|
+
tipMaybeSpent: fetched.tipMaybeSpent,
|
|
16436
|
+
showNeedsYou,
|
|
16437
|
+
topItemId: topSignature(payload)
|
|
16438
|
+
});
|
|
16439
|
+
if (!showNeedsYou && !tip) {
|
|
16440
|
+
if (nextEntry !== entry) {
|
|
16441
|
+
state[workspaceKey] = nextEntry;
|
|
16442
|
+
await saveGlanceState(state);
|
|
16443
|
+
}
|
|
16444
|
+
return;
|
|
16445
|
+
}
|
|
16354
16446
|
const printed = showNeedsYou ? renderFooter(payload, auth.apiUrl) : [];
|
|
16355
16447
|
if (tip) renderTip(tip, auth.apiUrl);
|
|
16356
|
-
state[workspaceKey] =
|
|
16357
|
-
...entry,
|
|
16358
|
-
...showNeedsYou ? { lastShownAt: now, lastTopItemId: topSignature(payload) } : {},
|
|
16359
|
-
...tip ? { lastTipAt: now } : {}
|
|
16360
|
-
};
|
|
16448
|
+
state[workspaceKey] = nextEntry;
|
|
16361
16449
|
await saveGlanceState(state);
|
|
16362
16450
|
await reportSeen({
|
|
16363
16451
|
apiUrl: auth.apiUrl,
|
|
@@ -16389,7 +16477,8 @@ function firstCommand(argv) {
|
|
|
16389
16477
|
}
|
|
16390
16478
|
async function fetchGlance(apiUrl, token, includeTip) {
|
|
16391
16479
|
const controller = new AbortController();
|
|
16392
|
-
const timer = setTimeout(() => controller.abort(),
|
|
16480
|
+
const timer = setTimeout(() => controller.abort(), fetchBudgetMs(includeTip));
|
|
16481
|
+
let tipMaybeSpent = includeTip;
|
|
16393
16482
|
try {
|
|
16394
16483
|
const response = await fetch(`${apiUrl}/api/mcp`, {
|
|
16395
16484
|
method: "POST",
|
|
@@ -16410,14 +16499,20 @@ async function fetchGlance(apiUrl, token, includeTip) {
|
|
|
16410
16499
|
}),
|
|
16411
16500
|
signal: controller.signal
|
|
16412
16501
|
});
|
|
16413
|
-
if (!response.ok)
|
|
16502
|
+
if (!response.ok) {
|
|
16503
|
+
tipMaybeSpent = false;
|
|
16504
|
+
return { payload: null, tipMaybeSpent };
|
|
16505
|
+
}
|
|
16414
16506
|
const data = await response.json();
|
|
16415
|
-
if (data.error) return null;
|
|
16416
|
-
return
|
|
16417
|
-
|
|
16418
|
-
|
|
16507
|
+
if (data.error) return { payload: null, tipMaybeSpent };
|
|
16508
|
+
return {
|
|
16509
|
+
payload: normalizeGlance(
|
|
16510
|
+
parseMcpPayload(data.result?.content ?? data.result)
|
|
16511
|
+
),
|
|
16512
|
+
tipMaybeSpent
|
|
16513
|
+
};
|
|
16419
16514
|
} catch {
|
|
16420
|
-
return null;
|
|
16515
|
+
return { payload: null, tipMaybeSpent };
|
|
16421
16516
|
} finally {
|
|
16422
16517
|
clearTimeout(timer);
|
|
16423
16518
|
}
|
|
@@ -16566,6 +16661,15 @@ function topSignature(payload) {
|
|
|
16566
16661
|
if (payload.topGoal) return `goal:${payload.topGoal.title}`;
|
|
16567
16662
|
return "empty";
|
|
16568
16663
|
}
|
|
16664
|
+
function nextGlanceState(entry, input) {
|
|
16665
|
+
const { now, tipMaybeSpent, showNeedsYou, topItemId } = input;
|
|
16666
|
+
if (!tipMaybeSpent && !showNeedsYou) return entry;
|
|
16667
|
+
return {
|
|
16668
|
+
...entry,
|
|
16669
|
+
...showNeedsYou && topItemId !== null ? { lastShownAt: now, lastTopItemId: topItemId } : {},
|
|
16670
|
+
...tipMaybeSpent ? { lastTipAt: now } : {}
|
|
16671
|
+
};
|
|
16672
|
+
}
|
|
16569
16673
|
function shouldShowGlance(input) {
|
|
16570
16674
|
const { urgency, topItemId, state, now } = input;
|
|
16571
16675
|
if (urgency > URGENT_THRESHOLD) return false;
|
|
@@ -16579,7 +16683,7 @@ function shouldRequestTip(input) {
|
|
|
16579
16683
|
return now - state.lastTipAt >= TIP_THROTTLE_INTERVAL_MS;
|
|
16580
16684
|
}
|
|
16581
16685
|
function getGlanceStatePath() {
|
|
16582
|
-
return
|
|
16686
|
+
return join7(homedir5(), ".gad", "glance-state.json");
|
|
16583
16687
|
}
|
|
16584
16688
|
async function loadGlanceState() {
|
|
16585
16689
|
try {
|
|
@@ -16595,7 +16699,7 @@ async function loadGlanceState() {
|
|
|
16595
16699
|
}
|
|
16596
16700
|
async function saveGlanceState(state) {
|
|
16597
16701
|
const path10 = getGlanceStatePath();
|
|
16598
|
-
await
|
|
16702
|
+
await mkdir5(dirname5(path10), { recursive: true });
|
|
16599
16703
|
await writeFile4(path10, JSON.stringify(state), "utf-8");
|
|
16600
16704
|
}
|
|
16601
16705
|
function glanceItemUrl(href, apiUrl) {
|
|
@@ -19640,18 +19744,18 @@ var proto = Object.defineProperties(() => {
|
|
|
19640
19744
|
}
|
|
19641
19745
|
}
|
|
19642
19746
|
});
|
|
19643
|
-
var createStyler = (
|
|
19747
|
+
var createStyler = (open2, close, parent) => {
|
|
19644
19748
|
let openAll;
|
|
19645
19749
|
let closeAll;
|
|
19646
19750
|
if (parent === void 0) {
|
|
19647
|
-
openAll =
|
|
19751
|
+
openAll = open2;
|
|
19648
19752
|
closeAll = close;
|
|
19649
19753
|
} else {
|
|
19650
|
-
openAll = parent.openAll +
|
|
19754
|
+
openAll = parent.openAll + open2;
|
|
19651
19755
|
closeAll = close + parent.closeAll;
|
|
19652
19756
|
}
|
|
19653
19757
|
return {
|
|
19654
|
-
open,
|
|
19758
|
+
open: open2,
|
|
19655
19759
|
close,
|
|
19656
19760
|
openAll,
|
|
19657
19761
|
closeAll,
|