@bahulam/code 0.1.6 → 0.1.7

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 (178) hide show
  1. package/LICENSE +1 -1
  2. package/NOTICE +6 -6
  3. package/README.md +10 -17
  4. package/package.json +9 -9
  5. package/src/agents/loader.mjs +1 -1
  6. package/src/agents/workflow_loader.mjs +2 -2
  7. package/src/auth/tarang-auth.mjs +3 -2
  8. package/src/config/model-catalog-default.json +4 -3
  9. package/src/config/model-catalog.mjs +2 -0
  10. package/src/context/prose-chunker.mjs +162 -5
  11. package/src/core/attachments.mjs +65 -3
  12. package/src/core/bundled-runtime.mjs +1 -1
  13. package/src/core/headless.mjs +14 -0
  14. package/src/core/jsonl-writer.mjs +3 -3
  15. package/src/core/lint-resolver.mjs +472 -0
  16. package/src/core/local-agent.mjs +15 -4
  17. package/src/core/local-store.mjs +4 -0
  18. package/src/core/output-filter.mjs +21 -25
  19. package/src/core/pricing.mjs +10 -3
  20. package/src/core/stream-client.mjs +9 -4
  21. package/src/core/tool-executor.mjs +105 -29
  22. package/src/daemon/http-dashboard.mjs +400 -0
  23. package/src/daemon/session-core.mjs +1 -0
  24. package/src/local-service/agent-relay.mjs +868 -0
  25. package/src/local-service/approval-bridge.mjs +222 -0
  26. package/src/local-service/browser.mjs +24 -0
  27. package/src/local-service/command.mjs +155 -0
  28. package/src/local-service/file-access.mjs +393 -0
  29. package/src/local-service/machine.mjs +86 -0
  30. package/src/local-service/paths.mjs +29 -0
  31. package/src/local-service/preview-converters.mjs +260 -0
  32. package/src/local-service/server.mjs +2644 -0
  33. package/src/local-service/session-store.mjs +221 -0
  34. package/src/onboarding/preflight.mjs +1 -1
  35. package/src/terminal/analytics.mjs +2 -6
  36. package/src/terminal/ansi.mjs +11 -3
  37. package/src/terminal/main.mjs +37 -11
  38. package/src/terminal/model-catalog-display.mjs +111 -0
  39. package/src/terminal/repl-format.mjs +4 -1
  40. package/src/terminal/repl-model-form.mjs +81 -14
  41. package/src/terminal/repl-render.mjs +35 -5
  42. package/src/terminal/repl-state.mjs +12 -0
  43. package/src/terminal/repl.mjs +231 -53
  44. package/src/terminal/tool-display.mjs +32 -0
  45. package/src/terminal/watch-state.mjs +118 -0
  46. package/src/tools/analyze-image.mjs +158 -0
  47. package/src/tools/bash.mjs +11 -9
  48. package/src/tools/generate-image.mjs +411 -0
  49. package/src/tools/lint.mjs +24 -43
  50. package/src/tools/registry.mjs +4 -0
  51. package/src/ui/icons.mjs +2 -0
  52. package/src/ui/palette.mjs +1 -1
  53. package/src/ui/slash-commands.mjs +4 -6
  54. package/src/ui/tool-card.mjs +7 -3
  55. package/pulse/app/activity/page.tsx +0 -190
  56. package/pulse/app/api/activity/route.ts +0 -138
  57. package/pulse/app/api/benchmark/route.ts +0 -113
  58. package/pulse/app/api/benchmarks/route.ts +0 -195
  59. package/pulse/app/api/costs/route.ts +0 -88
  60. package/pulse/app/api/export/route.ts +0 -77
  61. package/pulse/app/api/history/route.ts +0 -11
  62. package/pulse/app/api/import/route.ts +0 -31
  63. package/pulse/app/api/memory/route.ts +0 -50
  64. package/pulse/app/api/plans/route.ts +0 -9
  65. package/pulse/app/api/projects/[slug]/route.ts +0 -96
  66. package/pulse/app/api/projects/route.ts +0 -121
  67. package/pulse/app/api/sessions/[id]/replay/route.ts +0 -20
  68. package/pulse/app/api/sessions/[id]/route.ts +0 -31
  69. package/pulse/app/api/sessions/route.ts +0 -112
  70. package/pulse/app/api/settings/route.ts +0 -14
  71. package/pulse/app/api/stats/route.ts +0 -143
  72. package/pulse/app/api/todos/route.ts +0 -9
  73. package/pulse/app/api/tools/route.ts +0 -160
  74. package/pulse/app/benchmarks/page.tsx +0 -224
  75. package/pulse/app/costs/page.tsx +0 -179
  76. package/pulse/app/export/page.tsx +0 -465
  77. package/pulse/app/favicon.ico +0 -0
  78. package/pulse/app/globals.css +0 -263
  79. package/pulse/app/help/page.tsx +0 -143
  80. package/pulse/app/history/page.tsx +0 -157
  81. package/pulse/app/layout.tsx +0 -46
  82. package/pulse/app/memory/page.tsx +0 -365
  83. package/pulse/app/overview-client.tsx +0 -393
  84. package/pulse/app/page.tsx +0 -14
  85. package/pulse/app/plans/page.tsx +0 -308
  86. package/pulse/app/projects/[slug]/page.tsx +0 -390
  87. package/pulse/app/projects/page.tsx +0 -110
  88. package/pulse/app/sessions/[id]/page.tsx +0 -243
  89. package/pulse/app/sessions/page.tsx +0 -39
  90. package/pulse/app/settings/page.tsx +0 -188
  91. package/pulse/app/todos/page.tsx +0 -211
  92. package/pulse/app/tools/page.tsx +0 -249
  93. package/pulse/cli.js +0 -164
  94. package/pulse/components/activity/day-of-week-chart.tsx +0 -35
  95. package/pulse/components/activity/streak-card.tsx +0 -36
  96. package/pulse/components/costs/cache-efficiency-panel.tsx +0 -76
  97. package/pulse/components/costs/cost-by-project-chart.tsx +0 -48
  98. package/pulse/components/costs/cost-over-time-chart.tsx +0 -95
  99. package/pulse/components/costs/model-token-table.tsx +0 -60
  100. package/pulse/components/global-search.tsx +0 -193
  101. package/pulse/components/keyboard-nav-provider.tsx +0 -23
  102. package/pulse/components/layout/bottom-nav.tsx +0 -53
  103. package/pulse/components/layout/client-layout.tsx +0 -31
  104. package/pulse/components/layout/sidebar-context.tsx +0 -50
  105. package/pulse/components/layout/sidebar.tsx +0 -183
  106. package/pulse/components/layout/top-bar.tsx +0 -121
  107. package/pulse/components/overview/activity-heatmap.tsx +0 -107
  108. package/pulse/components/overview/conversation-table.tsx +0 -148
  109. package/pulse/components/overview/model-breakdown-donut.tsx +0 -95
  110. package/pulse/components/overview/peak-hours-chart.tsx +0 -87
  111. package/pulse/components/overview/project-activity-donut.tsx +0 -96
  112. package/pulse/components/overview/stat-card.tsx +0 -102
  113. package/pulse/components/overview/usage-over-time-chart.tsx +0 -166
  114. package/pulse/components/projects/project-card.tsx +0 -175
  115. package/pulse/components/sessions/replay/assistant-markdown.tsx +0 -94
  116. package/pulse/components/sessions/replay/compaction-card.tsx +0 -25
  117. package/pulse/components/sessions/replay/session-sidebar.tsx +0 -231
  118. package/pulse/components/sessions/replay/token-accumulation-chart.tsx +0 -98
  119. package/pulse/components/sessions/replay/tool-call-badge.tsx +0 -127
  120. package/pulse/components/sessions/replay/turn-cards.tsx +0 -220
  121. package/pulse/components/sessions/replay/user-tool-result.tsx +0 -158
  122. package/pulse/components/sessions/session-badges.tsx +0 -49
  123. package/pulse/components/sessions/session-table.tsx +0 -299
  124. package/pulse/components/theme-provider.tsx +0 -44
  125. package/pulse/components/tools/feature-adoption-table.tsx +0 -58
  126. package/pulse/components/tools/mcp-server-panel.tsx +0 -45
  127. package/pulse/components/tools/tool-ranking-chart.tsx +0 -57
  128. package/pulse/components/tools/version-history-table.tsx +0 -32
  129. package/pulse/components/ui/alert.tsx +0 -66
  130. package/pulse/components/ui/badge.tsx +0 -48
  131. package/pulse/components/ui/breadcrumb.tsx +0 -109
  132. package/pulse/components/ui/button.tsx +0 -64
  133. package/pulse/components/ui/calendar.tsx +0 -220
  134. package/pulse/components/ui/card.tsx +0 -92
  135. package/pulse/components/ui/command.tsx +0 -158
  136. package/pulse/components/ui/dialog.tsx +0 -158
  137. package/pulse/components/ui/input.tsx +0 -21
  138. package/pulse/components/ui/popover.tsx +0 -89
  139. package/pulse/components/ui/progress.tsx +0 -31
  140. package/pulse/components/ui/select.tsx +0 -190
  141. package/pulse/components/ui/separator.tsx +0 -28
  142. package/pulse/components/ui/sheet.tsx +0 -143
  143. package/pulse/components/ui/skeleton.tsx +0 -13
  144. package/pulse/components/ui/table.tsx +0 -116
  145. package/pulse/components/ui/tabs.tsx +0 -91
  146. package/pulse/components/ui/tooltip.tsx +0 -57
  147. package/pulse/components/use-global-keyboard-nav.ts +0 -79
  148. package/pulse/components.json +0 -23
  149. package/pulse/eslint.config.mjs +0 -18
  150. package/pulse/lib/bahulam-paths.ts +0 -23
  151. package/pulse/lib/claude-reader.ts +0 -592
  152. package/pulse/lib/decode.ts +0 -129
  153. package/pulse/lib/pricing.ts +0 -102
  154. package/pulse/lib/replay-parser.ts +0 -165
  155. package/pulse/lib/tool-categories.ts +0 -140
  156. package/pulse/lib/utils.ts +0 -6
  157. package/pulse/next-env.d.ts +0 -6
  158. package/pulse/next.config.ts +0 -16
  159. package/pulse/package.json +0 -45
  160. package/pulse/postcss.config.mjs +0 -7
  161. package/pulse/public/activity.png +0 -0
  162. package/pulse/public/cc-lens.png +0 -0
  163. package/pulse/public/command-k.png +0 -0
  164. package/pulse/public/costs.png +0 -0
  165. package/pulse/public/dashboard-dark.png +0 -0
  166. package/pulse/public/dashboard-white.png +0 -0
  167. package/pulse/public/export.png +0 -0
  168. package/pulse/public/file.svg +0 -1
  169. package/pulse/public/globe.svg +0 -1
  170. package/pulse/public/next.svg +0 -1
  171. package/pulse/public/projects.png +0 -0
  172. package/pulse/public/session-chat.png +0 -0
  173. package/pulse/public/todos.png +0 -0
  174. package/pulse/public/tools.png +0 -0
  175. package/pulse/public/vercel.svg +0 -1
  176. package/pulse/public/window.svg +0 -1
  177. package/pulse/tsconfig.json +0 -34
  178. package/pulse/types/claude.ts +0 -294
@@ -1,263 +0,0 @@
1
- @import "tailwindcss";
2
- @import "tw-animate-css";
3
-
4
- @custom-variant dark (&:is(.dark *));
5
-
6
- @theme inline {
7
- @keyframes accordion-down {
8
- from { height: 0; }
9
- to { height: var(--radix-accordion-content-height, var(--accordion-panel-height, auto)); }
10
- }
11
- @keyframes accordion-up {
12
- from { height: var(--radix-accordion-content-height, var(--accordion-panel-height, auto)); }
13
- to { height: 0; }
14
- }
15
- }
16
-
17
- @custom-variant data-open {
18
- &:where([data-state="open"]), &:where([data-open]:not([data-open="false"])) { @slot; }
19
- }
20
- @custom-variant data-closed {
21
- &:where([data-state="closed"]), &:where([data-closed]:not([data-closed="false"])) { @slot; }
22
- }
23
- @custom-variant data-checked {
24
- &:where([data-state="checked"]), &:where([data-checked]:not([data-checked="false"])) { @slot; }
25
- }
26
- @custom-variant data-unchecked {
27
- &:where([data-state="unchecked"]), &:where([data-unchecked]:not([data-unchecked="false"])) { @slot; }
28
- }
29
- @custom-variant data-selected {
30
- &:where([data-selected="true"]) { @slot; }
31
- }
32
- @custom-variant data-disabled {
33
- &:where([data-disabled="true"]), &:where([data-disabled]:not([data-disabled="false"])) { @slot; }
34
- }
35
- @custom-variant data-active {
36
- &:where([data-state="active"]), &:where([data-active]:not([data-active="false"])) { @slot; }
37
- }
38
- @custom-variant data-horizontal {
39
- &:where([data-orientation="horizontal"]) { @slot; }
40
- }
41
- @custom-variant data-vertical {
42
- &:where([data-orientation="vertical"]) { @slot; }
43
- }
44
- @utility no-scrollbar {
45
- -ms-overflow-style: none;
46
- scrollbar-width: none;
47
- &::-webkit-scrollbar { display: none; }
48
- }
49
-
50
- @theme inline {
51
- --color-background: var(--background);
52
- --color-foreground: var(--foreground);
53
- --font-sans: var(--font-geist-mono);
54
- --font-mono: var(--font-geist-mono);
55
- --color-sidebar-ring: var(--sidebar-ring);
56
- --color-sidebar-border: var(--sidebar-border);
57
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
58
- --color-sidebar-accent: var(--sidebar-accent);
59
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
60
- --color-sidebar-primary: var(--sidebar-primary);
61
- --color-sidebar-foreground: var(--sidebar-foreground);
62
- --color-sidebar: var(--sidebar);
63
- --color-chart-5: var(--chart-5);
64
- --color-chart-4: var(--chart-4);
65
- --color-chart-3: var(--chart-3);
66
- --color-chart-2: var(--chart-2);
67
- --color-chart-1: var(--chart-1);
68
- --color-ring: var(--ring);
69
- --color-input: var(--input);
70
- --color-border: var(--border);
71
- --color-destructive: var(--destructive);
72
- --color-accent-foreground: var(--accent-foreground);
73
- --color-accent: var(--accent);
74
- --color-muted-foreground: var(--muted-foreground);
75
- --color-muted: var(--muted);
76
- --color-secondary-foreground: var(--secondary-foreground);
77
- --color-secondary: var(--secondary);
78
- --color-primary-foreground: var(--primary-foreground);
79
- --color-primary: var(--primary);
80
- --color-popover-foreground: var(--popover-foreground);
81
- --color-popover: var(--popover);
82
- --color-card-foreground: var(--card-foreground);
83
- --color-card: var(--card);
84
- --radius-sm: calc(var(--radius) - 4px);
85
- --radius-md: calc(var(--radius) - 2px);
86
- --radius-lg: var(--radius);
87
- --radius-xl: calc(var(--radius) + 4px);
88
-
89
- /* Bahulam accent colors */
90
- --color-bahulam-cyan: #06b6d4;
91
- --color-bahulam-cyan-light: #22d3ee;
92
- --color-terminal-cyan: #06b6d4;
93
- --color-terminal-green: #34d399;
94
- --color-terminal-amber: #f59e0b;
95
- --color-terminal-blue: var(--viz-sky, #1d4ed8);
96
- --color-terminal-purple: #a78bfa;
97
- --color-terminal-red: #f87171;
98
- --color-terminal-dim: #9ca3af;
99
- --color-terminal-surface: #0f1117;
100
- }
101
-
102
- /* ─── Light theme (default) — higher contrast, clearer surfaces ─────────── */
103
- :root {
104
- --radius: 0.375rem;
105
- /* Zinc-based neutrals: page vs cards vs chrome read as distinct layers */
106
- --background: #f4f4f5;
107
- --foreground: #18181b;
108
- --card: #ffffff;
109
- --card-foreground: #18181b;
110
- --popover: #ffffff;
111
- --popover-foreground: #18181b;
112
- --primary: #0891b2;
113
- --primary-foreground: #ffffff;
114
- --secondary: #e4e4e7;
115
- --secondary-foreground: #27272a;
116
- --muted: #ececee;
117
- --muted-foreground: #52525b;
118
- --accent: #e4e4e7;
119
- --accent-foreground: #18181b;
120
- --destructive: #dc2626;
121
- --border: #d4d4d8;
122
- /* Input border token: visible edge on white fields */
123
- --input: #d4d4d8;
124
- --ring: #0891b2;
125
- --viz-sky: #1d4ed8;
126
- /* Tool / category colors (light) — saturated, distinct; SVG uses solid fill (no color-mix) */
127
- --viz-tool-read: #1d4ed8;
128
- --viz-tool-write: #4338ca;
129
- --viz-tool-edit: #0891b2;
130
- --viz-tool-grep: #db2777;
131
- --viz-tool-glob: #0891b2;
132
- --viz-tool-file-io: #2563eb;
133
- --viz-tool-shell: #06b6d4;
134
- --viz-tool-agent: #7c3aed;
135
- --viz-tool-web: #15803d;
136
- --viz-tool-planning: #ca8a04;
137
- --viz-tool-todo: #e11d48;
138
- --viz-tool-skill: #0e7490;
139
- --viz-tool-mcp: #059669;
140
- --viz-tool-other: #64748b;
141
- --chart-1: #0891b2;
142
- --chart-2: #059669;
143
- --chart-3: var(--viz-sky);
144
- --chart-4: #7c3aed;
145
- --chart-5: #06b6d4;
146
- --sidebar: #fafafa;
147
- --sidebar-foreground: #3f3f46;
148
- --sidebar-primary: #0891b2;
149
- --sidebar-primary-foreground: #ffffff;
150
- --sidebar-accent: #e4e4e7;
151
- --sidebar-accent-foreground: #18181b;
152
- --sidebar-border: #d4d4d8;
153
- --sidebar-ring: #0891b2;
154
- }
155
-
156
- /* ─── Dark theme ─────────────────────────────────────────────────────────── */
157
- .dark {
158
- --background: #0f1117;
159
- --foreground: #e8eaed;
160
- --card: #171921;
161
- --card-foreground: #e8eaed;
162
- --popover: #171921;
163
- --popover-foreground: #e8eaed;
164
- --primary: #06b6d4;
165
- --primary-foreground: #0f1117;
166
- --secondary: #1e212b;
167
- --secondary-foreground: #d1d5db;
168
- --muted: #1e212b;
169
- --muted-foreground: #94a3b8;
170
- --accent: #1e212b;
171
- --accent-foreground: #e8eaed;
172
- --destructive: #f87171;
173
- --border: #262a36;
174
- --input: #1e212b;
175
- --ring: #06b6d4;
176
- --viz-sky: #60a5fa;
177
- --viz-tool-read: #60a5fa;
178
- --viz-tool-write: #a78bfa;
179
- --viz-tool-edit: #67e8f9;
180
- --viz-tool-grep: #f472b6;
181
- --viz-tool-glob: #22d3ee;
182
- --viz-tool-file-io: #818cf8;
183
- --viz-tool-shell: #22d3ee;
184
- --viz-tool-agent: #c4b5fd;
185
- --viz-tool-web: #6ee7b7;
186
- --viz-tool-planning: #fcd34d;
187
- --viz-tool-todo: #fb7185;
188
- --viz-tool-skill: #5eead4;
189
- --viz-tool-mcp: #86efac;
190
- --viz-tool-other: #94a3b8;
191
- --chart-1: #06b6d4;
192
- --chart-2: #34d399;
193
- --chart-3: var(--viz-sky);
194
- --chart-4: #a78bfa;
195
- --chart-5: #22d3ee;
196
- --sidebar: #0b0d12;
197
- --sidebar-foreground: #d1d5db;
198
- --sidebar-primary: #06b6d4;
199
- --sidebar-primary-foreground: #0f1117;
200
- --sidebar-accent: #1a1d26;
201
- --sidebar-accent-foreground: #e8eaed;
202
- --sidebar-border: #1a1d26;
203
- --sidebar-ring: #06b6d4;
204
- }
205
-
206
- @layer base {
207
- * {
208
- @apply border-border outline-ring/50;
209
- }
210
- body {
211
- @apply bg-background text-foreground;
212
- font-family: var(--font-geist-mono), "JetBrains Mono", "Fira Code", "Consolas", monospace;
213
- font-size: 15px;
214
- }
215
- }
216
-
217
- /* ─── Light mode: subtle depth on cards (matches cyan primary) ──────────── */
218
- :root:not(.dark) [data-slot="card"] {
219
- box-shadow:
220
- 0 1px 2px 0 rgba(24, 24, 27, 0.04),
221
- 0 4px 16px -2px rgba(6, 182, 212, 0.08),
222
- 0 0 0 1px rgba(24, 24, 27, 0.05);
223
- }
224
-
225
- /* ─── Scrollbar ──────────────────────────────────────────────────────────── */
226
- ::-webkit-scrollbar {
227
- width: 6px;
228
- height: 6px;
229
- }
230
- ::-webkit-scrollbar-track {
231
- background: var(--background);
232
- }
233
- ::-webkit-scrollbar-thumb {
234
- background: var(--border);
235
- border-radius: 3px;
236
- }
237
- ::-webkit-scrollbar-thumb:hover {
238
- background: var(--muted-foreground);
239
- }
240
-
241
- /* ─── Terminal glow utilities ────────────────────────────────────────────── */
242
- .glow-cyan {
243
- text-shadow: 0 0 10px rgba(6, 182, 212, 0.5);
244
- }
245
- .glow-green {
246
- text-shadow: 0 0 10px rgba(52, 211, 153, 0.5);
247
- }
248
-
249
- /* ─── Recharts overrides ─────────────────────────────────────────────────── */
250
- .recharts-tooltip-wrapper .recharts-default-tooltip {
251
- background: var(--card) !important;
252
- border: 1px solid var(--border) !important;
253
- border-radius: 6px !important;
254
- }
255
- .recharts-cartesian-grid-horizontal line,
256
- .recharts-cartesian-grid-vertical line {
257
- stroke: var(--border) !important;
258
- }
259
- .recharts-text {
260
- fill: var(--muted-foreground) !important;
261
- font-family: var(--font-geist-mono), monospace !important;
262
- font-size: 13px !important;
263
- }
@@ -1,143 +0,0 @@
1
- import { TopBar } from '@/components/layout/top-bar'
2
- import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
3
-
4
- const CLI_COMMANDS = [
5
- { cmd: 'bahulam-code', desc: 'Start interactive REPL' },
6
- { cmd: 'bahulam-code "instruction"', desc: 'Run a single instruction and exit' },
7
- { cmd: 'bahulam-code dashboard', desc: 'Open Bahulam Pulse analytics dashboard' },
8
- { cmd: 'bahulam-code sessions', desc: 'List recent local sessions' },
9
- { cmd: 'bahulam-code stats', desc: 'Show aggregate local session stats' },
10
- { cmd: 'bahulam-code history', desc: 'Show recent prompt history' },
11
- { cmd: 'bahulam-code login', desc: 'Sign in via browser' },
12
- { cmd: 'bahulam-code version', desc: 'Show version' },
13
- ]
14
-
15
- const REPL_COMMANDS = [
16
- { cmd: '/help', desc: 'Show available commands' },
17
- { cmd: '/stats', desc: 'Session metrics — tokens, cost, tools' },
18
- { cmd: '/cost', desc: 'Detailed cost breakdown by model' },
19
- { cmd: '/history', desc: 'Conversation history' },
20
- { cmd: '/clear', desc: 'Clear conversation history' },
21
- { cmd: '/safety', desc: 'Show safety guardrail status' },
22
- { cmd: '/revoke', desc: 'Revoke auto-approvals' },
23
- { cmd: '/explore <query>', desc: 'Spawn read-only codebase explorer' },
24
- { cmd: '/review <query>', desc: 'Spawn code review agent' },
25
- { cmd: '/architect <query>', desc: 'Spawn architecture planning agent' },
26
- { cmd: '/exit', desc: 'Exit the REPL' },
27
- ]
28
-
29
- const KEYBOARD = [
30
- { key: 'Esc', desc: 'Cancel current execution' },
31
- { key: 'Space', desc: 'Pause / resume execution' },
32
- { key: 'Ctrl+C', desc: 'Exit' },
33
- { key: 'Tab', desc: 'Autocomplete slash commands' },
34
- { key: 'Up/Down', desc: 'Navigate input history' },
35
- ]
36
-
37
- const ENV_VARS = [
38
- { name: 'TARANG_ENV', desc: 'Set backend environment (local, development, production)' },
39
- { name: 'ANTHROPIC_API_KEY', desc: 'Direct Anthropic API key for local mode' },
40
- { name: 'OPENROUTER_API_KEY', desc: 'OpenRouter API key' },
41
- { name: 'BAHULAM_CONFIG_DIR', desc: 'Override config directory (default: ~/.bahulam)' },
42
- { name: 'KEPLER_CONFIG_DIR', desc: 'Legacy config directory override' },
43
- { name: 'TARANG_BACKEND_URL', desc: 'Override backend URL explicitly' },
44
- ]
45
-
46
- const FEATURES = [
47
- { title: 'Multi-Agent Orchestration', desc: 'Primary agent spawns explore, plan, and review sub-agents for complex tasks.' },
48
- { title: 'Smart Tool Routing', desc: 'Write operations routed to CLI for local execution. Read tools run server-side.' },
49
- { title: 'Safety Guardrails', desc: 'Destructive commands (rm, delete) always require approval. Path validation on all file operations.' },
50
- { title: 'Local JSONL Analytics', desc: 'Every session is recorded to ~/.bahulam/ for offline analytics via Bahulam Pulse.' },
51
- { title: 'Conversation History', desc: 'Multi-turn conversations within a REPL session. Context preserved across turns.' },
52
- { title: 'BM25 Code Index', desc: 'Project files indexed on startup for fast semantic code search.' },
53
- ]
54
-
55
- function CommandTable({ commands }: { commands: { cmd: string; desc: string }[] }) {
56
- return (
57
- <div className="space-y-1">
58
- {commands.map(({ cmd, desc }) => (
59
- <div key={cmd} className="flex items-start gap-4 py-1.5">
60
- <code className="text-sm font-mono text-primary whitespace-nowrap shrink-0 min-w-[200px]">{cmd}</code>
61
- <span className="text-sm text-muted-foreground">{desc}</span>
62
- </div>
63
- ))}
64
- </div>
65
- )
66
- }
67
-
68
- export default function HelpPage() {
69
- return (
70
- <div className="flex flex-col min-h-screen">
71
- <TopBar title="Help" subtitle="Bahulam Code CLI commands, shortcuts, and configuration" />
72
- <div className="px-6 py-6 space-y-6">
73
-
74
- <Card>
75
- <CardHeader>
76
- <CardTitle>CLI Commands</CardTitle>
77
- </CardHeader>
78
- <CardContent>
79
- <CommandTable commands={CLI_COMMANDS} />
80
- </CardContent>
81
- </Card>
82
-
83
- <Card>
84
- <CardHeader>
85
- <CardTitle>REPL Commands</CardTitle>
86
- </CardHeader>
87
- <CardContent>
88
- <CommandTable commands={REPL_COMMANDS} />
89
- </CardContent>
90
- </Card>
91
-
92
- <Card>
93
- <CardHeader>
94
- <CardTitle>Keyboard Shortcuts</CardTitle>
95
- </CardHeader>
96
- <CardContent>
97
- <div className="space-y-1">
98
- {KEYBOARD.map(({ key, desc }) => (
99
- <div key={key} className="flex items-start gap-4 py-1.5">
100
- <kbd className="text-sm font-mono bg-muted px-2 py-0.5 rounded border border-border whitespace-nowrap shrink-0 min-w-[100px] text-center">{key}</kbd>
101
- <span className="text-sm text-muted-foreground">{desc}</span>
102
- </div>
103
- ))}
104
- </div>
105
- </CardContent>
106
- </Card>
107
-
108
- <Card>
109
- <CardHeader>
110
- <CardTitle>Environment Variables</CardTitle>
111
- </CardHeader>
112
- <CardContent>
113
- <div className="space-y-1">
114
- {ENV_VARS.map(({ name, desc }) => (
115
- <div key={name} className="flex items-start gap-4 py-1.5">
116
- <code className="text-sm font-mono text-primary whitespace-nowrap shrink-0 min-w-[200px]">{name}</code>
117
- <span className="text-sm text-muted-foreground">{desc}</span>
118
- </div>
119
- ))}
120
- </div>
121
- </CardContent>
122
- </Card>
123
-
124
- <Card>
125
- <CardHeader>
126
- <CardTitle>Features</CardTitle>
127
- </CardHeader>
128
- <CardContent>
129
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
130
- {FEATURES.map(({ title, desc }) => (
131
- <div key={title} className="space-y-1">
132
- <h4 className="text-sm font-semibold">{title}</h4>
133
- <p className="text-sm text-muted-foreground">{desc}</p>
134
- </div>
135
- ))}
136
- </div>
137
- </CardContent>
138
- </Card>
139
-
140
- </div>
141
- </div>
142
- )
143
- }
@@ -1,157 +0,0 @@
1
- 'use client'
2
-
3
- import { useState, useMemo } from 'react'
4
- import useSWR from 'swr'
5
- import { TopBar } from '@/components/layout/top-bar'
6
- import type { HistoryEntry } from '@/types/claude'
7
- import { Input } from '@/components/ui/input'
8
- import { Button } from '@/components/ui/button'
9
- import { Badge } from '@/components/ui/badge'
10
- import { Skeleton } from '@/components/ui/skeleton'
11
- import { Alert, AlertDescription } from '@/components/ui/alert'
12
- import { Search, AlertTriangle, ChevronLeft, ChevronRight } from 'lucide-react'
13
-
14
- const fetcher = (url: string) =>
15
- fetch(url).then(r => { if (!r.ok) throw new Error(`API error ${r.status}`); return r.json() })
16
-
17
- function formatTime(ts: number) {
18
- return new Date(ts).toLocaleString('en-US', {
19
- month: 'short', day: 'numeric', year: 'numeric',
20
- hour: 'numeric', minute: '2-digit',
21
- })
22
- }
23
-
24
- function projectName(p: string) {
25
- const parts = p.replace(/\\/g, '/').split('/')
26
- return parts[parts.length - 1] || p
27
- }
28
-
29
- const PAGE_SIZE = 50
30
-
31
- export default function HistoryPage() {
32
- const { data, error, isLoading } = useSWR<{ history: HistoryEntry[] }>(
33
- '/api/history?limit=2000', fetcher, { refreshInterval: 30_000 }
34
- )
35
- const [search, setSearch] = useState('')
36
- const [page, setPage] = useState(1)
37
-
38
- const entries = useMemo(() => {
39
- const all = [...(data?.history ?? [])].reverse()
40
- if (!search) return all
41
- const q = search.toLowerCase()
42
- return all.filter(e =>
43
- e.display?.toLowerCase().includes(q) ||
44
- e.project?.toLowerCase().includes(q)
45
- )
46
- }, [data, search])
47
-
48
- const totalPages = Math.ceil(entries.length / PAGE_SIZE)
49
- const pageEntries = entries.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE)
50
-
51
- function handleSearch(v: string) {
52
- setSearch(v)
53
- setPage(1)
54
- }
55
-
56
- return (
57
- <div className="flex flex-col min-h-screen">
58
- <TopBar title="History" subtitle="~/.bahulam/history.jsonl" />
59
- <div className="p-4 md:p-6 space-y-4">
60
-
61
- {error && (
62
- <Alert variant="destructive">
63
- <AlertTriangle className="h-4 w-4" />
64
- <AlertDescription>Error loading data: {String(error)}</AlertDescription>
65
- </Alert>
66
- )}
67
-
68
- {isLoading && (
69
- <div className="space-y-2">
70
- {Array.from({ length: 8 }).map((_, i) => <Skeleton key={i} className="h-14 rounded-lg" />)}
71
- </div>
72
- )}
73
-
74
- {data && (
75
- <>
76
- {/* Search + count */}
77
- <div className="flex flex-col sm:flex-row items-start sm:items-center gap-3">
78
- <div className="relative flex-1 w-full">
79
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
80
- <Input
81
- placeholder="Search commands…"
82
- value={search}
83
- onChange={e => handleSearch(e.target.value)}
84
- className="pl-9"
85
- />
86
- </div>
87
- <Badge variant="outline" className="whitespace-nowrap text-sm px-3 py-1.5">
88
- {entries.length.toLocaleString()} entries
89
- </Badge>
90
- </div>
91
-
92
- {pageEntries.length === 0 ? (
93
- <div className="text-center py-16 text-muted-foreground text-sm">
94
- {(data.history?.length ?? 0) === 0
95
- ? 'No history found in ~/.bahulam/history.jsonl'
96
- : 'No entries match your search.'}
97
- </div>
98
- ) : (
99
- <>
100
- <div className="space-y-1">
101
- {pageEntries.map((entry, i) => (
102
- <div
103
- key={i}
104
- className="border border-border rounded-lg bg-card px-4 py-3 hover:border-primary/30 transition-colors"
105
- >
106
- <p className="text-sm font-mono text-foreground leading-relaxed break-words">
107
- {entry.display || '—'}
108
- </p>
109
- <div className="flex flex-wrap items-center gap-2 mt-1.5">
110
- {entry.timestamp && (
111
- <span className="text-xs text-muted-foreground/60">
112
- {formatTime(entry.timestamp)}
113
- </span>
114
- )}
115
- {entry.project && (
116
- <Badge variant="secondary" className="text-xs font-mono">
117
- {projectName(entry.project)}
118
- </Badge>
119
- )}
120
- </div>
121
- </div>
122
- ))}
123
- </div>
124
-
125
- {totalPages > 1 && (
126
- <div className="flex items-center justify-center gap-2 pt-2">
127
- <Button
128
- variant="outline"
129
- size="sm"
130
- onClick={() => setPage(p => Math.max(1, p - 1))}
131
- disabled={page === 1}
132
- >
133
- <ChevronLeft className="w-4 h-4" />
134
- Prev
135
- </Button>
136
- <span className="text-sm text-muted-foreground tabular-nums">
137
- {page} / {totalPages}
138
- </span>
139
- <Button
140
- variant="outline"
141
- size="sm"
142
- onClick={() => setPage(p => Math.min(totalPages, p + 1))}
143
- disabled={page === totalPages}
144
- >
145
- Next
146
- <ChevronRight className="w-4 h-4" />
147
- </Button>
148
- </div>
149
- )}
150
- </>
151
- )}
152
- </>
153
- )}
154
- </div>
155
- </div>
156
- )
157
- }
@@ -1,46 +0,0 @@
1
- import type { Metadata } from 'next'
2
- import { Geist_Mono, Press_Start_2P } from 'next/font/google'
3
- import './globals.css'
4
- import { Sidebar } from '@/components/layout/sidebar'
5
- import { BottomNav } from '@/components/layout/bottom-nav'
6
- import { ThemeProvider } from '@/components/theme-provider'
7
- import { KeyboardNavProvider } from '@/components/keyboard-nav-provider'
8
- import { SidebarProvider } from '@/components/layout/sidebar-context'
9
- import { ClientLayout } from '@/components/layout/client-layout'
10
-
11
- const geistMono = Geist_Mono({
12
- variable: '--font-geist-mono',
13
- subsets: ['latin'],
14
- })
15
-
16
- const pressStart2P = Press_Start_2P({
17
- variable: '--font-press-start',
18
- weight: '400',
19
- subsets: ['latin'],
20
- })
21
-
22
- export const metadata: Metadata = {
23
- title: 'Bahulam Pulse',
24
- description: 'Real-time analytics for your Bahulam Code agent sessions',
25
- }
26
-
27
- export default function RootLayout({
28
- children,
29
- }: Readonly<{ children: React.ReactNode }>) {
30
- return (
31
- <html lang="en" suppressHydrationWarning>
32
- <body suppressHydrationWarning className={`${geistMono.variable} ${pressStart2P.variable} antialiased`}>
33
- <ThemeProvider>
34
- <SidebarProvider>
35
- <div className="flex min-h-screen">
36
- <Sidebar />
37
- <ClientLayout>{children}</ClientLayout>
38
- </div>
39
- <BottomNav />
40
- <KeyboardNavProvider />
41
- </SidebarProvider>
42
- </ThemeProvider>
43
- </body>
44
- </html>
45
- )
46
- }