@a5c-ai/babysitter-observer-dashboard 1.0.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.
Files changed (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +490 -0
  3. package/next.config.mjs +25 -0
  4. package/package.json +104 -0
  5. package/postcss.config.mjs +8 -0
  6. package/src/app/actions/__tests__/approve-breakpoint.test.ts +246 -0
  7. package/src/app/actions/approve-breakpoint.ts +145 -0
  8. package/src/app/api/config/route.ts +137 -0
  9. package/src/app/api/digest/route.ts +45 -0
  10. package/src/app/api/runs/[runId]/events/route.ts +56 -0
  11. package/src/app/api/runs/[runId]/route.ts +84 -0
  12. package/src/app/api/runs/[runId]/tasks/[effectId]/route.ts +44 -0
  13. package/src/app/api/runs/route.ts +48 -0
  14. package/src/app/api/stream/route.ts +136 -0
  15. package/src/app/api/test/route.ts +1 -0
  16. package/src/app/api/version/route.ts +57 -0
  17. package/src/app/globals.css +555 -0
  18. package/src/app/icon.svg +20 -0
  19. package/src/app/layout.tsx +39 -0
  20. package/src/app/not-found.tsx +16 -0
  21. package/src/app/page.tsx +120 -0
  22. package/src/app/runs/[runId]/page.tsx +279 -0
  23. package/src/cli.ts +271 -0
  24. package/src/components/breakpoint/__tests__/breakpoint-approval.test.tsx +212 -0
  25. package/src/components/breakpoint/__tests__/breakpoint-panel.test.tsx +130 -0
  26. package/src/components/breakpoint/__tests__/file-preview.test.tsx +313 -0
  27. package/src/components/breakpoint/breakpoint-approval.tsx +138 -0
  28. package/src/components/breakpoint/breakpoint-panel.tsx +95 -0
  29. package/src/components/breakpoint/file-preview.tsx +215 -0
  30. package/src/components/dashboard/.gitkeep +0 -0
  31. package/src/components/dashboard/__tests__/breakpoint-banner.test.tsx +177 -0
  32. package/src/components/dashboard/__tests__/catch-up-banner.test.tsx +141 -0
  33. package/src/components/dashboard/__tests__/executive-summary-banner.test.tsx +164 -0
  34. package/src/components/dashboard/__tests__/kpi-grid.test.tsx +101 -0
  35. package/src/components/dashboard/__tests__/pagination-controls.test.tsx +125 -0
  36. package/src/components/dashboard/__tests__/project-accordion.test.tsx +97 -0
  37. package/src/components/dashboard/__tests__/project-list-view.test.tsx +174 -0
  38. package/src/components/dashboard/__tests__/project-search-input.test.tsx +110 -0
  39. package/src/components/dashboard/__tests__/project-section-header.test.tsx +91 -0
  40. package/src/components/dashboard/__tests__/project-section.test.tsx +151 -0
  41. package/src/components/dashboard/__tests__/run-card.test.tsx +164 -0
  42. package/src/components/dashboard/__tests__/run-filter-bar.test.tsx +109 -0
  43. package/src/components/dashboard/__tests__/run-list.test.tsx +123 -0
  44. package/src/components/dashboard/__tests__/search-filter.test.tsx +150 -0
  45. package/src/components/dashboard/__tests__/virtualized-run-list.test.tsx +179 -0
  46. package/src/components/dashboard/breakpoint-banner.tsx +301 -0
  47. package/src/components/dashboard/catch-up-banner.tsx +88 -0
  48. package/src/components/dashboard/executive-summary-banner.tsx +174 -0
  49. package/src/components/dashboard/global-search.tsx +323 -0
  50. package/src/components/dashboard/kpi-grid.tsx +140 -0
  51. package/src/components/dashboard/pagination-controls.tsx +100 -0
  52. package/src/components/dashboard/project-accordion.tsx +72 -0
  53. package/src/components/dashboard/project-health-card.tsx +536 -0
  54. package/src/components/dashboard/project-list-view.tsx +246 -0
  55. package/src/components/dashboard/project-search-input.tsx +41 -0
  56. package/src/components/dashboard/project-section-header.tsx +73 -0
  57. package/src/components/dashboard/project-section.tsx +89 -0
  58. package/src/components/dashboard/run-card.tsx +218 -0
  59. package/src/components/dashboard/run-filter-bar.tsx +100 -0
  60. package/src/components/dashboard/run-list.tsx +77 -0
  61. package/src/components/dashboard/search-filter.tsx +69 -0
  62. package/src/components/dashboard/virtualized-run-list.tsx +130 -0
  63. package/src/components/details/.gitkeep +0 -0
  64. package/src/components/details/__tests__/agent-panel.test.tsx +236 -0
  65. package/src/components/details/__tests__/json-tree.test.tsx +347 -0
  66. package/src/components/details/__tests__/log-viewer.test.tsx +168 -0
  67. package/src/components/details/__tests__/task-detail.test.tsx +212 -0
  68. package/src/components/details/__tests__/timing-panel.test.tsx +271 -0
  69. package/src/components/details/agent-panel.tsx +234 -0
  70. package/src/components/details/json-tree/categorize.ts +131 -0
  71. package/src/components/details/json-tree/index.tsx +120 -0
  72. package/src/components/details/json-tree/json-node.tsx +223 -0
  73. package/src/components/details/json-tree/smart-summary.tsx +596 -0
  74. package/src/components/details/json-tree/tree-controls.tsx +47 -0
  75. package/src/components/details/json-tree.tsx +9 -0
  76. package/src/components/details/log-viewer.tsx +140 -0
  77. package/src/components/details/task-detail.tsx +114 -0
  78. package/src/components/details/timing-panel.tsx +247 -0
  79. package/src/components/events/.gitkeep +0 -0
  80. package/src/components/events/__tests__/event-item.test.tsx +211 -0
  81. package/src/components/events/__tests__/event-stream.test.tsx +225 -0
  82. package/src/components/events/event-item.tsx +121 -0
  83. package/src/components/events/event-stream.tsx +260 -0
  84. package/src/components/notifications/.gitkeep +0 -0
  85. package/src/components/notifications/__tests__/notification-panel.test.tsx +287 -0
  86. package/src/components/notifications/__tests__/notification-provider.test.tsx +585 -0
  87. package/src/components/notifications/__tests__/toast-stack.test.tsx +217 -0
  88. package/src/components/notifications/notification-panel.tsx +124 -0
  89. package/src/components/notifications/notification-provider.tsx +175 -0
  90. package/src/components/notifications/toast-stack.tsx +75 -0
  91. package/src/components/pipeline/.gitkeep +0 -0
  92. package/src/components/pipeline/__tests__/parallel-group.test.tsx +88 -0
  93. package/src/components/pipeline/__tests__/pipeline-view.test.tsx +345 -0
  94. package/src/components/pipeline/__tests__/step-card.test.tsx +330 -0
  95. package/src/components/pipeline/parallel-group.tsx +39 -0
  96. package/src/components/pipeline/pipeline-view.tsx +197 -0
  97. package/src/components/pipeline/step-card.tsx +166 -0
  98. package/src/components/providers/event-stream-provider.tsx +29 -0
  99. package/src/components/providers.tsx +24 -0
  100. package/src/components/shared/.gitkeep +0 -0
  101. package/src/components/shared/__tests__/empty-state.test.tsx +49 -0
  102. package/src/components/shared/__tests__/friendly-id.test.tsx +47 -0
  103. package/src/components/shared/__tests__/kbd.test.tsx +45 -0
  104. package/src/components/shared/__tests__/kind-badge.test.tsx +71 -0
  105. package/src/components/shared/__tests__/metrics-row.test.tsx +74 -0
  106. package/src/components/shared/__tests__/outcome-banner.test.tsx +71 -0
  107. package/src/components/shared/__tests__/progress-bar.test.tsx +89 -0
  108. package/src/components/shared/__tests__/session-pill.test.tsx +62 -0
  109. package/src/components/shared/__tests__/settings-modal.test.tsx +201 -0
  110. package/src/components/shared/__tests__/shortcuts-help.test.tsx +103 -0
  111. package/src/components/shared/__tests__/status-badge.test.tsx +98 -0
  112. package/src/components/shared/__tests__/theme-provider.test.tsx +100 -0
  113. package/src/components/shared/__tests__/truncated-id.test.tsx +53 -0
  114. package/src/components/shared/app-footer.tsx +80 -0
  115. package/src/components/shared/app-header.tsx +160 -0
  116. package/src/components/shared/empty-state.tsx +18 -0
  117. package/src/components/shared/error-boundary.tsx +81 -0
  118. package/src/components/shared/friendly-id.tsx +48 -0
  119. package/src/components/shared/kbd.tsx +15 -0
  120. package/src/components/shared/kind-badge.tsx +51 -0
  121. package/src/components/shared/metrics-row.tsx +106 -0
  122. package/src/components/shared/outcome-banner.tsx +56 -0
  123. package/src/components/shared/progress-bar.tsx +42 -0
  124. package/src/components/shared/session-pill.tsx +69 -0
  125. package/src/components/shared/settings-modal.tsx +509 -0
  126. package/src/components/shared/shortcuts-help.tsx +113 -0
  127. package/src/components/shared/status-badge.tsx +110 -0
  128. package/src/components/shared/theme-provider.tsx +46 -0
  129. package/src/components/shared/truncated-id.tsx +51 -0
  130. package/src/components/ui/.gitkeep +0 -0
  131. package/src/components/ui/__tests__/accordion.test.tsx +96 -0
  132. package/src/components/ui/__tests__/badge.test.tsx +69 -0
  133. package/src/components/ui/__tests__/button.test.tsx +113 -0
  134. package/src/components/ui/__tests__/tabs.test.tsx +75 -0
  135. package/src/components/ui/__tests__/tooltip.test.tsx +90 -0
  136. package/src/components/ui/accordion.tsx +61 -0
  137. package/src/components/ui/badge.tsx +25 -0
  138. package/src/components/ui/button.tsx +40 -0
  139. package/src/components/ui/card.tsx +21 -0
  140. package/src/components/ui/scroll-area.tsx +35 -0
  141. package/src/components/ui/separator.tsx +24 -0
  142. package/src/components/ui/tabs.tsx +64 -0
  143. package/src/components/ui/tooltip.tsx +37 -0
  144. package/src/hooks/.gitkeep +0 -0
  145. package/src/hooks/__tests__/use-animated-number.test.ts +184 -0
  146. package/src/hooks/__tests__/use-batched-updates.test.ts +315 -0
  147. package/src/hooks/__tests__/use-event-stream.test.ts +243 -0
  148. package/src/hooks/__tests__/use-keyboard.test.ts +217 -0
  149. package/src/hooks/__tests__/use-notifications.test.ts +230 -0
  150. package/src/hooks/__tests__/use-polling.test.ts +274 -0
  151. package/src/hooks/__tests__/use-project-runs.test.ts +163 -0
  152. package/src/hooks/__tests__/use-projects.test.ts +248 -0
  153. package/src/hooks/__tests__/use-run-dashboard.test.ts +168 -0
  154. package/src/hooks/__tests__/use-run-detail.test.ts +273 -0
  155. package/src/hooks/__tests__/use-smart-polling.test.ts +305 -0
  156. package/src/hooks/use-animated-number.ts +87 -0
  157. package/src/hooks/use-batched-updates.ts +150 -0
  158. package/src/hooks/use-event-stream.ts +150 -0
  159. package/src/hooks/use-keyboard.ts +45 -0
  160. package/src/hooks/use-notifications.ts +82 -0
  161. package/src/hooks/use-persisted-state.ts +60 -0
  162. package/src/hooks/use-polling.ts +60 -0
  163. package/src/hooks/use-project-runs.ts +51 -0
  164. package/src/hooks/use-projects.ts +26 -0
  165. package/src/hooks/use-run-dashboard.ts +207 -0
  166. package/src/hooks/use-run-detail.ts +77 -0
  167. package/src/hooks/use-smart-polling.ts +144 -0
  168. package/src/lib/.gitkeep +0 -0
  169. package/src/lib/__tests__/cn.test.ts +69 -0
  170. package/src/lib/__tests__/config-loader.test.ts +210 -0
  171. package/src/lib/__tests__/config.test.ts +561 -0
  172. package/src/lib/__tests__/error-handler.test.ts +143 -0
  173. package/src/lib/__tests__/fetcher.test.ts +517 -0
  174. package/src/lib/__tests__/global-registry.test.ts +214 -0
  175. package/src/lib/__tests__/parser.test.ts +1532 -0
  176. package/src/lib/__tests__/path-resolver.test.ts +112 -0
  177. package/src/lib/__tests__/run-cache.test.ts +591 -0
  178. package/src/lib/__tests__/server-init.test.ts +512 -0
  179. package/src/lib/__tests__/source-discovery.test.ts +246 -0
  180. package/src/lib/__tests__/utils.test.ts +160 -0
  181. package/src/lib/__tests__/watcher.test.ts +227 -0
  182. package/src/lib/cn.ts +6 -0
  183. package/src/lib/config-loader.ts +195 -0
  184. package/src/lib/config.ts +20 -0
  185. package/src/lib/error-handler.ts +76 -0
  186. package/src/lib/fetcher.ts +394 -0
  187. package/src/lib/global-registry.ts +117 -0
  188. package/src/lib/parser.ts +794 -0
  189. package/src/lib/path-resolver.ts +16 -0
  190. package/src/lib/run-cache.ts +404 -0
  191. package/src/lib/server-init.ts +226 -0
  192. package/src/lib/services/__tests__/run-query-service.test.ts +819 -0
  193. package/src/lib/services/run-query-service.ts +286 -0
  194. package/src/lib/source-discovery.ts +216 -0
  195. package/src/lib/utils.ts +103 -0
  196. package/src/lib/watcher.ts +265 -0
  197. package/src/test/fixtures.ts +269 -0
  198. package/src/test/mocks/handlers.ts +110 -0
  199. package/src/test/mocks/server.ts +17 -0
  200. package/src/test/setup.ts +200 -0
  201. package/src/test/test-utils.tsx +36 -0
  202. package/src/types/.gitkeep +0 -0
  203. package/src/types/breakpoint.ts +17 -0
  204. package/src/types/index.ts +214 -0
  205. package/tsconfig.json +50 -0
@@ -0,0 +1,200 @@
1
+ import { expect, afterEach, vi } from 'vitest';
2
+ import { cleanup } from '@testing-library/react';
3
+ import * as matchers from '@testing-library/jest-dom/matchers';
4
+ import React from 'react';
5
+
6
+ // Mock next/navigation
7
+ vi.mock('next/navigation', () => ({
8
+ useRouter: () => ({ push: vi.fn(), replace: vi.fn(), back: vi.fn(), prefetch: vi.fn() }),
9
+ usePathname: () => '/',
10
+ useSearchParams: () => new URLSearchParams(),
11
+ useParams: () => ({}),
12
+ }));
13
+
14
+ // Mock next/dynamic — pass through to the real component synchronously.
15
+ // The loader function (e.g. () => import("./agent-panel")) returns a Promise,
16
+ // but in vitest the module is already loaded. We extract the module path from
17
+ // the loader's toString() to resolve it synchronously. As a fallback, we use
18
+ // async resolution with React state.
19
+ vi.mock('next/dynamic', () => {
20
+ const dynamic = (loader: () => Promise<any>, _opts?: any) => {
21
+ // Attempt synchronous resolution: call loader and intercept the result.
22
+ // In vitest, the dynamic import resolves on the next microtick, so we
23
+ // eagerly kick it off and cache the result for subsequent renders.
24
+ let Resolved: React.ComponentType<any> | null = null;
25
+ const loadPromise = loader().then((mod: any) => {
26
+ Resolved = mod.default || mod;
27
+ });
28
+
29
+ const DynamicComponent = (props: any) => {
30
+ const [Comp, setComp] = React.useState<React.ComponentType<any> | null>(() => Resolved);
31
+
32
+ React.useEffect(() => {
33
+ if (!Comp && !Resolved) {
34
+ loadPromise.then(() => {
35
+ if (Resolved) setComp(() => Resolved);
36
+ });
37
+ } else if (!Comp && Resolved) {
38
+ setComp(() => Resolved);
39
+ }
40
+ }, [Comp]);
41
+
42
+ const Active = Comp || Resolved;
43
+ if (Active) {
44
+ return React.createElement(Active, props);
45
+ }
46
+ if (_opts?.loading) {
47
+ return React.createElement(_opts.loading, {});
48
+ }
49
+ return null;
50
+ };
51
+ DynamicComponent.displayName = 'DynamicComponent';
52
+ (DynamicComponent as any).preload = () => loadPromise;
53
+ return DynamicComponent;
54
+ };
55
+ return { __esModule: true, default: dynamic };
56
+ });
57
+
58
+ // Mock lucide-react to avoid React version mismatch in monorepo
59
+ // (observer has React 18 locally, root has React 19)
60
+ vi.mock('lucide-react', () => {
61
+ const createIconMock = (name: string) => {
62
+ const Icon = React.forwardRef<SVGSVGElement, any>(
63
+ function IconMock(props: any, ref: any) {
64
+ return React.createElement('svg', {
65
+ ...props,
66
+ ref,
67
+ 'data-testid': `icon-${name}`,
68
+ 'data-lucide': name,
69
+ });
70
+ },
71
+ );
72
+ Icon.displayName = name;
73
+ return Icon;
74
+ };
75
+
76
+ // All icon names used across the codebase
77
+ const iconNames = [
78
+ 'Activity', 'AlertCircle', 'AlertTriangle', 'ArrowLeft', 'ArrowRight',
79
+ 'ArrowUpDown', 'Bell', 'Bot',
80
+ 'CalendarDays', 'Check', 'CheckCircle2', 'ChevronDown', 'ChevronLeft',
81
+ 'ChevronRight', 'ChevronUp', 'Circle', 'Clock', 'Code', 'Cog', 'Copy',
82
+ 'ExternalLink', 'Eye', 'EyeOff', 'FileJson', 'FileText', 'FolderOpen',
83
+ 'GitBranch', 'Github',
84
+ 'Hand', 'Hash', 'HelpCircle', 'History', 'Inbox', 'Info', 'Layers',
85
+ 'Loader2', 'Moon', 'Palette',
86
+ 'Pause', 'Percent', 'Pin', 'Plus', 'Puzzle', 'RefreshCw', 'Search', 'Settings',
87
+ 'Sun', 'Tag', 'Terminal', 'Timer', 'Trash2', 'Wifi', 'WifiOff',
88
+ 'X', 'XCircle',
89
+ ];
90
+
91
+ const mocks: Record<string, any> = {};
92
+ for (const name of iconNames) {
93
+ mocks[name] = createIconMock(name);
94
+ }
95
+ return mocks;
96
+ });
97
+
98
+ // Extend vitest's expect with jest-dom matchers
99
+ expect.extend(matchers);
100
+
101
+ // Clean up after each test.
102
+ // We also re-apply the raf/caf polyfills BEFORE cleanup because some tests
103
+ // (e.g. use-animated-number) call vi.restoreAllMocks() which removes stubs
104
+ // including cancelAnimationFrame. React's passive-effect cleanup still needs it.
105
+ afterEach(() => {
106
+ if (typeof globalThis.cancelAnimationFrame !== 'function') {
107
+ globalThis.cancelAnimationFrame = (id: number) => clearTimeout(id);
108
+ }
109
+ if (typeof globalThis.requestAnimationFrame !== 'function') {
110
+ globalThis.requestAnimationFrame = (cb: FrameRequestCallback) => setTimeout(cb, 0) as unknown as number;
111
+ }
112
+ cleanup();
113
+ });
114
+
115
+ // Mock window.matchMedia
116
+ Object.defineProperty(window, 'matchMedia', {
117
+ writable: true,
118
+ value: (query: string) => ({
119
+ matches: false,
120
+ media: query,
121
+ onchange: null,
122
+ addListener: () => {},
123
+ removeListener: () => {},
124
+ addEventListener: () => {},
125
+ removeEventListener: () => {},
126
+ dispatchEvent: () => false,
127
+ }),
128
+ });
129
+
130
+ // Mock IntersectionObserver
131
+ class MockIntersectionObserver implements IntersectionObserver {
132
+ readonly root: Element | null = null;
133
+ readonly rootMargin: string = '';
134
+ readonly thresholds: ReadonlyArray<number> = [];
135
+
136
+ constructor(
137
+ private callback: IntersectionObserverCallback,
138
+ _options?: IntersectionObserverInit,
139
+ ) {}
140
+
141
+ observe(): void {}
142
+ unobserve(): void {}
143
+ disconnect(): void {}
144
+ takeRecords(): IntersectionObserverEntry[] {
145
+ return [];
146
+ }
147
+ }
148
+
149
+ Object.defineProperty(window, 'IntersectionObserver', {
150
+ writable: true,
151
+ value: MockIntersectionObserver,
152
+ });
153
+
154
+ // Mock navigator.clipboard (configurable so userEvent can re-stub it)
155
+ Object.defineProperty(navigator, 'clipboard', {
156
+ writable: true,
157
+ configurable: true,
158
+ value: {
159
+ writeText: async (_text: string) => {},
160
+ readText: async () => '',
161
+ write: async () => {},
162
+ read: async () => [],
163
+ addEventListener: () => {},
164
+ removeEventListener: () => {},
165
+ dispatchEvent: () => false,
166
+ },
167
+ });
168
+
169
+ // Mock ResizeObserver (used by Radix UI components)
170
+ class MockResizeObserver {
171
+ observe(): void {}
172
+ unobserve(): void {}
173
+ disconnect(): void {}
174
+ }
175
+
176
+ Object.defineProperty(window, 'ResizeObserver', {
177
+ writable: true,
178
+ value: MockResizeObserver,
179
+ });
180
+
181
+ // Polyfill requestAnimationFrame/cancelAnimationFrame for jsdom
182
+ // Some jsdom versions do not expose these globals — ensure they exist on both
183
+ // window and globalThis so component cleanup callbacks can find them.
184
+ const _raf = (cb: FrameRequestCallback) => setTimeout(cb, 0) as unknown as number;
185
+ const _caf = (id: number) => clearTimeout(id);
186
+
187
+ if (typeof globalThis.requestAnimationFrame === 'undefined') {
188
+ globalThis.requestAnimationFrame = _raf;
189
+ }
190
+ if (typeof globalThis.cancelAnimationFrame === 'undefined') {
191
+ globalThis.cancelAnimationFrame = _caf;
192
+ }
193
+ if (typeof window !== 'undefined') {
194
+ if (typeof window.requestAnimationFrame === 'undefined') {
195
+ window.requestAnimationFrame = _raf;
196
+ }
197
+ if (typeof window.cancelAnimationFrame === 'undefined') {
198
+ window.cancelAnimationFrame = _caf;
199
+ }
200
+ }
@@ -0,0 +1,36 @@
1
+ import React, { type ReactElement } from 'react';
2
+ import { render, type RenderOptions } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+
5
+ /**
6
+ * Minimal test wrapper that provides the contexts needed by most components.
7
+ * We avoid importing the real Providers tree because it depends on hooks that
8
+ * fire network requests (polling, SSE) which would interfere with tests.
9
+ * Individual tests that need a specific provider can compose their own wrapper.
10
+ */
11
+ function TestWrapper({ children }: { children: React.ReactNode }) {
12
+ return <>{children}</>;
13
+ }
14
+
15
+ /**
16
+ * Custom render that wraps the component in TestWrapper.
17
+ * Use this instead of importing render directly from @testing-library/react.
18
+ */
19
+ function customRender(
20
+ ui: ReactElement,
21
+ options?: Omit<RenderOptions, 'wrapper'> & { wrapper?: React.ComponentType },
22
+ ) {
23
+ const Wrapper = options?.wrapper ?? TestWrapper;
24
+ return render(ui, { wrapper: Wrapper, ...options });
25
+ }
26
+
27
+ // Re-export everything from testing-library
28
+ export * from '@testing-library/react';
29
+
30
+ // Override render with our custom version
31
+ export { customRender as render };
32
+
33
+ // Export a pre-configured userEvent instance
34
+ export function setupUser() {
35
+ return userEvent.setup();
36
+ }
File without changes
@@ -0,0 +1,17 @@
1
+ // Breakpoint-related types
2
+
3
+ export interface BreakpointFile {
4
+ path: string;
5
+ format: string;
6
+ language?: string;
7
+ }
8
+
9
+ export interface BreakpointPayload {
10
+ question: string;
11
+ title: string;
12
+ options?: string[];
13
+ context?: {
14
+ files?: BreakpointFile[];
15
+ };
16
+ }
17
+
@@ -0,0 +1,214 @@
1
+ // Re-export breakpoint types
2
+ export * from "./breakpoint";
3
+
4
+ // Run status
5
+ export type RunStatus = "pending" | "waiting" | "completed" | "failed";
6
+
7
+ // Task/effect kind
8
+ export type TaskKind = "node" | "agent" | "skill" | "breakpoint" | "shell" | "sleep";
9
+
10
+ // Task status
11
+ export type TaskStatus = "requested" | "resolved" | "error";
12
+
13
+ // Journal event types
14
+ export type EventType =
15
+ | "RUN_CREATED"
16
+ | "EFFECT_REQUESTED"
17
+ | "EFFECT_RESOLVED"
18
+ | "RUN_COMPLETED"
19
+ | "RUN_FAILED";
20
+
21
+ // Journal event
22
+ export interface JournalEvent {
23
+ seq: number;
24
+ id: string;
25
+ ts: string;
26
+ type: EventType;
27
+ payload: Record<string, unknown>;
28
+ }
29
+
30
+ export interface RunCreatedPayload {
31
+ runId: string;
32
+ processId: string;
33
+ processRevision?: string;
34
+ entrypoint?: {
35
+ importPath: string;
36
+ exportName: string;
37
+ };
38
+ inputsRef?: string;
39
+ }
40
+
41
+ export interface EffectRequestedPayload {
42
+ effectId: string;
43
+ invocationKey: string;
44
+ stepId: string;
45
+ taskId: string;
46
+ kind: TaskKind;
47
+ label: string;
48
+ taskDefRef?: string;
49
+ inputsRef?: string;
50
+ }
51
+
52
+ export interface EffectResolvedPayload {
53
+ effectId: string;
54
+ status: "ok" | "error";
55
+ resultRef?: string;
56
+ stdoutRef?: string;
57
+ stderrRef?: string;
58
+ startedAt?: string;
59
+ finishedAt?: string;
60
+ error?: {
61
+ name: string;
62
+ message: string;
63
+ stack?: string;
64
+ };
65
+ }
66
+
67
+ // Parsed task/effect
68
+ export interface TaskEffect {
69
+ effectId: string;
70
+ kind: TaskKind;
71
+ title: string;
72
+ label: string;
73
+ status: TaskStatus;
74
+ invocationKey: string;
75
+ stepId: string;
76
+ taskId: string;
77
+ requestedAt: string;
78
+ resolvedAt?: string;
79
+ startedAt?: string;
80
+ finishedAt?: string;
81
+ duration?: number; // ms
82
+ error?: {
83
+ name: string;
84
+ message: string;
85
+ stack?: string;
86
+ };
87
+ breakpointQuestion?: string;
88
+ agent?: {
89
+ name: string;
90
+ prompt?: {
91
+ role: string;
92
+ task: string;
93
+ instructions: string[];
94
+ };
95
+ };
96
+ }
97
+
98
+ // Full task detail (on-demand)
99
+ export interface TaskDetail extends TaskEffect {
100
+ input?: Record<string, unknown>;
101
+ result?: Record<string, unknown>;
102
+ stdout?: string;
103
+ stderr?: string;
104
+ taskDef?: Record<string, unknown>;
105
+ breakpoint?: import("./breakpoint").BreakpointPayload;
106
+ }
107
+
108
+ // Run summary
109
+ export interface Run {
110
+ runId: string;
111
+ processId: string;
112
+ status: RunStatus;
113
+ createdAt: string;
114
+ updatedAt: string;
115
+ completedAt?: string;
116
+ sessionId?: string;
117
+ tasks: TaskEffect[];
118
+ events: JournalEvent[];
119
+ totalTasks: number;
120
+ completedTasks: number;
121
+ failedTasks: number;
122
+ duration?: number; // ms
123
+ failedStep?: string;
124
+ failureError?: string;
125
+ failureMessage?: string;
126
+ breakpointQuestion?: string;
127
+ sourceLabel?: string;
128
+ projectName?: string;
129
+ isStale?: boolean;
130
+ waitingKind?: 'breakpoint' | 'task';
131
+ }
132
+
133
+ // Lightweight digest for polling
134
+ export interface RunDigest {
135
+ runId: string;
136
+ latestSeq: number;
137
+ status: RunStatus;
138
+ taskCount: number;
139
+ completedTasks: number;
140
+ updatedAt: string;
141
+ pendingBreakpoints?: number;
142
+ breakpointQuestion?: string;
143
+ breakpointEffectId?: string;
144
+ sourceLabel?: string;
145
+ projectName?: string;
146
+ isStale?: boolean;
147
+ waitingKind?: 'breakpoint' | 'task';
148
+ }
149
+
150
+ // Project grouping for dashboard
151
+ export interface ProjectGroup {
152
+ projectName: string;
153
+ runs: Run[];
154
+ totalRuns: number;
155
+ activeRuns: number;
156
+ completedRuns: number;
157
+ failedRuns: number;
158
+ latestUpdate: string;
159
+ }
160
+
161
+ // Breakpoint info for a single waiting run
162
+ export interface BreakpointRunInfo {
163
+ runId: string;
164
+ effectId: string;
165
+ projectName: string;
166
+ processId: string;
167
+ breakpointQuestion: string;
168
+ }
169
+
170
+ // Project summary (lightweight, no run payloads)
171
+ export interface ProjectSummary {
172
+ projectName: string;
173
+ totalRuns: number;
174
+ activeRuns: number;
175
+ completedRuns: number;
176
+ failedRuns: number;
177
+ staleRuns: number;
178
+ totalTasks: number;
179
+ completedTasksAggregate: number;
180
+ latestUpdate: string;
181
+ pendingBreakpoints: number;
182
+ breakpointRuns: BreakpointRunInfo[];
183
+ }
184
+
185
+ // Session info
186
+ export interface SessionInfo {
187
+ sessionId: string;
188
+ active: boolean;
189
+ startedAt?: string;
190
+ runId?: string;
191
+ iteration?: number;
192
+ }
193
+
194
+ // API response types
195
+ export interface DigestResponse {
196
+ runs: RunDigest[];
197
+ }
198
+
199
+ export interface RunsResponse {
200
+ runs: Run[];
201
+ }
202
+
203
+ export interface RunDetailResponse {
204
+ run: Run;
205
+ }
206
+
207
+ export interface EventsResponse {
208
+ events: JournalEvent[];
209
+ total: number;
210
+ }
211
+
212
+ export interface TaskDetailResponse {
213
+ task: TaskDetail;
214
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": [
5
+ "dom",
6
+ "dom.iterable",
7
+ "esnext"
8
+ ],
9
+ "allowJs": true,
10
+ "skipLibCheck": true,
11
+ "strict": true,
12
+ "noEmit": true,
13
+ "esModuleInterop": true,
14
+ "module": "esnext",
15
+ "moduleResolution": "bundler",
16
+ "resolveJsonModule": true,
17
+ "isolatedModules": true,
18
+ "jsx": "react-jsx",
19
+ "incremental": true,
20
+ "plugins": [
21
+ {
22
+ "name": "next"
23
+ }
24
+ ],
25
+ "typeRoots": [
26
+ "./node_modules/@types",
27
+ "../../node_modules/@types"
28
+ ],
29
+ "paths": {
30
+ "@/*": [
31
+ "./src/*"
32
+ ]
33
+ }
34
+ },
35
+ "include": [
36
+ "next-env.d.ts",
37
+ "**/*.ts",
38
+ "**/*.tsx",
39
+ ".next/types/**/*.ts",
40
+ ".next/dev/types/**/*.ts"
41
+ ],
42
+ "exclude": [
43
+ "node_modules",
44
+ "e2e",
45
+ "playwright.config.ts",
46
+ "src/**/__tests__/**",
47
+ "src/**/*.test.ts",
48
+ "src/**/*.test.tsx"
49
+ ]
50
+ }