@cryptiklemur/lattice 1.22.2 → 1.23.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.
@@ -10,7 +10,7 @@ import { useSidebar } from "../../hooks/useSidebar";
10
10
  import { useSession } from "../../hooks/useSession";
11
11
  import { clearSession } from "../../stores/session";
12
12
  import { useOnline } from "../../hooks/useOnline";
13
- import { openTab, openSessionTab, getWorkspaceStore } from "../../stores/workspace";
13
+ import { openTab, openSessionTab, closeTab, getWorkspaceStore } from "../../stores/workspace";
14
14
  import { getSidebarStore, goToAnalytics, openSettings } from "../../stores/sidebar";
15
15
  import { setAnalyticsScope } from "../../stores/analytics";
16
16
  import { ProjectRail } from "./ProjectRail";
@@ -269,6 +269,22 @@ export function Sidebar({ onSessionSelect }: { onSessionSelect?: () => void }) {
269
269
  </div>
270
270
  <div className="flex-1 overflow-auto px-4 py-3 pb-16">
271
271
  <div className="flex flex-col gap-0.5 mb-3">
272
+ <button
273
+ type="button"
274
+ onClick={function () {
275
+ var store = getWorkspaceStore();
276
+ var state = store.state;
277
+ var activePane = state.panes.find(function (p) { return p.id === state.activePaneId; });
278
+ var activeTab = activePane ? state.tabs.find(function (t) { return t.id === activePane!.activeTabId; }) : null;
279
+ if (activeTab && activeTab.id !== "chat") {
280
+ closeTab(activeTab.id);
281
+ }
282
+ }}
283
+ className="flex items-center gap-2 w-full px-2 py-1.5 rounded-lg text-[11px] text-base-content/40 hover:text-base-content/70 hover:bg-base-300/30 transition-colors"
284
+ >
285
+ <LayoutDashboard size={12} />
286
+ <span className="font-mono tracking-wide">Dashboard</span>
287
+ </button>
272
288
  <button
273
289
  type="button"
274
290
  onClick={function () {
@@ -78,11 +78,22 @@ export function openTab(type: TabType): void {
78
78
  label: labels[type],
79
79
  closeable: type !== "chat",
80
80
  };
81
+
82
+ var defaultChat = state.tabs.find(function (t) { return t.id === "chat" && !t.sessionId; });
83
+ var hasOnlyDefaultChat = defaultChat && state.tabs.length === 1;
84
+
85
+ var newTabs = hasOnlyDefaultChat
86
+ ? [tab]
87
+ : [...state.tabs, tab];
88
+
81
89
  var newPanes = state.panes.map(function (p) {
82
90
  if (p.id === state.activePaneId) {
91
+ var updatedTabIds = hasOnlyDefaultChat
92
+ ? p.tabIds.map(function (id) { return id === "chat" ? tab.id : id; })
93
+ : [...p.tabIds, tab.id];
83
94
  return {
84
95
  ...p,
85
- tabIds: [...p.tabIds, tab.id],
96
+ tabIds: updatedTabIds,
86
97
  activeTabId: tab.id,
87
98
  };
88
99
  }
@@ -90,7 +101,7 @@ export function openTab(type: TabType): void {
90
101
  });
91
102
  return {
92
103
  ...state,
93
- tabs: [...state.tabs, tab],
104
+ tabs: newTabs,
94
105
  panes: newPanes,
95
106
  };
96
107
  });
@@ -223,6 +234,18 @@ export function closeTab(tabId: string): void {
223
234
  };
224
235
  }
225
236
 
237
+ var hasEmptySinglePane = newPanes.length === 1 && newPanes[0].tabIds.length === 0;
238
+ if (hasEmptySinglePane) {
239
+ var defaultTab: Tab = { id: "chat", type: "chat", label: "Chat", closeable: false };
240
+ return {
241
+ tabs: [defaultTab],
242
+ panes: [{ ...newPanes[0], tabIds: ["chat"], activeTabId: "chat" }],
243
+ activePaneId: newPanes[0].id,
244
+ splitDirection: null,
245
+ splitRatio: 0.5,
246
+ };
247
+ }
248
+
226
249
  return {
227
250
  ...state,
228
251
  tabs: filteredTabs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cryptiklemur/lattice",
3
- "version": "1.22.2",
3
+ "version": "1.23.0",
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>",