@modelprofile.com/authswitch 10.0.1 → 10.1.0

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.
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Human time text: countdowns to a deadline and timestamps in local calendar time.
3
+ *
4
+ * It imports nothing, so the browser-safe `./preuse-text` entry point can render a reset exactly as the
5
+ * command line does without pulling a Node built-in into a bundle.
6
+ */
7
+ /** A countdown is a snapshot of the provider's deadline, not proof a quota has reset. */
8
+ export const until = (timestampArg, nowArg) => {
9
+ if (timestampArg === null)
10
+ return 'Not scheduled';
11
+ const remaining = Date.parse(timestampArg) - nowArg;
12
+ if (!Number.isFinite(remaining))
13
+ return 'Unavailable';
14
+ if (remaining <= 0)
15
+ return 'due';
16
+ const minutes = Math.floor(remaining / 60000);
17
+ if (!minutes)
18
+ return '<1min';
19
+ const days = Math.floor(minutes / 1440);
20
+ const hours = Math.floor(minutes % 1440 / 60);
21
+ return [days ? `${days}d` : '', hours ? `${hours}h` : '', minutes % 60 ? `${minutes % 60}min` : ''].filter(Boolean).join(' ');
22
+ };
23
+ /**
24
+ * A two-unit countdown for condensed tables: `2h 13m`, `3d 4h`, `45m`.
25
+ *
26
+ * `until` stays the long form used by the list view and the TUI. This one trades the third unit for
27
+ * a column that never wraps, and it never invents a deadline: an unknown or unparseable timestamp is
28
+ * reported as such rather than as zero time remaining.
29
+ */
30
+ const twoUnits = (millisecondsArg) => {
31
+ const minutes = Math.floor(millisecondsArg / 60000);
32
+ const days = Math.floor(minutes / 1440);
33
+ const hours = Math.floor(minutes % 1440 / 60);
34
+ if (days)
35
+ return hours ? `${days}d ${hours}h` : `${days}d`;
36
+ if (hours)
37
+ return minutes % 60 ? `${hours}h ${minutes % 60}m` : `${hours}h`;
38
+ return `${minutes}m`;
39
+ };
40
+ export const compactUntil = (timestampArg, nowArg, unavailableArg = 'n/a') => {
41
+ if (timestampArg === null)
42
+ return 'not scheduled';
43
+ const remaining = Date.parse(timestampArg) - nowArg;
44
+ if (!Number.isFinite(remaining))
45
+ return unavailableArg;
46
+ if (remaining <= 0)
47
+ return 'due';
48
+ return remaining < 60000 ? '<1m' : twoUnits(remaining);
49
+ };
50
+ /**
51
+ * The same two-unit form for a past timestamp, for "saved 3d 4h ago".
52
+ *
53
+ * The result is always a bare duration or the caller's unavailable marker, never a phrase: callers
54
+ * suffix it ("... ago"), and a phrase would read as "just now ago". A span under a minute is `<1m`,
55
+ * exactly as `compactUntil` reports one.
56
+ */
57
+ export const compactSince = (timestampArg, nowArg, unavailableArg = 'n/a') => {
58
+ if (timestampArg === null)
59
+ return unavailableArg;
60
+ const elapsed = nowArg - Date.parse(timestampArg);
61
+ if (!Number.isFinite(elapsed))
62
+ return unavailableArg;
63
+ return elapsed < 60000 ? '<1m' : twoUnits(elapsed);
64
+ };
65
+ const twoDigits = (valueArg) => String(valueArg).padStart(2, '0');
66
+ /**
67
+ * A timestamp in local calendar time: `2026-10-08`, or `2026-10-08 23:14` with the time. Human output never prints
68
+ * a raw ISO timestamp; an unknown or unparseable one reads as the caller's unavailable marker.
69
+ */
70
+ const localTimestamp = (timestampArg, withTimeArg, unavailableArg) => {
71
+ const time = timestampArg === null ? Number.NaN : Date.parse(timestampArg);
72
+ if (!Number.isFinite(time))
73
+ return unavailableArg;
74
+ const date = new Date(time);
75
+ const day = `${date.getFullYear()}-${twoDigits(date.getMonth() + 1)}-${twoDigits(date.getDate())}`;
76
+ return withTimeArg ? `${day} ${twoDigits(date.getHours())}:${twoDigits(date.getMinutes())}` : day;
77
+ };
78
+ export const localDate = (timestampArg, unavailableArg = 'n/a') => localTimestamp(timestampArg, false, unavailableArg);
79
+ export const localDateTime = (timestampArg, unavailableArg = 'n/a') => localTimestamp(timestampArg, true, unavailableArg);
80
+ /** A moment's local time of day with seconds, `14:02:07`, for a log line whose date is implied. */
81
+ export const localTime = (timeArg) => {
82
+ const date = new Date(timeArg);
83
+ return [date.getHours(), date.getMinutes(), date.getSeconds()].map(twoDigits).join(':');
84
+ };
85
+ const ISO_TIMESTAMP = /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})/g;
86
+ /** Provider text with every ISO 8601 timestamp in it rewritten as local date and time. */
87
+ export const localiseTimestamps = (textArg) => textArg.replace(ISO_TIMESTAMP, match => localDateTime(match, match));
88
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZXRleHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy90aW1ldGV4dC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7R0FLRztBQUVILHlGQUF5RjtBQUN6RixNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxZQUEyQixFQUFFLE1BQWMsRUFBVSxFQUFFO0lBQzNFLElBQUksWUFBWSxLQUFLLElBQUk7UUFBRSxPQUFPLGVBQWUsQ0FBQztJQUNsRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxHQUFHLE1BQU0sQ0FBQztJQUNwRCxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUM7UUFBRSxPQUFPLGFBQWEsQ0FBQztJQUN0RCxJQUFJLFNBQVMsSUFBSSxDQUFDO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDakMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDOUMsSUFBSSxDQUFDLE9BQU87UUFBRSxPQUFPLE9BQU8sQ0FBQztJQUM3QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsQ0FBQztJQUN4QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDOUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLE9BQU8sR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsT0FBTyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FB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
@@ -1,4 +1,5 @@
1
- import { compactUntil, usagePercentText } from './accounts.js';
1
+ import { usagePercentText } from './accounts.js';
2
+ import { compactUntil } from './timetext.js';
2
3
  import { plainText } from './formatting.js';
3
4
  /**
4
5
  * How far below the threshold a switch target must be on every limit, so that a switch never lands on an account that
@@ -79,4 +80,4 @@ export const decideWatchAction = (inputArg) => {
79
80
  }
80
81
  return stay(true, `every limit below ${threshold}%`);
81
82
  };
82
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F0Y2hwb2xpY3kuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy93YXRjaHBvbGljeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLGdCQUFnQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQy9ELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQThCNUM7OztHQUdHO0FBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxFQUFFLENBQUM7QUFFNUIsTUFBTSxjQUFjLEdBQUcsQ0FBQyxVQUF5QixFQUF5QixFQUFFLENBQUMsQ0FBQyxVQUFVLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEtBQUssU0FBUyxDQUFDLENBQUM7QUFDckosTUFBTSxjQUFjLEdBQUcsQ0FBQyxVQUF5QixFQUF5QixFQUFFLENBQUMsQ0FBQyxVQUFVLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEtBQUssU0FBUyxDQUFDLENBQUM7QUFFckosNkhBQTZIO0FBQzdILE1BQU0sT0FBTyxHQUFHLENBQUMsVUFBMEMsRUFBRSxZQUFvQixFQUFtQyxFQUFFLENBQ3BILFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsV0FBVyxJQUFJLFlBQVksQ0FBQztLQUM1RCxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxXQUFXLElBQUksS0FBSyxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFFcEgsTUFBTSxTQUFTLEdBQUcsQ0FBQyxTQUE4QixFQUFFLFlBQW9CLEVBQVUs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
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F0Y2hwb2xpY3kuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy93YXRjaHBvbGljeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDakQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM3QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUE4QjVDOzs7R0FHRztBQUNILE1BQU0sZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO0FBRTVCLE1BQU0sY0FBYyxHQUFHLENBQUMsVUFBeUIsRUFBeUIsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxLQUFLLFNBQVMsQ0FBQyxDQUFDO0FBQ3JKLE1BQU0sY0FBYyxHQUFHLENBQUMsVUFBeUIsRUFBeUIsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxLQUFLLFNBQVMsQ0FBQyxDQUFDO0FBRXJKLDZIQUE2SDtBQUM3SCxNQUFNLE9BQU8sR0FBRyxDQUFDLFVBQTBDLEVBQUUsWUFBb0IsRUFBbUMsRUFBRSxDQUNwSCxVQUFVLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLFdBQVcsSUFBSSxZQUFZLENBQUM7S0FDNUQsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBRXBILE1BQU0sU0FBUyxH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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelprofile.com/authswitch",
3
- "version": "10.0.1",
3
+ "version": "10.1.0",
4
4
  "private": false,
5
5
  "description": "Manage Codex, OpenCode and Claude Code accounts with guided switching and live usage status",
6
6
  "main": "dist_ts/index.js",
@@ -14,6 +14,10 @@
14
14
  "types": "./dist_ts/mutation.d.ts",
15
15
  "import": "./dist_ts/mutation.js"
16
16
  },
17
+ "./preuse-text": {
18
+ "types": "./dist_ts/preuse-text.d.ts",
19
+ "import": "./dist_ts/preuse-text.js"
20
+ },
17
21
  "./authority-contract": {
18
22
  "types": "./dist_ts/authority-contract.d.ts",
19
23
  "import": "./dist_ts/authority-contract.js"
package/readme.md CHANGED
@@ -291,6 +291,26 @@ reason is `outcome_unknown` with problem `request_uncertain` and carries its cau
291
291
  (`{ kind, status, providerCode }`, for example `{ "kind": "http", "status": 503, "providerCode": null }`),
292
292
  never the provider's text. Human output prints both as sentences.
293
293
 
294
+ A host that shows receipts in a browser words them the same way through
295
+ `@modelprofile.com/authswitch/preuse-text`, the browser-safe entry point for those sentences:
296
+
297
+ ```ts
298
+ import { describePreuseFailure, describePreuseLimit, localDateTime } from '@modelprofile.com/authswitch/preuse-text';
299
+ import type { IAuthSwitchPreuseOperation } from '@modelprofile.com/authswitch/authority-contract';
300
+
301
+ const lines = (operation: IAuthSwitchPreuseOperation): string[] => [
302
+ ...(operation.limit ? [describePreuseLimit(operation.limit, Date.now())] : []),
303
+ ...(operation.failure ? [`Cause: ${describePreuseFailure(operation.failure)}`] : []),
304
+ ];
305
+ ```
306
+
307
+ `describePreuseLimit(limit, now)` names the window and the limit, and a stated reset as a countdown from
308
+ `now` with the local time (`Weekly usage limit reached, resets in 16h 46min (2026-09-27 05:12)`, or `due
309
+ to reset now` once it has passed); `describePreuseFailure(failure)` names the cause as the tail of a
310
+ sentence (`the provider answered HTTP 503`). `localDateTime(timestamp)` is the local time both use,
311
+ `2026-09-27 05:12`. The module loads nothing but that time text, which imports nothing either; the package
312
+ root exports the same three functions from the same source.
313
+
294
314
  For `account add`, `account reauth` and `account operation resume`, `--json` writes JSON Lines:
295
315
  each line is one complete operation receipt, and unchanged revisions are omitted. `account
296
316
  operation get --json` and `account operation cancel --json` each write one JSON object followed by
@@ -784,8 +804,8 @@ such as AGL all read this one rule; `remove` and a save that keeps the login
784
804
  active leave the loaded login in place.
785
805
 
786
806
  That rule, `assertAuthSwitchMutation` and the `TAuthSwitchMutation` command are also
787
- published on their own at `@modelprofile.com/authswitch/mutation`, which is the one
788
- import of this package a browser can bundle:
807
+ published on their own at `@modelprofile.com/authswitch/mutation`, which a browser can
808
+ bundle, as it can the preuse sentences at `./preuse-text`:
789
809
 
790
810
  ```ts
791
811
  import { authSwitchMutationReplacesLogin, type TAuthSwitchMutation } from '@modelprofile.com/authswitch/mutation';
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@modelprofile.com/authswitch',
6
- version: '10.0.1',
6
+ version: '10.1.0',
7
7
  description: 'Manage Codex, OpenCode and Claude Code accounts with guided switching and live usage status'
8
8
  }
package/ts/accounts.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { IAccountType, IAuthHarness, IHarnessAccount, IHarnessAccountStatus, IHarnessCredentialDrift, IHarnessState, IHarnessStatusOptions, IHarnessUsageWindow } from './interfaces.harness.js';
2
2
  import { plainText } from './formatting.js';
3
+ import { compactUntil, localDateTime, localiseTimestamps, until } from './timetext.js';
3
4
 
4
5
  export interface IAccountRow {
5
6
  harness: IAuthHarness;
@@ -23,75 +24,6 @@ const WINDOW_PERIODS: ReadonlyMap<number, string> = new Map([[18000, 'five-hour'
23
24
  * The narrow table cells stay on the compact form throughout (`5h 37% · 2h 13m`); a column is not a label.
24
25
  */
25
26
  export const usageWindowPeriod = (secondsArg: number): string => WINDOW_PERIODS.get(secondsArg) ?? duration(secondsArg);
26
- /** A countdown is a snapshot of the provider's deadline, not proof a quota has reset. */
27
- export const until = (timestampArg: string | null, nowArg: number): string => {
28
- if (timestampArg === null) return 'Not scheduled';
29
- const remaining = Date.parse(timestampArg) - nowArg;
30
- if (!Number.isFinite(remaining)) return 'Unavailable';
31
- if (remaining <= 0) return 'due';
32
- const minutes = Math.floor(remaining / 60000);
33
- if (!minutes) return '<1min';
34
- const days = Math.floor(minutes / 1440);
35
- const hours = Math.floor(minutes % 1440 / 60);
36
- return [days ? `${days}d` : '', hours ? `${hours}h` : '', minutes % 60 ? `${minutes % 60}min` : ''].filter(Boolean).join(' ');
37
- };
38
- /**
39
- * A two-unit countdown for condensed tables: `2h 13m`, `3d 4h`, `45m`.
40
- *
41
- * `until` stays the long form used by the list view and the TUI. This one trades the third unit for
42
- * a column that never wraps, and it never invents a deadline: an unknown or unparseable timestamp is
43
- * reported as such rather than as zero time remaining.
44
- */
45
- const twoUnits = (millisecondsArg: number): string => {
46
- const minutes = Math.floor(millisecondsArg / 60000);
47
- const days = Math.floor(minutes / 1440);
48
- const hours = Math.floor(minutes % 1440 / 60);
49
- if (days) return hours ? `${days}d ${hours}h` : `${days}d`;
50
- if (hours) return minutes % 60 ? `${hours}h ${minutes % 60}m` : `${hours}h`;
51
- return `${minutes}m`;
52
- };
53
- export const compactUntil = (timestampArg: string | null, nowArg: number, unavailableArg = 'n/a'): string => {
54
- if (timestampArg === null) return 'not scheduled';
55
- const remaining = Date.parse(timestampArg) - nowArg;
56
- if (!Number.isFinite(remaining)) return unavailableArg;
57
- if (remaining <= 0) return 'due';
58
- return remaining < 60000 ? '<1m' : twoUnits(remaining);
59
- };
60
- /**
61
- * The same two-unit form for a past timestamp, for "saved 3d 4h ago".
62
- *
63
- * The result is always a bare duration or the caller's unavailable marker, never a phrase: callers
64
- * suffix it ("... ago"), and a phrase would read as "just now ago". A span under a minute is `<1m`,
65
- * exactly as `compactUntil` reports one.
66
- */
67
- export const compactSince = (timestampArg: string | null, nowArg: number, unavailableArg = 'n/a'): string => {
68
- if (timestampArg === null) return unavailableArg;
69
- const elapsed = nowArg - Date.parse(timestampArg);
70
- if (!Number.isFinite(elapsed)) return unavailableArg;
71
- return elapsed < 60000 ? '<1m' : twoUnits(elapsed);
72
- };
73
- const twoDigits = (valueArg: number): string => String(valueArg).padStart(2, '0');
74
- /**
75
- * A timestamp in local calendar time: `2026-10-08`, or `2026-10-08 23:14` with the time. Human output never prints
76
- * a raw ISO timestamp; an unknown or unparseable one reads as the caller's unavailable marker.
77
- */
78
- const localTimestamp = (timestampArg: string | null, withTimeArg: boolean, unavailableArg: string): string => {
79
- const time = timestampArg === null ? Number.NaN : Date.parse(timestampArg);
80
- if (!Number.isFinite(time)) return unavailableArg;
81
- const date = new Date(time);
82
- const day = `${date.getFullYear()}-${twoDigits(date.getMonth() + 1)}-${twoDigits(date.getDate())}`;
83
- return withTimeArg ? `${day} ${twoDigits(date.getHours())}:${twoDigits(date.getMinutes())}` : day;
84
- };
85
- export const localDate = (timestampArg: string | null, unavailableArg = 'n/a'): string => localTimestamp(timestampArg, false, unavailableArg);
86
- export const localDateTime = (timestampArg: string | null, unavailableArg = 'n/a'): string => localTimestamp(timestampArg, true, unavailableArg);
87
- /** A moment's local time of day with seconds, `14:02:07`, for a log line whose date is implied. */
88
- export const localTime = (timeArg: number): string => {
89
- const date = new Date(timeArg);
90
- return [date.getHours(), date.getMinutes(), date.getSeconds()].map(twoDigits).join(':');
91
- };
92
- const ISO_TIMESTAMP = /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})/g;
93
- /** Provider text with every ISO 8601 timestamp in it rewritten as local date and time. */
94
- export const localiseTimestamps = (textArg: string): string => textArg.replace(ISO_TIMESTAMP, match => localDateTime(match, match));
95
27
 
96
28
  /**
97
29
  * One sentence for a credential file that no longer holds the account the last switch wrote.
@@ -6,7 +6,8 @@ import type { IAuthSwitchImportInventory, IAuthSwitchImportResult, IAuthSwitchIm
6
6
  IReq_AuthSwitchImportStatus, TAuthSwitchImportAction } from './authority-import-contract.js';
7
7
  import { AuthSwitchClient } from './classes.authorityclient.js';
8
8
  import { resolveAuthSwitchAuthorityPaths } from './classes.authorityservice.js';
9
- import { defaultPreusePrompt, describePreuseFailure, describePreuseLimit, validatePreuseOptions } from './preuse.js';
9
+ import { defaultPreusePrompt, validatePreuseOptions } from './preuse.js';
10
+ import { describePreuseFailure, describePreuseLimit } from './preuse-text.js';
10
11
  import { plainText } from './formatting.js';
11
12
  import * as plugins from './plugins.js';
12
13
 
package/ts/classes.cli.ts CHANGED
@@ -9,7 +9,8 @@ import { readAccountList } from './classes.accountlist.js';
9
9
  import { AccountListRenderer } from './classes.listrenderer.js';
10
10
  import { accountLimits, activeAccounts, CondensedRenderer } from './classes.limits.js';
11
11
  import { consoleHeading, consoleTable } from './consoletable.js';
12
- import { accountName, credentialDriftNote, readAccountBadges, until, usagePercentText } from './accounts.js';
12
+ import { accountName, credentialDriftNote, readAccountBadges, usagePercentText } from './accounts.js';
13
+ import { until } from './timetext.js';
13
14
  import { describeHarnessProcesses, describeStopOutcome } from './classes.harnessprocesses.js';
14
15
  import { defaultPreusePrompt, preuseAccounts, preuseCountsText, PreuseError, preuseTargets, validatePreuseOptions,
15
16
  type IPreuseRunSummary, type TPreuseAccountResult, type TPreuseOutcome, type TPreuseRunEvent } from './preuse.js';
@@ -1,8 +1,8 @@
1
1
  import * as plugins from './plugins.js';
2
2
  import type { ICodexIdentity } from './interfaces.js';
3
3
  import type { IHarnessPreuseOptions, IHarnessPreuseResult } from './interfaces.harness.js';
4
- import { PreuseError, PreuseFailureError, PreuseLimitError, preuseMayHaveConsumed, validatePreuseOptions,
5
- type IPreuseLimit } from './preuse.js';
4
+ import type { IAuthSwitchPreuseLimit } from './authority-contract.js';
5
+ import { PreuseError, PreuseFailureError, PreuseLimitError, preuseMayHaveConsumed, validatePreuseOptions } from './preuse.js';
6
6
  import { parseOpenAiTokenClaims } from './openaiauth.js';
7
7
  import { OpenAiBackendError, readOpenAiAccountUsage, type IOpenAiAccountUsage } from './openaiusage.js';
8
8
  import { usageWindowPeriod } from './accounts.js';
@@ -14,7 +14,7 @@ const PREUSE_TIMEOUT_MS = 180_000;
14
14
  * The limit the account's own usage reading says is reached, or null. Every window at its limit must reset
15
15
  * before a prompt can pass, so the one that resets last is named.
16
16
  */
17
- const reachedLimit = (usage: IOpenAiAccountUsage): IPreuseLimit | null => {
17
+ const reachedLimit = (usage: IOpenAiAccountUsage): IAuthSwitchPreuseLimit | null => {
18
18
  const limit = usage.rateLimits.rateLimit;
19
19
  if (!limit || (limit.allowed && !limit.limitReached)) return null;
20
20
  const exhausted = [limit.primaryWindow, limit.secondaryWindow]
@@ -1,5 +1,6 @@
1
1
  import * as plugins from './plugins.js';
2
- import { accountTypeText, compactSince, compactUntil, credentialDriftNote, localDate, orderedUsageWindows, usagePercentText } from './accounts.js';
2
+ import { accountTypeText, credentialDriftNote, orderedUsageWindows, usagePercentText } from './accounts.js';
3
+ import { compactSince, compactUntil, localDate } from './timetext.js';
3
4
  import { consoleHeading, consoleNote, consoleTable } from './consoletable.js';
4
5
  import type { IAccountList, IAccountLimitRow, IAccountLimits, IActiveAccountDrift, IActiveAccountRow, IActiveAccounts, IHarnessAccountList } from './interfaces.list.js';
5
6
  import type { IAccountType, IAuthHarness, IHarnessBilling, IHarnessCredentialDrift, TUsageSeverity } from './interfaces.harness.js';
@@ -1,5 +1,6 @@
1
1
  import * as plugins from './plugins.js';
2
- import { accountUsageWindows, compactUsageLine, credentialDriftProblem, localDate, localDateTime, localiseTimestamps } from './accounts.js';
2
+ import { accountUsageWindows, compactUsageLine, credentialDriftProblem } from './accounts.js';
3
+ import { localDate, localDateTime, localiseTimestamps } from './timetext.js';
3
4
  import { accountBilling, accountCell, accountLimits, accountType, CondensedRenderer, nextRenewal, renewalCell, UNAVAILABLE, usageColor, type THarnessTraits } from './classes.limits.js';
4
5
  import { consoleHeading, consoleNote, consoleTable, consoleWidth } from './consoletable.js';
5
6
  import type { IHarnessStatusFact, IHarnessStatusSummary } from './interfaces.harness.js';
package/ts/classes.tui.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as plugins from './plugins.js';
2
2
  import type { IAuthHarness, IHarnessAccount, IHarnessOutcome, IHarnessProcess, IHarnessState, IHarnessStopOutcome } from './interfaces.harness.js';
3
- import { accountBadge, accountDetails, accountPlan, accountQuotaSummary, accountResets, accountState, accountUsageWindows, usageWindowName, until, readAccountRows, type IAccountRow } from './accounts.js';
3
+ import { accountBadge, accountDetails, accountPlan, accountQuotaSummary, accountResets, accountState, accountUsageWindows, usageWindowName, readAccountRows, type IAccountRow } from './accounts.js';
4
+ import { until } from './timetext.js';
4
5
  import { defaultPreusePrompt, preuseAccounts, preuseCountsText, preuseTargets, type TPreuseAccountResult } from './preuse.js';
5
6
  import { plainText } from './formatting.js';
6
7
  import { AuthSwitchOperations, authSwitchMutationReplacesLogin, type TAuthSwitchMutation } from './classes.operations.js';
@@ -1,4 +1,5 @@
1
- import { accountBadge, accountName, durationText, localTime, readAccountRows, type IAccountRow } from './accounts.js';
1
+ import { accountBadge, accountName, durationText, readAccountRows, type IAccountRow } from './accounts.js';
2
+ import { localTime } from './timetext.js';
2
3
  import { pause } from './helpers.js';
3
4
  import { bold, dim, green, orange, plainText, red } from './formatting.js';
4
5
  import { decideWatchAction, type IWatchReading } from './watchpolicy.js';
package/ts/index.ts CHANGED
@@ -11,6 +11,7 @@ export * from './classes.claudestatus.js';
11
11
  export * from './classes.codexstatus.js';
12
12
  export * from './classes.codexpreuse.js';
13
13
  export * from './preuse.js';
14
+ export * from './preuse-text.js';
14
15
  export * from './helpers.js';
15
16
  export * from './classes.codexhome.js';
16
17
  export * from './classes.codexauth.js';
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The sentences that name what stopped a preuse, with no Node dependency.
3
+ *
4
+ * A preuse receipt carries its limit and its cause as data (`IAuthSwitchPreuseOperation.limit` and `.failure`);
5
+ * the command line and a host that shows receipts, AGL's web client for one, must word them alike. This module
6
+ * therefore loads nothing but the time text it renders a reset with, which imports nothing either, so that it can
7
+ * be bundled for a browser through the `@modelprofile.com/authswitch/preuse-text` entry point. The receipt types
8
+ * are type-only imports, which the emitted JavaScript drops.
9
+ */
10
+ import type { IAuthSwitchPreuseFailure, IAuthSwitchPreuseLimit } from './authority-contract.js';
11
+ import { localDateTime, until } from './timetext.js';
12
+
13
+ export { localDateTime } from './timetext.js';
14
+
15
+ /**
16
+ * `Weekly usage limit reached, resets in 16h 46min (2026-09-27 05:12)`: human text, so the reset reads in local time.
17
+ * The limit itself keeps its ISO `resetsAt` for receipts and JSON output.
18
+ */
19
+ export const describePreuseLimit = (limitArg: IAuthSwitchPreuseLimit, nowArg: number): string => {
20
+ const name = `${limitArg.window === null ? '' : `${limitArg.window} `}${limitArg.kind === 'usage_limit' ? 'usage' : 'rate'} limit reached`;
21
+ const countdown = limitArg.resetsAt === null ? null : until(limitArg.resetsAt, nowArg);
22
+ const at = localDateTime(limitArg.resetsAt);
23
+ const reset = limitArg.resetsAt === null ? ''
24
+ : countdown === 'due' ? `, due to reset now (${at})` : `, resets in ${countdown} (${at})`;
25
+ return `${name.charAt(0).toUpperCase()}${name.slice(1)}${reset}`;
26
+ };
27
+
28
+ /** `the provider answered HTTP 503`: the cause of a failed preuse, as the tail of a sentence. */
29
+ export const describePreuseFailure = (failureArg: IAuthSwitchPreuseFailure): string => {
30
+ const status = failureArg.status === null ? null : `HTTP ${failureArg.status}`;
31
+ switch (failureArg.kind) {
32
+ case 'http': return `the provider answered ${status ?? 'with an HTTP error'}`;
33
+ case 'stream':
34
+ return `the answer stream reported an error${failureArg.providerCode === null ? '' : ` (code ${failureArg.providerCode})`}`;
35
+ case 'response': return `the provider's answer${status ? ` (${status})` : ''} could not be read`;
36
+ case 'network': return 'no answer arrived: the connection failed';
37
+ case 'aborted': return 'the request was aborted';
38
+ case 'unknown': return 'the request ended in an error that names no cause';
39
+ }
40
+ };
package/ts/preuse.ts CHANGED
@@ -1,4 +1,6 @@
1
- import { localDateTime, orderedUsageWindows, until } from './accounts.js';
1
+ import type { IAuthSwitchPreuseFailure, IAuthSwitchPreuseLimit } from './authority-contract.js';
2
+ import { orderedUsageWindows } from './accounts.js';
3
+ import { describePreuseFailure, describePreuseLimit } from './preuse-text.js';
2
4
  import type { IAuthHarness, IHarnessAccount, IHarnessPreuseOptions, IHarnessPreuseResult, IHarnessUsageWindow } from './interfaces.harness.js';
3
5
 
4
6
  export const defaultPreusePrompt = 'Write 2000 words about strawberries.';
@@ -18,31 +20,8 @@ export class PreuseError extends Error {
18
20
  constructor(messageArg: string, public readonly requestStarted = false) { super(messageArg); }
19
21
  }
20
22
 
21
- /**
22
- * A limit that kept a preuse prompt from being answered.
23
- *
24
- * `usage_limit` is the account's quota, spent until it resets; `rate_limit` a short throttle. `window` names the
25
- * window by its length (`weekly`, `five-hour`) and `resetsAt` is an ISO time; either is null when the account's
26
- * usage reading or the provider's refusal did not state it.
27
- */
28
- export interface IPreuseLimit {
29
- kind: 'usage_limit' | 'rate_limit';
30
- window: string | null;
31
- resetsAt: string | null;
32
- }
33
-
34
- /**
35
- * `Weekly usage limit reached, resets in 16h 46min (2026-09-27 05:12)`: human text, so the reset reads in local time.
36
- * The limit itself keeps its ISO `resetsAt` for receipts and JSON output.
37
- */
38
- export const describePreuseLimit = (limitArg: IPreuseLimit, nowArg: number): string => {
39
- const name = `${limitArg.window === null ? '' : `${limitArg.window} `}${limitArg.kind === 'usage_limit' ? 'usage' : 'rate'} limit reached`;
40
- const countdown = limitArg.resetsAt === null ? null : until(limitArg.resetsAt, nowArg);
41
- const at = localDateTime(limitArg.resetsAt);
42
- const reset = limitArg.resetsAt === null ? ''
43
- : countdown === 'due' ? `, due to reset now (${at})` : `, resets in ${countdown} (${at})`;
44
- return `${name.charAt(0).toUpperCase()}${name.slice(1)}${reset}`;
45
- };
23
+ /** The authority's `IAuthSwitchPreuseLimit`, under the name the package root has exported since 10.0.0. */
24
+ export type IPreuseLimit = IAuthSwitchPreuseLimit;
46
25
 
47
26
  /**
48
27
  * A preuse a limit stopped. `usage` is the account's own usage reading before anything was sent; `provider`
@@ -50,7 +29,7 @@ export const describePreuseLimit = (limitArg: IPreuseLimit, nowArg: number): str
50
29
  * answer: a refusal before its answer consumed nothing.
51
30
  */
52
31
  export class PreuseLimitError extends PreuseError {
53
- constructor(public readonly limit: IPreuseLimit, public readonly source: 'usage' | 'provider',
32
+ constructor(public readonly limit: IAuthSwitchPreuseLimit, public readonly source: 'usage' | 'provider',
54
33
  public readonly generationStarted: boolean, nowArg: number) {
55
34
  const described = describePreuseLimit(limit, nowArg);
56
35
  super(source === 'usage' ? `${described}. No preuse prompt was sent.`
@@ -61,37 +40,12 @@ export class PreuseLimitError extends PreuseError {
61
40
  }
62
41
  }
63
42
 
64
- /**
65
- * Why a sent preuse prompt failed without a limit, and never with the provider's text.
66
- *
67
- * `http` is an answer with an HTTP error status; `stream` an error the answer stream reported after it began,
68
- * with the machine-readable code the provider stated and no status, since its answer was a success; `response` an answer that could not be read;
69
- * `network` a connection that failed before any answer; `aborted` an abort that was neither the caller's nor the
70
- * deadline; `unknown` anything else. `status` and `providerCode` are null when the failure did not state them.
71
- */
72
- export interface IPreuseFailure {
73
- kind: 'http' | 'stream' | 'response' | 'network' | 'aborted' | 'unknown';
74
- status: number | null;
75
- providerCode: string | null;
76
- }
77
-
78
- /** `the provider answered HTTP 503`: the cause of a failed preuse, as the tail of a sentence. */
79
- export const describePreuseFailure = (failureArg: IPreuseFailure): string => {
80
- const status = failureArg.status === null ? null : `HTTP ${failureArg.status}`;
81
- switch (failureArg.kind) {
82
- case 'http': return `the provider answered ${status ?? 'with an HTTP error'}`;
83
- case 'stream':
84
- return `the answer stream reported an error${failureArg.providerCode === null ? '' : ` (code ${failureArg.providerCode})`}`;
85
- case 'response': return `the provider's answer${status ? ` (${status})` : ''} could not be read`;
86
- case 'network': return 'no answer arrived: the connection failed';
87
- case 'aborted': return 'the request was aborted';
88
- case 'unknown': return 'the request ended in an error that names no cause';
89
- }
90
- };
43
+ /** The authority's `IAuthSwitchPreuseFailure`, under the name the package root has exported since 10.0.0. */
44
+ export type IPreuseFailure = IAuthSwitchPreuseFailure;
91
45
 
92
46
  /** A sent preuse prompt that failed for the stated cause; its tokens may have been consumed. */
93
47
  export class PreuseFailureError extends PreuseError {
94
- constructor(public readonly failure: IPreuseFailure) {
48
+ constructor(public readonly failure: IAuthSwitchPreuseFailure) {
95
49
  super(`Preuse did not complete: ${describePreuseFailure(failure)}. ${preuseMayHaveConsumed}`, true);
96
50
  }
97
51
  }
package/ts/timetext.ts ADDED
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Human time text: countdowns to a deadline and timestamps in local calendar time.
3
+ *
4
+ * It imports nothing, so the browser-safe `./preuse-text` entry point can render a reset exactly as the
5
+ * command line does without pulling a Node built-in into a bundle.
6
+ */
7
+
8
+ /** A countdown is a snapshot of the provider's deadline, not proof a quota has reset. */
9
+ export const until = (timestampArg: string | null, nowArg: number): string => {
10
+ if (timestampArg === null) return 'Not scheduled';
11
+ const remaining = Date.parse(timestampArg) - nowArg;
12
+ if (!Number.isFinite(remaining)) return 'Unavailable';
13
+ if (remaining <= 0) return 'due';
14
+ const minutes = Math.floor(remaining / 60000);
15
+ if (!minutes) return '<1min';
16
+ const days = Math.floor(minutes / 1440);
17
+ const hours = Math.floor(minutes % 1440 / 60);
18
+ return [days ? `${days}d` : '', hours ? `${hours}h` : '', minutes % 60 ? `${minutes % 60}min` : ''].filter(Boolean).join(' ');
19
+ };
20
+ /**
21
+ * A two-unit countdown for condensed tables: `2h 13m`, `3d 4h`, `45m`.
22
+ *
23
+ * `until` stays the long form used by the list view and the TUI. This one trades the third unit for
24
+ * a column that never wraps, and it never invents a deadline: an unknown or unparseable timestamp is
25
+ * reported as such rather than as zero time remaining.
26
+ */
27
+ const twoUnits = (millisecondsArg: number): string => {
28
+ const minutes = Math.floor(millisecondsArg / 60000);
29
+ const days = Math.floor(minutes / 1440);
30
+ const hours = Math.floor(minutes % 1440 / 60);
31
+ if (days) return hours ? `${days}d ${hours}h` : `${days}d`;
32
+ if (hours) return minutes % 60 ? `${hours}h ${minutes % 60}m` : `${hours}h`;
33
+ return `${minutes}m`;
34
+ };
35
+ export const compactUntil = (timestampArg: string | null, nowArg: number, unavailableArg = 'n/a'): string => {
36
+ if (timestampArg === null) return 'not scheduled';
37
+ const remaining = Date.parse(timestampArg) - nowArg;
38
+ if (!Number.isFinite(remaining)) return unavailableArg;
39
+ if (remaining <= 0) return 'due';
40
+ return remaining < 60000 ? '<1m' : twoUnits(remaining);
41
+ };
42
+ /**
43
+ * The same two-unit form for a past timestamp, for "saved 3d 4h ago".
44
+ *
45
+ * The result is always a bare duration or the caller's unavailable marker, never a phrase: callers
46
+ * suffix it ("... ago"), and a phrase would read as "just now ago". A span under a minute is `<1m`,
47
+ * exactly as `compactUntil` reports one.
48
+ */
49
+ export const compactSince = (timestampArg: string | null, nowArg: number, unavailableArg = 'n/a'): string => {
50
+ if (timestampArg === null) return unavailableArg;
51
+ const elapsed = nowArg - Date.parse(timestampArg);
52
+ if (!Number.isFinite(elapsed)) return unavailableArg;
53
+ return elapsed < 60000 ? '<1m' : twoUnits(elapsed);
54
+ };
55
+ const twoDigits = (valueArg: number): string => String(valueArg).padStart(2, '0');
56
+ /**
57
+ * A timestamp in local calendar time: `2026-10-08`, or `2026-10-08 23:14` with the time. Human output never prints
58
+ * a raw ISO timestamp; an unknown or unparseable one reads as the caller's unavailable marker.
59
+ */
60
+ const localTimestamp = (timestampArg: string | null, withTimeArg: boolean, unavailableArg: string): string => {
61
+ const time = timestampArg === null ? Number.NaN : Date.parse(timestampArg);
62
+ if (!Number.isFinite(time)) return unavailableArg;
63
+ const date = new Date(time);
64
+ const day = `${date.getFullYear()}-${twoDigits(date.getMonth() + 1)}-${twoDigits(date.getDate())}`;
65
+ return withTimeArg ? `${day} ${twoDigits(date.getHours())}:${twoDigits(date.getMinutes())}` : day;
66
+ };
67
+ export const localDate = (timestampArg: string | null, unavailableArg = 'n/a'): string => localTimestamp(timestampArg, false, unavailableArg);
68
+ export const localDateTime = (timestampArg: string | null, unavailableArg = 'n/a'): string => localTimestamp(timestampArg, true, unavailableArg);
69
+ /** A moment's local time of day with seconds, `14:02:07`, for a log line whose date is implied. */
70
+ export const localTime = (timeArg: number): string => {
71
+ const date = new Date(timeArg);
72
+ return [date.getHours(), date.getMinutes(), date.getSeconds()].map(twoDigits).join(':');
73
+ };
74
+ const ISO_TIMESTAMP = /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})/g;
75
+ /** Provider text with every ISO 8601 timestamp in it rewritten as local date and time. */
76
+ export const localiseTimestamps = (textArg: string): string => textArg.replace(ISO_TIMESTAMP, match => localDateTime(match, match));
package/ts/watchpolicy.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { compactUntil, usagePercentText } from './accounts.js';
1
+ import { usagePercentText } from './accounts.js';
2
+ import { compactUntil } from './timetext.js';
2
3
  import { plainText } from './formatting.js';
3
4
  import type { IHarnessUsageWindow } from './interfaces.harness.js';
4
5