@modelprofile.com/authswitch 10.0.0 → 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.
Files changed (44) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/accounts.d.ts +0 -17
  3. package/dist_ts/accounts.js +2 -82
  4. package/dist_ts/classes.authoritycli.js +3 -2
  5. package/dist_ts/classes.claudeauthority.d.ts +5 -0
  6. package/dist_ts/classes.claudeauthority.js +47 -4
  7. package/dist_ts/classes.claudecodelocks.d.ts +6 -0
  8. package/dist_ts/classes.claudecodelocks.js +30 -2
  9. package/dist_ts/classes.claudenative.d.ts +37 -2
  10. package/dist_ts/classes.claudenative.js +142 -13
  11. package/dist_ts/classes.cli.js +3 -2
  12. package/dist_ts/classes.codexpreuse.js +1 -1
  13. package/dist_ts/classes.limits.js +3 -2
  14. package/dist_ts/classes.listrenderer.js +3 -2
  15. package/dist_ts/classes.tui.js +3 -2
  16. package/dist_ts/classes.watch.js +3 -2
  17. package/dist_ts/index.d.ts +1 -0
  18. package/dist_ts/index.js +2 -1
  19. package/dist_ts/preuse-text.d.ts +18 -0
  20. package/dist_ts/preuse-text.js +28 -0
  21. package/dist_ts/preuse.d.ts +9 -36
  22. package/dist_ts/preuse.js +3 -27
  23. package/dist_ts/timetext.d.ts +23 -0
  24. package/dist_ts/timetext.js +88 -0
  25. package/dist_ts/watchpolicy.js +3 -2
  26. package/package.json +5 -1
  27. package/readme.md +38 -7
  28. package/ts/00_commitinfo_data.ts +1 -1
  29. package/ts/accounts.ts +1 -69
  30. package/ts/classes.authoritycli.ts +2 -1
  31. package/ts/classes.claudeauthority.ts +37 -3
  32. package/ts/classes.claudecodelocks.ts +31 -1
  33. package/ts/classes.claudenative.ts +161 -14
  34. package/ts/classes.cli.ts +2 -1
  35. package/ts/classes.codexpreuse.ts +3 -3
  36. package/ts/classes.limits.ts +2 -1
  37. package/ts/classes.listrenderer.ts +2 -1
  38. package/ts/classes.tui.ts +2 -1
  39. package/ts/classes.watch.ts +2 -1
  40. package/ts/index.ts +1 -0
  41. package/ts/preuse-text.ts +40 -0
  42. package/ts/preuse.ts +9 -55
  43. package/ts/timetext.ts +76 -0
  44. package/ts/watchpolicy.ts +2 -1
@@ -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.0",
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
@@ -332,10 +352,21 @@ been adopted. Until a verified `claude_native` import has adopted one, every Cla
332
352
  `CLAUDE_CONFIG_DIR` that is not an absolute path is refused when the daemon starts, because the same
333
353
  variable also decides which file the import would read; it is never resolved against a working directory.
334
354
 
335
- A switch is only attempted when the host can prove Claude Code uses that native login: exactly the
336
- verified Claude Code release, a subscriber login in the store, no credential override in the
337
- environment, no managed or local settings selecting another auth source, and no scoped Claude session
338
- running. Anything else refuses and leaves both logins where they were. A move that reaches the home and
355
+ A switch is only attempted when the host can prove Claude Code uses that native login: Claude Code
356
+ 2.1.273 or newer installed, a subscriber login in the store, no credential override in the environment
357
+ (including the remote well-known token files), no managed or local settings selecting another auth source,
358
+ and every Claude Code session running in that home on a verified release -- one whose lock table, live
359
+ credential pickup and refresh compare-and-swap were read from its bundle, currently 2.1.273 and 2.1.282.
360
+ An installed release above 2.1.273 that is not verified is proven by Claude Code's own answer instead:
361
+ `claude auth status --json` must report the claude.ai login of the outgoing account -- its organization and
362
+ email, the only account identifiers it names -- read from this home and with no API key, before the write,
363
+ and of the incoming account after it. That path runs only while
364
+ no Claude Code session runs in the home. If Claude Code does not report the incoming login after the
365
+ write, or the proof fails for any other reason, the exact outgoing bytes are written back while the locks
366
+ are provably still held and the handoff is aborted with `problem: unsupported_effective_auth`; when they
367
+ cannot be, the home is quarantined. A write whose proof never ran is proven by the reconcile that finds it
368
+ before it can commit. Anything else refuses and leaves
369
+ both logins where they were. A move that reaches the home and
339
370
  then cannot complete that proof is quarantined with `problem: unsupported_effective_auth`, and the
340
371
  handoff's optional `proofFailure` names which condition failed -- `unsupported_release`, `subscription`,
341
372
  `override`, `settings`, `profile`, `profile_unreadable` or `running_session` -- so an owner is told what
@@ -649,7 +680,7 @@ copy's own tokens, and nothing else. `preuse` remains a Codex capability.
649
680
 
650
681
  **Claude Code picks a switch up live.** A running session re-reads its credential
651
682
  file whenever the file changes, before its next request, and reloads `.claude.json`
652
- when that changes (verified against Claude Code 2.1.273). So `use`, `stash` and a
683
+ when that changes (verified against Claude Code 2.1.273 and 2.1.282). So `use`, `stash` and a
653
684
  backend activation never ask for Claude Code to be stopped and never suggest a
654
685
  restart; a switch reports `Running Claude Code sessions use it from their next
655
686
  request.` What authswitch must not do is write in the middle of that session's own
@@ -773,8 +804,8 @@ such as AGL all read this one rule; `remove` and a save that keeps the login
773
804
  active leave the loaded login in place.
774
805
 
775
806
  That rule, `assertAuthSwitchMutation` and the `TAuthSwitchMutation` command are also
776
- published on their own at `@modelprofile.com/authswitch/mutation`, which is the one
777
- 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`:
778
809
 
779
810
  ```ts
780
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.0',
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
 
@@ -418,7 +418,13 @@ export class ClaudeNativeAuthority {
418
418
  return publicHandoff(result.handoff);
419
419
  }
420
420
 
421
- private async classify(operationId: string, session: IClaudeNativeLockedSession): Promise<IAuthSwitchClaudeNativeHandoff> {
421
+ /**
422
+ * Settles a handoff from what its native home holds. A pair that is exactly the prepared target commits only
423
+ * once Claude Code is proven to select it: by the switch that just wrote it (`targetProven`), or here, under
424
+ * this lease -- which is what a restarted daemon relies on for a write whose proof it never ran.
425
+ */
426
+ private async classify(operationId: string, session: IClaudeNativeLockedSession,
427
+ options: { targetProven?: boolean } = {}): Promise<IAuthSwitchClaudeNativeHandoff> {
422
428
  const context = await this.database.readClaudeHandoffContext(operationId);
423
429
  if (!context) throw new Error('Claude handoff operation is missing.');
424
430
  const handoff = context.handoff;
@@ -441,6 +447,14 @@ export class ClaudeNativeAuthority {
441
447
  if (handoff.after && samePair(observed, handoff.after)
442
448
  && sameIdentity(observed.identity, handoff.targetIdentity)
443
449
  && accessDigest === handoff.targetAccessDigest) {
450
+ if (!options.targetProven) {
451
+ try { await session.proveEffectiveLogin(await this.unsealLogin(context.incomingAccount, context.incoming)); }
452
+ catch (error) {
453
+ // The original bytes are not journaled, so an unproven write cannot be undone here; it is held apart.
454
+ return this.settle(operationId, 'quarantined', observed.runningEffectiveAuth, 'unsupported_effective_auth',
455
+ error instanceof ClaudeNativeEffectiveAuthUnsupportedError ? error.reason : null);
456
+ }
457
+ }
444
458
  return this.settle(operationId, 'committed', observed.runningEffectiveAuth);
445
459
  }
446
460
  return this.settle(operationId, 'quarantined', observed.runningEffectiveAuth, 'foreign_or_torn');
@@ -504,6 +518,14 @@ export class ClaudeNativeAuthority {
504
518
  if (!context || !sameIdentity(before.identity, context.handoff.sourceIdentity) || !before.login) {
505
519
  return this.classify(operationId, session);
506
520
  }
521
+ // Claude Code must be running on the outgoing login before anything is written, or nothing here says
522
+ // what the handoff replaces; nothing is written yet, so the reservation is simply undone.
523
+ try { await session.proveEffectiveLogin(before.login); }
524
+ catch (error) {
525
+ if (!(error instanceof ClaudeNativeEffectiveAuthUnsupportedError)) throw error;
526
+ return this.settle(operationId, 'aborted', before.runningEffectiveAuth, 'unsupported_effective_auth',
527
+ error.reason);
528
+ }
507
529
  let outgoingProof: Awaited<ReturnType<IClaudeNativeLockedSession['verifyProfileIdentity']>>;
508
530
  try { outgoingProof = await session.verifyProfileIdentity(before, context.handoff.sourceIdentity); }
509
531
  catch {
@@ -518,8 +540,20 @@ export class ClaudeNativeAuthority {
518
540
  await this.prepare(operationId, loginId, prepared.plan.before, prepared.plan.after,
519
541
  outgoingProof.accessTokenDigest, prepared.plan.profile.accessTokenDigest,
520
542
  sealedOutgoing, before.runningEffectiveAuth);
521
- session.writePreparedIfCurrent(prepared.plan);
522
- return this.classify(operationId, session);
543
+ const written = session.writePreparedIfCurrent(prepared.plan);
544
+ if (written.kind !== 'written') return this.classify(operationId, session);
545
+ // Claude Code must now select the incoming login. Whatever keeps that from being proven -- its answer,
546
+ // a lost lock, a failed read -- is a failed proof: the exact outgoing bytes go back while the locks are
547
+ // provably still held and the handoff is aborted; if they cannot, the home is quarantined.
548
+ try { await session.proveEffectiveLogin(incomingLogin); }
549
+ catch (error) {
550
+ const reason = error instanceof ClaudeNativeEffectiveAuthUnsupportedError ? error.reason : null;
551
+ let restored = false;
552
+ try { restored = session.restorePreparedSource(prepared.plan); } catch { restored = false; }
553
+ return this.settle(operationId, restored ? 'aborted' : 'quarantined', written.snapshot.runningEffectiveAuth,
554
+ 'unsupported_effective_auth', reason);
555
+ }
556
+ return this.classify(operationId, session, { targetProven: true });
523
557
  });
524
558
  } catch {
525
559
  const outcome = await this.reconcileOperation(operationId);
@@ -17,8 +17,18 @@ interface IClaudeCodeLock {
17
17
  interface IHeldLock {
18
18
  lockfilePath: string;
19
19
  release: () => Promise<void>;
20
+ /** After how long another process may take this lock over when its time is not renewed. */
21
+ stale: number;
22
+ /** The lock directory as it was created for this hold: a takeover removes it and creates another. */
23
+ identity: { device: number; inode: number; birthtimeMs: number };
20
24
  }
21
25
 
26
+ /**
27
+ * How much of a lock's stale time must remain when a lease is asserted. Everything a caller does after an
28
+ * assertion is a synchronous file write, so no other process can find the lock stale before it completes.
29
+ */
30
+ const HOLD_MARGIN_MS = 2_000;
31
+
22
32
  export interface IClaudeCodeLocksOptions {
23
33
  /** How long an operation waits for a lock that Claude Code holds. */
24
34
  timeoutMs?: number;
@@ -26,6 +36,12 @@ export interface IClaudeCodeLocksOptions {
26
36
 
27
37
  /** The vendor locks may be lost while an awaited database operation is in flight. */
28
38
  export interface IClaudeCodeLockLease {
39
+ /**
40
+ * Proves, at this moment, that every lock is still this hold's: its directory is the one this hold created,
41
+ * and its time was renewed recently enough that no other process may take it over before a synchronous write
42
+ * that follows completes. A lock whose renewal stalled -- an event loop blocked past its update interval --
43
+ * fails this even when nobody has taken it yet.
44
+ */
29
45
  assertHeld(): void;
30
46
  }
31
47
 
@@ -134,6 +150,16 @@ export class ClaudeCodeLocks {
134
150
  const lease: IClaudeCodeLockLease = {
135
151
  assertHeld: () => {
136
152
  if (!active || compromised) throw new ClaudeCodeLockOutcomeUnknownError(false);
153
+ for (const lock of held) {
154
+ let current: plugins.fs.Stats;
155
+ try { current = plugins.fs.lstatSync(lock.lockfilePath); }
156
+ catch { throw new ClaudeCodeLockOutcomeUnknownError(false); }
157
+ if (!current.isDirectory() || current.dev !== lock.identity.device || current.ino !== lock.identity.inode
158
+ || current.birthtimeMs !== lock.identity.birthtimeMs
159
+ || Date.now() - current.mtimeMs > lock.stale - HOLD_MARGIN_MS) {
160
+ throw new ClaudeCodeLockOutcomeUnknownError(false);
161
+ }
162
+ }
137
163
  },
138
164
  };
139
165
  const releaseAll = async (): Promise<void> => {
@@ -189,7 +215,11 @@ export class ClaudeCodeLocks {
189
215
  const release = await lockfileArg.lock(lock.file, {
190
216
  lockfilePath: lock.lockfilePath, realpath: false, stale: lock.stale, update: lock.update, onCompromised: onCompromisedArg,
191
217
  });
192
- heldArg.push({ lockfilePath: lock.lockfilePath, release });
218
+ let created: plugins.fs.Stats;
219
+ try { created = plugins.fs.lstatSync(lock.lockfilePath); }
220
+ catch (error) { await release().catch(() => undefined); throw error; }
221
+ heldArg.push({ lockfilePath: lock.lockfilePath, release, stale: lock.stale,
222
+ identity: { device: created.dev, inode: created.ino, birthtimeMs: created.birthtimeMs } });
193
223
  } catch (error) {
194
224
  if (errorCode(error) === 'ELOCKED') return lock;
195
225
  if (requireAllArg || !lock.bestEffort) {