@1presence/bridge 0.71.0 → 0.73.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.
package/README.md CHANGED
@@ -53,7 +53,7 @@ Your OAuth tokens and vault data stay server-side — nothing sensitive is store
53
53
 
54
54
  ## Model
55
55
 
56
- On first run the bridge asks which Claude model you want it to use. Pick "Use Claude Code default" to defer to your local Claude Code default, or choose a specific model id to pin it (e.g. `claude-opus-4-8[1m]`, `claude-opus-4-8`, `claude-sonnet-4-6`, `claude-haiku-4-5`). The default selection (auto-chosen if the prompt times out) is `claude-opus-4-8[1m]`the latest Opus with a 1M-token context window. The choice is saved to `~/.1presence/config.json` and reused on every subsequent run.
56
+ On first run the bridge asks which Claude model you want it to use. Pick "Use Claude Code default" to defer to your local Claude Code default, or choose a specific model id to pin it (e.g. `claude-opus-5`, `claude-opus-4-8`, `claude-sonnet-5`, `claude-haiku-4-5`). The default selection (auto-chosen if the prompt times out) is "Use Claude Code default" it tracks whatever model Claude Code serves for your plan. The choice is saved to `~/.1presence/config.json` and reused on every subsequent run.
57
57
 
58
58
  The first reply each session prints the model and credential source so you can confirm what's running. To change your pick later, edit or delete `~/.1presence/config.json` — the bridge will prompt again on the next start.
59
59
 
package/dist/config.js CHANGED
@@ -94,12 +94,13 @@ function detectClaudeDefaultModel() {
94
94
  // actually a tool-schema bug that hit every model — see vault/Bugs.md.)
95
95
  const MODEL_OPTIONS = [
96
96
  { num: 1, model: null, label: 'Use Claude Code default' },
97
- { num: 2, model: 'claude-opus-4-8', label: 'claude-opus-4-8' },
98
- { num: 3, model: 'claude-opus-4-7', label: 'claude-opus-4-7' },
99
- { num: 4, model: 'claude-fable-5', label: 'claude-fable-5' },
100
- { num: 5, model: 'claude-sonnet-5', label: 'claude-sonnet-5' },
101
- { num: 6, model: 'claude-sonnet-4-6', label: 'claude-sonnet-4-6' },
102
- { num: 7, model: 'claude-haiku-4-5', label: 'claude-haiku-4-5' },
97
+ { num: 2, model: 'claude-opus-5', label: 'claude-opus-5' },
98
+ { num: 3, model: 'claude-opus-4-8', label: 'claude-opus-4-8' },
99
+ { num: 4, model: 'claude-opus-4-7', label: 'claude-opus-4-7' },
100
+ { num: 5, model: 'claude-fable-5', label: 'claude-fable-5' },
101
+ { num: 6, model: 'claude-sonnet-5', label: 'claude-sonnet-5' },
102
+ { num: 7, model: 'claude-sonnet-4-6', label: 'claude-sonnet-4-6' },
103
+ { num: 8, model: 'claude-haiku-4-5', label: 'claude-haiku-4-5' },
103
104
  ];
104
105
  const PROMPT_TIMEOUT_MS = 10_000;
105
106
  // Default to option 1 ("Use Claude Code default") — the dynamic choice that
package/dist/index.js CHANGED
@@ -47,6 +47,10 @@ const PWA_URL = process.env.BRIDGE_PWA_URL ?? GATEWAY_HTTP.replace('://api.', ':
47
47
  // ─── In-memory state ──────────────────────────────────────────────────────────
48
48
  let currentAuth = null;
49
49
  let currentWs = null;
50
+ // When the socket first dropped, for reporting how long the bridge was offline
51
+ // once it reconnects. Set on the first disconnect of an outage (repeated failed
52
+ // reconnect attempts don't reset it), cleared on a successful open.
53
+ let disconnectedAt = null;
50
54
  // Running cost across all turns this process has handled, for the cost segment
51
55
  // of the per-turn status line. On a pure subscription the CLI often reports a
52
56
  // per-turn cost of 0, in which case this stays at 0 and reads as "plan usage".
@@ -67,16 +71,19 @@ const MAX_AUTH_REJECTIONS = 3;
67
71
  // 5h/7d subscription rate-limit windows it also shows are deliberately absent —
68
72
  // those ride in the API's rate-limit response HEADERS, which the bridge (a
69
73
  // consumer of the CLI's stream-json stdout only) never sees. Display only.
70
- // Raw model id (claude-opus-4-7, claude-sonnet-4-6-20250101) to friendly "Opus
71
- // 4.7". Regex-based so new dated snapshots format without a table edit; an
72
- // unrecognised shape falls back to the raw id rather than guessing.
74
+ // Raw model id (claude-opus-5, claude-opus-4-7, claude-sonnet-4-6-20250101) to
75
+ // friendly "Opus 5" / "Opus 4.7". Regex-based so new dated snapshots format
76
+ // without a table edit; an unrecognised shape falls back to the raw id rather
77
+ // than guessing. The minor version is capped at 2 digits so a dated snapshot on
78
+ // a single-number id (claude-opus-5-20260724) reads "Opus 5", not "Opus 5.2026…".
73
79
  function friendlyModelName(model) {
74
80
  if (!model)
75
81
  return 'unknown';
76
- const m = /claude-(opus|sonnet|haiku)-(\d+)-(\d+)/i.exec(model);
82
+ const m = /claude-(opus|sonnet|haiku|fable|mythos)-(\d+)(?:-(\d{1,2})(?!\d))?/i.exec(model);
77
83
  if (!m)
78
84
  return model;
79
- return `${m[1].charAt(0).toUpperCase()}${m[1].slice(1)} ${m[2]}.${m[3]}`;
85
+ const family = `${m[1].charAt(0).toUpperCase()}${m[1].slice(1)}`;
86
+ return m[3] ? `${family} ${m[2]}.${m[3]}` : `${family} ${m[2]}`;
80
87
  }
81
88
  // Context window (tokens) per model, for the context-fill estimate. Keyed by a
82
89
  // family regex against the raw model id; first match wins, and an unrecognised
@@ -90,6 +97,10 @@ function friendlyModelName(model) {
90
97
  // else. (The percentage is of the raw window — local Claude's own gauge also
91
98
  // reserves output headroom, so its reading runs a few points higher near full.)
92
99
  const CONTEXT_WINDOWS = [
100
+ // 5-generation Opus/Sonnet + Mythos-class ship with a 1M window as the
101
+ // DEFAULT (not an opt-in beta), so the bridge's print mode gets it too.
102
+ // Haiku is deliberately excluded (4.5 is 200k and falls to the baseline).
103
+ { match: /claude-(opus|sonnet|fable|mythos)-5/i, tokens: 1_000_000 },
93
104
  { match: /claude-(opus|sonnet|haiku)-4/i, tokens: 200_000 },
94
105
  ];
95
106
  const DEFAULT_CONTEXT_WINDOW = 200_000;
@@ -622,7 +633,14 @@ function connect(auth, retryDelay = 1000) {
622
633
  // 4001 refresh-retry budget so a future expiry gets the full allowance.
623
634
  authRejections = 0;
624
635
  const who = auth.email ? ` as ${auth.email}` : '';
625
- console.log(`✓ Bridge connected${who}. Local Mode active on all your devices.\n`);
636
+ if (disconnectedAt !== null) {
637
+ const downFor = formatElapsed(Math.round((Date.now() - disconnectedAt) / 1000));
638
+ disconnectedAt = null;
639
+ console.log(`✓ Bridge reconnected${who} after ${downFor} offline. Local Mode active on all your devices.\n`);
640
+ }
641
+ else {
642
+ console.log(`✓ Bridge connected${who}. Local Mode active on all your devices.\n`);
643
+ }
626
644
  startPing();
627
645
  // Drain any save records left behind by an earlier crashed/dropped session.
628
646
  // Fire-and-forget — the network is up, the gateway is reachable, and we
@@ -725,9 +743,14 @@ function connect(auth, retryDelay = 1000) {
725
743
  function scheduleReconnect(closeCode, retryDelay) {
726
744
  const authFailure = closeCode === 4001;
727
745
  const delay = Math.min(retryDelay, 30_000);
746
+ // Stamp the start of the outage — only on the first drop, so the offline
747
+ // duration reported on reconnect spans failed retry cycles too.
748
+ if (disconnectedAt === null)
749
+ disconnectedAt = Date.now();
750
+ const who = currentAuth?.email ? ` for ${currentAuth.email}` : '';
728
751
  console.log(authFailure
729
- ? `Authentication expired (${closeCode}). Refreshing token and reconnecting in ${delay / 1000}s…`
730
- : `Bridge disconnected (${closeCode}). Reconnecting in ${delay / 1000}s…`);
752
+ ? `Authentication expired (${closeCode})${who}. Refreshing token and reconnecting in ${delay / 1000}s…`
753
+ : `Bridge disconnected (${closeCode})${who}. Reconnecting in ${delay / 1000}s…`);
731
754
  setTimeout(async () => {
732
755
  if (!currentAuth)
733
756
  return;
package/dist/timer.js CHANGED
@@ -17,9 +17,14 @@ function draw() {
17
17
  export function formatElapsed(seconds) {
18
18
  if (seconds < 60)
19
19
  return `${seconds}s`;
20
- const m = Math.floor(seconds / 60);
21
- const s = seconds % 60;
22
- return `${m}m ${s.toString().padStart(2, '0')}s`;
20
+ if (seconds < 3600) {
21
+ const m = Math.floor(seconds / 60);
22
+ const s = seconds % 60;
23
+ return `${m}m ${s.toString().padStart(2, '0')}s`;
24
+ }
25
+ const h = Math.floor(seconds / 3600);
26
+ const m = Math.floor((seconds % 3600) / 60);
27
+ return `${h}h ${m.toString().padStart(2, '0')}m`;
23
28
  }
24
29
  export function startTurnTimer() {
25
30
  if (intervalId !== null)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1presence/bridge",
3
- "version": "0.71.0",
3
+ "version": "0.73.0",
4
4
  "description": "Run 1Presence on your Mac and use your Claude.ai Pro subscription from any device",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",