agent-limit 0.7.0 → 0.7.2

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 CHANGED
@@ -2,35 +2,31 @@
2
2
 
3
3
  Terminal dashboard to monitor Claude Code and Codex usage limits.
4
4
 
5
- ## Install
6
-
7
- ### Via npm (requires Bun)
5
+ ## Quickstart
8
6
 
9
7
  ```bash
10
8
  npm install -g agent-limit
9
+ agent-limit usage
11
10
  ```
12
11
 
13
- ### Standalone Binary (no dependencies)
14
-
15
- Download from [GitHub Releases](https://github.com/AgentWorkforce/limit/releases):
16
-
17
- ```bash
18
- # Apple Silicon
19
- curl -L https://github.com/AgentWorkforce/limit/releases/latest/download/agent-limit-darwin-arm64 -o /usr/local/bin/agent-limit
20
- chmod +x /usr/local/bin/agent-limit
12
+ ## Example
21
13
 
22
- # Intel Mac
23
- curl -L https://github.com/AgentWorkforce/limit/releases/latest/download/agent-limit-darwin-x64 -o /usr/local/bin/agent-limit
24
- chmod +x /usr/local/bin/agent-limit
14
+ ```
15
+ [███████░░░░|░░░░░░░░░] 30% ↓12%
16
+ ^ you should be at 42%, but you're at 30% (12% under pace)
25
17
  ```
26
18
 
27
- ## Quick Start
19
+ - `↓X%` (green) = under pace, you have headroom
20
+ - `↑X%` (red) = over pace, might hit limits early
28
21
 
29
- ```bash
30
- agent-limit usage
31
- ```
22
+ ## Features
23
+
24
+ - Real-time usage tracking for Claude Code and Codex
25
+ - Trajectory markers showing if you're ahead or behind your usage pace
26
+ - Auto-refresh every 60 seconds
27
+ - Color-coded usage indicators
32
28
 
33
- ## CLI
29
+ ## CLI Reference
34
30
 
35
31
  | Command | Description |
36
32
  |---------|-------------|
@@ -38,20 +34,13 @@ agent-limit usage
38
34
  | `agent-limit version` | Show version |
39
35
  | `agent-limit help` | Show help message |
40
36
 
41
- ## Dashboard Controls
37
+ ### Dashboard Controls
42
38
 
43
39
  | Key | Action |
44
40
  |-----|--------|
45
41
  | `q` | Quit |
46
42
  | `r` | Refresh |
47
43
 
48
- ## Features
49
-
50
- - Real-time usage tracking for Claude Code and Codex
51
- - Trajectory markers showing if you're ahead or behind your usage pace
52
- - Auto-refresh every 60 seconds
53
- - Color-coded usage indicators
54
-
55
44
  ## Supported Providers
56
45
 
57
46
  | Provider | Status | Data Source |
@@ -59,6 +48,42 @@ agent-limit usage
59
48
  | Claude Code | Full support | macOS Keychain + Anthropic API |
60
49
  | Codex | Full support | `~/.codex/auth.json` + OpenAI API |
61
50
 
51
+ ## How It Works
52
+
53
+ agent-limit reads credentials from standard locations:
54
+
55
+ - **Claude Code**: macOS Keychain (`Claude Code-credentials`)
56
+ - **Codex**: `~/.codex/auth.json`
57
+
58
+ It then fetches usage data from each provider's API and displays it in a unified dashboard.
59
+
60
+ ## Installation Options
61
+
62
+ ### Via npm
63
+
64
+ ```bash
65
+ npm install -g agent-limit
66
+ ```
67
+
68
+ ### Standalone Binary (no dependencies)
69
+
70
+ Download from [GitHub Releases](https://github.com/AgentWorkforce/limit/releases):
71
+
72
+ ```bash
73
+ # Apple Silicon
74
+ curl -L https://github.com/AgentWorkforce/limit/releases/latest/download/agent-limit-darwin-arm64 -o /usr/local/bin/agent-limit
75
+ chmod +x /usr/local/bin/agent-limit
76
+
77
+ # Intel Mac
78
+ curl -L https://github.com/AgentWorkforce/limit/releases/latest/download/agent-limit-darwin-x64 -o /usr/local/bin/agent-limit
79
+ chmod +x /usr/local/bin/agent-limit
80
+ ```
81
+
82
+ ## Requirements
83
+
84
+ - macOS (uses Keychain for credential storage)
85
+ - Active CLI authentication for providers you want to monitor
86
+
62
87
  ## Development
63
88
 
64
89
  ```bash
@@ -96,32 +121,6 @@ bun run build:x64 # Intel
96
121
 
97
122
  Binaries are output to `dist/`.
98
123
 
99
- ## How It Works
100
-
101
- agent-limit reads credentials from standard locations:
102
-
103
- - **Claude Code**: macOS Keychain (`Claude Code-credentials`)
104
- - **Codex**: `~/.codex/auth.json`
105
-
106
- It then fetches usage data from each provider's API and displays it in a unified dashboard.
107
-
108
- ### Trajectory Indicator
109
-
110
- Each progress bar shows a `|` marker indicating where your usage "should be" based on time elapsed in the reset period:
111
-
112
- ```
113
- [███████░░░░|░░░░░░░░░] 30% ↓12%
114
- ^ you should be at 42%, but you're at 30% (12% under pace)
115
- ```
116
-
117
- - `↓X%` (green) = under pace, you have headroom
118
- - `↑X%` (red) = over pace, might hit limits early
119
-
120
- ## Requirements
121
-
122
- - macOS (uses Keychain for credential storage)
123
- - Active CLI authentication for providers you want to monitor
124
-
125
124
  ## License
126
125
 
127
126
  MIT
package/bin/cli.tsx CHANGED
@@ -14,9 +14,10 @@ if (command === "usage") {
14
14
 
15
15
  const root = createRoot(renderer);
16
16
 
17
- const cleanup = () => {
17
+ const cleanup = async () => {
18
18
  root.unmount();
19
- renderer.destroy();
19
+ await renderer.destroy();
20
+ process.stdout.write("\x1b[?25h"); // Ensure cursor is visible
20
21
  process.exit(0);
21
22
  };
22
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-limit",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "Terminal dashboard to monitor Claude Code, Codex, and other agent usage limits",
5
5
  "type": "module",
6
6
  "main": "src/index.tsx",
@@ -1,30 +1,16 @@
1
1
  import {
2
2
  getClaudeCredentials,
3
- refreshClaudeToken,
4
- saveClaudeCredentials,
5
3
  type ClaudeCredentials,
6
4
  } from "../utils/keychain";
7
5
  import { timeUntil } from "../utils/time";
8
6
  import type { ProviderStatus } from "./types";
9
7
 
10
- const TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000;
11
-
12
8
  interface ClaudeUsageResponse {
13
9
  five_hour: { utilization: number; resets_at: string | null } | null;
14
10
  seven_day: { utilization: number; resets_at: string | null } | null;
15
11
  seven_day_opus: { utilization: number; resets_at: string | null } | null;
16
12
  }
17
13
 
18
- async function tryRefreshCredentials(
19
- credentials: ClaudeCredentials
20
- ): Promise<ClaudeCredentials | null> {
21
- const refreshed = await refreshClaudeToken(credentials.refreshToken);
22
- if (refreshed) {
23
- await saveClaudeCredentials(refreshed);
24
- }
25
- return refreshed;
26
- }
27
-
28
14
  async function fetchUsageWithCredentials(
29
15
  credentials: ClaudeCredentials
30
16
  ): Promise<Response> {
@@ -41,7 +27,7 @@ async function fetchUsageWithCredentials(
41
27
  }
42
28
 
43
29
  export async function fetchClaudeUsage(): Promise<ProviderStatus> {
44
- let credentials = await getClaudeCredentials();
30
+ const credentials = await getClaudeCredentials();
45
31
 
46
32
  if (!credentials) {
47
33
  return {
@@ -52,24 +38,8 @@ export async function fetchClaudeUsage(): Promise<ProviderStatus> {
52
38
  };
53
39
  }
54
40
 
55
- const tokenExpiresSoon = credentials.expiresAt < Date.now() + TOKEN_REFRESH_BUFFER_MS;
56
- if (tokenExpiresSoon) {
57
- const refreshed = await tryRefreshCredentials(credentials);
58
- if (refreshed) {
59
- credentials = refreshed;
60
- }
61
- }
62
-
63
41
  try {
64
- let response = await fetchUsageWithCredentials(credentials);
65
-
66
- if (response.status === 401) {
67
- const refreshed = await tryRefreshCredentials(credentials);
68
- if (refreshed) {
69
- credentials = refreshed;
70
- response = await fetchUsageWithCredentials(credentials);
71
- }
72
- }
42
+ const response = await fetchUsageWithCredentials(credentials);
73
43
 
74
44
  if (!response.ok) {
75
45
  if (response.status === 401) {
@@ -1,7 +1,5 @@
1
1
  import { $ } from "bun";
2
2
 
3
- const CLAUDE_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
4
- const CLAUDE_TOKEN_ENDPOINT = "https://console.anthropic.com/v1/oauth/token";
5
3
  const KEYCHAIN_SERVICE = "Claude Code-credentials";
6
4
 
7
5
  export async function getKeychainCredentials(service: string): Promise<string | null> {
@@ -15,16 +13,6 @@ export async function getKeychainCredentials(service: string): Promise<string |
15
13
  }
16
14
  }
17
15
 
18
- async function setKeychainCredentials(service: string, data: string): Promise<boolean> {
19
- try {
20
- await $`security delete-generic-password -s ${service}`.quiet().nothrow();
21
- await $`security add-generic-password -s ${service} -w ${data}`.quiet();
22
- return true;
23
- } catch {
24
- return false;
25
- }
26
- }
27
-
28
16
  export interface ClaudeCredentials {
29
17
  accessToken: string;
30
18
  refreshToken: string;
@@ -45,62 +33,6 @@ export async function getClaudeCredentials(): Promise<ClaudeCredentials | null>
45
33
  }
46
34
  }
47
35
 
48
- interface TokenRefreshResponse {
49
- token_type: string;
50
- access_token: string;
51
- expires_in: number;
52
- refresh_token: string;
53
- scope: string;
54
- }
55
-
56
- export async function refreshClaudeToken(
57
- refreshToken: string
58
- ): Promise<ClaudeCredentials | null> {
59
- try {
60
- const response = await fetch(CLAUDE_TOKEN_ENDPOINT, {
61
- method: "POST",
62
- headers: { "Content-Type": "application/json" },
63
- body: JSON.stringify({
64
- grant_type: "refresh_token",
65
- refresh_token: refreshToken,
66
- client_id: CLAUDE_CLIENT_ID,
67
- }),
68
- });
69
-
70
- if (!response.ok) {
71
- return null;
72
- }
73
-
74
- const data: TokenRefreshResponse = await response.json();
75
-
76
- return {
77
- accessToken: data.access_token,
78
- refreshToken: data.refresh_token,
79
- expiresAt: Date.now() + data.expires_in * 1000,
80
- scopes: data.scope.split(" "),
81
- subscriptionType: "Pro",
82
- };
83
- } catch {
84
- return null;
85
- }
86
- }
87
-
88
- export async function saveClaudeCredentials(
89
- credentials: ClaudeCredentials
90
- ): Promise<boolean> {
91
- try {
92
- const raw = await getKeychainCredentials(KEYCHAIN_SERVICE);
93
- if (!raw) return false;
94
-
95
- const parsed = JSON.parse(raw);
96
- parsed.claudeAiOauth = credentials;
97
-
98
- return await setKeychainCredentials(KEYCHAIN_SERVICE, JSON.stringify(parsed));
99
- } catch {
100
- return false;
101
- }
102
- }
103
-
104
36
  export interface CodexCredentials {
105
37
  accessToken: string;
106
38
  accountId: string;