@great-arrow/cli 0.1.11 → 0.1.12
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/README.md +1 -1
- package/dist/index.js +384 -40
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -186,7 +186,7 @@ When stdout is not a TTY (piped), colors and interactive prompts are automatical
|
|
|
186
186
|
Optional config file at `~/.gadrc`:
|
|
187
187
|
|
|
188
188
|
```ini
|
|
189
|
-
api_url = https://www.
|
|
189
|
+
api_url = https://www.greatarrow.ai
|
|
190
190
|
default_workspace = my-project
|
|
191
191
|
output_format = table
|
|
192
192
|
token = gad_xxxxx
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,11 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
14
14
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
15
15
|
});
|
|
16
16
|
var __commonJS = (cb, mod) => function __require2() {
|
|
17
|
-
|
|
17
|
+
try {
|
|
18
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
19
|
+
} catch (e) {
|
|
20
|
+
throw mod = 0, e;
|
|
21
|
+
}
|
|
18
22
|
};
|
|
19
23
|
var __copyProps = (to, from, except, desc) => {
|
|
20
24
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -3818,8 +3822,8 @@ var require_graceful_fs = __commonJS({
|
|
|
3818
3822
|
fs6.createReadStream = createReadStream;
|
|
3819
3823
|
fs6.createWriteStream = createWriteStream;
|
|
3820
3824
|
var fs$readFile = fs6.readFile;
|
|
3821
|
-
fs6.readFile =
|
|
3822
|
-
function
|
|
3825
|
+
fs6.readFile = readFile4;
|
|
3826
|
+
function readFile4(path9, options, cb) {
|
|
3823
3827
|
if (typeof options === "function")
|
|
3824
3828
|
cb = options, options = null;
|
|
3825
3829
|
return go$readFile(path9, options, cb);
|
|
@@ -3835,8 +3839,8 @@ var require_graceful_fs = __commonJS({
|
|
|
3835
3839
|
}
|
|
3836
3840
|
}
|
|
3837
3841
|
var fs$writeFile = fs6.writeFile;
|
|
3838
|
-
fs6.writeFile =
|
|
3839
|
-
function
|
|
3842
|
+
fs6.writeFile = writeFile4;
|
|
3843
|
+
function writeFile4(path9, data, options, cb) {
|
|
3840
3844
|
if (typeof options === "function")
|
|
3841
3845
|
cb = options, options = null;
|
|
3842
3846
|
return go$writeFile(path9, data, options, cb);
|
|
@@ -5253,7 +5257,7 @@ var require_minimist = __commonJS({
|
|
|
5253
5257
|
var require_rc = __commonJS({
|
|
5254
5258
|
"node_modules/.pnpm/rc@1.2.8/node_modules/rc/index.js"(exports, module) {
|
|
5255
5259
|
var cc = require_utils();
|
|
5256
|
-
var
|
|
5260
|
+
var join6 = __require("path").join;
|
|
5257
5261
|
var deepExtend = require_deep_extend();
|
|
5258
5262
|
var etc = "/etc";
|
|
5259
5263
|
var win = process.platform === "win32";
|
|
@@ -5278,15 +5282,15 @@ var require_rc = __commonJS({
|
|
|
5278
5282
|
}
|
|
5279
5283
|
if (!win)
|
|
5280
5284
|
[
|
|
5281
|
-
|
|
5282
|
-
|
|
5285
|
+
join6(etc, name, "config"),
|
|
5286
|
+
join6(etc, name + "rc")
|
|
5283
5287
|
].forEach(addConfigFile);
|
|
5284
5288
|
if (home)
|
|
5285
5289
|
[
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
+
join6(home, ".config", name, "config"),
|
|
5291
|
+
join6(home, ".config", name),
|
|
5292
|
+
join6(home, "." + name, "config"),
|
|
5293
|
+
join6(home, "." + name + "rc")
|
|
5290
5294
|
].forEach(addConfigFile);
|
|
5291
5295
|
addConfigFile(cc.find("." + name + "rc"));
|
|
5292
5296
|
if (env4.config) addConfigFile(env4.config);
|
|
@@ -5792,8 +5796,8 @@ var require_graceful_fs2 = __commonJS({
|
|
|
5792
5796
|
fs6.createReadStream = createReadStream;
|
|
5793
5797
|
fs6.createWriteStream = createWriteStream;
|
|
5794
5798
|
var fs$readFile = fs6.readFile;
|
|
5795
|
-
fs6.readFile =
|
|
5796
|
-
function
|
|
5799
|
+
fs6.readFile = readFile4;
|
|
5800
|
+
function readFile4(path9, options, cb) {
|
|
5797
5801
|
if (typeof options === "function")
|
|
5798
5802
|
cb = options, options = null;
|
|
5799
5803
|
return go$readFile(path9, options, cb);
|
|
@@ -5809,8 +5813,8 @@ var require_graceful_fs2 = __commonJS({
|
|
|
5809
5813
|
}
|
|
5810
5814
|
}
|
|
5811
5815
|
var fs$writeFile = fs6.writeFile;
|
|
5812
|
-
fs6.writeFile =
|
|
5813
|
-
function
|
|
5816
|
+
fs6.writeFile = writeFile4;
|
|
5817
|
+
function writeFile4(path9, data, options, cb) {
|
|
5814
5818
|
if (typeof options === "function")
|
|
5815
5819
|
cb = options, options = null;
|
|
5816
5820
|
return go$writeFile(path9, data, options, cb);
|
|
@@ -6624,11 +6628,11 @@ var require_util = __commonJS({
|
|
|
6624
6628
|
if (files.includes("node_modules") || files.includes("package.json") || files.includes("package.json5") || files.includes("package.yaml") || files.includes("pnpm-workspace.yaml")) {
|
|
6625
6629
|
return name2;
|
|
6626
6630
|
}
|
|
6627
|
-
const
|
|
6628
|
-
if (
|
|
6631
|
+
const dirname5 = path9.dirname(name2);
|
|
6632
|
+
if (dirname5 === name2) {
|
|
6629
6633
|
return original;
|
|
6630
6634
|
}
|
|
6631
|
-
return find(
|
|
6635
|
+
return find(dirname5, original);
|
|
6632
6636
|
} catch (error) {
|
|
6633
6637
|
if (name2 === original) {
|
|
6634
6638
|
if (error.code === "ENOENT") {
|
|
@@ -9309,8 +9313,8 @@ function isNodeError(value) {
|
|
|
9309
9313
|
|
|
9310
9314
|
// src/lib/version.ts
|
|
9311
9315
|
var CLI_PACKAGE_NAME = "@great-arrow/cli";
|
|
9312
|
-
var CLI_VERSION = "0.1.
|
|
9313
|
-
var GAD_INSTALL_VERSION = "2026.07.
|
|
9316
|
+
var CLI_VERSION = "0.1.12";
|
|
9317
|
+
var GAD_INSTALL_VERSION = "2026.07.11";
|
|
9314
9318
|
var GAD_INSTALL_MIN_VERSION = "2026.06.22";
|
|
9315
9319
|
var GAD_INSTALL_HEADER = "X-GAD-Install-Version";
|
|
9316
9320
|
var GAD_CLI_VERSION_HEADER = "X-GAD-CLI-Version";
|
|
@@ -9393,7 +9397,7 @@ import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
|
9393
9397
|
import { homedir } from "node:os";
|
|
9394
9398
|
import { join, dirname } from "node:path";
|
|
9395
9399
|
var DEFAULTS = {
|
|
9396
|
-
api_url: "https://www.
|
|
9400
|
+
api_url: "https://www.greatarrow.ai",
|
|
9397
9401
|
default_workspace: "",
|
|
9398
9402
|
output_format: "table",
|
|
9399
9403
|
token: "",
|
|
@@ -10039,7 +10043,7 @@ function createFormatter(options) {
|
|
|
10039
10043
|
}
|
|
10040
10044
|
|
|
10041
10045
|
// src/commands/login.ts
|
|
10042
|
-
var DEFAULT_API_URL = "https://www.
|
|
10046
|
+
var DEFAULT_API_URL = "https://www.greatarrow.ai";
|
|
10043
10047
|
function maskToken(token) {
|
|
10044
10048
|
if (token.length <= 8) return token + "...";
|
|
10045
10049
|
return token.slice(0, 8) + "...";
|
|
@@ -10139,7 +10143,7 @@ var logoutCommand = new Command("logout").description("Remove stored authenticat
|
|
|
10139
10143
|
});
|
|
10140
10144
|
|
|
10141
10145
|
// src/lib/auth.ts
|
|
10142
|
-
var DEFAULT_API_URL2 = "https://www.
|
|
10146
|
+
var DEFAULT_API_URL2 = "https://www.greatarrow.ai";
|
|
10143
10147
|
var REFRESH_SKEW_MS = 12e4;
|
|
10144
10148
|
var inflightRefresh = null;
|
|
10145
10149
|
async function resolveAuth() {
|
|
@@ -13357,28 +13361,28 @@ async function pathExists(path9) {
|
|
|
13357
13361
|
}
|
|
13358
13362
|
}
|
|
13359
13363
|
async function installCodexConfig(apiUrl, token, repoUrl) {
|
|
13360
|
-
const { homedir:
|
|
13361
|
-
const { join:
|
|
13362
|
-
const { chmod, copyFile: copyFile2, mkdir:
|
|
13363
|
-
const codexDir =
|
|
13364
|
-
const configPath =
|
|
13365
|
-
const envPath =
|
|
13364
|
+
const { homedir: homedir4 } = await import("node:os");
|
|
13365
|
+
const { join: join6 } = await import("node:path");
|
|
13366
|
+
const { chmod, copyFile: copyFile2, mkdir: mkdir4, readFile: readFile4, writeFile: writeFile4 } = await import("node:fs/promises");
|
|
13367
|
+
const codexDir = join6(homedir4(), ".codex");
|
|
13368
|
+
const configPath = join6(codexDir, "config.toml");
|
|
13369
|
+
const envPath = join6(codexDir, ".env");
|
|
13366
13370
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
13367
|
-
await
|
|
13368
|
-
const existingConfig = await pathExists(configPath) ? await
|
|
13371
|
+
await mkdir4(codexDir, { recursive: true });
|
|
13372
|
+
const existingConfig = await pathExists(configPath) ? await readFile4(configPath, "utf8") : "";
|
|
13369
13373
|
if (existingConfig.trim()) {
|
|
13370
13374
|
await copyFile2(configPath, `${configPath}.bak.${timestamp}`);
|
|
13371
13375
|
}
|
|
13372
|
-
await
|
|
13376
|
+
await writeFile4(
|
|
13373
13377
|
configPath,
|
|
13374
13378
|
upsertCodexServerBlock(existingConfig, apiUrl, repoUrl),
|
|
13375
13379
|
"utf8"
|
|
13376
13380
|
);
|
|
13377
|
-
const existingEnv = await pathExists(envPath) ? await
|
|
13381
|
+
const existingEnv = await pathExists(envPath) ? await readFile4(envPath, "utf8") : "";
|
|
13378
13382
|
if (existingEnv.trim()) {
|
|
13379
13383
|
await copyFile2(envPath, `${envPath}.bak.${timestamp}`);
|
|
13380
13384
|
}
|
|
13381
|
-
await
|
|
13385
|
+
await writeFile4(
|
|
13382
13386
|
envPath,
|
|
13383
13387
|
upsertEnvValue(existingEnv, "GREAT_ARROW_TOKEN", token),
|
|
13384
13388
|
"utf8"
|
|
@@ -13634,6 +13638,45 @@ var installCommand = new Command("install").description("Generate MCP configurat
|
|
|
13634
13638
|
);
|
|
13635
13639
|
return;
|
|
13636
13640
|
}
|
|
13641
|
+
if (clientName === "gemini") {
|
|
13642
|
+
const config2 = generateMcpConfig(
|
|
13643
|
+
clientName,
|
|
13644
|
+
auth.apiUrl,
|
|
13645
|
+
auth.token,
|
|
13646
|
+
repoUrl
|
|
13647
|
+
);
|
|
13648
|
+
const configJson2 = JSON.stringify(config2, null, 2);
|
|
13649
|
+
if (options.stdout) {
|
|
13650
|
+
process.stdout.write(configJson2 + "\n");
|
|
13651
|
+
return;
|
|
13652
|
+
}
|
|
13653
|
+
const { homedir: homedir4 } = await import("node:os");
|
|
13654
|
+
const { join: join7 } = await import("node:path");
|
|
13655
|
+
const { mkdir: mkdir4, readFile: readFile4, writeFile: writeFile5 } = await import("node:fs/promises");
|
|
13656
|
+
const geminiDir = join7(homedir4(), ".gemini");
|
|
13657
|
+
const mcpPath = join7(geminiDir, "settings.json");
|
|
13658
|
+
await mkdir4(geminiDir, { recursive: true });
|
|
13659
|
+
let existingConfig = {};
|
|
13660
|
+
try {
|
|
13661
|
+
const content = await readFile4(mcpPath, "utf-8");
|
|
13662
|
+
existingConfig = JSON.parse(content);
|
|
13663
|
+
} catch {
|
|
13664
|
+
}
|
|
13665
|
+
existingConfig = {
|
|
13666
|
+
...existingConfig,
|
|
13667
|
+
mcpServers: {
|
|
13668
|
+
...existingConfig.mcpServers || {},
|
|
13669
|
+
...config2.mcpServers
|
|
13670
|
+
}
|
|
13671
|
+
};
|
|
13672
|
+
await writeFile5(
|
|
13673
|
+
mcpPath,
|
|
13674
|
+
JSON.stringify(existingConfig, null, 2) + "\n",
|
|
13675
|
+
"utf-8"
|
|
13676
|
+
);
|
|
13677
|
+
fmt.success(`Wrote gemini MCP config to ${mcpPath}`);
|
|
13678
|
+
return;
|
|
13679
|
+
}
|
|
13637
13680
|
const config = generateMcpConfig(
|
|
13638
13681
|
clientName,
|
|
13639
13682
|
auth.apiUrl,
|
|
@@ -13645,10 +13688,10 @@ var installCommand = new Command("install").description("Generate MCP configurat
|
|
|
13645
13688
|
process.stdout.write(configJson + "\n");
|
|
13646
13689
|
return;
|
|
13647
13690
|
}
|
|
13648
|
-
const { writeFile:
|
|
13649
|
-
const { join:
|
|
13650
|
-
const outputPath =
|
|
13651
|
-
await
|
|
13691
|
+
const { writeFile: writeFile4 } = await import("node:fs/promises");
|
|
13692
|
+
const { join: join6 } = await import("node:path");
|
|
13693
|
+
const outputPath = join6(process.cwd(), ".mcp.json");
|
|
13694
|
+
await writeFile4(outputPath, configJson + "\n", "utf-8");
|
|
13652
13695
|
fmt.success(`Wrote ${clientName} MCP config to .mcp.json`);
|
|
13653
13696
|
}
|
|
13654
13697
|
);
|
|
@@ -14023,6 +14066,305 @@ function askCommand() {
|
|
|
14023
14066
|
return cmd;
|
|
14024
14067
|
}
|
|
14025
14068
|
|
|
14069
|
+
// src/lib/glance-footer.ts
|
|
14070
|
+
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "node:fs/promises";
|
|
14071
|
+
import { homedir as homedir3 } from "node:os";
|
|
14072
|
+
import { join as join5, dirname as dirname4 } from "node:path";
|
|
14073
|
+
var FETCH_TIMEOUT_MS = 1500;
|
|
14074
|
+
var THROTTLE_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
14075
|
+
var URGENT_THRESHOLD = 15;
|
|
14076
|
+
var SKIP_COMMANDS = /* @__PURE__ */ new Set(["status", "login", "logout", "help"]);
|
|
14077
|
+
async function maybeShowGlanceFooter(argv) {
|
|
14078
|
+
try {
|
|
14079
|
+
if (!shouldRunGlanceFooter(argv)) return;
|
|
14080
|
+
const auth = await resolveAuth();
|
|
14081
|
+
const payload = await fetchGlance(auth.apiUrl, auth.token);
|
|
14082
|
+
if (!payload) return;
|
|
14083
|
+
if (payload.urgency === null) return;
|
|
14084
|
+
const workspaceKey = auth.activeWorkspace ?? "default";
|
|
14085
|
+
const signature = topSignature(payload);
|
|
14086
|
+
const state = await loadGlanceState();
|
|
14087
|
+
const now = Date.now();
|
|
14088
|
+
if (!shouldShowGlance({
|
|
14089
|
+
urgency: payload.urgency,
|
|
14090
|
+
topItemId: signature,
|
|
14091
|
+
state: state[workspaceKey] ?? {},
|
|
14092
|
+
now
|
|
14093
|
+
})) {
|
|
14094
|
+
return;
|
|
14095
|
+
}
|
|
14096
|
+
renderFooter(payload);
|
|
14097
|
+
state[workspaceKey] = { lastShownAt: now, lastTopItemId: signature };
|
|
14098
|
+
await saveGlanceState(state);
|
|
14099
|
+
} catch {
|
|
14100
|
+
}
|
|
14101
|
+
}
|
|
14102
|
+
function shouldRunGlanceFooter(argv) {
|
|
14103
|
+
if (!process.stderr.isTTY) return false;
|
|
14104
|
+
if (process.env.CI) return false;
|
|
14105
|
+
if (process.env.GAD_NO_GLANCE) return false;
|
|
14106
|
+
if (argv.includes("--json")) return false;
|
|
14107
|
+
if (argv.includes("--quiet")) return false;
|
|
14108
|
+
if (argv.includes("--stdout")) return false;
|
|
14109
|
+
if (argv.includes("--no-glance")) return false;
|
|
14110
|
+
const command = firstCommand(argv);
|
|
14111
|
+
if (!command) return false;
|
|
14112
|
+
if (SKIP_COMMANDS.has(command)) return false;
|
|
14113
|
+
return true;
|
|
14114
|
+
}
|
|
14115
|
+
function firstCommand(argv) {
|
|
14116
|
+
for (const token of argv.slice(2)) {
|
|
14117
|
+
if (!token.startsWith("-")) return token;
|
|
14118
|
+
}
|
|
14119
|
+
return null;
|
|
14120
|
+
}
|
|
14121
|
+
async function fetchGlance(apiUrl, token) {
|
|
14122
|
+
const controller = new AbortController();
|
|
14123
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
14124
|
+
try {
|
|
14125
|
+
const response = await fetch(`${apiUrl}/api/mcp`, {
|
|
14126
|
+
method: "POST",
|
|
14127
|
+
headers: {
|
|
14128
|
+
"Content-Type": "application/json",
|
|
14129
|
+
Authorization: `Bearer ${token}`
|
|
14130
|
+
},
|
|
14131
|
+
body: JSON.stringify({
|
|
14132
|
+
jsonrpc: "2.0",
|
|
14133
|
+
id: `cli-glance-${Date.now()}`,
|
|
14134
|
+
method: "tools/call",
|
|
14135
|
+
params: { name: "glance", arguments: {} }
|
|
14136
|
+
}),
|
|
14137
|
+
signal: controller.signal
|
|
14138
|
+
});
|
|
14139
|
+
if (!response.ok) return null;
|
|
14140
|
+
const data = await response.json();
|
|
14141
|
+
if (data.error) return null;
|
|
14142
|
+
return normalizeGlance(
|
|
14143
|
+
parseMcpPayload(data.result?.content ?? data.result)
|
|
14144
|
+
);
|
|
14145
|
+
} catch {
|
|
14146
|
+
return null;
|
|
14147
|
+
} finally {
|
|
14148
|
+
clearTimeout(timer);
|
|
14149
|
+
}
|
|
14150
|
+
}
|
|
14151
|
+
function normalizeGlance(raw) {
|
|
14152
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
14153
|
+
const obj = raw;
|
|
14154
|
+
const needsYou = asArray2(obj.needsYou).flatMap((item) => {
|
|
14155
|
+
if (typeof item !== "object" || item === null) return [];
|
|
14156
|
+
const it = item;
|
|
14157
|
+
if (typeof it.title !== "string") return [];
|
|
14158
|
+
return [
|
|
14159
|
+
{
|
|
14160
|
+
kind: typeof it.kind === "string" ? it.kind : "nudge",
|
|
14161
|
+
title: it.title,
|
|
14162
|
+
action: typeof it.action === "string" ? it.action : null,
|
|
14163
|
+
...typeof it.rank === "number" ? { rank: it.rank } : {}
|
|
14164
|
+
}
|
|
14165
|
+
];
|
|
14166
|
+
});
|
|
14167
|
+
const integrations = asArray2(obj.integrations).flatMap((item) => {
|
|
14168
|
+
if (typeof item !== "object" || item === null) return [];
|
|
14169
|
+
const it = item;
|
|
14170
|
+
if (typeof it.kind !== "string") return [];
|
|
14171
|
+
return [
|
|
14172
|
+
{
|
|
14173
|
+
kind: it.kind,
|
|
14174
|
+
staleFor: typeof it.staleFor === "string" ? it.staleFor : null,
|
|
14175
|
+
refresh: typeof it.refresh === "string" ? it.refresh : null
|
|
14176
|
+
}
|
|
14177
|
+
];
|
|
14178
|
+
});
|
|
14179
|
+
const agents = asArray2(obj.agents).flatMap((item) => {
|
|
14180
|
+
if (typeof item !== "object" || item === null) return [];
|
|
14181
|
+
const it = item;
|
|
14182
|
+
if (typeof it.name !== "string") return [];
|
|
14183
|
+
return [
|
|
14184
|
+
{
|
|
14185
|
+
name: it.name,
|
|
14186
|
+
tool: typeof it.tool === "string" ? it.tool : null,
|
|
14187
|
+
card: typeof it.card === "string" ? it.card : null
|
|
14188
|
+
}
|
|
14189
|
+
];
|
|
14190
|
+
});
|
|
14191
|
+
let topGoal = null;
|
|
14192
|
+
if (typeof obj.topGoal === "object" && obj.topGoal !== null) {
|
|
14193
|
+
const g = obj.topGoal;
|
|
14194
|
+
if (typeof g.title === "string") {
|
|
14195
|
+
topGoal = {
|
|
14196
|
+
title: g.title,
|
|
14197
|
+
done: typeof g.done === "number" ? g.done : 0,
|
|
14198
|
+
total: typeof g.total === "number" ? g.total : 0,
|
|
14199
|
+
eta: typeof g.eta === "string" ? g.eta : null
|
|
14200
|
+
};
|
|
14201
|
+
}
|
|
14202
|
+
}
|
|
14203
|
+
return {
|
|
14204
|
+
needsYou,
|
|
14205
|
+
topGoal,
|
|
14206
|
+
integrations,
|
|
14207
|
+
agents,
|
|
14208
|
+
urgency: typeof obj.urgency === "number" ? obj.urgency : null,
|
|
14209
|
+
generatedAt: typeof obj.generatedAt === "string" ? obj.generatedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
14210
|
+
};
|
|
14211
|
+
}
|
|
14212
|
+
function asArray2(value) {
|
|
14213
|
+
return Array.isArray(value) ? value : [];
|
|
14214
|
+
}
|
|
14215
|
+
function topSignature(payload) {
|
|
14216
|
+
const top = payload.needsYou[0];
|
|
14217
|
+
if (top) return `needs:${top.kind}:${top.title}`;
|
|
14218
|
+
const integration = payload.integrations[0];
|
|
14219
|
+
if (integration) return `stale:${integration.kind}`;
|
|
14220
|
+
const agent = payload.agents[0];
|
|
14221
|
+
if (agent) return `agent:${agent.name}`;
|
|
14222
|
+
if (payload.topGoal) return `goal:${payload.topGoal.title}`;
|
|
14223
|
+
return "empty";
|
|
14224
|
+
}
|
|
14225
|
+
function shouldShowGlance(input) {
|
|
14226
|
+
const { urgency, topItemId, state, now } = input;
|
|
14227
|
+
if (urgency > URGENT_THRESHOLD) return false;
|
|
14228
|
+
if (state.lastShownAt === void 0) return true;
|
|
14229
|
+
if (state.lastTopItemId !== topItemId) return true;
|
|
14230
|
+
return now - state.lastShownAt >= THROTTLE_INTERVAL_MS;
|
|
14231
|
+
}
|
|
14232
|
+
function getGlanceStatePath() {
|
|
14233
|
+
return join5(homedir3(), ".gad", "glance-state.json");
|
|
14234
|
+
}
|
|
14235
|
+
async function loadGlanceState() {
|
|
14236
|
+
try {
|
|
14237
|
+
const content = await readFile3(getGlanceStatePath(), "utf-8");
|
|
14238
|
+
const parsed = JSON.parse(content);
|
|
14239
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
14240
|
+
return parsed;
|
|
14241
|
+
}
|
|
14242
|
+
return {};
|
|
14243
|
+
} catch {
|
|
14244
|
+
return {};
|
|
14245
|
+
}
|
|
14246
|
+
}
|
|
14247
|
+
async function saveGlanceState(state) {
|
|
14248
|
+
const path9 = getGlanceStatePath();
|
|
14249
|
+
await mkdir3(dirname4(path9), { recursive: true });
|
|
14250
|
+
await writeFile3(path9, JSON.stringify(state), "utf-8");
|
|
14251
|
+
}
|
|
14252
|
+
function renderFooter(payload) {
|
|
14253
|
+
const c = createColor(false);
|
|
14254
|
+
const lines = [];
|
|
14255
|
+
for (const item of payload.needsYou.slice(0, 2)) {
|
|
14256
|
+
lines.push(`${c.yellow("!")} ${item.title}`);
|
|
14257
|
+
if (item.action) lines.push(` ${c.dim("\u2192")} ${c.cyan(item.action)}`);
|
|
14258
|
+
}
|
|
14259
|
+
if (lines.length === 0) {
|
|
14260
|
+
const integration = payload.integrations[0];
|
|
14261
|
+
if (integration) {
|
|
14262
|
+
const stale = integration.staleFor ? ` (stale ${integration.staleFor})` : "";
|
|
14263
|
+
lines.push(`${c.yellow("!")} ${integration.kind}${stale}`);
|
|
14264
|
+
if (integration.refresh) {
|
|
14265
|
+
lines.push(` ${c.dim("\u2192")} ${c.cyan(integration.refresh)}`);
|
|
14266
|
+
}
|
|
14267
|
+
}
|
|
14268
|
+
}
|
|
14269
|
+
if (lines.length === 0) return;
|
|
14270
|
+
lines.push(`${c.dim("\u2192")} ${c.cyan("gad status")} for the full picture.`);
|
|
14271
|
+
process.stderr.write("\n" + brandedBlock("needs you", lines) + "\n");
|
|
14272
|
+
}
|
|
14273
|
+
function brandedBlock(title, lines) {
|
|
14274
|
+
const header = `\u{1F3F9} Great Arrow \xB7 ${title}`;
|
|
14275
|
+
const rule = "\u2500".repeat(Math.min(60, header.length));
|
|
14276
|
+
return [header, rule, ...lines].join("\n");
|
|
14277
|
+
}
|
|
14278
|
+
|
|
14279
|
+
// src/commands/status.ts
|
|
14280
|
+
function statusCommand2() {
|
|
14281
|
+
const cmd = new Command("status").description(
|
|
14282
|
+
"Show what needs you: blockers, Goal progress, stale data, agents"
|
|
14283
|
+
).option("--json", "Output the raw glance payload as JSON").option("--quiet", "Suppress decorative output").option("--no-color", "Disable color output").action(async (options, command) => {
|
|
14284
|
+
const g = globalOutputOpts(command);
|
|
14285
|
+
const auth = await resolveAuth();
|
|
14286
|
+
const client = new GadClient({
|
|
14287
|
+
token: auth.token,
|
|
14288
|
+
apiUrl: auth.apiUrl
|
|
14289
|
+
});
|
|
14290
|
+
const fmt = createFormatter({
|
|
14291
|
+
json: g.json,
|
|
14292
|
+
quiet: g.quiet,
|
|
14293
|
+
isTTY: isTTY(),
|
|
14294
|
+
noColor: options.color === false
|
|
14295
|
+
});
|
|
14296
|
+
let result;
|
|
14297
|
+
try {
|
|
14298
|
+
result = await client.mcpCall("glance", {});
|
|
14299
|
+
} catch {
|
|
14300
|
+
fmt.error(
|
|
14301
|
+
"Couldn't reach Great Arrow. Check your connection, or run 'gad doctor'."
|
|
14302
|
+
);
|
|
14303
|
+
return;
|
|
14304
|
+
}
|
|
14305
|
+
if (g.json) {
|
|
14306
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
14307
|
+
return;
|
|
14308
|
+
}
|
|
14309
|
+
const payload = normalizeGlance(result);
|
|
14310
|
+
if (!payload) {
|
|
14311
|
+
fmt.warn("No status available.");
|
|
14312
|
+
return;
|
|
14313
|
+
}
|
|
14314
|
+
renderStatus(payload, g.noColor || g.quiet);
|
|
14315
|
+
});
|
|
14316
|
+
return cmd;
|
|
14317
|
+
}
|
|
14318
|
+
function renderStatus(payload, plain) {
|
|
14319
|
+
const c = createColor(plain);
|
|
14320
|
+
const lines = [];
|
|
14321
|
+
const hasAny = payload.needsYou.length > 0 || payload.topGoal !== null || payload.integrations.length > 0 || payload.agents.length > 0;
|
|
14322
|
+
if (!hasAny) {
|
|
14323
|
+
lines.push(
|
|
14324
|
+
`${c.green("\u2713")} You're all clear \u2014 nothing needs you right now.`
|
|
14325
|
+
);
|
|
14326
|
+
process.stdout.write(brandedBlock("status", lines) + "\n");
|
|
14327
|
+
return;
|
|
14328
|
+
}
|
|
14329
|
+
if (payload.needsYou.length > 0) {
|
|
14330
|
+
lines.push(c.bold("Needs you"));
|
|
14331
|
+
for (const item of payload.needsYou) {
|
|
14332
|
+
lines.push(` ${c.yellow("!")} ${item.title}`);
|
|
14333
|
+
if (item.action) lines.push(` ${c.dim("\u2192")} ${c.cyan(item.action)}`);
|
|
14334
|
+
}
|
|
14335
|
+
lines.push("");
|
|
14336
|
+
}
|
|
14337
|
+
if (payload.topGoal) {
|
|
14338
|
+
const { title, done, total, eta } = payload.topGoal;
|
|
14339
|
+
const etaText = eta ? ` \xB7 ${eta}` : "";
|
|
14340
|
+
lines.push(c.bold("Top Goal"));
|
|
14341
|
+
lines.push(` ${title} \u2014 ${done} of ${total} done${etaText}`);
|
|
14342
|
+
lines.push(` ${c.dim("\u2192")} ${c.cyan("gad todo list")}`);
|
|
14343
|
+
lines.push("");
|
|
14344
|
+
}
|
|
14345
|
+
if (payload.integrations.length > 0) {
|
|
14346
|
+
lines.push(c.bold("Stale integrations"));
|
|
14347
|
+
for (const integration of payload.integrations) {
|
|
14348
|
+
const stale = integration.staleFor ? ` (stale ${integration.staleFor})` : "";
|
|
14349
|
+
lines.push(` ${c.yellow("!")} ${integration.kind}${stale}`);
|
|
14350
|
+
const refresh = integration.refresh ?? `gad integrations sync ${integration.kind}`;
|
|
14351
|
+
lines.push(` ${c.dim("\u2192")} ${c.cyan(refresh)}`);
|
|
14352
|
+
}
|
|
14353
|
+
lines.push("");
|
|
14354
|
+
}
|
|
14355
|
+
if (payload.agents.length > 0) {
|
|
14356
|
+
lines.push(c.bold("Agents active"));
|
|
14357
|
+
for (const agent of payload.agents) {
|
|
14358
|
+
const detail = [agent.tool, agent.card].filter(Boolean).join(" \xB7 ");
|
|
14359
|
+
lines.push(` ${agent.name}${detail ? ` \xB7 ${detail}` : ""}`);
|
|
14360
|
+
}
|
|
14361
|
+
lines.push(` ${c.dim("\u2192")} ${c.cyan("gad work status")}`);
|
|
14362
|
+
lines.push("");
|
|
14363
|
+
}
|
|
14364
|
+
while (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
14365
|
+
process.stdout.write(brandedBlock("status", lines) + "\n");
|
|
14366
|
+
}
|
|
14367
|
+
|
|
14026
14368
|
// src/lib/completions.ts
|
|
14027
14369
|
var COMMANDS = [
|
|
14028
14370
|
"login",
|
|
@@ -17642,7 +17984,7 @@ if (shouldRunUpdateNotifier(process.argv)) {
|
|
|
17642
17984
|
pkg: { name: CLI_PACKAGE_NAME, version: CLI_VERSION }
|
|
17643
17985
|
}).notify();
|
|
17644
17986
|
}
|
|
17645
|
-
var program2 = new Command().name("gad").description("Great Arrow Digital CLI \u2014 terminal access to the GAD platform").version(CLI_VERSION, "-v, --version").option("--json", "Output as JSON").option("--quiet", "Suppress decorative output").option("--no-color", "Disable color output");
|
|
17987
|
+
var program2 = new Command().name("gad").description("Great Arrow Digital CLI \u2014 terminal access to the GAD platform").version(CLI_VERSION, "-v, --version").option("--json", "Output as JSON").option("--quiet", "Suppress decorative output").option("--no-color", "Disable color output").option("--no-glance", "Suppress the ambient proactive footer");
|
|
17646
17988
|
program2.addCommand(login_default);
|
|
17647
17989
|
program2.addCommand(logoutCommand);
|
|
17648
17990
|
program2.addCommand(whoamiCommand());
|
|
@@ -17654,6 +17996,7 @@ program2.addCommand(work_default());
|
|
|
17654
17996
|
program2.addCommand(worktree_default);
|
|
17655
17997
|
program2.addCommand(install_hooks_default);
|
|
17656
17998
|
program2.addCommand(guardrailsCommand());
|
|
17999
|
+
program2.addCommand(statusCommand2());
|
|
17657
18000
|
program2.addCommand(doctorCommand());
|
|
17658
18001
|
program2.addCommand(integrations_default);
|
|
17659
18002
|
program2.addCommand(mcp_default);
|
|
@@ -17665,6 +18008,7 @@ program2.addCommand(smokeCommand());
|
|
|
17665
18008
|
program2.addCommand(completionsCommand());
|
|
17666
18009
|
try {
|
|
17667
18010
|
await program2.parseAsync(process.argv);
|
|
18011
|
+
await maybeShowGlanceFooter(process.argv);
|
|
17668
18012
|
} catch (error) {
|
|
17669
18013
|
if (error instanceof CliError) {
|
|
17670
18014
|
console.error(`Error: ${error.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@great-arrow/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Great Arrow Digital CLI tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^22.0.0",
|
|
25
|
-
"esbuild": "^0.28.
|
|
25
|
+
"esbuild": "^0.28.1",
|
|
26
26
|
"fast-check": "^4.7.0",
|
|
27
27
|
"vitest": "^4.1.5"
|
|
28
28
|
},
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"url": "git+https://github.com/Clapptastic/great-arrow-digital.git",
|
|
39
39
|
"directory": "packages/cli"
|
|
40
40
|
},
|
|
41
|
-
"homepage": "https://www.
|
|
41
|
+
"homepage": "https://www.greatarrow.ai",
|
|
42
42
|
"bugs": {
|
|
43
|
-
"url": "https://www.
|
|
43
|
+
"url": "https://www.greatarrow.ai/support"
|
|
44
44
|
},
|
|
45
|
-
"author": "Great Arrow Digital <support@
|
|
45
|
+
"author": "Great Arrow Digital <support@greatarrow.ai>",
|
|
46
46
|
"optionalDependencies": {
|
|
47
47
|
"keytar": "^7.9.0"
|
|
48
48
|
}
|