claude-smart 0.2.22 → 0.2.24

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 (113) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/README.md +69 -27
  3. package/bin/claude-smart.js +296 -11
  4. package/package.json +11 -1
  5. package/plugin/.claude-plugin/plugin.json +17 -0
  6. package/plugin/.codex-plugin/plugin.json +35 -0
  7. package/plugin/LICENSE +202 -0
  8. package/plugin/README.md +37 -0
  9. package/plugin/bin/cs-cite +77 -0
  10. package/plugin/commands/clear-all.md +8 -0
  11. package/plugin/commands/dashboard.md +8 -0
  12. package/plugin/commands/learn.md +12 -0
  13. package/plugin/commands/restart.md +8 -0
  14. package/plugin/commands/show.md +8 -0
  15. package/plugin/dashboard/AGENTS.md +6 -0
  16. package/plugin/dashboard/app/api/claude-settings/route.ts +19 -0
  17. package/plugin/dashboard/app/api/config/route.ts +16 -0
  18. package/plugin/dashboard/app/api/health/route.ts +10 -0
  19. package/plugin/dashboard/app/api/reflexio/[...path]/route.ts +63 -0
  20. package/plugin/dashboard/app/api/sessions/[id]/route.ts +28 -0
  21. package/plugin/dashboard/app/api/sessions/route.ts +14 -0
  22. package/plugin/dashboard/app/configure/env/page.tsx +318 -0
  23. package/plugin/dashboard/app/configure/layout.tsx +47 -0
  24. package/plugin/dashboard/app/configure/page.tsx +5 -0
  25. package/plugin/dashboard/app/configure/server/page.tsx +258 -0
  26. package/plugin/dashboard/app/dashboard/page.tsx +227 -0
  27. package/plugin/dashboard/app/globals.css +129 -0
  28. package/plugin/dashboard/app/icon.png +0 -0
  29. package/plugin/dashboard/app/layout.tsx +40 -0
  30. package/plugin/dashboard/app/page.tsx +5 -0
  31. package/plugin/dashboard/app/preferences/[id]/page.tsx +531 -0
  32. package/plugin/dashboard/app/preferences/page.tsx +126 -0
  33. package/plugin/dashboard/app/providers.tsx +12 -0
  34. package/plugin/dashboard/app/sessions/[sessionId]/page.tsx +321 -0
  35. package/plugin/dashboard/app/sessions/page.tsx +186 -0
  36. package/plugin/dashboard/app/skills/page.tsx +362 -0
  37. package/plugin/dashboard/app/skills/project/[id]/page.tsx +597 -0
  38. package/plugin/dashboard/app/skills/shared/[id]/page.tsx +830 -0
  39. package/plugin/dashboard/components/common/delete-all-button.tsx +45 -0
  40. package/plugin/dashboard/components/common/empty-state.tsx +34 -0
  41. package/plugin/dashboard/components/common/learnings-badge.tsx +34 -0
  42. package/plugin/dashboard/components/common/page-header.tsx +34 -0
  43. package/plugin/dashboard/components/common/page-tabs.tsx +115 -0
  44. package/plugin/dashboard/components/common/stat-card.tsx +38 -0
  45. package/plugin/dashboard/components/layout/nav-items.ts +22 -0
  46. package/plugin/dashboard/components/layout/sidebar.tsx +45 -0
  47. package/plugin/dashboard/components/layout/top-bar.tsx +64 -0
  48. package/plugin/dashboard/components/stall-banner.tsx +53 -0
  49. package/plugin/dashboard/components/ui/badge.tsx +52 -0
  50. package/plugin/dashboard/components/ui/button.tsx +60 -0
  51. package/plugin/dashboard/components/ui/collapsible.tsx +21 -0
  52. package/plugin/dashboard/components/ui/input.tsx +20 -0
  53. package/plugin/dashboard/components/ui/label.tsx +20 -0
  54. package/plugin/dashboard/components/ui/scroll-area.tsx +55 -0
  55. package/plugin/dashboard/components/ui/select.tsx +201 -0
  56. package/plugin/dashboard/components/ui/separator.tsx +25 -0
  57. package/plugin/dashboard/components/ui/sheet.tsx +135 -0
  58. package/plugin/dashboard/components/ui/switch.tsx +32 -0
  59. package/plugin/dashboard/components.json +25 -0
  60. package/plugin/dashboard/eslint.config.mjs +16 -0
  61. package/plugin/dashboard/hooks/use-settings.tsx +88 -0
  62. package/plugin/dashboard/hooks/use-stall-state.ts +59 -0
  63. package/plugin/dashboard/lib/claude-settings-file.ts +114 -0
  64. package/plugin/dashboard/lib/config-file.ts +131 -0
  65. package/plugin/dashboard/lib/format.ts +58 -0
  66. package/plugin/dashboard/lib/reflexio-client.ts +238 -0
  67. package/plugin/dashboard/lib/reflexio-url.ts +17 -0
  68. package/plugin/dashboard/lib/session-reader.ts +245 -0
  69. package/plugin/dashboard/lib/status.ts +24 -0
  70. package/plugin/dashboard/lib/types.ts +145 -0
  71. package/plugin/dashboard/lib/utils.ts +6 -0
  72. package/plugin/dashboard/next.config.ts +7 -0
  73. package/plugin/dashboard/package-lock.json +10275 -0
  74. package/plugin/dashboard/package.json +37 -0
  75. package/plugin/dashboard/postcss.config.mjs +7 -0
  76. package/plugin/dashboard/public/claude-smart-icon.png +0 -0
  77. package/plugin/dashboard/tsconfig.json +34 -0
  78. package/plugin/hooks/codex-hooks.json +67 -0
  79. package/plugin/hooks/hooks.json +111 -0
  80. package/plugin/pyproject.toml +49 -0
  81. package/plugin/scripts/_codex_env.sh +27 -0
  82. package/plugin/scripts/_lib.sh +325 -0
  83. package/plugin/scripts/backend-service.sh +208 -0
  84. package/plugin/scripts/cli.sh +40 -0
  85. package/plugin/scripts/dashboard-build.sh +139 -0
  86. package/plugin/scripts/dashboard-open.sh +107 -0
  87. package/plugin/scripts/dashboard-service.sh +195 -0
  88. package/plugin/scripts/ensure-plugin-root.sh +84 -0
  89. package/plugin/scripts/hook_entry.sh +70 -0
  90. package/plugin/scripts/smart-install.sh +411 -0
  91. package/plugin/src/claude_smart/__init__.py +3 -0
  92. package/plugin/src/claude_smart/cli.py +1273 -0
  93. package/plugin/src/claude_smart/context_format.py +277 -0
  94. package/plugin/src/claude_smart/context_inject.py +92 -0
  95. package/plugin/src/claude_smart/cs_cite.py +236 -0
  96. package/plugin/src/claude_smart/events/__init__.py +1 -0
  97. package/plugin/src/claude_smart/events/post_tool.py +148 -0
  98. package/plugin/src/claude_smart/events/pre_tool.py +52 -0
  99. package/plugin/src/claude_smart/events/session_end.py +20 -0
  100. package/plugin/src/claude_smart/events/session_start.py +119 -0
  101. package/plugin/src/claude_smart/events/stop.py +393 -0
  102. package/plugin/src/claude_smart/events/user_prompt.py +73 -0
  103. package/plugin/src/claude_smart/hook.py +114 -0
  104. package/plugin/src/claude_smart/ids.py +56 -0
  105. package/plugin/src/claude_smart/internal_call.py +89 -0
  106. package/plugin/src/claude_smart/optimizer_assistant.py +203 -0
  107. package/plugin/src/claude_smart/publish.py +71 -0
  108. package/plugin/src/claude_smart/query_compose.py +51 -0
  109. package/plugin/src/claude_smart/reflexio_adapter.py +403 -0
  110. package/plugin/src/claude_smart/runtime.py +52 -0
  111. package/plugin/src/claude_smart/stall_banner.py +61 -0
  112. package/plugin/src/claude_smart/state.py +276 -0
  113. package/plugin/uv.lock +3720 -0
@@ -0,0 +1,227 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import Link from "next/link";
5
+ import {
6
+ BookOpen,
7
+ MessageSquare,
8
+ Sparkles,
9
+ Activity,
10
+ ExternalLink,
11
+ } from "lucide-react";
12
+ import { LearningsBadge } from "@/components/common/learnings-badge";
13
+ import { PageHeader } from "@/components/common/page-header";
14
+ import { StatCard } from "@/components/common/stat-card";
15
+ import { EmptyState } from "@/components/common/empty-state";
16
+ import { Badge } from "@/components/ui/badge";
17
+ import { reflexio } from "@/lib/reflexio-client";
18
+ import { useSettings } from "@/hooks/use-settings";
19
+ import { formatRelative, truncateId } from "@/lib/format";
20
+ import { agentPlaybookStatusLabel } from "@/lib/status";
21
+ import type { AgentPlaybook, SessionSummary, UserPlaybook } from "@/lib/types";
22
+
23
+ export default function DashboardPage() {
24
+ const { reflexioUrl } = useSettings();
25
+ const [sessions, setSessions] = useState<SessionSummary[] | null>(null);
26
+ const [projectSkills, setProjectSkills] = useState<UserPlaybook[] | null>(null);
27
+ const [sharedSkills, setSharedSkills] = useState<AgentPlaybook[] | null>(null);
28
+ const [error, setError] = useState<string | null>(null);
29
+
30
+ useEffect(() => {
31
+ let cancelled = false;
32
+ async function load() {
33
+ setError(null);
34
+ try {
35
+ const [sRes, projectRes, sharedRes] = await Promise.all([
36
+ fetch("/api/sessions", { cache: "no-store" }).then((r) => r.json()),
37
+ reflexio
38
+ .getUserPlaybooks({ reflexioUrl })
39
+ .catch(() => ({ user_playbooks: [] as UserPlaybook[] })),
40
+ reflexio
41
+ .getAgentPlaybooks({ reflexioUrl })
42
+ .catch(() => ({ agent_playbooks: [] as AgentPlaybook[] })),
43
+ ]);
44
+ if (cancelled) return;
45
+ setSessions(sRes.sessions ?? []);
46
+ setProjectSkills(projectRes.user_playbooks ?? []);
47
+ setSharedSkills(sharedRes.agent_playbooks ?? []);
48
+ } catch (e) {
49
+ if (!cancelled)
50
+ setError(e instanceof Error ? e.message : "failed to load");
51
+ }
52
+ }
53
+ load();
54
+ return () => {
55
+ cancelled = true;
56
+ };
57
+ }, [reflexioUrl]);
58
+
59
+ // CURRENT project-specific skills arrive as `status: null` (response_model_exclude_none
60
+ // strips the field). Anything else (e.g. "archived", "pending") is excluded.
61
+ const currentProjectSkills = (projectSkills ?? []).filter((p) => p.status == null);
62
+ const approvedSharedSkills = (sharedSkills ?? []).filter(
63
+ (p) => agentPlaybookStatusLabel(p) === "APPROVED",
64
+ );
65
+ const learningInteractionTotal = (sessions ?? []).reduce(
66
+ (acc, s) => acc + s.learning_interaction_count,
67
+ 0,
68
+ );
69
+ return (
70
+ <div className="flex-1 overflow-auto">
71
+ <PageHeader
72
+ title="Dashboard"
73
+ description="Overview of claude-smart learning across sessions and projects."
74
+ />
75
+
76
+ <div className="p-6 space-y-6">
77
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3">
78
+ <StatCard
79
+ label="Sessions recorded"
80
+ value={sessions?.length ?? "—"}
81
+ hint="JSONL buffers on disk"
82
+ icon={Activity}
83
+ />
84
+ <StatCard
85
+ label="Project-specific skills"
86
+ value={currentProjectSkills.length || "—"}
87
+ hint="current project-specific rules"
88
+ icon={BookOpen}
89
+ />
90
+ <StatCard
91
+ label="Shared skills"
92
+ value={approvedSharedSkills.length || "—"}
93
+ hint="approved shared rules"
94
+ icon={BookOpen}
95
+ />
96
+ <StatCard
97
+ label="Interactions with learnings applied"
98
+ value={learningInteractionTotal}
99
+ hint="turns where a skill or preference was cited"
100
+ icon={Sparkles}
101
+ />
102
+ </div>
103
+
104
+ {error && (
105
+ <div className="rounded-lg border border-destructive/30 bg-destructive/5 text-destructive px-4 py-3 text-sm">
106
+ {error}
107
+ </div>
108
+ )}
109
+
110
+ <section>
111
+ <div className="flex items-center justify-between mb-3">
112
+ <h2 className="text-sm font-semibold">Recent sessions</h2>
113
+ <Link
114
+ href="/sessions"
115
+ className="text-xs text-muted-foreground hover:text-foreground inline-flex items-center gap-1"
116
+ >
117
+ View all <ExternalLink className="h-3 w-3" />
118
+ </Link>
119
+ </div>
120
+ {sessions && sessions.length > 0 ? (
121
+ <div className="rounded-xl border border-border divide-y divide-border bg-card">
122
+ {sessions.slice(0, 5).map((s) => (
123
+ <Link
124
+ key={s.session_id}
125
+ href={`/sessions/${s.session_id}`}
126
+ className="flex items-center justify-between px-4 py-3 hover:bg-accent/40 transition-colors"
127
+ >
128
+ <div className="min-w-0 flex items-center gap-3">
129
+ <MessageSquare className="h-4 w-4 text-muted-foreground shrink-0" />
130
+ <code className="font-mono text-xs truncate">
131
+ {truncateId(s.session_id, 10, 6)}
132
+ </code>
133
+ <LearningsBadge count={s.learning_interaction_count} />
134
+ </div>
135
+ <div className="flex items-center gap-4 text-xs text-muted-foreground shrink-0">
136
+ <span>{s.turn_count} turns</span>
137
+ <span>{formatRelative(s.last_activity)}</span>
138
+ </div>
139
+ </Link>
140
+ ))}
141
+ </div>
142
+ ) : (
143
+ <EmptyState
144
+ icon={MessageSquare}
145
+ title="No sessions yet"
146
+ description="Run Claude Code with claude-smart enabled — sessions will appear here."
147
+ />
148
+ )}
149
+ </section>
150
+
151
+ <section>
152
+ <div className="flex items-center justify-between mb-3">
153
+ <h2 className="text-sm font-semibold">Recent skills</h2>
154
+ <Link
155
+ href="/skills"
156
+ className="text-xs text-muted-foreground hover:text-foreground inline-flex items-center gap-1"
157
+ >
158
+ View all <ExternalLink className="h-3 w-3" />
159
+ </Link>
160
+ </div>
161
+ {currentProjectSkills.length > 0 || approvedSharedSkills.length > 0 ? (
162
+ <div className="grid gap-3 sm:grid-cols-2">
163
+ {currentProjectSkills.slice(0, 2).map((p) => (
164
+ <Link
165
+ key={`project:${p.user_playbook_id}`}
166
+ href={`/skills/project/${p.user_playbook_id}`}
167
+ className="block rounded-xl border border-border bg-card p-4 hover:bg-accent/40 transition-colors"
168
+ >
169
+ <div className="flex items-center justify-between gap-2 mb-2">
170
+ <Badge variant="outline" className="font-mono text-[10px]">
171
+ {p.agent_version || "default"}
172
+ </Badge>
173
+ <Badge variant="secondary" className="text-[10px]">
174
+ project-specific
175
+ </Badge>
176
+ <span className="text-[11px] text-muted-foreground">
177
+ {formatRelative(p.created_at)}
178
+ </span>
179
+ </div>
180
+ <p className="text-sm line-clamp-3">{p.content}</p>
181
+ {p.trigger && (
182
+ <p className="text-xs text-muted-foreground mt-2 line-clamp-1">
183
+ <span className="font-medium">trigger:</span> {p.trigger}
184
+ </p>
185
+ )}
186
+ </Link>
187
+ ))}
188
+ {approvedSharedSkills.slice(0, 2).map((p) => (
189
+ <Link
190
+ key={`shared:${p.agent_playbook_id}`}
191
+ href={`/skills/shared/${p.agent_playbook_id}`}
192
+ className="block rounded-xl border border-border bg-card p-4 hover:bg-accent/40 transition-colors"
193
+ >
194
+ <div className="flex items-center justify-between gap-2 mb-2">
195
+ <div className="flex items-center gap-2">
196
+ <Badge variant="outline" className="font-mono text-[10px]">
197
+ {p.agent_version || "default"}
198
+ </Badge>
199
+ <Badge variant="secondary" className="text-[10px]">
200
+ shared
201
+ </Badge>
202
+ </div>
203
+ <span className="text-[11px] text-muted-foreground">
204
+ {formatRelative(p.created_at)}
205
+ </span>
206
+ </div>
207
+ <p className="text-sm line-clamp-3">{p.content}</p>
208
+ {p.trigger && (
209
+ <p className="text-xs text-muted-foreground mt-2 line-clamp-1">
210
+ <span className="font-medium">trigger:</span> {p.trigger}
211
+ </p>
212
+ )}
213
+ </Link>
214
+ ))}
215
+ </div>
216
+ ) : (
217
+ <EmptyState
218
+ icon={BookOpen}
219
+ title="No skills yet"
220
+ description="Keep using Claude with claude-smart enabled. Skills are extracted automatically when patterns emerge."
221
+ />
222
+ )}
223
+ </section>
224
+ </div>
225
+ </div>
226
+ );
227
+ }
@@ -0,0 +1,129 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+ @import "shadcn/tailwind.css";
4
+
5
+ @custom-variant dark (&:is(.dark *));
6
+
7
+ @theme inline {
8
+ --color-background: var(--background);
9
+ --color-foreground: var(--foreground);
10
+ --font-sans: var(--font-sans);
11
+ --font-mono: var(--font-geist-mono);
12
+ --color-sidebar-ring: var(--sidebar-ring);
13
+ --color-sidebar-border: var(--sidebar-border);
14
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
15
+ --color-sidebar-accent: var(--sidebar-accent);
16
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
17
+ --color-sidebar-primary: var(--sidebar-primary);
18
+ --color-sidebar-foreground: var(--sidebar-foreground);
19
+ --color-sidebar: var(--sidebar);
20
+ --color-chart-5: var(--chart-5);
21
+ --color-chart-4: var(--chart-4);
22
+ --color-chart-3: var(--chart-3);
23
+ --color-chart-2: var(--chart-2);
24
+ --color-chart-1: var(--chart-1);
25
+ --color-ring: var(--ring);
26
+ --color-input: var(--input);
27
+ --color-border: var(--border);
28
+ --color-destructive: var(--destructive);
29
+ --color-accent-foreground: var(--accent-foreground);
30
+ --color-accent: var(--accent);
31
+ --color-muted-foreground: var(--muted-foreground);
32
+ --color-muted: var(--muted);
33
+ --color-secondary-foreground: var(--secondary-foreground);
34
+ --color-secondary: var(--secondary);
35
+ --color-primary-foreground: var(--primary-foreground);
36
+ --color-primary: var(--primary);
37
+ --color-popover-foreground: var(--popover-foreground);
38
+ --color-popover: var(--popover);
39
+ --color-card-foreground: var(--card-foreground);
40
+ --color-card: var(--card);
41
+ --radius-sm: calc(var(--radius) * 0.6);
42
+ --radius-md: calc(var(--radius) * 0.8);
43
+ --radius-lg: var(--radius);
44
+ --radius-xl: calc(var(--radius) * 1.4);
45
+ --radius-2xl: calc(var(--radius) * 1.8);
46
+ --radius-3xl: calc(var(--radius) * 2.2);
47
+ --radius-4xl: calc(var(--radius) * 2.6);
48
+ }
49
+
50
+ :root {
51
+ --background: oklch(1 0 0);
52
+ --foreground: oklch(0.145 0 0);
53
+ --card: oklch(1 0 0);
54
+ --card-foreground: oklch(0.145 0 0);
55
+ --popover: oklch(1 0 0);
56
+ --popover-foreground: oklch(0.145 0 0);
57
+ --primary: oklch(0.205 0 0);
58
+ --primary-foreground: oklch(0.985 0 0);
59
+ --secondary: oklch(0.97 0 0);
60
+ --secondary-foreground: oklch(0.205 0 0);
61
+ --muted: oklch(0.97 0 0);
62
+ --muted-foreground: oklch(0.556 0 0);
63
+ --accent: oklch(0.97 0 0);
64
+ --accent-foreground: oklch(0.205 0 0);
65
+ --destructive: oklch(0.577 0.245 27.325);
66
+ --border: oklch(0.922 0 0);
67
+ --input: oklch(0.922 0 0);
68
+ --ring: oklch(0.708 0 0);
69
+ --chart-1: oklch(0.809 0.105 251.813);
70
+ --chart-2: oklch(0.623 0.214 259.815);
71
+ --chart-3: oklch(0.546 0.245 262.881);
72
+ --chart-4: oklch(0.488 0.243 264.376);
73
+ --chart-5: oklch(0.424 0.199 265.638);
74
+ --radius: 0.625rem;
75
+ --sidebar: oklch(0.985 0 0);
76
+ --sidebar-foreground: oklch(0.145 0 0);
77
+ --sidebar-primary: oklch(0.205 0 0);
78
+ --sidebar-primary-foreground: oklch(0.985 0 0);
79
+ --sidebar-accent: oklch(0.97 0 0);
80
+ --sidebar-accent-foreground: oklch(0.205 0 0);
81
+ --sidebar-border: oklch(0.922 0 0);
82
+ --sidebar-ring: oklch(0.708 0 0);
83
+ }
84
+
85
+ .dark {
86
+ --background: oklch(0.145 0 0);
87
+ --foreground: oklch(0.985 0 0);
88
+ --card: oklch(0.205 0 0);
89
+ --card-foreground: oklch(0.985 0 0);
90
+ --popover: oklch(0.205 0 0);
91
+ --popover-foreground: oklch(0.985 0 0);
92
+ --primary: oklch(0.922 0 0);
93
+ --primary-foreground: oklch(0.205 0 0);
94
+ --secondary: oklch(0.269 0 0);
95
+ --secondary-foreground: oklch(0.985 0 0);
96
+ --muted: oklch(0.269 0 0);
97
+ --muted-foreground: oklch(0.708 0 0);
98
+ --accent: oklch(0.269 0 0);
99
+ --accent-foreground: oklch(0.985 0 0);
100
+ --destructive: oklch(0.704 0.191 22.216);
101
+ --border: oklch(1 0 0 / 10%);
102
+ --input: oklch(1 0 0 / 15%);
103
+ --ring: oklch(0.556 0 0);
104
+ --chart-1: oklch(0.809 0.105 251.813);
105
+ --chart-2: oklch(0.623 0.214 259.815);
106
+ --chart-3: oklch(0.546 0.245 262.881);
107
+ --chart-4: oklch(0.488 0.243 264.376);
108
+ --chart-5: oklch(0.424 0.199 265.638);
109
+ --sidebar: oklch(0.205 0 0);
110
+ --sidebar-foreground: oklch(0.985 0 0);
111
+ --sidebar-primary: oklch(0.488 0.243 264.376);
112
+ --sidebar-primary-foreground: oklch(0.985 0 0);
113
+ --sidebar-accent: oklch(0.269 0 0);
114
+ --sidebar-accent-foreground: oklch(0.985 0 0);
115
+ --sidebar-border: oklch(1 0 0 / 10%);
116
+ --sidebar-ring: oklch(0.556 0 0);
117
+ }
118
+
119
+ @layer base {
120
+ * {
121
+ @apply border-border outline-ring/50;
122
+ }
123
+ body {
124
+ @apply bg-background text-foreground;
125
+ }
126
+ html {
127
+ @apply font-sans;
128
+ }
129
+ }
Binary file
@@ -0,0 +1,40 @@
1
+ import type { Metadata } from "next";
2
+ import { Inter } from "next/font/google";
3
+ import "./globals.css";
4
+ import { Providers } from "./providers";
5
+ import { Sidebar } from "@/components/layout/sidebar";
6
+ import { TopBar } from "@/components/layout/top-bar";
7
+ import { StallBanner } from "@/components/stall-banner";
8
+
9
+ const inter = Inter({
10
+ variable: "--font-sans",
11
+ subsets: ["latin"],
12
+ });
13
+
14
+ export const metadata: Metadata = {
15
+ title: "Claude-Smart Dashboard",
16
+ description: "Manage sessions, preferences, skills, and configuration",
17
+ };
18
+
19
+ export default function RootLayout({
20
+ children,
21
+ }: Readonly<{
22
+ children: React.ReactNode;
23
+ }>) {
24
+ return (
25
+ <html lang="en" className={`${inter.variable} h-full`} suppressHydrationWarning>
26
+ <body className="h-full flex flex-col antialiased font-sans">
27
+ <Providers>
28
+ <StallBanner />
29
+ <TopBar />
30
+ <div className="flex flex-1 min-h-0">
31
+ <aside className="hidden lg:block w-60 border-r border-border shrink-0">
32
+ <Sidebar />
33
+ </aside>
34
+ <main className="flex-1 min-w-0 flex flex-col">{children}</main>
35
+ </div>
36
+ </Providers>
37
+ </body>
38
+ </html>
39
+ );
40
+ }
@@ -0,0 +1,5 @@
1
+ import { redirect } from "next/navigation";
2
+
3
+ export default function RootPage() {
4
+ redirect("/dashboard");
5
+ }