@vibelord/lanes 1.0.0 → 1.0.1

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 (34) hide show
  1. package/package.json +1 -1
  2. package/payload/lanes/README.md +56 -1
  3. package/payload/lanes/VERSION +1 -1
  4. package/payload/lanes/bin/lanes +281 -104
  5. package/payload/lanes/client/lanes-launch +44 -2
  6. package/payload/lanes/container/env.sh +8 -0
  7. package/payload/lanes/container/lane +19 -2
  8. package/payload/lanes/docs/ARCHITECTURE.md +86 -1
  9. package/payload/lanes/docs/DESIGN.md +72 -0
  10. package/payload/lanes/docs/INSTALL.md +39 -0
  11. package/payload/lanes/docs/RUNBOOK.md +94 -1
  12. package/payload/lanes/holders/ssh.sh +18 -0
  13. package/payload/lanes/install/enable-phone.sh +15 -6
  14. package/payload/lanes/install/enable-web.sh +19 -6
  15. package/payload/lanes/libexec/agent_state.py +214 -0
  16. package/payload/lanes/libexec/connection.py +178 -0
  17. package/payload/lanes/libexec/cursor_sync.py +139 -6
  18. package/payload/lanes/libexec/device_sync.py +134 -0
  19. package/payload/lanes/libexec/lanes_lib.py +158 -5
  20. package/payload/lanes/libexec/registrations.py +148 -0
  21. package/payload/lanes/libexec/session_actions.py +47 -15
  22. package/payload/lanes/libexec/sidebar.py +372 -61
  23. package/payload/lanes/libexec/statusd.py +126 -33
  24. package/payload/lanes/libexec/tokens.py +279 -0
  25. package/payload/lanes/libexec/tokens.sh +11 -0
  26. package/payload/lanes/libexec/view.sh +9 -8
  27. package/payload/lanes/web/README.md +15 -0
  28. package/payload/lanes/web/browser.css +22 -0
  29. package/payload/lanes/web/browser.js +73 -0
  30. package/payload/lanes/web/mobile.css +65 -33
  31. package/payload/lanes/web/mobile.js +23 -5
  32. package/payload/lanes/workspaces.example/README.md +9 -3
  33. package/payload/lanes/zellij/config.kdl +61 -3
  34. package/payload/manifest.json +6 -3
@@ -0,0 +1,22 @@
1
+ /* LNS-31 laptop/tablet extras, outside the phone's mobile.css budget (spec §8). No scroll-time paint. */
2
+ /* Tablet (LNS-31): the dock joins the top bar; the workspace sheet is a left panel */
3
+ html.lanes-tablet, html.lanes-tablet.lanes-keyboard { --lanes-dock: 0px; }
4
+ .lanes-tablet .lanes-dock { position: static; display: flex; gap: 4px; width: auto; height: 48px; padding: 0; border: 0; background: none; }
5
+ .lanes-tablet .lanes-dock .lanes-button { flex-direction: row; gap: 6px; min-height: 44px; padding: 0 10px; }
6
+ .lanes-tablet .lanes-dock .lanes-button span { font-size: 13px; }
7
+ .lanes-tablet .lanes-terminal-input { width: 140px; height: 44px; }
8
+ .lanes-tablet .lanes-input-label { flex-direction: row; }
9
+ .lanes-tablet .lanes-filter-bar { flex: 0 1 220px; }
10
+ .lanes-tablet .lanes-sheet { align-items: stretch; padding: 0; }
11
+ .lanes-tablet .lanes-sheet-panel {
12
+ width: min(400px, 85vw); max-height: none; border: 1px solid var(--lanes-border); border-left: 0;
13
+ border-radius: 0 24px 24px 0; padding: calc(20px + var(--lanes-safe-top)) 16px calc(8px + var(--lanes-safe-bottom)) calc(16px + var(--lanes-safe-left));
14
+ }
15
+
16
+ /* Desktop (LNS-31): the plain client plus a Lanes chip and its overlay bar; system colours */
17
+ .lanes-chip, .lanes-bar { position: fixed; z-index: 600; color-scheme: dark; font: 13px system-ui, sans-serif; }
18
+ .lanes-chip { top: 4px; right: 8px; padding: 2px 10px; border: 1px solid GrayText; border-radius: 12px; background: Canvas; color: CanvasText; opacity: .7; cursor: pointer; }
19
+ .lanes-chip:hover, .lanes-chip[aria-expanded="true"] { opacity: 1; }
20
+ .lanes-bar { top: 0; left: 0; right: 0; height: 34px; display: flex; gap: 8px; align-items: center; padding: 0 80px 0 8px; background: Canvas; border-bottom: 1px solid GrayText; }
21
+ .lanes-bar[hidden] { display: none; }
22
+ .lanes-bar select { max-width: 40%; height: 26px; border: 1px solid GrayText; border-radius: 6px; background: Canvas; color: CanvasText; font: inherit; }
@@ -0,0 +1,73 @@
1
+ /* LNS-31 laptop/tablet extras; see docs/ARCHITECTURE.md (Web and phone). */
2
+ function laneBarModel(d) {
3
+ const panes = (d?.panes || []).filter(p => !p.is_plugin), at = d?.active_pane || {}, ws = new Map();
4
+ const first = t => t && panes.find(p => p.tab_position === t.position);
5
+ for (const t of d?.tabs || []) {
6
+ const name = t.name.replace(/ ☰$/, '');
7
+ ws.set(name, {...ws.get(name), name, [name === t.name ? 'view' : 'picker']: t});
8
+ }
9
+ const here = [...ws.values()].find(g => [g.view, g.picker].some(t => t && t.position === at.tab_position));
10
+ const item = (label, p, current = p?.pane_id === at.pane_id) => p && {label, pane: p.pane_id, current};
11
+ return {
12
+ workspaces: [...ws.values()].map(g => item(g.name, first(g.view) || first(g.picker), g === here)).filter(Boolean),
13
+ lanes: [item('☰ Choose a lane', first(here?.picker)), ...panes.filter(p => p.tab_position === here?.view?.position)
14
+ .map(p => item(p.title || `Pane ${p.pane_id}`, p))].filter(Boolean),
15
+ };
16
+ }
17
+ // Tablet: upstream starts single pane on every load; once, send its own switch-to-desktop prefs.
18
+ function laneFullRender(api, send) {
19
+ let done;
20
+ return () => {
21
+ const s = api.getState?.();
22
+ if (done || !s?.initialPrefsSent || s.renderMode !== 'single-pane') return false;
23
+ done = s.renderMode = 'full';
24
+ s.fitEnabled = true;
25
+ send({type: 'SetMobileRenderPreferences', single_pane: false, fit: true});
26
+ return true;
27
+ };
28
+ }
29
+ if (typeof module === 'object') module.exports = {laneBarModel, laneFullRender};
30
+ (() => {
31
+ const mode = globalThis.document?.documentElement.dataset.lanesShell;
32
+ if (mode !== 'desktop' && mode !== 'tablet') return;
33
+ const send = p => window.__zjSendControl?.(p), focus = () => window.term?.focus();
34
+ const make = (tag, props) => Object.assign(document.createElement(tag), props);
35
+ const ready = api => {
36
+ const setData = api.setData, after = mode === 'tablet' ? tablet(api) : desktop(api);
37
+ api.setData = v => {setData.call(api, v); after();};
38
+ after();
39
+ };
40
+ const tablet = api => {
41
+ const full = laneFullRender(api, send);
42
+ return () => full() && dispatchEvent(new Event('zellij:rendering-resize'));
43
+ };
44
+ // Desktop: the chip toggles an overlay bar (no refit); picks send the phone picker's FocusPane.
45
+ const desktop = api => {
46
+ let last;
47
+ const picks = ['Workspace', 'Lane'].map(title => make('select', {title, onchange() {
48
+ send({type: 'FocusPane', pane_id: +this.value, is_plugin: false});
49
+ focus();
50
+ }}));
51
+ const bar = make('nav', {className: 'lanes-bar', hidden: true});
52
+ const render = () => {
53
+ const m = !bar.hidden && laneBarModel(api.getState()?.data), sig = JSON.stringify(m);
54
+ if (!m || sig === last) return;
55
+ last = sig;
56
+ [m.workspaces, m.lanes].forEach((l, i) => picks[i].replaceChildren(...l.map(o => new Option(o.label, o.pane, 0, o.current))));
57
+ };
58
+ const chip = make('button', {className: 'lanes-chip', textContent: 'Lanes', ariaExpanded: false, onclick() {
59
+ chip.ariaExpanded = !(bar.hidden = !bar.hidden);
60
+ last = '';
61
+ render();
62
+ window.term?.focus();
63
+ }});
64
+ chip.addEventListener('mousedown', ev => ev.preventDefault()); // the terminal keeps the keys
65
+ bar.addEventListener('keydown', ev => ev.key === 'Escape' && focus());
66
+ bar.append(...picks);
67
+ document.body.append(bar, chip);
68
+ return render;
69
+ };
70
+ const ui = () => window.__zjMobileUi; // set synchronously after the client appends its mobile root
71
+ if (ui()) return ready(ui());
72
+ new MutationObserver((_, o) => ui() && (o.disconnect(), ready(ui()))).observe(document.body, {childList: true});
73
+ })();
@@ -1,15 +1,70 @@
1
- /* Safe areas apply in Home Screen mode and on both sides of landscape Safari. */
1
+ /* BEGIN lanes tokens (generated by libexec/tokens.py --css; do not edit by hand) */
2
2
  html.lanes-mobile {
3
- --lanes-bg: #101318;
4
- --lanes-panel: #191e25;
5
- --lanes-border: #2c333d;
6
- --lanes-text: #edf1f5;
7
- --lanes-muted: #9ca7b5;
8
- --lanes-accent: #b4e3bf;
9
- --lanes-current: #1a2721;
10
- --lanes-current-border: #4b6955;
3
+ --lanes-surface: #101318;
4
+ --lanes-surface-raised: #191e25;
5
+ --lanes-line: #2c333d;
6
+ --lanes-accent-wash: #1a2721;
7
+ --lanes-accent-line: #4b6955;
11
8
  --lanes-press: #26332c;
12
- --lanes-chip: #ffffff09;
9
+ --lanes-chip: #ffffff0f;
10
+ --lanes-ink: #edf1f5;
11
+ --lanes-ink-dim: #9ca7b5;
12
+ --lanes-ink-faint: #6b7683;
13
+ --lanes-accent: #b4e3bf;
14
+ --lanes-on-accent: #101318;
15
+ --lanes-on-accent-urgent: #7a1a12;
16
+ --lanes-tone-urgent: #f28b7d;
17
+ --lanes-tone-attention: #e5b84a;
18
+ --lanes-tone-working: #7fb3f2;
19
+ --lanes-tone-done: #6fd39a;
20
+ --lanes-scrim: #000000a6;
21
+ --lanes-shadow: 0 -16px 80px #0007;
22
+ color-scheme: dark;
23
+ }
24
+ html.lanes-mobile:root[data-zj-theme="light"] {
25
+ --lanes-surface: #f3f5f2;
26
+ --lanes-surface-raised: #ffffff;
27
+ --lanes-line: #d5ded6;
28
+ --lanes-accent-wash: #e5f0e6;
29
+ --lanes-accent-line: #acc9b4;
30
+ --lanes-press: #d8e9db;
31
+ --lanes-chip: #edf3ec;
32
+ --lanes-ink: #17241b;
33
+ --lanes-ink-dim: #56616d;
34
+ --lanes-ink-faint: #7f8a96;
35
+ --lanes-accent: #2f6b45;
36
+ --lanes-on-accent: #ffffff;
37
+ --lanes-on-accent-urgent: #ffd3cc;
38
+ --lanes-tone-urgent: #b7322a;
39
+ --lanes-tone-attention: #8a5a00;
40
+ --lanes-tone-working: #2456a8;
41
+ --lanes-tone-done: #1b7142;
42
+ --lanes-scrim: #1a222b80;
43
+ --lanes-shadow: 0 -16px 80px #0003;
44
+ color-scheme: light;
45
+ }
46
+ html.lanes-mobile:root {
47
+ --lanes-bg: var(--lanes-surface);
48
+ --lanes-panel: var(--lanes-surface-raised);
49
+ --lanes-border: var(--lanes-line);
50
+ --lanes-text: var(--lanes-ink);
51
+ --lanes-muted: var(--lanes-ink-dim);
52
+ --lanes-current: var(--lanes-accent-wash);
53
+ --lanes-current-border: var(--lanes-accent-line);
54
+ --zj-bg: var(--lanes-surface);
55
+ --zj-surface: var(--lanes-surface-raised);
56
+ --zj-border: var(--lanes-line);
57
+ --zj-text: var(--lanes-ink);
58
+ --zj-text-dim: var(--lanes-ink-dim);
59
+ --zj-green: var(--lanes-tone-done);
60
+ --zj-blue: var(--lanes-tone-working);
61
+ --zj-red: var(--lanes-tone-urgent);
62
+ --zj-yellow: var(--lanes-tone-attention);
63
+ }
64
+ /* END lanes tokens */
65
+ /* Non-colour layout variables; colours come from the generated token block above.
66
+ Safe areas apply in Home Screen mode and on both sides of landscape Safari. */
67
+ html.lanes-mobile {
13
68
  --lanes-safe-top: env(safe-area-inset-top, 0px);
14
69
  --lanes-safe-bottom: env(safe-area-inset-bottom, 0px);
15
70
  --lanes-safe-left: env(safe-area-inset-left, 0px);
@@ -21,32 +76,9 @@ html.lanes-mobile {
21
76
  --lanes-vw: 100vw;
22
77
  --lanes-offset-top: 0px;
23
78
  --lanes-offset-left: 0px;
24
- color-scheme: dark;
25
79
  -webkit-text-size-adjust: 100%;
26
80
  overscroll-behavior: none;
27
81
  }
28
- html.lanes-mobile:root {
29
- --zj-bg: var(--lanes-bg);
30
- --zj-surface: var(--lanes-panel);
31
- --zj-border: var(--lanes-border);
32
- --zj-text: var(--lanes-text);
33
- --zj-text-dim: var(--lanes-muted);
34
- --zj-green: var(--lanes-accent);
35
- --zj-blue: var(--lanes-accent);
36
- }
37
- html.lanes-mobile:root[data-zj-theme="light"] {
38
- --lanes-bg: #f3f5f2;
39
- --lanes-panel: #ffffff;
40
- --lanes-border: #d5ded6;
41
- --lanes-text: #17241b;
42
- --lanes-muted: #59695f;
43
- --lanes-accent: #356544;
44
- --lanes-current: #e5f0e6;
45
- --lanes-current-border: #acc9b4;
46
- --lanes-press: #d8e9db;
47
- --lanes-chip: #edf3ec;
48
- color-scheme: light;
49
- }
50
82
  html.lanes-keyboard {
51
83
  --lanes-dock: 48px;
52
84
  --lanes-keys: 48px;
@@ -1,12 +1,29 @@
1
- /* Lanes mobile shell. Uses the public window hooks in the pinned Zellij 0.45.1 client.
2
- * Authentication, terminal input, rendering, and transport remain in the upstream client. */
1
+ /* Lanes browser shell over the pinned Zellij 0.45.1 client's window hooks; auth, input, rendering and transport
2
+ * stay upstream. LNS-31: phone (today's rule or a coarse landscape phone), tablet (other touch), desktop. */
3
+ function laneShellMode({userAgent, coarse, width, height} = {}) {
4
+ if (/iPhone|iPod|Android.*Mobile/i.test(userAgent) || (coarse && (width <= 600 || height <= 500))) return 'phone';
5
+ return coarse ? 'tablet' : 'desktop';
6
+ }
7
+ if (typeof module === 'object') module.exports = {laneShellMode};
3
8
  (() => {
4
9
  'use strict';
5
- const isPhone = /iPhone|iPod|Android.*Mobile/i.test(navigator.userAgent) ||
6
- (matchMedia('(pointer: coarse)').matches && innerWidth <= 600);
7
- if (!isPhone) return;
10
+ if (typeof document === 'undefined') return;
11
+ const mode = laneShellMode({userAgent: navigator.userAgent, coarse: matchMedia('(pointer: coarse)').matches,
12
+ width: innerWidth, height: innerHeight});
8
13
  const root = document.documentElement;
14
+ root.dataset.lanesShell = mode; // web/browser.js: the desktop bar and the tablet's full rendering
15
+ if (mode !== 'phone') { // laptop/tablet extras: a phone never fetches them
16
+ const add = (tag, props) => document.head.append(Object.assign(document.createElement(tag), props));
17
+ add('link', {rel: 'stylesheet', href: '/lanes-assets/browser.css'});
18
+ add('script', {src: '/lanes-assets/browser.js'});
19
+ }
20
+ if (mode === 'desktop') return;
9
21
  root.classList.add('lanes-mobile');
22
+ if (mode === 'tablet') {
23
+ // iPad Safari's UA is desktop: ask for the mobile UI (a stored 'off' stays).
24
+ root.classList.add('lanes-tablet');
25
+ try {localStorage.getItem('zellij:mobile-ui') || localStorage.setItem('zellij:mobile-ui', 'on');} catch (_) {}
26
+ }
10
27
 
11
28
  // Only a browser's native tap/focus on an input may summon the keyboard. Zellij
12
29
  // otherwise refocuses a hidden input on touchstart, touchend, click and server
@@ -234,6 +251,7 @@
234
251
  else if (!ev.shiftKey && document.activeElement === last) {ev.preventDefault(); first.focus();}
235
252
  });
236
253
  shell.append(header, dock, sheet); document.body.append(shell);
254
+ if (mode === 'tablet') more.before(dock);
237
255
  root.classList.add('lanes-ready');
238
256
  // Upstream cancels pointerdown on extra keys, which also suppresses their
239
257
  // touch click in Safari. Cancel mousedown instead: keep typing focus while
@@ -13,10 +13,16 @@ Copy this folder to `~/.config/lanes/workspaces/` and edit it.
13
13
  | `catalog.json` | The boards, in tab order: `id` (also the uploads/watch-folder name), `title` (the tab), `manifest`. |
14
14
  | `workspaces.<board>.json` | Where the board's lanes come from: one or more `repositories`, each naming the workspace **container** (`host`) and the board's terminal registry (`registry`: the repository's `.vscode/terminals.json`). Optional per repository: `prefix` (prepended to lane titles), `displayNames`, `bindingOverrides` (tmux socket/session for a terminal whose registry entry has none), `cursor` (a second file to project the board into, for boards whose registry lives outside a repository). `monitor` adds the full-pane Throttle monitor tab. |
15
15
  | `commit-targets.json` | Only for `lanes cursor-commit`: repository, branch and author for committing the normalized registries. |
16
+ | `registered-sessions.json` | Optional, created by **Add to workspace** or `lanes register`: `version: 1`, plus `sessions` records with `id`, `workspace`, `name`, `container`, `tmux: {socket, session}`, and `folder`. Preserve this file in site backups. |
16
17
 
17
- A lane is whatever the registry says it is: `lanes sync` (every two minutes, read-only) turns each terminal into a
18
- lane with a stable id `<board>--<slug of the terminal name>`. Adding a lane = adding a terminal to the repository's
19
- `.vscode/terminals.json`; nothing in this folder changes.
18
+ A lane is whatever the registry says it is: `lanes sync` (every two minutes, read-only) turns each repository
19
+ terminal into a lane with a stable id `<board>--<slug of the terminal name>` (with the repository `prefix`). A
20
+ `displayNames` entry, which the sidebar `R` key and `lanes rename <lane-id> <name>` write into the repository's block
21
+ of `workspaces.<board>.json` (first write keeps a `.bak-<UTC>` copy beside it), changes only the shown name, never the
22
+ id. Add a terminal to `.vscode/terminals.json` for an editor-defined lane.
23
+ Alternatively, use **+** beside a discovered session to register its existing binding and ID in a workspace
24
+ using the same container. Sync includes these local registrations; they never run a create command.
25
+ Repository declarations take precedence when they declare the same binding. Legacy Docker shells cannot be adopted.
20
26
 
21
27
  After editing: `lanes sync && lanes doctor`.
22
28
 
@@ -331,12 +331,70 @@ env {
331
331
  FORCE_COLOR "3"
332
332
  FORCE_HYPERLINK "1"
333
333
  }
334
+ osc8_hyperlinks true
335
+ // BEGIN lanes tokens (generated by libexec/tokens.py --kdl; do not edit by hand)
336
+ themes {
337
+ lanes-dark {
338
+ text_unselected { base "#edf1f5"; background "#101318"; emphasis_0 "#e5b84a"; emphasis_1 "#6fd39a"; emphasis_2 "#b4e3bf"; emphasis_3 "#7fb3f2"; }
339
+ text_selected { base "#edf1f5"; background "#1a2721"; emphasis_0 "#e5b84a"; emphasis_1 "#6fd39a"; emphasis_2 "#b4e3bf"; emphasis_3 "#7fb3f2"; }
340
+ ribbon_selected { base "#101318"; background "#b4e3bf"; emphasis_0 "#7a1a12"; emphasis_1 "#101318"; emphasis_2 "#101318"; emphasis_3 "#101318"; }
341
+ ribbon_unselected { base "#9ca7b5"; background "#191e25"; emphasis_0 "#f28b7d"; emphasis_1 "#edf1f5"; emphasis_2 "#e5b84a"; emphasis_3 "#7fb3f2"; }
342
+ table_title { base "#b4e3bf"; background "#101318"; emphasis_0 "#e5b84a"; emphasis_1 "#6fd39a"; emphasis_2 "#b4e3bf"; emphasis_3 "#7fb3f2"; }
343
+ table_cell_selected { base "#edf1f5"; background "#1a2721"; emphasis_0 "#e5b84a"; emphasis_1 "#6fd39a"; emphasis_2 "#b4e3bf"; emphasis_3 "#7fb3f2"; }
344
+ table_cell_unselected { base "#edf1f5"; background "#101318"; emphasis_0 "#e5b84a"; emphasis_1 "#6fd39a"; emphasis_2 "#b4e3bf"; emphasis_3 "#7fb3f2"; }
345
+ list_selected { base "#edf1f5"; background "#1a2721"; emphasis_0 "#e5b84a"; emphasis_1 "#6fd39a"; emphasis_2 "#b4e3bf"; emphasis_3 "#7fb3f2"; }
346
+ list_unselected { base "#edf1f5"; background "#101318"; emphasis_0 "#e5b84a"; emphasis_1 "#6fd39a"; emphasis_2 "#b4e3bf"; emphasis_3 "#7fb3f2"; }
347
+ frame_selected { base "#b4e3bf"; background "#101318"; emphasis_0 "#e5b84a"; emphasis_1 "#6fd39a"; emphasis_2 "#7fb3f2"; emphasis_3 "#f28b7d"; }
348
+ frame_highlight { base "#e5b84a"; background "#101318"; emphasis_0 "#f28b7d"; emphasis_1 "#6fd39a"; emphasis_2 "#b4e3bf"; emphasis_3 "#7fb3f2"; }
349
+ exit_code_success { base "#6fd39a"; background "#101318"; emphasis_0 "#6fd39a"; emphasis_1 "#6fd39a"; emphasis_2 "#6fd39a"; emphasis_3 "#6fd39a"; }
350
+ exit_code_error { base "#f28b7d"; background "#101318"; emphasis_0 "#f28b7d"; emphasis_1 "#f28b7d"; emphasis_2 "#f28b7d"; emphasis_3 "#f28b7d"; }
351
+ multiplayer_user_colors { player_1 "#7fb3f2"; player_2 "#e5b84a"; player_3 "#6fd39a"; player_4 "#f28b7d"; player_5 "#b4e3bf"; player_6 "#c9a6ff"; player_7 "#6fd6d0"; player_8 "#f7cf7f"; player_9 "#8fe0a3"; player_10 "#ff9d96"; }
352
+ }
353
+ lanes-light {
354
+ text_unselected { base "#17241b"; background "#f3f5f2"; emphasis_0 "#8a5a00"; emphasis_1 "#1b7142"; emphasis_2 "#2f6b45"; emphasis_3 "#2456a8"; }
355
+ text_selected { base "#17241b"; background "#e5f0e6"; emphasis_0 "#8a5a00"; emphasis_1 "#1b7142"; emphasis_2 "#2f6b45"; emphasis_3 "#2456a8"; }
356
+ ribbon_selected { base "#ffffff"; background "#2f6b45"; emphasis_0 "#ffd3cc"; emphasis_1 "#ffffff"; emphasis_2 "#ffffff"; emphasis_3 "#ffffff"; }
357
+ ribbon_unselected { base "#56616d"; background "#ffffff"; emphasis_0 "#b7322a"; emphasis_1 "#17241b"; emphasis_2 "#8a5a00"; emphasis_3 "#2456a8"; }
358
+ table_title { base "#2f6b45"; background "#f3f5f2"; emphasis_0 "#8a5a00"; emphasis_1 "#1b7142"; emphasis_2 "#2f6b45"; emphasis_3 "#2456a8"; }
359
+ table_cell_selected { base "#17241b"; background "#e5f0e6"; emphasis_0 "#8a5a00"; emphasis_1 "#1b7142"; emphasis_2 "#2f6b45"; emphasis_3 "#2456a8"; }
360
+ table_cell_unselected { base "#17241b"; background "#f3f5f2"; emphasis_0 "#8a5a00"; emphasis_1 "#1b7142"; emphasis_2 "#2f6b45"; emphasis_3 "#2456a8"; }
361
+ list_selected { base "#17241b"; background "#e5f0e6"; emphasis_0 "#8a5a00"; emphasis_1 "#1b7142"; emphasis_2 "#2f6b45"; emphasis_3 "#2456a8"; }
362
+ list_unselected { base "#17241b"; background "#f3f5f2"; emphasis_0 "#8a5a00"; emphasis_1 "#1b7142"; emphasis_2 "#2f6b45"; emphasis_3 "#2456a8"; }
363
+ frame_selected { base "#2f6b45"; background "#f3f5f2"; emphasis_0 "#8a5a00"; emphasis_1 "#1b7142"; emphasis_2 "#2456a8"; emphasis_3 "#b7322a"; }
364
+ frame_highlight { base "#8a5a00"; background "#f3f5f2"; emphasis_0 "#b7322a"; emphasis_1 "#1b7142"; emphasis_2 "#2f6b45"; emphasis_3 "#2456a8"; }
365
+ exit_code_success { base "#1b7142"; background "#f3f5f2"; emphasis_0 "#1b7142"; emphasis_1 "#1b7142"; emphasis_2 "#1b7142"; emphasis_3 "#1b7142"; }
366
+ exit_code_error { base "#b7322a"; background "#f3f5f2"; emphasis_0 "#b7322a"; emphasis_1 "#b7322a"; emphasis_2 "#b7322a"; emphasis_3 "#b7322a"; }
367
+ multiplayer_user_colors { player_1 "#2456a8"; player_2 "#8a5a00"; player_3 "#1b7142"; player_4 "#b7322a"; player_5 "#2f6b45"; player_6 "#7a3fb8"; player_7 "#0f7b7b"; player_8 "#8f5a00"; player_9 "#1b7a38"; player_10 "#c2332a"; }
368
+ }
369
+ }
370
+ theme_dark "lanes-dark"
371
+ theme_light "lanes-light"
334
372
  web_client {
335
373
  font "monospace"
374
+ theme {
375
+ background "#101318"
376
+ foreground "#edf1f5"
377
+ black "#7d8896"
378
+ red "#f28b7d"
379
+ green "#6fd39a"
380
+ yellow "#e5b84a"
381
+ blue "#7fb3f2"
382
+ magenta "#c9a6ff"
383
+ cyan "#6fd6d0"
384
+ white "#9ca7b5"
385
+ bright_black "#8a95a3"
386
+ bright_red "#ff9d96"
387
+ bright_green "#8fe0a3"
388
+ bright_yellow "#f7cf7f"
389
+ bright_blue "#a5cbff"
390
+ bright_magenta "#dcc6ff"
391
+ bright_cyan "#9ae6e0"
392
+ bright_white "#edf1f5"
393
+ selection_background "#1a2721"
394
+ selection_foreground "#edf1f5"
395
+ }
336
396
  }
337
- osc8_hyperlinks true
338
- theme_dark "tokyo-night"
339
- theme_light "catppuccin-latte"
397
+ // END lanes tokens
340
398
  default_mode "normal"
341
399
  mouse_mode true
342
400
  copy_clipboard "system"
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@vibelord/lanes",
3
- "version": "1.0.0",
4
- "commit": "a3692b61a114c851b493618bf7f5446b7a84336a",
5
- "digest": "sha256:20b6265bee253def6bce29dbf66e35678e6ecbe9c81c86b03cdf2091660bb5ae",
3
+ "version": "1.0.1",
4
+ "commit": "7eefe03dd9362ca62d05abd2d23cbc958d6af346",
5
+ "digest": "sha256:09b4d87fb5687fe5e72140baa68f9518ec96cbf9a3b08c55d7f9e99afb55b295",
6
6
  "executables": [
7
7
  "bin/lanes",
8
8
  "client/install.sh",
@@ -13,14 +13,17 @@
13
13
  "container/lane",
14
14
  "container/lane-run",
15
15
  "holders/exec.sh",
16
+ "holders/ssh.sh",
16
17
  "holders/tmux.sh",
17
18
  "holders/zmx.sh",
18
19
  "install.sh",
19
20
  "install/enable-web.sh",
20
21
  "install/host-install.sh",
22
+ "libexec/connection.py",
21
23
  "libexec/sidebar",
22
24
  "libexec/sidebar.py",
23
25
  "libexec/statusd.py",
26
+ "libexec/tokens.py",
24
27
  "libexec/view.sh",
25
28
  "sudo/host-guard.sh",
26
29
  "sudo/one-time-root.sh"