@circuitwall/jarela 1.9.2 → 1.9.3

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 (57) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +1 -1
  3. package/.next/standalone/.next/build-manifest.json +2 -2
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  6. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  16. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  17. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  18. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  20. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/page.js +688 -427
  24. package/.next/standalone/.next/server/app/page.js.map +1 -1
  25. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  26. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  27. package/.next/standalone/.next/server/app-paths-manifest.json +1 -1
  28. package/.next/standalone/.next/server/chunks/4045.js.map +1 -1
  29. package/.next/standalone/.next/server/middleware-build-manifest.js +2 -2
  30. package/.next/standalone/.next/server/pages/404.html +2 -2
  31. package/.next/standalone/.next/server/pages/500.html +1 -1
  32. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  33. package/.next/standalone/.next/static/chunks/2747-4a6287cacd57d231.js.map +1 -1
  34. package/.next/standalone/.next/static/chunks/{1998-31a617131197a83a.js → 962-fe2372e00f85e23a.js} +111 -2
  35. package/.next/standalone/.next/static/chunks/962-fe2372e00f85e23a.js.map +1 -0
  36. package/.next/standalone/.next/static/chunks/app/layout-84c6f211a7a1ca36.js.map +1 -1
  37. package/.next/standalone/.next/static/chunks/app/{page-afdef9bd1108a656.js → page-c5b9f4407416c3f9.js} +332 -154
  38. package/.next/standalone/.next/static/chunks/app/page-c5b9f4407416c3f9.js.map +1 -0
  39. package/.next/standalone/.next/static/css/b8e04d59a2bfff04.css +5 -0
  40. package/.next/standalone/.next/static/css/b8e04d59a2bfff04.css.map +1 -0
  41. package/.next/standalone/package.json +1 -1
  42. package/CHANGELOG.md +25 -0
  43. package/components/credentials/CredentialsPanel.tsx +1 -1
  44. package/components/layout/AppShell.tsx +6 -0
  45. package/components/layout/MenuPanel.tsx +15 -91
  46. package/components/settings/AppearancePanel.tsx +93 -0
  47. package/components/settings/SettingsPanel.tsx +94 -0
  48. package/contexts/AppContext.tsx +1 -1
  49. package/hooks/useUrlSync.ts +1 -1
  50. package/lib/ui/navigate.ts +1 -1
  51. package/package.json +1 -1
  52. package/.next/standalone/.next/static/chunks/1998-31a617131197a83a.js.map +0 -1
  53. package/.next/standalone/.next/static/chunks/app/page-afdef9bd1108a656.js.map +0 -1
  54. package/.next/standalone/.next/static/css/44f9bbea39fef458.css +0 -5
  55. package/.next/standalone/.next/static/css/44f9bbea39fef458.css.map +0 -1
  56. /package/.next/standalone/.next/static/{rr-Rxxi6kkXe1Bw8-Hzq2 → EOkgU73YJOpR-vFcKMgL0}/_buildManifest.js +0 -0
  57. /package/.next/standalone/.next/static/{rr-Rxxi6kkXe1Bw8-Hzq2 → EOkgU73YJOpR-vFcKMgL0}/_ssgManifest.js +0 -0
@@ -1,11 +1,10 @@
1
1
  "use client";
2
- import { BarChart3, Bot, Brain, Calendar, ChevronDown, Cpu, FolderSearch, Key, MessageSquare, Monitor, Moon, ScrollText, ServerCog, Shapes, Smartphone, Sun, User, Wrench } from "lucide-react";
2
+ import { BarChart3, Bot, Brain, Calendar, ChevronDown, Cpu, FolderSearch, Key, MessageSquare, ScrollText, ServerCog, Settings, Shapes, Smartphone, User, Wrench } from "lucide-react";
3
3
  import { useEffect, useState } from "react";
4
4
  import { useAppContext, type Tab } from "@/contexts/AppContext";
5
5
  import type { AgentConfig } from "@/api/types";
6
6
  import { api } from "@/api/client";
7
7
  import { useUnreadByAgent } from "@/lib/ui/toasts";
8
- import { useTheme, type Theme } from "@/contexts/ThemeContext";
9
8
 
10
9
  interface Props {
11
10
  activeTab: Tab;
@@ -32,6 +31,7 @@ const TAB_ICONS: Record<Tab, React.ReactNode> = {
32
31
  harness: <Shapes size={13} />,
33
32
  logs: <ScrollText size={13} />,
34
33
  env: <ServerCog size={13} />,
34
+ settings: <Settings size={13} />,
35
35
  };
36
36
 
37
37
  const TAB_TITLES: Record<Tab, string> = {
@@ -51,6 +51,7 @@ const TAB_TITLES: Record<Tab, string> = {
51
51
  harness: "Harness",
52
52
  logs: "Logs",
53
53
  env: "Defaults",
54
+ settings: "Settings",
54
55
  };
55
56
 
56
57
  const TAB_SHORT: Record<Tab, string> = {
@@ -70,11 +71,14 @@ const TAB_SHORT: Record<Tab, string> = {
70
71
  harness: "Test",
71
72
  logs: "Logs",
72
73
  env: "Defaults",
74
+ settings: "Setup",
73
75
  };
74
76
 
75
- // Two-tier menu. "Common" surfaces the day-to-day verbs plus the most
76
- // relevant configuration touchpoints. "Advanced" hides the less-frequently
77
- // used engine-room surfaces behind a collapsible header.
77
+ // Two-tier menu. "Common" surfaces the day-to-day verbs. Settings is
78
+ // the single home for previously top-level chrome (credentials, models,
79
+ // harness, logs, defaults, appearance, networking) those legacy Tab
80
+ // values still exist for deep-link compat but no longer appear in this
81
+ // menu grid.
78
82
  //
79
83
  // Capability-presence surfaces (documents, memory, MCP, extensions,
80
84
  // bridges, built-in tool categories) all live under the "Tools" tab now —
@@ -82,15 +86,8 @@ const TAB_SHORT: Record<Tab, string> = {
82
86
  // answering the same question: "what can the agent see / do?". The legacy
83
87
  // top-level Tab entries remain wired so deep-links (?tab=documents&item=…)
84
88
  // still resolve, but they're hidden from the menu grid.
85
- //
86
- // "credentials" is the single home for every auth surface — saved API
87
- // keys + built-in integrations (Gmail, GitHub, Atlassian…) live there as
88
- // sub-tabs.
89
- //
90
- // "models" lives in Advanced — most users let the default model do its
91
- // job; switching providers is power-user territory.
92
- const COMMON_TABS: Tab[] = ["chat", "dashboard", "agents", "credentials", "tools", "tasks", "profile"];
93
- const ADVANCED_TABS: Tab[] = ["models", "harness", "logs", "env"];
89
+ const COMMON_TABS: Tab[] = ["chat", "dashboard", "agents", "tools", "tasks", "profile", "settings"];
90
+ const ADVANCED_TABS: Tab[] = [];
94
91
 
95
92
  const ADVANCED_KEY = "jarela.menu.advanced";
96
93
 
@@ -118,6 +115,7 @@ const TAB_ACCENT: Partial<Record<Tab, string>> = {
118
115
  harness: "from-orange-500/20 to-amber-500/5",
119
116
  logs: "from-slate-500/20 to-zinc-500/5",
120
117
  env: "from-teal-500/20 to-cyan-500/5",
118
+ settings: "from-slate-500/20 to-zinc-500/5",
121
119
  };
122
120
 
123
121
  function avatarGradient(id: string): string {
@@ -231,12 +229,8 @@ export function MenuPanel({
231
229
  onAgentChange,
232
230
  onSetTab,
233
231
  }: Props) {
234
- const { state, dispatch } = useAppContext();
232
+ const { state } = useAppContext();
235
233
  const isFullMode = state.experienceMode === "full";
236
- const setMode = (mode: "essential" | "full") => {
237
- if ((mode === "full") === isFullMode) return;
238
- dispatch({ type: "SET_EXPERIENCE_MODE", mode });
239
- };
240
234
  // Advanced section starts collapsed once the user has dismissed it
241
235
  // once (persisted to localStorage). Defaults to *expanded* on first
242
236
  // boot so the engine room is visible to power users out of the box.
@@ -295,42 +289,11 @@ export function MenuPanel({
295
289
  style={{ top: "calc(3rem + var(--app-safe-top))" }}
296
290
  >
297
291
  {/* Common navigation — the day-to-day surface. */}
298
- <div className="px-3 pt-2 pb-1 border-b border-border/60 bg-gradient-to-r from-surface-2/50 to-transparent">
299
- <div className="flex items-center justify-between gap-2">
300
- <span className="text-[10px] uppercase tracking-wide text-fg-faint">Workspace mode</span>
301
- <div
302
- role="radiogroup"
303
- aria-label="Workspace mode"
304
- className="inline-flex items-center rounded-full border border-border bg-surface-3 p-0.5"
305
- >
306
- {(["essential", "full"] as const).map((mode) => {
307
- const active = (mode === "full") === isFullMode;
308
- return (
309
- <button
310
- key={mode}
311
- type="button"
312
- role="radio"
313
- aria-checked={active}
314
- onClick={() => setMode(mode)}
315
- title={active ? `${mode} mode (current)` : `Switch to ${mode} mode`}
316
- className={`control-tap text-[10px] uppercase tracking-wide px-2 py-0.5 rounded-full transition-colors ${
317
- active
318
- ? "bg-accent/15 text-fg-subtle"
319
- : "text-fg-faint hover:text-fg-muted"
320
- }`}
321
- >
322
- {mode}
323
- </button>
324
- );
325
- })}
326
- </div>
327
- </div>
328
- </div>
329
- <div className="grid grid-cols-4 sm:grid-cols-6 gap-1.5 px-2 py-2 border-b border-border shrink-0">
292
+ <div className="grid grid-cols-4 sm:grid-cols-6 gap-1.5 px-2 py-2 border-b border-border shrink-0 bg-gradient-to-r from-surface-2/50 to-transparent">
330
293
  {COMMON_TABS.map(renderTabButton)}
331
294
  </div>
332
295
 
333
- {isFullMode && (
296
+ {isFullMode && ADVANCED_TABS.length > 0 && (
334
297
  <div className="border-b border-border shrink-0">
335
298
  <button
336
299
  type="button"
@@ -359,45 +322,6 @@ export function MenuPanel({
359
322
  onSelect={(id) => { onAgentChange(id); onSetTab("chat"); onClose(); }}
360
323
  />
361
324
  </div>
362
-
363
- {/* Display toggles */}
364
- <div className="border-t border-border px-3 py-3 shrink-0 bg-surface-1/30">
365
- <p className="text-[11px] text-fg-faint mb-1.5 font-medium uppercase tracking-wide">Display</p>
366
- <div className="flex flex-col gap-1.5">
367
- <ThemePicker />
368
- </div>
369
- </div>
370
- </div>
371
- );
372
- }
373
-
374
- function ThemePicker() {
375
- const { theme, setTheme } = useTheme();
376
- const options: { value: Theme; label: string; icon: React.ReactNode }[] = [
377
- { value: "light", label: "Light", icon: <Sun size={12} /> },
378
- { value: "dark", label: "Dark", icon: <Moon size={12} /> },
379
- { value: "system", label: "System", icon: <Monitor size={12} /> },
380
- ];
381
- return (
382
- <div className="flex items-center gap-2 text-xs text-fg-muted rounded-lg border border-border bg-surface-3/70 px-2.5 py-2">
383
- <span className="shrink-0">Theme</span>
384
- <div className="flex flex-1 rounded-lg border border-border overflow-hidden bg-surface">
385
- {options.map((o) => (
386
- <button
387
- key={o.value}
388
- onClick={() => setTheme(o.value)}
389
- title={o.label}
390
- className={`control-tap flex-1 inline-flex items-center justify-center gap-1 py-1 text-[11px] transition-colors ${
391
- theme === o.value
392
- ? "bg-surface-3 text-fg shadow-sm"
393
- : "text-fg-faint hover:text-fg-muted hover:bg-surface-3/50"
394
- }`}
395
- >
396
- {o.icon}
397
- <span>{o.label}</span>
398
- </button>
399
- ))}
400
- </div>
401
325
  </div>
402
326
  );
403
327
  }
@@ -0,0 +1,93 @@
1
+ "use client";
2
+ import { Monitor, Moon, Palette, Sun } from "lucide-react";
3
+ import { useTheme, type Theme } from "@/contexts/ThemeContext";
4
+ import { useAppContext, type ExperienceMode } from "@/contexts/AppContext";
5
+
6
+ // Visual + chrome settings that used to live in the MenuPanel footer
7
+ // (theme) and the top of the menu (Workspace mode). Hoisted here so
8
+ // every settings surface has the same shape: a Settings sub-tab with
9
+ // its own header.
10
+
11
+ export function AppearancePanel() {
12
+ const { state, dispatch } = useAppContext();
13
+ const { theme, setTheme } = useTheme();
14
+ const isFullMode = state.experienceMode === "full";
15
+
16
+ const themeOptions: { value: Theme; label: string; icon: React.ReactNode; description: string }[] = [
17
+ { value: "light", label: "Light", icon: <Sun size={14} />, description: "Bright UI; ignores system preference." },
18
+ { value: "dark", label: "Dark", icon: <Moon size={14} />, description: "Dimmed UI; ignores system preference." },
19
+ { value: "system", label: "System", icon: <Monitor size={14} />, description: "Follow the OS-level light/dark preference." },
20
+ ];
21
+
22
+ const modeOptions: { value: ExperienceMode; label: string; description: string }[] = [
23
+ { value: "essential", label: "Essential", description: "Day-to-day surfaces only. Hides Memory, Bridges, Harness, Logs, Defaults from the menu." },
24
+ { value: "full", label: "Full", description: "Everything visible: engine-room tabs, power-user settings, all advanced sub-tabs." },
25
+ ];
26
+
27
+ function setMode(mode: ExperienceMode) {
28
+ if (mode === state.experienceMode) return;
29
+ dispatch({ type: "SET_EXPERIENCE_MODE", mode });
30
+ }
31
+
32
+ return (
33
+ <div className="flex flex-col h-full">
34
+ <div className="border-b border-border px-4 py-3 flex items-center gap-2">
35
+ <Palette size={14} className="text-fg-subtle" />
36
+ <h2 className="text-sm font-semibold text-fg mr-auto">Appearance</h2>
37
+ </div>
38
+
39
+ <div className="flex-1 overflow-y-auto px-4 py-4 space-y-6">
40
+ <section>
41
+ <h3 className="text-[11px] uppercase tracking-wide text-fg-faint mb-2 px-1">Theme</h3>
42
+ <div className="grid grid-cols-1 sm:grid-cols-3 gap-2">
43
+ {themeOptions.map((o) => {
44
+ const active = theme === o.value;
45
+ return (
46
+ <button
47
+ key={o.value}
48
+ onClick={() => setTheme(o.value)}
49
+ aria-pressed={active}
50
+ className={`text-left rounded-lg border px-3 py-2.5 transition-colors ${
51
+ active
52
+ ? "border-accent bg-accent/10 text-fg"
53
+ : "border-border bg-surface-2 text-fg-muted hover:bg-surface-3"
54
+ }`}
55
+ >
56
+ <div className="flex items-center gap-2 mb-1">
57
+ <span className="text-fg-subtle">{o.icon}</span>
58
+ <span className="text-sm font-medium text-fg">{o.label}</span>
59
+ </div>
60
+ <p className="text-[11px] text-fg-faint leading-snug">{o.description}</p>
61
+ </button>
62
+ );
63
+ })}
64
+ </div>
65
+ </section>
66
+
67
+ <section>
68
+ <h3 className="text-[11px] uppercase tracking-wide text-fg-faint mb-2 px-1">Workspace mode</h3>
69
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
70
+ {modeOptions.map((o) => {
71
+ const active = isFullMode ? o.value === "full" : o.value === "essential";
72
+ return (
73
+ <button
74
+ key={o.value}
75
+ onClick={() => setMode(o.value)}
76
+ aria-pressed={active}
77
+ className={`text-left rounded-lg border px-3 py-2.5 transition-colors ${
78
+ active
79
+ ? "border-accent bg-accent/10 text-fg"
80
+ : "border-border bg-surface-2 text-fg-muted hover:bg-surface-3"
81
+ }`}
82
+ >
83
+ <div className="text-sm font-medium text-fg mb-1">{o.label}</div>
84
+ <p className="text-[11px] text-fg-faint leading-snug">{o.description}</p>
85
+ </button>
86
+ );
87
+ })}
88
+ </div>
89
+ </section>
90
+ </div>
91
+ </div>
92
+ );
93
+ }
@@ -0,0 +1,94 @@
1
+ "use client";
2
+ import { Cpu, Globe, Key, Palette, ScrollText, ServerCog, Shapes } from "lucide-react";
3
+ import { useAppContext } from "@/contexts/AppContext";
4
+ import { CredentialsListPanel } from "@/components/credentials/CredentialsPanel";
5
+ import { NetworkPanel } from "@/components/integrations/NetworkPanel";
6
+ import { ModelsPanel } from "@/components/models/ModelsPanel";
7
+ import { HarnessPanel } from "@/components/harness/HarnessPanel";
8
+ import { LogsPanel } from "@/components/logs/LogsPanel";
9
+ import { EnvVarsPanel } from "@/components/env/EnvVarsPanel";
10
+ import { AppearancePanel } from "./AppearancePanel";
11
+
12
+ // Settings is the consolidated home for everything that used to live as
13
+ // its own top-level tab (credentials, models, harness, logs, defaults)
14
+ // plus appearance/networking. The individual Tab values still exist so
15
+ // deep links like ?tab=credentials and ?tab=models keep working — this
16
+ // surface is the new top-of-funnel for menu navigation.
17
+
18
+ type Sub =
19
+ | "appearance"
20
+ | "networking"
21
+ | "credentials"
22
+ | "models"
23
+ | "harness"
24
+ | "logs"
25
+ | "defaults";
26
+
27
+ const SUBS: ReadonlyArray<{ id: Sub; label: string; icon: React.ReactNode; advancedOnly?: boolean }> = [
28
+ { id: "appearance", label: "Appearance", icon: <Palette size={13} /> },
29
+ { id: "networking", label: "Networking", icon: <Globe size={13} /> },
30
+ { id: "credentials", label: "Credentials", icon: <Key size={13} /> },
31
+ { id: "models", label: "Models", icon: <Cpu size={13} /> },
32
+ { id: "harness", label: "Harness", icon: <Shapes size={13} />, advancedOnly: true },
33
+ { id: "logs", label: "Logs", icon: <ScrollText size={13} />, advancedOnly: true },
34
+ { id: "defaults", label: "Defaults", icon: <ServerCog size={13} />, advancedOnly: true },
35
+ ];
36
+
37
+ const VALID = new Set<Sub>(SUBS.map((s) => s.id));
38
+
39
+ function parseSub(raw: string | undefined): Sub {
40
+ if (raw && VALID.has(raw as Sub)) return raw as Sub;
41
+ return "appearance";
42
+ }
43
+
44
+ export function SettingsPanel() {
45
+ const { state, dispatch } = useAppContext();
46
+ const isFullMode = state.experienceMode === "full";
47
+ const active = parseSub(state.selectedItem.settings);
48
+
49
+ const setSub = (s: Sub) =>
50
+ dispatch({ type: "SET_SELECTION", tab: "settings", itemId: s });
51
+
52
+ const visibleSubs = SUBS.filter((s) => isFullMode || !s.advancedOnly);
53
+
54
+ return (
55
+ <div className="flex flex-col h-full min-h-0">
56
+ <div
57
+ role="tablist"
58
+ aria-label="Settings sub-section"
59
+ className="flex gap-1 border-b border-[var(--border)] bg-[var(--bg-secondary)] px-3 pt-2 overflow-x-auto"
60
+ >
61
+ {visibleSubs.map((s) => {
62
+ const selected = s.id === active;
63
+ return (
64
+ <button
65
+ key={s.id}
66
+ role="tab"
67
+ type="button"
68
+ aria-selected={selected}
69
+ onClick={() => setSub(s.id)}
70
+ className={
71
+ "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-t-md border-b-2 -mb-px transition-colors whitespace-nowrap " +
72
+ (selected
73
+ ? "border-[var(--accent)] text-[var(--text-primary)] bg-[var(--bg-primary)]"
74
+ : "border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]")
75
+ }
76
+ >
77
+ <span className="text-fg-subtle">{s.icon}</span>
78
+ <span>{s.label}</span>
79
+ </button>
80
+ );
81
+ })}
82
+ </div>
83
+ <div className="flex-1 min-h-0 overflow-hidden">
84
+ {active === "appearance" && <AppearancePanel />}
85
+ {active === "networking" && <NetworkPanel />}
86
+ {active === "credentials" && <CredentialsListPanel />}
87
+ {active === "models" && <ModelsPanel />}
88
+ {active === "harness" && <HarnessPanel />}
89
+ {active === "logs" && <LogsPanel />}
90
+ {active === "defaults" && <EnvVarsPanel />}
91
+ </div>
92
+ </div>
93
+ );
94
+ }
@@ -13,7 +13,7 @@ function parseStoredMode(raw: string | null): ExperienceMode | null {
13
13
  return null;
14
14
  }
15
15
 
16
- export type Tab = "chat" | "dashboard" | "agents" | "memory" | "documents" | "models" | "credentials" | "mcp" | "extensions" | "tools" | "tasks" | "bridges" | "profile" | "harness" | "logs" | "env";
16
+ export type Tab = "chat" | "dashboard" | "agents" | "memory" | "documents" | "models" | "credentials" | "mcp" | "extensions" | "tools" | "tasks" | "bridges" | "profile" | "harness" | "logs" | "env" | "settings";
17
17
 
18
18
  interface AppState {
19
19
  activeThreadId: string | null;
@@ -15,7 +15,7 @@ import { useEffect, useRef } from "react";
15
15
  import { useAppContext, type Tab } from "@/contexts/AppContext";
16
16
  import { buildHref, parseHref } from "@/lib/ui/navigate";
17
17
 
18
- const TABS: Tab[] = ["chat", "dashboard", "agents", "memory", "documents", "models", "credentials", "mcp", "extensions", "tools", "tasks", "bridges", "profile", "harness"];
18
+ const TABS: Tab[] = ["chat", "dashboard", "agents", "memory", "documents", "models", "credentials", "mcp", "extensions", "tools", "tasks", "bridges", "profile", "harness", "settings"];
19
19
 
20
20
  export function useUrlSync() {
21
21
  const { state, dispatch } = useAppContext();
@@ -18,7 +18,7 @@ export interface ParsedHref {
18
18
  external: boolean;
19
19
  }
20
20
 
21
- const TABS: Tab[] = ["chat", "dashboard", "agents", "memory", "models", "credentials", "mcp", "extensions", "tools", "tasks", "bridges", "profile", "harness", "documents"];
21
+ const TABS: Tab[] = ["chat", "dashboard", "agents", "memory", "models", "credentials", "mcp", "extensions", "tools", "tasks", "bridges", "profile", "harness", "documents", "settings"];
22
22
 
23
23
  export function parseHref(input: string | null | undefined): ParsedHref {
24
24
  if (!input) return { external: false };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@circuitwall/jarela",
3
- "version": "1.9.2",
3
+ "version": "1.9.3",
4
4
  "description": "Jarela — local chat interface for LangGraph agents (multi-provider, single-process, SQLite-backed).",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Andrew Ge Wu",