@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.
- package/CHANGELOG.md +27 -0
- package/bin/leftoff.js +266 -266
- package/mod/.claude-plugin/plugin.json +1 -1
- package/mod/hooks/core.js +122 -5
- package/mod/hooks/register.js +31 -8
- package/package.json +1 -1
- package/ui/app.css +29 -3
- package/ui/app.js +237 -60
- package/ui/relay-client.js +7 -1
- package/ui/repos.js +2 -0
- package/ui/settings-nav.js +2 -2
package/ui/relay-client.js
CHANGED
|
@@ -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 & 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
|
|
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 & 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'
|
package/ui/settings-nav.js
CHANGED
|
@@ -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: '
|
|
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 = []) {
|