@phnx-labs/agents-cli 1.22.81 → 1.22.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.22.82
4
+
5
+ - **The Claude status line names the signed-in account before the model (PHNX-3987).** The managed `agents __claude-statusline` render now reads `host · account · model · 5h n% · 7d n% · ◆ reminder`, where the account is the email the running Claude is signed into (plus the org name for a Team/Enterprise seat, the same label `agents view` renders), read from the `.claude.json` of the home Claude is actually running with — the version home under the launch shim, `$HOME` otherwise. A never-signed-in home omits the part. Source: `cli/src/lib/claude-statusline.ts`.
6
+
3
7
  ## 1.22.81
4
8
 
5
9
  - **Same-task page reopen refreshes the SAME tab instead of duplicating it (PHNX-2399).** When an agent reopens a URL that is already live in one of its browser task's OWN tabs, `agents browser navigate` / `tab add` now issue a real `Page.reload` on that same tab — keeping its tab id and CDP target, marking it current without stealing window focus — and report `refreshed: true` with the note `Tab already open—refreshed`, rather than opening a second copy. Borrowed Arc/user tabs are excluded, a stale registered tab or a failed reload never reports a phantom refresh, and the lookup→reload/create→persist section is serialized per task (and first-use creation per caller) so concurrent requests converge on one tab and the same id. The implicit first-open at the create boundary is reported as a genuine open, not disguised as a refresh. `navigate` / `tab add` gain `--json` (`{ ok, task, tabId, url, created, refreshed, message }`), and `agents browser tabs` again marks the current tab. Source: `cli/src/lib/browser/service.ts`, `cli/src/lib/browser/ipc.ts`, `cli/src/lib/browser/types.ts`, `cli/src/commands/browser.ts`.
@@ -1,3 +1,4 @@
1
+ import { type ClaudeHomeIdentity } from './agent-spec/agents.js';
1
2
  export declare const CLAUDE_STATUSLINE_COMMAND = "agents __claude-statusline";
2
3
  /**
3
4
  * True when `command` re-invokes THIS status-line producer (our private
@@ -28,7 +29,28 @@ interface ClaudeStatusLinePayload {
28
29
  };
29
30
  };
30
31
  }
31
- export declare function ingestClaudeStatusLineUsage(payload: ClaudeStatusLinePayload, versionHome: string): boolean;
32
+ export declare function ingestClaudeStatusLineUsage(payload: ClaudeStatusLinePayload, identity: ClaudeHomeIdentity | null): boolean;
33
+ /**
34
+ * Where the running Claude keeps the config this render attributes to: the version
35
+ * home when the launch shim set CLAUDE_CONFIG_DIR, otherwise the real HOME — the
36
+ * same resolution Claude Code applies, so a Claude launched without the shim (IDE
37
+ * extension, direct binary) still shows the account it is actually signed into.
38
+ */
39
+ export declare function claudeHomeFromEnv(env: NodeJS.ProcessEnv): string;
40
+ /**
41
+ * The identity of the running Claude, read ONCE per render from the `.claude.json`
42
+ * of the home it is actually running with: it keys the usage ingest above and
43
+ * names the account part below. Null when the home has never signed in. Sync and
44
+ * file-only on purpose — this runs on every status-line refresh.
45
+ */
46
+ export declare function readClaudeIdentity(claudeHome: string): ClaudeHomeIdentity | null;
47
+ /**
48
+ * Format the signed-in account as a statusline part ('' when never signed in),
49
+ * with the label every other account-aware surface (`agents view`, `agents
50
+ * accounts`) uses — the email, plus the org name for a multi-seat Team/Enterprise
51
+ * seat.
52
+ */
53
+ export declare function formatAccountPart(identity: ClaudeHomeIdentity | null): string;
32
54
  export declare function renderDelegate(payload: string, versionHome: string): string;
33
55
  /**
34
56
  * Format a reminder as a dimmed statusline part (empty string when none). The
@@ -36,7 +58,7 @@ export declare function renderDelegate(payload: string, versionHome: string): st
36
58
  * keeps it quiet next to the live figures.
37
59
  */
38
60
  export declare function formatReminderPart(short: string | undefined): string;
39
- export declare function renderClaudeStatusLine(payload: ClaudeStatusLinePayload, host?: string, delegated?: string, reminder?: string): string;
61
+ export declare function renderClaudeStatusLine(payload: ClaudeStatusLinePayload, host?: string, delegated?: string, reminder?: string, account?: string): string;
40
62
  /**
41
63
  * Resolve the per-session reminder for the statusline, or '' when none is
42
64
  * configured. A malformed reminders file is swallowed here on purpose — a broken
@@ -2,7 +2,7 @@ import * as fs from 'fs';
2
2
  import * as os from 'os';
3
3
  import * as path from 'path';
4
4
  import { spawnSync } from 'child_process';
5
- import { readClaudeHomeConfig } from './agent-spec/agents.js';
5
+ import { accountDisplayLabel, readClaudeHomeConfig, } from './agent-spec/agents.js';
6
6
  import { atomicWriteFileSync } from './fs-atomic.js';
7
7
  import { mergeClaudeUsageCacheWindows } from './accounting/usage.js';
8
8
  import { loadReminders, pickReminderForSession } from './reminders.js';
@@ -61,8 +61,7 @@ function windowFromNative(key, value) {
61
61
  windowMinutes: key === 'session' ? 300 : 10_080,
62
62
  };
63
63
  }
64
- export function ingestClaudeStatusLineUsage(payload, versionHome) {
65
- const identity = readClaudeHomeConfig(versionHome)?.identity;
64
+ export function ingestClaudeStatusLineUsage(payload, identity) {
66
65
  if (!identity?.usageKey || !payload.rate_limits)
67
66
  return false;
68
67
  const windows = [
@@ -79,6 +78,35 @@ export function ingestClaudeStatusLineUsage(payload, versionHome) {
79
78
  });
80
79
  return true;
81
80
  }
81
+ /**
82
+ * Where the running Claude keeps the config this render attributes to: the version
83
+ * home when the launch shim set CLAUDE_CONFIG_DIR, otherwise the real HOME — the
84
+ * same resolution Claude Code applies, so a Claude launched without the shim (IDE
85
+ * extension, direct binary) still shows the account it is actually signed into.
86
+ */
87
+ export function claudeHomeFromEnv(env) {
88
+ return versionHomeFromEnv(env) ?? os.homedir();
89
+ }
90
+ /**
91
+ * The identity of the running Claude, read ONCE per render from the `.claude.json`
92
+ * of the home it is actually running with: it keys the usage ingest above and
93
+ * names the account part below. Null when the home has never signed in. Sync and
94
+ * file-only on purpose — this runs on every status-line refresh.
95
+ */
96
+ export function readClaudeIdentity(claudeHome) {
97
+ return readClaudeHomeConfig(claudeHome)?.identity ?? null;
98
+ }
99
+ /**
100
+ * Format the signed-in account as a statusline part ('' when never signed in),
101
+ * with the label every other account-aware surface (`agents view`, `agents
102
+ * accounts`) uses — the email, plus the org name for a multi-seat Team/Enterprise
103
+ * seat.
104
+ */
105
+ export function formatAccountPart(identity) {
106
+ if (!identity)
107
+ return '';
108
+ return accountDisplayLabel({ ...identity, signedIn: true });
109
+ }
82
110
  function delegatePath(versionHome) {
83
111
  return path.join(versionHome, DELEGATE_FILE);
84
112
  }
@@ -113,9 +141,14 @@ export function formatReminderPart(short) {
113
141
  const text = short?.trim();
114
142
  return text ? `\x1b[2m◆ ${text}\x1b[22m` : '';
115
143
  }
116
- export function renderClaudeStatusLine(payload, host = os.hostname().split('.')[0] || os.hostname(), delegated = '', reminder = '') {
144
+ export function renderClaudeStatusLine(payload, host = os.hostname().split('.')[0] || os.hostname(), delegated = '', reminder = '', account = '') {
117
145
  const model = payload.model?.display_name?.trim() || payload.model?.id?.trim() || 'model pending';
118
- const parts = [host, model];
146
+ // host · account · model: who is running, as which account, on which model —
147
+ // the account sits before the model so a glance answers "whose quota is this".
148
+ const parts = [host];
149
+ if (account)
150
+ parts.push(account);
151
+ parts.push(model);
119
152
  if (delegated)
120
153
  parts.push(delegated);
121
154
  const fiveHour = payload.rate_limits?.five_hour?.used_percentage;
@@ -158,9 +191,10 @@ export async function runClaudeStatusLine() {
158
191
  payload = {};
159
192
  }
160
193
  const versionHome = versionHomeFromEnv(process.env);
194
+ const identity = readClaudeIdentity(claudeHomeFromEnv(process.env));
161
195
  if (versionHome)
162
- ingestClaudeStatusLineUsage(payload, versionHome);
163
- process.stdout.write(renderClaudeStatusLine(payload, undefined, versionHome ? renderDelegate(raw, versionHome) : '', resolveReminderPart(payload.session_id)));
196
+ ingestClaudeStatusLineUsage(payload, identity);
197
+ process.stdout.write(renderClaudeStatusLine(payload, undefined, versionHome ? renderDelegate(raw, versionHome) : '', resolveReminderPart(payload.session_id), formatAccountPart(identity)));
164
198
  return 0;
165
199
  }
166
200
  export function installClaudeStatusLine(versionHome) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phnx-labs/agents-cli",
3
- "version": "1.22.81",
3
+ "version": "1.22.82",
4
4
  "description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams (now with first-class Grok Build CLI support)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",