@great-arrow/cli 0.1.36 → 0.1.37

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.
Files changed (2) hide show
  1. package/dist/index.js +52 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -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.36";
9402
+ var CLI_VERSION = "0.1.37";
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";
@@ -16304,29 +16304,35 @@ async function reportSeen(opts) {
16304
16304
  // src/lib/glance-footer.ts
16305
16305
  var FETCH_TIMEOUT_MS = 1500;
16306
16306
  var THROTTLE_INTERVAL_MS = 4 * 60 * 60 * 1e3;
16307
+ var TIP_THROTTLE_INTERVAL_MS = 20 * 60 * 60 * 1e3;
16307
16308
  var URGENT_THRESHOLD = 15;
16308
16309
  var SKIP_COMMANDS = /* @__PURE__ */ new Set(["status", "needs", "login", "logout", "help"]);
16309
16310
  async function maybeShowGlanceFooter(argv) {
16310
16311
  try {
16311
16312
  if (!shouldRunGlanceFooter(argv)) return;
16312
16313
  const auth = await resolveAuth();
16313
- const payload = await fetchGlance(auth.apiUrl, auth.token);
16314
- if (!payload) return;
16315
- if (payload.urgency === null) return;
16316
16314
  const workspaceKey = auth.activeWorkspace ?? "default";
16317
- const signature = topSignature(payload);
16318
16315
  const state = await loadGlanceState();
16316
+ const entry = state[workspaceKey] ?? {};
16319
16317
  const now = Date.now();
16320
- if (!shouldShowGlance({
16318
+ const askForTip = shouldRequestTip({ state: entry, now });
16319
+ const payload = await fetchGlance(auth.apiUrl, auth.token, askForTip);
16320
+ if (!payload) return;
16321
+ const showNeedsYou = payload.urgency !== null && shouldShowGlance({
16321
16322
  urgency: payload.urgency,
16322
- topItemId: signature,
16323
- state: state[workspaceKey] ?? {},
16323
+ topItemId: topSignature(payload),
16324
+ state: entry,
16324
16325
  now
16325
- })) {
16326
- return;
16327
- }
16328
- const printed = renderFooter(payload, auth.apiUrl);
16329
- state[workspaceKey] = { lastShownAt: now, lastTopItemId: signature };
16326
+ });
16327
+ const tip = payload.tip;
16328
+ if (!showNeedsYou && !tip) return;
16329
+ const printed = showNeedsYou ? renderFooter(payload, auth.apiUrl) : [];
16330
+ if (tip) renderTip(tip, auth.apiUrl);
16331
+ state[workspaceKey] = {
16332
+ ...entry,
16333
+ ...showNeedsYou ? { lastShownAt: now, lastTopItemId: topSignature(payload) } : {},
16334
+ ...tip ? { lastTipAt: now } : {}
16335
+ };
16330
16336
  await saveGlanceState(state);
16331
16337
  await reportSeen({
16332
16338
  apiUrl: auth.apiUrl,
@@ -16356,7 +16362,7 @@ function firstCommand(argv) {
16356
16362
  }
16357
16363
  return null;
16358
16364
  }
16359
- async function fetchGlance(apiUrl, token) {
16365
+ async function fetchGlance(apiUrl, token, includeTip) {
16360
16366
  const controller = new AbortController();
16361
16367
  const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
16362
16368
  try {
@@ -16370,7 +16376,12 @@ async function fetchGlance(apiUrl, token) {
16370
16376
  jsonrpc: "2.0",
16371
16377
  id: `cli-glance-${Date.now()}`,
16372
16378
  method: "tools/call",
16373
- params: { name: "glance", arguments: {} }
16379
+ params: {
16380
+ name: "glance",
16381
+ // Omitted entirely rather than sent as `false`, so an older server
16382
+ // that does not know this argument sees the request it always saw.
16383
+ arguments: includeTip ? { include_tip: true } : {}
16384
+ }
16374
16385
  }),
16375
16386
  signal: controller.signal
16376
16387
  });
@@ -16472,7 +16483,20 @@ function normalizeGlance(raw) {
16472
16483
  newestPreview: typeof w.newestPreview === "string" ? w.newestPreview : null
16473
16484
  };
16474
16485
  }
16486
+ let tip = null;
16487
+ if (typeof obj.tip === "object" && obj.tip !== null) {
16488
+ const t = obj.tip;
16489
+ if (typeof t.text === "string" && t.text.trim() !== "") {
16490
+ tip = {
16491
+ id: typeof t.id === "string" ? t.id : "",
16492
+ text: t.text,
16493
+ deepLink: typeof t.deepLink === "string" ? t.deepLink : null,
16494
+ whySeen: typeof t.whySeen === "string" ? t.whySeen : null
16495
+ };
16496
+ }
16497
+ }
16475
16498
  return {
16499
+ tip,
16476
16500
  workspace: typeof obj.workspace === "string" && obj.workspace !== "" ? obj.workspace : null,
16477
16501
  // An older server sends no `reads` at all, so this normalizes to an empty
16478
16502
  // list rather than inventing the pinned workspace as the read set — the
@@ -16524,6 +16548,11 @@ function shouldShowGlance(input) {
16524
16548
  if (state.lastTopItemId !== topItemId) return true;
16525
16549
  return now - state.lastShownAt >= THROTTLE_INTERVAL_MS;
16526
16550
  }
16551
+ function shouldRequestTip(input) {
16552
+ const { state, now } = input;
16553
+ if (state.lastTipAt === void 0) return true;
16554
+ return now - state.lastTipAt >= TIP_THROTTLE_INTERVAL_MS;
16555
+ }
16527
16556
  function getGlanceStatePath() {
16528
16557
  return join6(homedir4(), ".gad", "glance-state.json");
16529
16558
  }
@@ -16602,6 +16631,14 @@ function renderFooter(payload, apiUrl) {
16602
16631
  process.stderr.write("\n" + brandedBlock("needs you", lines) + "\n");
16603
16632
  return printed;
16604
16633
  }
16634
+ function renderTip(tip, apiUrl) {
16635
+ const c = createColor(false);
16636
+ const lines = [`${c.yellow("\u{1F4A1}")} ${tip.text}`];
16637
+ if (tip.whySeen) lines.push(` ${c.dim(tip.whySeen)}`);
16638
+ const url = glanceItemUrl(tip.deepLink, apiUrl);
16639
+ if (url) lines.push(` ${c.dim("\u2192")} ${c.cyan(url)}`);
16640
+ process.stderr.write("\n" + brandedBlock("tip", lines) + "\n");
16641
+ }
16605
16642
  var GAD_MARK = "\u{1F3F9}";
16606
16643
  function brandedBlock(title, lines) {
16607
16644
  const header = `${GAD_MARK} Great Arrow \xB7 ${title}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@great-arrow/cli",
3
- "version": "0.1.36",
3
+ "version": "0.1.37",
4
4
  "description": "GreatArrow.ai CLI tool",
5
5
  "type": "module",
6
6
  "bin": {