@bridge4dev/runner 0.44.1 → 0.44.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.
@@ -67,6 +67,20 @@ export declare function parseElicitation(params: Record<string, unknown>): Agent
67
67
  * never enumerated on our side.
68
68
  */
69
69
  export declare function readEfforts(value: unknown): EffortOption[];
70
+ /**
71
+ * When a Codex window resets → ISO, or null if it did not say.
72
+ *
73
+ * Epoch SECONDS on the wire, captured live from codex-cli 0.147.0 on 2026-08-16:
74
+ * `resetsAt: 1787221437` is 2026-08-20. Read as a string it was silently dropped,
75
+ * which is why no Codex window has ever shown a reset time and why #258 had
76
+ * nothing to schedule a wake-up from on this agent.
77
+ *
78
+ * The range check is not decoration. A clock built from a misread number is
79
+ * worse than no clock at all: milliseconds mistaken for seconds would promise a
80
+ * reset in the year 58600, and #258 would arm a timer on it. Outside the range,
81
+ * we say we do not know — which is the honest answer and the safe one.
82
+ */
83
+ export declare function codexResetsAt(raw: unknown): string | null;
70
84
  export declare class CodexAdapter implements AgentAdapter {
71
85
  private readonly deps;
72
86
  readonly id: "codex";
@@ -1399,16 +1399,28 @@ class CodexSession {
1399
1399
  const usedPercent = num(window['usedPercent'] ?? window['used_percent']);
1400
1400
  if (usedPercent === undefined)
1401
1401
  continue;
1402
- const minutes = num(window['windowMinutes'] ?? window['window_minutes']) ?? null;
1403
- // Live 2026-08-15: Codex sent a percentage with NO length, so the label
1404
- // fell back to «Limit window» — true but useless. The slot itself carries
1405
- // the answer on every ChatGPT plan: `primary` is the short window,
1406
- // `secondary` the weekly one. Used only when the minutes are missing, so
1407
- // a provider that does state them still wins.
1402
+ // `windowDurationMins` is the name codex-cli 0.147.0 actually sends —
1403
+ // captured from a live `account/rateLimits/updated` on 2026-08-16:
1404
+ //
1405
+ // primary: {usedPercent: 4, windowDurationMins: 10080, resetsAt: 1787221437}
1406
+ // secondary: null
1407
+ //
1408
+ // The two older spellings are kept behind it, not in front: a Codex that
1409
+ // still sends them keeps working, and the current one stops being read as
1410
+ // «length unknown». That misreading is what made the panel label a WEEKLY
1411
+ // window «5 hours» — the number was right and the heading was not.
1412
+ const minutes = num(window['windowDurationMins'] ?? window['windowMinutes'] ?? window['window_minutes']) ??
1413
+ null;
1408
1414
  // Only when the length is ABSENT. A stated length we do not recognise is
1409
1415
  // information — 43 200 minutes is a monthly window, and calling it «5
1410
1416
  // hours» because it arrived first would be worse than admitting we have
1411
1417
  // no name for it.
1418
+ //
1419
+ // The slot fallback stays for exactly that case, but it is now the last
1420
+ // resort rather than the usual path. And note what the live payload shows:
1421
+ // `primary` is NOT reliably the short window. Here it is the weekly one
1422
+ // and `secondary` is null, so guessing by slot was wrong in the only case
1423
+ // we have ever observed.
1412
1424
  const key = minutes === null
1413
1425
  ? slot === 'primary'
1414
1426
  ? 'five_hour'
@@ -1418,7 +1430,12 @@ class CodexSession {
1418
1430
  key,
1419
1431
  windowMinutes: minutes,
1420
1432
  usedPercent: clampPercent(usedPercent),
1421
- resetsAt: str(window['resetsAt'] ?? window['resets_at']) ?? null,
1433
+ // Epoch SECONDS on the wire, not an ISO string — reading it with `str()`
1434
+ // returned undefined for every snapshot ever received, which is why no
1435
+ // Codex window has ever shown a reset time. The string form is still
1436
+ // accepted in case a future version switches. Same fact, two encodings,
1437
+ // one place that knows it — exactly as the Claude adapter already does.
1438
+ resetsAt: codexResetsAt(window['resetsAt'] ?? window['resets_at']),
1422
1439
  });
1423
1440
  }
1424
1441
  this.rateLimitWindows = windows.sort((a, b) => (a.windowMinutes ?? Number.MAX_SAFE_INTEGER) - (b.windowMinutes ?? Number.MAX_SAFE_INTEGER));
@@ -1474,8 +1491,15 @@ class CodexSession {
1474
1491
  }
1475
1492
  }
1476
1493
  rateLimitRefusal(error) {
1494
+ // The machine-readable cause FIRST. Codex 0.147.0 says `usageLimitExceeded`
1495
+ // — Exceeded, not Reached — so not one of the four substrings below ever
1496
+ // matched it, and the auto-pause never armed on this agent at all: a refused
1497
+ // turn went to FAILED instead of sleeping until the window reopened.
1498
+ // Demonstrated by test, 2026-08-16, not inferred.
1499
+ const code = str(asRecord(error)['codexErrorInfo']);
1477
1500
  const haystack = JSON.stringify(error).toLowerCase();
1478
- const refused = haystack.includes('ratelimitreached') ||
1501
+ const refused = code === 'usageLimitExceeded' ||
1502
+ haystack.includes('ratelimitreached') ||
1479
1503
  haystack.includes('rate_limit_reached') ||
1480
1504
  haystack.includes('usage_limit_reached') ||
1481
1505
  haystack.includes('usagelimitreached');
@@ -1913,6 +1937,31 @@ function truncateRecord(value) {
1913
1937
  }
1914
1938
  return out;
1915
1939
  }
1940
+ /**
1941
+ * When a Codex window resets → ISO, or null if it did not say.
1942
+ *
1943
+ * Epoch SECONDS on the wire, captured live from codex-cli 0.147.0 on 2026-08-16:
1944
+ * `resetsAt: 1787221437` is 2026-08-20. Read as a string it was silently dropped,
1945
+ * which is why no Codex window has ever shown a reset time and why #258 had
1946
+ * nothing to schedule a wake-up from on this agent.
1947
+ *
1948
+ * The range check is not decoration. A clock built from a misread number is
1949
+ * worse than no clock at all: milliseconds mistaken for seconds would promise a
1950
+ * reset in the year 58600, and #258 would arm a timer on it. Outside the range,
1951
+ * we say we do not know — which is the honest answer and the safe one.
1952
+ */
1953
+ export function codexResetsAt(raw) {
1954
+ if (typeof raw === 'string' && raw) {
1955
+ const parsed = Date.parse(raw);
1956
+ return Number.isNaN(parsed) ? null : new Date(parsed).toISOString();
1957
+ }
1958
+ if (typeof raw !== 'number' || !Number.isFinite(raw))
1959
+ return null;
1960
+ // 2001-09-09 … 2286-11-20 in epoch seconds.
1961
+ if (raw < 1_000_000_000 || raw > 9_999_999_999)
1962
+ return null;
1963
+ return new Date(raw * 1000).toISOString();
1964
+ }
1916
1965
  function stringifyMcpResult(item) {
1917
1966
  const errorMessage = str(asRecord(item['error'])['message']);
1918
1967
  if (errorMessage)
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const RUNNER_VERSION = "0.44.1";
1
+ export declare const RUNNER_VERSION = "0.44.2";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Kept in sync with package.json by the release script (manual for now).
2
- export const RUNNER_VERSION = '0.44.1';
2
+ export const RUNNER_VERSION = '0.44.2';
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bridge4dev/runner",
3
- "version": "0.44.1",
3
+ "version": "0.44.2",
4
4
  "description": "DevBridge dev runner — connects a dev server to DevBridge and runs agent sessions (Claude Code / Codex)",
5
5
  "homepage": "https://bridge4.dev",
6
6
  "license": "MIT",