@leftoff/cli 0.6.5 → 0.6.8

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.
@@ -152,9 +152,13 @@ function needsKey() {
152
152
  screen('Pair this browser again', '<p>This browser has a pass for ' + esc(RELAY_USER) + '.leftoff.dev but not the key that unlocks your board (it lives only in this browser, and it’s gone: private browsing, cleared website data, or another browser).</p>' +
153
153
  '<p>On a Mac: Settings → Phone &amp; remote → <b>Pair a phone</b>, then scan the QR code.</p><p><a class="btn primary" href="/pair.html">I have a code</a></p>')
154
154
  }
155
+ let notPairedShown = false
155
156
  function notPaired(revoked) {
157
+ // once shown, a later 401 (the event stream, a poll) doesn't redraw it
158
+ if (notPairedShown) return
159
+ notPairedShown = true
156
160
  forgetDeviceKey()
157
- screen('This browser isn’t paired anymore', '<p>' + (revoked ? 'It was revoked on one of your Macs.' : 'It was revoked, or its pass expired.') + ' Pair it again from a Mac: Settings → Phone &amp; remote → <b>Pair a phone</b>.</p><p><a class="btn primary" href="/pair.html">I have a code</a></p>')
161
+ screen('This browser isn’t paired anymore', '<p>' + (revoked === 'self' ? 'You revoked it.' : revoked ? 'It was revoked on one of your devices.' : 'It was revoked, or its pass expired.') + ' Pair it again from a Mac: Settings → Phone &amp; remote → <b>Pair a phone</b>.</p><p><a class="btn primary" href="/pair.html">I have a code</a></p>')
158
162
  }
159
163
  let asleepShown = false
160
164
  function asleep() {
@@ -175,6 +179,8 @@ export const leftoffRelay = {
175
179
  status: () => refreshStatus(),
176
180
  // Switch Macs: the board reloads from the other one.
177
181
  pick(mac) { remember(mac); cookieMac(mac); location.reload() },
182
+ // This browser revoked itself (0.6.6).
183
+ unpaired() { notPaired('self') },
178
184
  }
179
185
 
180
186
  if (RELAY_USER) {
package/ui/repos.js CHANGED
@@ -95,6 +95,8 @@ export const STATUS_FILTERS = {
95
95
  waiting: ['waiting'],
96
96
  dormant: ['dormant', 'stale'],
97
97
  ended: ['ended'],
98
+ // 0.6.7: every ended session, not just today's (the Board's Closed view)
99
+ closed: ['ended'],
98
100
  }
99
101
 
100
102
  export const STORE_KEY = 'cp.repos'
@@ -9,10 +9,10 @@ export const SETTINGS = [
9
9
  { key: 'agents', label: 'Agents', icon: 'bot', sub: 'Work from AI assistants outside Claude Code.', words: 'tab feed agent key url host hosting add refresh remove' },
10
10
  { key: 'models', label: 'Models & summaries', icon: 'sparkles', sub: 'Who writes your checkpoints, and how long they are.', words: 'summarizer provider model ollama anthropic openai claude haiku sonnet opus api key server url length short long informative', save: true },
11
11
  { key: 'phone', label: 'Phone & remote', icon: 'smartphone', sub: 'Your board on your iPhone, from anywhere or over Tailscale.', words: 'use from anywhere relay leftoff.dev subdomain pair pairing device devices revoke tailscale remote access qr code sign in signed iphone home screen url app' },
12
- { key: 'security', label: 'Privacy & security', icon: 'shield', sub: 'Who can answer prompts here, and machine keys.', words: 'answer answering permission prompts other machines go keys fingerprint trust privacy data protected encryption', save: true },
12
+ { key: 'security', label: 'Privacy & security', icon: 'shield', sub: 'Trust my paired devices, and machine keys.', words: 'answer answering permission prompts trust trusted paired devices phone other machines go keys fingerprint privacy data protected encryption advanced', save: true },
13
13
  { key: 'updates', label: 'Updates & about', icon: 'info', sub: 'Version, updates and this Mac.', words: 'update upgrade version check about machine folder what’s new whats new changelog', save: true },
14
14
  ]
15
- export const SETTINGS_ALIAS = { anywhere: 'phone', relay: 'phone', remote: 'phone', tailscale: 'phone', iphone: 'phone', machines: 'security', answering: 'security', privacy: 'security', summaries: 'models', summarizer: 'models', model: 'models', ai: 'models', syncthing: 'sync', pairing: 'sync', pair: 'sync', about: 'updates', update: 'updates', version: 'updates', checkpoints: 'general', appearance: 'general', theme: 'general', notify: 'general' }
15
+ export const SETTINGS_ALIAS = { anywhere: 'phone', relay: 'phone', remote: 'phone', tailscale: 'phone', iphone: 'phone', machines: 'security', answering: 'security', trust: 'security', privacy: 'security', summaries: 'models', summarizer: 'models', model: 'models', ai: 'models', syncthing: 'sync', pairing: 'sync', pair: 'sync', about: 'updates', update: 'updates', version: 'updates', checkpoints: 'general', appearance: 'general', theme: 'general', notify: 'general' }
16
16
  // The section a route asks for: #/settings/<key>, or the old ?<key> form
17
17
  // (#/settings?spaces, ?sync, ?remote…); null means the list.
18
18
  export function settingsKeyFor(arg, paramKeys = []) {