@saadnvd1/agent-os 0.3.567 → 0.3.570

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.
@@ -1,15 +1,23 @@
1
1
  /**
2
- * The account's rolling usage windows. The 5-hour one comes from the
3
- * statusline's samples (lib/orchestrator/usage.ts), which also give its burn
4
- * rate; the weekly one only the agent knows, so it's asked through a
5
- * short-lived agent start (no turn is spent) and kept for a few minutes.
2
+ * The account's rolling usage windows. The 5-hour one comes from the samples
3
+ * in lib/orchestrator/usage.ts (AgentOS's own agents and the terminal
4
+ * statusline, whichever is fresher), which also give its burn rate; the
5
+ * weekly one from the readings AgentOS's agents store, else the plan's answer
6
+ * to a short-lived agent start (no turn is spent), kept for a few minutes.
7
+ * With nothing fresh, the last value seen is shown as such.
6
8
  */
7
9
 
8
10
  import os from "os";
9
11
  import { query, type SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
10
12
  import { InputQueue } from "../chat/queue";
11
- import { readUsage } from "../orchestrator/usage";
12
- import { currentWindow, type WindowReading } from "./rate-limits";
13
+ import { readUsage, type LastSeen } from "../orchestrator/usage";
14
+ import {
15
+ currentWindow,
16
+ lastReading,
17
+ parseRateLimit,
18
+ recordReadings,
19
+ type WindowReading,
20
+ } from "./rate-limits";
13
21
 
14
22
  export interface WindowView {
15
23
  pct: number;
@@ -20,6 +28,11 @@ export interface WindowView {
20
28
  burnPerMin?: number | null;
21
29
  // Worked out from recorded usage, not read from the account.
22
30
  estimated?: boolean;
31
+ // Not sampled lately: the last value seen, and when (epoch ms).
32
+ stale?: boolean;
33
+ sampledAt?: number;
34
+ // Seconds since then, when this was worked out.
35
+ ageSec?: number;
23
36
  }
24
37
 
25
38
  export interface UsageWindows {
@@ -71,7 +84,12 @@ async function askAgent(): Promise<PlanLimits | null> {
71
84
  );
72
85
  }),
73
86
  ]);
74
- return usage.rate_limits_available ? (usage.rate_limits ?? null) : null;
87
+ const limits = usage.rate_limits_available
88
+ ? ((usage.rate_limits ?? null) as PlanLimits | null)
89
+ : null;
90
+ // A plan answer is a reading too: keep it for the screens and brakes.
91
+ if (limits) recordReadings(parseRateLimit(limits), "plan");
92
+ return limits;
75
93
  } finally {
76
94
  clearTimeout(timer);
77
95
  input.end();
@@ -125,6 +143,34 @@ const fromReading = (
125
143
  }
126
144
  : null;
127
145
 
146
+ // The last value seen, shown as such, while its window is still open.
147
+ export function fromLast(
148
+ last: LastSeen | null | undefined,
149
+ nowSec = Date.now() / 1000
150
+ ): WindowView | null {
151
+ if (!last || (last.resetsAt !== null && last.resetsAt <= nowSec)) return null;
152
+ return {
153
+ pct: last.pct,
154
+ resetsIn:
155
+ last.resetsAt === null ? null : Math.round(last.resetsAt - nowSec),
156
+ stale: true,
157
+ sampledAt: Math.round(last.sampledAt * 1000),
158
+ ageSec: Math.max(0, Math.round(nowSec - last.sampledAt)),
159
+ };
160
+ }
161
+
162
+ function lastWeekly(nowMs: number): WindowView | null {
163
+ const r = lastReading("seven_day");
164
+ return fromLast(
165
+ r && {
166
+ pct: Math.round(r.utilization),
167
+ resetsAt: r.resetsAt === null ? null : r.resetsAt / 1000,
168
+ sampledAt: r.at / 1000,
169
+ },
170
+ nowMs / 1000
171
+ );
172
+ }
173
+
128
174
  export async function usageWindows(): Promise<UsageWindows> {
129
175
  const sampled = readUsage();
130
176
  const read = (w: "five_hour" | "seven_day") => {
@@ -144,14 +190,23 @@ export async function usageWindows(): Promise<UsageWindows> {
144
190
  capsIn: sampled.window.capsIn,
145
191
  burnPerMin: sampled.window.burnPerMin,
146
192
  }
147
- : (fromPlan(plan.limits?.five_hour) ?? read("five_hour"));
148
- const sevenDay = fromPlan(plan.limits?.seven_day) ?? read("seven_day");
193
+ : (fromPlan(plan.limits?.five_hour) ??
194
+ read("five_hour") ??
195
+ ("unknown" in sampled ? fromLast(sampled.last) : null));
196
+ let sevenDay: WindowView | null = null;
197
+ try {
198
+ sevenDay =
199
+ fromPlan(plan.limits?.seven_day) ??
200
+ read("seven_day") ??
201
+ lastWeekly(Date.now());
202
+ } catch {
203
+ // No readings to show.
204
+ }
149
205
  const note =
150
- !sevenDay || !fiveHour
151
- ? (plan.error ??
152
- ("unknown" in sampled
153
- ? sampled.unknown
154
- : "the plan's limits aren't available for this login"))
155
- : undefined;
206
+ "unknown" in sampled && (!fiveHour || fiveHour.stale)
207
+ ? sampled.unknown
208
+ : !sevenDay || !fiveHour
209
+ ? (plan.error ?? "the plan's limits aren't available for this login")
210
+ : undefined;
156
211
  return { fiveHour, sevenDay, note };
157
212
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saadnvd1/agent-os",
3
- "version": "0.3.567",
3
+ "version": "0.3.570",
4
4
  "description": "Self-hosted web UI for managing Claude Code sessions",
5
5
  "bin": {
6
6
  "agent-os": "scripts/agent-os"
@@ -124,11 +124,14 @@
124
124
  "class-variance-authority": "^0.7.1",
125
125
  "clsx": "^2.1.1",
126
126
  "esbuild": "^0.28.0",
127
+ "hast-util-from-html": "^2.0.3",
128
+ "hast-util-to-mdast": "^10.1.2",
127
129
  "highlight.js": "^11.11.1",
128
130
  "lowlight": "^3.3.0",
129
131
  "lucide-react": "^0.556.0",
130
132
  "mdast-util-from-markdown": "^2.1.0",
131
133
  "mdast-util-gfm": "^3.1.0",
134
+ "mdast-util-to-markdown": "^2.2.0",
132
135
  "mermaid": "^11.17.2",
133
136
  "micromark-extension-gfm": "^3.0.0",
134
137
  "monaco-editor": "^0.57.0",