@cryptiklemur/lattice 1.24.6 → 1.25.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.
@@ -2,7 +2,7 @@ import { Store } from "@tanstack/react-store";
2
2
  import type { ProjectSettingsSection } from "@lattice/shared";
3
3
  import { encodeWorkspaceUrl, decodeWorkspaceUrl, isLegacySessionUrl, shortSessionId } from "../lib/workspace-url";
4
4
  import type { DecodedWorkspace } from "../lib/workspace-url";
5
- import { getWorkspaceStore, restoreWorkspace, setUrlSyncCallback } from "./workspace";
5
+ import { getWorkspaceStore, restoreWorkspace, setUrlSyncCallback, switchProjectWorkspace, setCurrentProjectKey } from "./workspace";
6
6
 
7
7
  export type { ProjectSettingsSection };
8
8
 
@@ -106,6 +106,7 @@ function parseInitialUrl(): ParsedUrl {
106
106
 
107
107
  const initialUrl = parseInitialUrl();
108
108
 
109
+ setCurrentProjectKey(initialUrl.settingsSection ? null : initialUrl.projectSlug);
109
110
  if (initialUrl.decodedWorkspace) {
110
111
  restoreWorkspace(initialUrl.decodedWorkspace);
111
112
  }
@@ -196,6 +197,7 @@ export function getSidebarStore(): Store<SidebarState> {
196
197
  }
197
198
 
198
199
  export function setActiveProjectSlug(slug: string | null): void {
200
+ let prevSlug = sidebarStore.state.activeProjectSlug;
199
201
  sidebarStore.setState(function (state) {
200
202
  return {
201
203
  ...state,
@@ -215,6 +217,8 @@ export function setActiveProjectSlug(slug: string | null): void {
215
217
  window.history.pushState(null, "", path);
216
218
  }
217
219
  lastEncodedUrl = "";
220
+ // Switch workspace AFTER sidebar state is set so React sees both in same render
221
+ switchProjectWorkspace(prevSlug, slug);
218
222
  }
219
223
 
220
224
  export function setActiveSessionId(sessionId: string | null): void {
@@ -340,6 +344,7 @@ export function goToProjectDashboard(): void {
340
344
  }
341
345
 
342
346
  export function goToDashboard(): void {
347
+ let prevSlug = sidebarStore.state.activeProjectSlug;
343
348
  sidebarStore.setState(function (state) {
344
349
  return {
345
350
  ...state,
@@ -354,6 +359,7 @@ export function goToDashboard(): void {
354
359
  if (window.location.pathname + window.location.search !== "/") {
355
360
  window.history.pushState(null, "", "/");
356
361
  }
362
+ switchProjectWorkspace(prevSlug, null);
357
363
  lastEncodedUrl = "";
358
364
  }
359
365
 
@@ -416,6 +416,82 @@ export function restoreWorkspace(data: DecodedWorkspace): void {
416
416
  urlSyncSuppressed = false;
417
417
  }
418
418
 
419
+ var currentProjectKey: string = "__global__";
420
+
421
+ export function setCurrentProjectKey(slug: string | null): void {
422
+ currentProjectKey = slug || "__global__";
423
+ }
424
+
425
+ function storageKey(projectSlug: string | null): string {
426
+ return "lattice:workspace:" + (projectSlug || "__global__");
427
+ }
428
+
429
+ export function saveWorkspaceForProject(projectSlug: string | null): void {
430
+ let key = storageKey(projectSlug);
431
+ let state = workspaceStore.state;
432
+ try {
433
+ localStorage.setItem(key, JSON.stringify({
434
+ tabs: state.tabs,
435
+ panes: state.panes,
436
+ activePaneId: state.activePaneId,
437
+ splitDirection: state.splitDirection,
438
+ splitRatio: state.splitRatio,
439
+ }));
440
+ } catch {}
441
+ }
442
+
443
+ export function loadWorkspaceForProject(projectSlug: string | null): void {
444
+ let key = storageKey(projectSlug);
445
+ currentProjectKey = projectSlug || "__global__";
446
+
447
+ try {
448
+ let raw = localStorage.getItem(key);
449
+ if (raw) {
450
+ let saved = JSON.parse(raw) as WorkspaceState;
451
+ if (saved.tabs && saved.panes && saved.tabs.length > 0 && saved.panes.length > 0) {
452
+ urlSyncSuppressed = true;
453
+ workspaceStore.setState(function () {
454
+ return {
455
+ tabs: saved.tabs,
456
+ panes: saved.panes,
457
+ activePaneId: saved.activePaneId || saved.panes[0].id,
458
+ splitDirection: saved.splitDirection || null,
459
+ splitRatio: saved.splitRatio || 0.5,
460
+ };
461
+ });
462
+ urlSyncSuppressed = false;
463
+ return;
464
+ }
465
+ }
466
+ } catch {}
467
+
468
+ urlSyncSuppressed = true;
469
+ workspaceStore.setState(function () {
470
+ return {
471
+ tabs: [{ id: "chat", type: "chat" as TabType, label: "Chat", closeable: false }],
472
+ panes: [{ id: "pane-1", tabIds: ["chat"], activeTabId: "chat" }],
473
+ activePaneId: "pane-1",
474
+ splitDirection: null,
475
+ splitRatio: 0.5,
476
+ };
477
+ });
478
+ urlSyncSuppressed = false;
479
+ }
480
+
481
+ var saveSuppressed = false;
482
+
483
+ export function switchProjectWorkspace(fromSlug: string | null, toSlug: string | null): void {
484
+ saveSuppressed = true;
485
+ saveWorkspaceForProject(fromSlug);
486
+ loadWorkspaceForProject(toSlug);
487
+ saveSuppressed = false;
488
+ }
489
+
419
490
  workspaceStore.subscribe(function () {
420
491
  notifyUrlSync();
492
+ if (!saveSuppressed) {
493
+ try {
494
+ saveWorkspaceForProject(currentProjectKey === "__global__" ? null : currentProjectKey);
495
+ } catch {}
496
+ }
421
497
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cryptiklemur/lattice",
3
- "version": "1.24.6",
3
+ "version": "1.25.1",
4
4
  "description": "Multi-machine agentic dashboard for Claude Code. Monitor sessions, manage MCP servers and skills, orchestrate across mesh-networked nodes.",
5
5
  "license": "MIT",
6
6
  "author": "Aaron Scherer <me@aaronscherer.me>",