agent-runway 0.2.0 → 0.2.1

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.
@@ -11,7 +11,7 @@
11
11
  "displayName": "Agent Runway",
12
12
  "source": "./",
13
13
  "description": "Quota and model discovery for the coding agents installed on this machine: how much runway each has left, and which model slugs each binary will actually accept.",
14
- "version": "0.2.0",
14
+ "version": "0.2.1",
15
15
  "author": {
16
16
  "name": "jberdah",
17
17
  "url": "https://github.com/jberdah"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-runway",
3
3
  "displayName": "Agent Runway",
4
- "version": "0.2.0",
4
+ "version": "0.2.1",
5
5
  "description": "Quota and model discovery for the coding agents installed on this machine: how much runway each has left, and which model slugs each binary will actually accept.",
6
6
  "author": {
7
7
  "name": "jberdah",
package/README.md CHANGED
@@ -70,10 +70,17 @@ unless you pass `--force`.
70
70
  ### As a Claude Code plugin (skill + MCP tool)
71
71
 
72
72
  ```
73
- /plugin marketplace add jberdah/agent-runway
73
+ /plugin marketplace add https://github.com/jberdah/agent-runway.git
74
74
  /plugin install agent-runway@agent-runway
75
75
  ```
76
76
 
77
+ The full HTTPS URL rather than the `owner/repo` shorthand: the shorthand
78
+ resolves to SSH, which fails on any machine that has not accepted GitHub's host
79
+ key. If the clone then fails with *"self signed certificate in certificate
80
+ chain"*, a proxy is inspecting TLS; on Windows, `git config --global
81
+ http.sslBackend schannel` makes git trust the certificate store the rest of the
82
+ system already uses.
83
+
77
84
  Claude then reads your usage whenever it is relevant — ask "how much quota do I
78
85
  have left?" or let it check before a long task.
79
86
 
@@ -356,10 +363,17 @@ npm run smoke # drives the MCP server over stdio; needs network and a token
356
363
  ```
357
364
 
358
365
  The runtime has **zero dependencies**. `src/mcp.mjs` speaks JSON-RPC directly
359
- rather than importing the MCP SDK, because a Claude Code plugin installed from
360
- git is never `npm install`ed an imported dependency would have to be vendored.
361
- `scripts/smoke-mcp.mjs` connects the official SDK client to it, so the
362
- hand-rolled framing is checked against the real implementation.
366
+ rather than importing the MCP SDK, and `scripts/smoke-mcp.mjs` connects the
367
+ official SDK client to it so the hand-rolled framing is checked against the real
368
+ implementation.
369
+
370
+ That choice was originally justified by a belief that a Claude Code plugin
371
+ installed from git is never `npm install`ed. **That is wrong**: installing this
372
+ plugin produced 91 packages in the plugin cache, devDependencies included. The
373
+ constraint is kept anyway, for reasons that survive the correction — nobody
374
+ installing a CLI that makes one HTTP request should wait on 91 packages, the
375
+ supply-chain surface stays at zero, and it keeps working where `npm install`
376
+ does not, which on a corporate network is not hypothetical.
363
377
 
364
378
  ```
365
379
  src/core.mjs token resolution, HTTP, response normalization
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-runway",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Quota and model discovery for the coding agents installed on this machine: how much runway each has left, and which model slugs each binary will actually accept.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/core.mjs CHANGED
@@ -7,7 +7,7 @@ import fs from "node:fs";
7
7
  import os from "node:os";
8
8
  import path from "node:path";
9
9
 
10
- export const VERSION = "0.2.0";
10
+ export const VERSION = "0.2.1";
11
11
 
12
12
  const USER_AGENT = `agent-runway/${VERSION} (+https://github.com/jberdah/agent-runway)`;
13
13
 
@@ -106,7 +106,7 @@ export function capacity(results, { threshold = 90 } = {}) {
106
106
  if (r.allowed === false) {
107
107
  return {
108
108
  provider: r.provider, label: r.label, decision: "defer", reason: "provider_says_limit_reached",
109
- binding, retryAt: binding.resetsAt, retryAtBasis: "reported_reset",
109
+ binding, windows: r.windows, retryAt: binding.resetsAt, retryAtBasis: "reported_reset",
110
110
  };
111
111
  }
112
112
 
@@ -117,6 +117,10 @@ export function capacity(results, { threshold = 90 } = {}) {
117
117
  decision: over ? "defer" : "proceed",
118
118
  reason: over ? "threshold_exceeded" : "within_threshold",
119
119
  binding,
120
+ // The binding window decides, but hiding the rest loses information the
121
+ // read already paid for: a session at 0% next to a weekly at 89% is a
122
+ // different situation from a session at 0% alone.
123
+ windows: r.windows,
120
124
  retryAt: over ? binding.resetsAt : null,
121
125
  // The reset is when the window rolls over, not a promise that service
122
126
  // resumes exactly then. Naming the basis keeps the two apart.
@@ -56,9 +56,20 @@ export function makeWindow({
56
56
  model = null,
57
57
  unit = "requests",
58
58
  }) {
59
- const startsAt =
59
+ // A start can only be derived from a window that is actually running. When a
60
+ // provider has nothing to report it answers with the whole window ahead —
61
+ // Codex returns reset_at = now + 18000s at 0% consumption — and subtracting
62
+ // the duration then yields "now", which reads as a window that just began
63
+ // when none has. A start that lands on or after the present moment is not a
64
+ // measurement, so it is withheld rather than invented.
65
+ const derivedStart =
60
66
  resetsAt && Number.isFinite(windowSeconds)
61
- ? new Date(Date.parse(resetsAt) - windowSeconds * 1000).toISOString()
67
+ ? Date.parse(resetsAt) - windowSeconds * 1000
68
+ : null;
69
+ const UNKNOWABLE_MS = 60_000;
70
+ const startsAt =
71
+ derivedStart != null && derivedStart < Date.now() - UNKNOWABLE_MS
72
+ ? new Date(derivedStart).toISOString()
62
73
  : null;
63
74
 
64
75
  return {