@grackle-ai/web-components 0.107.2

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 (279) hide show
  1. package/.rush/temp/3ae72563f781afd72723475938136f113846603e.untar.log +10 -0
  2. package/.rush/temp/bc1d5bf9201ce71abeaeaddd096deb9b0805d703.untar.log +10 -0
  3. package/.rush/temp/operation/_phase_build/all.log +18 -0
  4. package/.rush/temp/operation/_phase_build/log-chunks.jsonl +18 -0
  5. package/.rush/temp/operation/_phase_build/state.json +3 -0
  6. package/.rush/temp/operation/_phase_test/all.log +121 -0
  7. package/.rush/temp/operation/_phase_test/log-chunks.jsonl +121 -0
  8. package/.rush/temp/operation/_phase_test/state.json +3 -0
  9. package/.rush/temp/shrinkwrap-deps.json +938 -0
  10. package/.storybook/main.ts +22 -0
  11. package/.storybook/preview.tsx +30 -0
  12. package/config/rig.json +4 -0
  13. package/config/rush-project.json +12 -0
  14. package/dist/index.css +1 -0
  15. package/dist/index.js +39221 -0
  16. package/eslint.config.cjs +5 -0
  17. package/package.json +83 -0
  18. package/rush-logs/web-components._phase_build.cache.log +4 -0
  19. package/rush-logs/web-components._phase_test.cache.log +4 -0
  20. package/src/components/chat/ChatInput.module.scss +81 -0
  21. package/src/components/chat/ChatInput.stories.tsx +91 -0
  22. package/src/components/chat/ChatInput.tsx +168 -0
  23. package/src/components/chat/index.ts +6 -0
  24. package/src/components/dag/DagView.module.scss +149 -0
  25. package/src/components/dag/DagView.stories.tsx +125 -0
  26. package/src/components/dag/DagView.tsx +109 -0
  27. package/src/components/dag/TaskNode.stories.tsx +133 -0
  28. package/src/components/dag/TaskNode.tsx +40 -0
  29. package/src/components/dag/useDagLayout.ts +139 -0
  30. package/src/components/display/Breadcrumbs.module.scss +71 -0
  31. package/src/components/display/Breadcrumbs.stories.tsx +80 -0
  32. package/src/components/display/Breadcrumbs.tsx +46 -0
  33. package/src/components/display/Button.module.scss +110 -0
  34. package/src/components/display/Button.stories.tsx +88 -0
  35. package/src/components/display/Button.tsx +40 -0
  36. package/src/components/display/ConfirmDialog.module.scss +67 -0
  37. package/src/components/display/ConfirmDialog.stories.tsx +81 -0
  38. package/src/components/display/ConfirmDialog.tsx +88 -0
  39. package/src/components/display/CopyButton.module.scss +41 -0
  40. package/src/components/display/CopyButton.stories.tsx +78 -0
  41. package/src/components/display/CopyButton.tsx +64 -0
  42. package/src/components/display/DemoBanner.module.scss +37 -0
  43. package/src/components/display/DemoBanner.stories.tsx +40 -0
  44. package/src/components/display/DemoBanner.tsx +23 -0
  45. package/src/components/display/EventHoverRow.module.scss +102 -0
  46. package/src/components/display/EventHoverRow.stories.tsx +99 -0
  47. package/src/components/display/EventHoverRow.tsx +154 -0
  48. package/src/components/display/EventRenderer.module.scss +272 -0
  49. package/src/components/display/EventRenderer.stories.tsx +186 -0
  50. package/src/components/display/EventRenderer.tsx +271 -0
  51. package/src/components/display/EventStream.module.scss +93 -0
  52. package/src/components/display/EventStream.stories.tsx +249 -0
  53. package/src/components/display/EventStream.tsx +369 -0
  54. package/src/components/display/FloatingActionBar.module.scss +107 -0
  55. package/src/components/display/FloatingActionBar.stories.tsx +122 -0
  56. package/src/components/display/FloatingActionBar.tsx +119 -0
  57. package/src/components/display/SessionAttemptSelector.module.scss +50 -0
  58. package/src/components/display/SessionAttemptSelector.stories.tsx +78 -0
  59. package/src/components/display/SessionAttemptSelector.tsx +49 -0
  60. package/src/components/display/SessionPicker.module.scss +200 -0
  61. package/src/components/display/SessionPicker.stories.tsx +169 -0
  62. package/src/components/display/SessionPicker.tsx +214 -0
  63. package/src/components/display/Skeleton.module.scss +58 -0
  64. package/src/components/display/Skeleton.stories.tsx +94 -0
  65. package/src/components/display/Skeleton.tsx +127 -0
  66. package/src/components/display/Spinner.module.scss +41 -0
  67. package/src/components/display/Spinner.stories.tsx +66 -0
  68. package/src/components/display/Spinner.tsx +32 -0
  69. package/src/components/display/SplashScreen.module.scss +20 -0
  70. package/src/components/display/SplashScreen.stories.tsx +26 -0
  71. package/src/components/display/SplashScreen.tsx +16 -0
  72. package/src/components/display/SplitButton.module.scss +166 -0
  73. package/src/components/display/SplitButton.stories.tsx +95 -0
  74. package/src/components/display/SplitButton.tsx +128 -0
  75. package/src/components/display/Tooltip.module.scss +84 -0
  76. package/src/components/display/Tooltip.stories.tsx +240 -0
  77. package/src/components/display/Tooltip.tsx +184 -0
  78. package/src/components/display/extractText.test.tsx +48 -0
  79. package/src/components/display/index.ts +20 -0
  80. package/src/components/editable/EditableCheckbox.stories.tsx +54 -0
  81. package/src/components/editable/EditableCheckbox.tsx +39 -0
  82. package/src/components/editable/EditableField.module.scss +135 -0
  83. package/src/components/editable/EditableSelect.tsx +164 -0
  84. package/src/components/editable/EditableTextArea.stories.tsx +50 -0
  85. package/src/components/editable/EditableTextArea.tsx +148 -0
  86. package/src/components/editable/EditableTextField.stories.tsx +62 -0
  87. package/src/components/editable/EditableTextField.tsx +153 -0
  88. package/src/components/editable/EnvironmentSelect.module.scss +17 -0
  89. package/src/components/editable/EnvironmentSelect.stories.tsx +61 -0
  90. package/src/components/editable/EnvironmentSelect.tsx +87 -0
  91. package/src/components/editable/index.ts +13 -0
  92. package/src/components/editable/useEditableField.test.tsx +233 -0
  93. package/src/components/editable/useEditableField.ts +173 -0
  94. package/src/components/index.ts +20 -0
  95. package/src/components/knowledge/KnowledgeDetailPanel.module.scss +162 -0
  96. package/src/components/knowledge/KnowledgeDetailPanel.stories.tsx +208 -0
  97. package/src/components/knowledge/KnowledgeDetailPanel.tsx +122 -0
  98. package/src/components/knowledge/KnowledgeGraph.module.scss +110 -0
  99. package/src/components/knowledge/KnowledgeGraph.stories.tsx +180 -0
  100. package/src/components/knowledge/KnowledgeGraph.tsx +455 -0
  101. package/src/components/knowledge/KnowledgeNav.module.scss +130 -0
  102. package/src/components/knowledge/KnowledgeNav.stories.tsx +108 -0
  103. package/src/components/knowledge/KnowledgeNav.tsx +138 -0
  104. package/src/components/knowledge/index.ts +3 -0
  105. package/src/components/layout/AppNav.module.scss +82 -0
  106. package/src/components/layout/AppNav.stories.tsx +115 -0
  107. package/src/components/layout/AppNav.tsx +133 -0
  108. package/src/components/layout/BottomStatusBar.module.scss +58 -0
  109. package/src/components/layout/BottomStatusBar.stories.tsx +35 -0
  110. package/src/components/layout/BottomStatusBar.tsx +206 -0
  111. package/src/components/layout/Sidebar.module.scss +60 -0
  112. package/src/components/layout/Sidebar.stories.tsx +46 -0
  113. package/src/components/layout/Sidebar.tsx +84 -0
  114. package/src/components/layout/StatusBar.module.scss +108 -0
  115. package/src/components/layout/StatusBar.stories.tsx +119 -0
  116. package/src/components/layout/StatusBar.tsx +70 -0
  117. package/src/components/layout/index.ts +9 -0
  118. package/src/components/lists/EnvironmentNav.module.scss +118 -0
  119. package/src/components/lists/EnvironmentNav.stories.tsx +121 -0
  120. package/src/components/lists/EnvironmentNav.tsx +133 -0
  121. package/src/components/lists/FindingsNav.module.scss +126 -0
  122. package/src/components/lists/FindingsNav.tsx +146 -0
  123. package/src/components/lists/TaskList.module.scss +206 -0
  124. package/src/components/lists/TaskList.stories.tsx +401 -0
  125. package/src/components/lists/TaskList.tsx +509 -0
  126. package/src/components/lists/index.ts +6 -0
  127. package/src/components/lists/listHelpers.tsx +130 -0
  128. package/src/components/notifications/Callout.module.scss +83 -0
  129. package/src/components/notifications/Callout.stories.tsx +81 -0
  130. package/src/components/notifications/Callout.tsx +64 -0
  131. package/src/components/notifications/Toast.module.scss +86 -0
  132. package/src/components/notifications/Toast.stories.tsx +71 -0
  133. package/src/components/notifications/Toast.tsx +51 -0
  134. package/src/components/notifications/ToastContainer.module.scss +23 -0
  135. package/src/components/notifications/ToastContainer.stories.tsx +66 -0
  136. package/src/components/notifications/ToastContainer.tsx +29 -0
  137. package/src/components/notifications/UpdateBanner.stories.tsx +77 -0
  138. package/src/components/notifications/UpdateBanner.test.tsx +64 -0
  139. package/src/components/notifications/UpdateBanner.tsx +44 -0
  140. package/src/components/notifications/index.ts +8 -0
  141. package/src/components/panels/AboutPanel.stories.tsx +70 -0
  142. package/src/components/panels/AboutPanel.tsx +66 -0
  143. package/src/components/panels/AppearancePanel.stories.tsx +45 -0
  144. package/src/components/panels/AppearancePanel.tsx +97 -0
  145. package/src/components/panels/CredentialProvidersPanel.stories.tsx +62 -0
  146. package/src/components/panels/CredentialProvidersPanel.tsx +111 -0
  147. package/src/components/panels/EnvironmentEditPanel.module.scss +170 -0
  148. package/src/components/panels/EnvironmentEditPanel.stories.tsx +206 -0
  149. package/src/components/panels/EnvironmentEditPanel.tsx +785 -0
  150. package/src/components/panels/FindingsPanel.module.scss +94 -0
  151. package/src/components/panels/FindingsPanel.stories.tsx +109 -0
  152. package/src/components/panels/FindingsPanel.tsx +76 -0
  153. package/src/components/panels/KeyboardShortcutsPanel.module.scss +65 -0
  154. package/src/components/panels/KeyboardShortcutsPanel.stories.tsx +40 -0
  155. package/src/components/panels/KeyboardShortcutsPanel.tsx +104 -0
  156. package/src/components/panels/PluginsPanel.tsx +77 -0
  157. package/src/components/panels/SettingsPanel.module.scss +336 -0
  158. package/src/components/panels/TaskActionButtons.module.scss +22 -0
  159. package/src/components/panels/TaskActionButtons.stories.tsx +125 -0
  160. package/src/components/panels/TaskActionButtons.tsx +87 -0
  161. package/src/components/panels/TaskEditPanel.module.scss +202 -0
  162. package/src/components/panels/TaskEditPanel.stories.tsx +75 -0
  163. package/src/components/panels/TaskEditPanel.tsx +328 -0
  164. package/src/components/panels/TaskOverviewPanel.module.scss +236 -0
  165. package/src/components/panels/TaskOverviewPanel.stories.tsx +219 -0
  166. package/src/components/panels/TaskOverviewPanel.tsx +270 -0
  167. package/src/components/panels/TokensPanel.stories.tsx +131 -0
  168. package/src/components/panels/TokensPanel.tsx +143 -0
  169. package/src/components/panels/WorkpadPanel.module.scss +39 -0
  170. package/src/components/panels/WorkpadPanel.stories.tsx +56 -0
  171. package/src/components/panels/WorkpadPanel.tsx +63 -0
  172. package/src/components/panels/index.ts +13 -0
  173. package/src/components/personas/McpToolSelector.module.scss +109 -0
  174. package/src/components/personas/McpToolSelector.stories.tsx +129 -0
  175. package/src/components/personas/McpToolSelector.tsx +180 -0
  176. package/src/components/personas/PersonaManager.module.scss +233 -0
  177. package/src/components/personas/PersonaManager.stories.tsx +139 -0
  178. package/src/components/personas/PersonaManager.tsx +122 -0
  179. package/src/components/schedules/ScheduleManager.module.scss +98 -0
  180. package/src/components/schedules/ScheduleManager.stories.tsx +78 -0
  181. package/src/components/schedules/ScheduleManager.tsx +160 -0
  182. package/src/components/settings/SettingsNav.module.scss +82 -0
  183. package/src/components/settings/SettingsNav.stories.tsx +83 -0
  184. package/src/components/settings/SettingsNav.tsx +104 -0
  185. package/src/components/streams/StreamDetailPanel.module.scss +206 -0
  186. package/src/components/streams/StreamDetailPanel.stories.tsx +132 -0
  187. package/src/components/streams/StreamDetailPanel.tsx +119 -0
  188. package/src/components/streams/StreamList.module.scss +92 -0
  189. package/src/components/streams/StreamList.stories.tsx +99 -0
  190. package/src/components/streams/StreamList.tsx +114 -0
  191. package/src/components/streams/index.ts +10 -0
  192. package/src/components/tools/AgentToolCard.module.scss +118 -0
  193. package/src/components/tools/AgentToolCard.stories.tsx +304 -0
  194. package/src/components/tools/AgentToolCard.tsx +247 -0
  195. package/src/components/tools/FileEditCard.stories.tsx +138 -0
  196. package/src/components/tools/FileEditCard.tsx +160 -0
  197. package/src/components/tools/FileReadCard.stories.tsx +120 -0
  198. package/src/components/tools/FileReadCard.tsx +106 -0
  199. package/src/components/tools/FindingCard.stories.tsx +124 -0
  200. package/src/components/tools/FindingCard.tsx +178 -0
  201. package/src/components/tools/GenericToolCard.stories.tsx +80 -0
  202. package/src/components/tools/GenericToolCard.tsx +111 -0
  203. package/src/components/tools/IpcCard.stories.tsx +129 -0
  204. package/src/components/tools/IpcCard.tsx +178 -0
  205. package/src/components/tools/KnowledgeCard.stories.tsx +112 -0
  206. package/src/components/tools/KnowledgeCard.tsx +165 -0
  207. package/src/components/tools/MetadataCard.stories.tsx +32 -0
  208. package/src/components/tools/MetadataCard.tsx +39 -0
  209. package/src/components/tools/SearchCard.stories.tsx +74 -0
  210. package/src/components/tools/SearchCard.tsx +86 -0
  211. package/src/components/tools/ShellCard.stories.tsx +112 -0
  212. package/src/components/tools/ShellCard.tsx +106 -0
  213. package/src/components/tools/TaskCard.stories.tsx +123 -0
  214. package/src/components/tools/TaskCard.tsx +203 -0
  215. package/src/components/tools/TodoCard.module.scss +131 -0
  216. package/src/components/tools/TodoCard.stories.tsx +202 -0
  217. package/src/components/tools/TodoCard.tsx +200 -0
  218. package/src/components/tools/ToolCard.stories.tsx +177 -0
  219. package/src/components/tools/ToolCard.tsx +60 -0
  220. package/src/components/tools/ToolCardProps.ts +20 -0
  221. package/src/components/tools/ToolSearchCard.stories.tsx +81 -0
  222. package/src/components/tools/ToolSearchCard.tsx +86 -0
  223. package/src/components/tools/WorkpadCard.stories.tsx +106 -0
  224. package/src/components/tools/WorkpadCard.tsx +125 -0
  225. package/src/components/tools/classifyTool.test.ts +44 -0
  226. package/src/components/tools/classifyTool.ts +134 -0
  227. package/src/components/tools/parseDiff.ts +95 -0
  228. package/src/components/tools/parseShellOutput.ts +28 -0
  229. package/src/components/tools/toolCardHelpers.test.ts +53 -0
  230. package/src/components/tools/toolCards.module.scss +234 -0
  231. package/src/components/workspace/WorkspaceBoard.module.scss +238 -0
  232. package/src/components/workspace/WorkspaceBoard.stories.tsx +240 -0
  233. package/src/components/workspace/WorkspaceBoard.tsx +232 -0
  234. package/src/components/workspace/WorkspaceFormFields.module.scss +79 -0
  235. package/src/components/workspace/WorkspaceFormFields.stories.tsx +133 -0
  236. package/src/components/workspace/WorkspaceFormFields.tsx +185 -0
  237. package/src/context/GrackleContext.ts +28 -0
  238. package/src/context/GrackleContextTypes.ts +64 -0
  239. package/src/context/SidebarContext.tsx +53 -0
  240. package/src/context/ThemeContext.tsx +21 -0
  241. package/src/context/ToastContext.tsx +56 -0
  242. package/src/hooks/types.ts +864 -0
  243. package/src/hooks/useEventSelection.test.ts +204 -0
  244. package/src/hooks/useEventSelection.ts +158 -0
  245. package/src/hooks/useSmartScroll.ts +151 -0
  246. package/src/hooks/useTheme.ts +228 -0
  247. package/src/index.ts +210 -0
  248. package/src/mocks/MockGrackleProvider.tsx +1397 -0
  249. package/src/mocks/mockData.ts +1966 -0
  250. package/src/mocks/mockKnowledgeData.ts +294 -0
  251. package/src/scss.d.ts +12 -0
  252. package/src/styles/global.scss +244 -0
  253. package/src/styles/mixins.scss +278 -0
  254. package/src/styles/prism-theme.scss +148 -0
  255. package/src/styles/theme.scss +1102 -0
  256. package/src/test-utils/storybook-decorators.tsx +50 -0
  257. package/src/test-utils/storybook-helpers.ts +262 -0
  258. package/src/themes.ts +142 -0
  259. package/src/utils/boardColumns.ts +141 -0
  260. package/src/utils/breadcrumbs.test.ts +285 -0
  261. package/src/utils/breadcrumbs.ts +222 -0
  262. package/src/utils/dashboard.test.ts +156 -0
  263. package/src/utils/dashboard.ts +195 -0
  264. package/src/utils/eventContent.test.ts +353 -0
  265. package/src/utils/eventContent.ts +209 -0
  266. package/src/utils/findingCategory.ts +33 -0
  267. package/src/utils/format.ts +27 -0
  268. package/src/utils/iconSize.ts +18 -0
  269. package/src/utils/navigation.ts +205 -0
  270. package/src/utils/route-config.test.ts +128 -0
  271. package/src/utils/scrollUtils.test.ts +65 -0
  272. package/src/utils/scrollUtils.ts +49 -0
  273. package/src/utils/sessionEvents.test.ts +302 -0
  274. package/src/utils/sessionEvents.ts +233 -0
  275. package/src/utils/taskStatus.tsx +137 -0
  276. package/src/utils/time.ts +92 -0
  277. package/tsconfig.json +8 -0
  278. package/vite.config.ts +20 -0
  279. package/vitest.config.ts +10 -0
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Mock knowledge graph data for the demo/mock mode.
3
+ * Extracted from mockData.ts to keep files within the max-lines lint limit.
4
+ * @module
5
+ */
6
+
7
+ import type { GraphNode, GraphLink, NodeDetail } from "../hooks/types.js";
8
+
9
+ // ─── Knowledge Graph ────────────────────────────────
10
+
11
+ /** Mock knowledge graph nodes representing concepts, decisions, and references discovered by agents. */
12
+ export const MOCK_KNOWLEDGE_NODES: GraphNode[] = [
13
+ // ── Concept nodes ──
14
+ {
15
+ id: "kn-auth-flow",
16
+ label: "Authentication Flow",
17
+ kind: "knowledge",
18
+ category: "concept",
19
+ content: "The application uses JWT Bearer tokens for stateless authentication. Access tokens expire after 24h. Refresh tokens are stored in the database and rotated on use. The auth middleware verifies tokens and attaches the decoded payload to req.user.",
20
+ tags: ["auth", "jwt", "security"],
21
+ workspaceId: "proj-alpha",
22
+ createdAt: "2026-02-25T10:30:00Z",
23
+ updatedAt: "2026-02-27T08:15:00Z",
24
+ val: 5,
25
+ },
26
+ {
27
+ id: "kn-db-schema",
28
+ label: "Database Schema",
29
+ kind: "knowledge",
30
+ category: "concept",
31
+ content: "PostgreSQL database with tables: users, sessions, refresh_tokens, audit_log. Uses UUID primary keys, TIMESTAMPTZ for all timestamps, and JSONB for flexible metadata columns. Connection pooling via pg-pool with per-tenant isolation.",
32
+ tags: ["database", "postgres", "schema"],
33
+ workspaceId: "proj-alpha",
34
+ createdAt: "2026-02-23T11:00:00Z",
35
+ updatedAt: "2026-02-26T22:45:00Z",
36
+ val: 4,
37
+ },
38
+ {
39
+ id: "kn-error-handling",
40
+ label: "Error Response Pattern",
41
+ kind: "knowledge",
42
+ category: "concept",
43
+ content: "All API errors follow the shape { error: string, code: string, details?: unknown }. HTTP status codes map to: 400 (validation), 401 (unauthenticated), 403 (forbidden), 404 (not found), 409 (conflict), 429 (rate limited), 500 (internal).",
44
+ tags: ["api", "errors", "patterns"],
45
+ workspaceId: "proj-alpha",
46
+ createdAt: "2026-02-27T08:17:00Z",
47
+ updatedAt: "2026-02-27T08:17:00Z",
48
+ val: 3,
49
+ },
50
+ {
51
+ id: "kn-rate-limiting",
52
+ label: "Rate Limiting Strategy",
53
+ kind: "knowledge",
54
+ category: "concept",
55
+ content: "Token-bucket algorithm with in-memory state per client IP. Default rate: 100 requests/minute, burst: 20. Returns 429 with Retry-After header. Redis adapter available for multi-instance deployments.",
56
+ tags: ["api", "rate-limiting", "infrastructure"],
57
+ workspaceId: "proj-alpha",
58
+ createdAt: "2026-02-27T09:00:00Z",
59
+ updatedAt: "2026-02-27T09:00:00Z",
60
+ val: 2,
61
+ },
62
+ {
63
+ id: "kn-etl-pipeline",
64
+ label: "ETL Pipeline Architecture",
65
+ kind: "knowledge",
66
+ category: "concept",
67
+ content: "Data pipelines follow an Extract-Transform-Load pattern with pluggable stages. Each stage reads from a source (Postgres, S3, API), transforms via configurable mappers, and loads into a target (Parquet, BigQuery, S3). Incremental loads use high-watermark tracking.",
68
+ tags: ["etl", "pipeline", "architecture"],
69
+ workspaceId: "proj-beta",
70
+ createdAt: "2026-02-26T08:00:00Z",
71
+ updatedAt: "2026-02-27T09:05:00Z",
72
+ val: 4,
73
+ },
74
+ {
75
+ id: "kn-parquet-format",
76
+ label: "Parquet Output Format",
77
+ kind: "knowledge",
78
+ category: "concept",
79
+ content: "Parquet files are written with row-group buffering (configurable batch size, default 10000 rows). Supports Snappy, ZSTD, and GZIP compression. Schema is derived from the internal column type system using Arrow type mapping.",
80
+ tags: ["parquet", "data-format", "compression"],
81
+ workspaceId: "proj-beta",
82
+ createdAt: "2026-02-26T08:05:00Z",
83
+ updatedAt: "2026-02-26T08:15:00Z",
84
+ val: 3,
85
+ },
86
+
87
+ // ── Decision nodes ──
88
+ {
89
+ id: "kn-jwt-over-session",
90
+ label: "JWT over Session Auth",
91
+ kind: "knowledge",
92
+ category: "decision",
93
+ content: "Chose JWT tokens over server-side sessions for stateless auth. Rationale: (1) no session store needed, (2) works across microservices without shared state, (3) supports mobile clients natively. Trade-off: tokens can't be revoked instantly (mitigated by short expiry + refresh rotation).",
94
+ tags: ["auth", "decision", "jwt"],
95
+ workspaceId: "proj-alpha",
96
+ createdAt: "2026-02-25T10:00:00Z",
97
+ updatedAt: "2026-02-25T10:00:00Z",
98
+ val: 3,
99
+ },
100
+ {
101
+ id: "kn-pg-pool-decision",
102
+ label: "pg-pool over Knex",
103
+ kind: "knowledge",
104
+ category: "decision",
105
+ content: "Chose pg-pool over Knex for connection pooling. pg-pool gives direct control over idle timeout, max connections, and health check queries. Knex wraps pg-pool and adds query-building overhead we don't need since we write raw SQL with parameterized queries.",
106
+ tags: ["database", "decision", "postgres"],
107
+ workspaceId: "proj-alpha",
108
+ createdAt: "2026-02-23T11:30:00Z",
109
+ updatedAt: "2026-02-23T11:30:00Z",
110
+ val: 2,
111
+ },
112
+ {
113
+ id: "kn-watermark-decision",
114
+ label: "Local Watermark Storage",
115
+ kind: "knowledge",
116
+ category: "decision",
117
+ content: "Currently using local SQLite for watermark storage. This works for single-worker pipelines but needs to move to a shared store (Redis or Postgres) for production multi-worker scenarios. Tracked as a follow-up task.",
118
+ tags: ["pipeline", "decision", "watermarks"],
119
+ workspaceId: "proj-beta",
120
+ createdAt: "2026-02-27T09:05:00Z",
121
+ updatedAt: "2026-02-27T09:05:00Z",
122
+ val: 2,
123
+ },
124
+
125
+ // ── Snippet nodes ──
126
+ {
127
+ id: "kn-jwt-middleware",
128
+ label: "JWT Verify Middleware",
129
+ kind: "knowledge",
130
+ category: "snippet",
131
+ content: "```typescript\nexport function verifyToken(req: Request, res: Response, next: NextFunction): void {\n const header = req.headers.authorization;\n if (!header?.startsWith(\"Bearer \")) {\n res.status(401).json({ error: \"Missing token\" });\n return;\n }\n const decoded = jwt.verify(header.slice(7), JWT_SECRET) as JwtPayload;\n req.user = decoded;\n next();\n}\n```",
132
+ tags: ["auth", "jwt", "middleware", "typescript"],
133
+ workspaceId: "proj-alpha",
134
+ createdAt: "2026-02-27T08:15:14Z",
135
+ updatedAt: "2026-02-27T08:15:14Z",
136
+ val: 2,
137
+ },
138
+ {
139
+ id: "kn-audit-schema",
140
+ label: "Audit Log Schema",
141
+ kind: "knowledge",
142
+ category: "snippet",
143
+ content: "```sql\nCREATE TABLE audit_log (\n id BIGSERIAL PRIMARY KEY,\n user_id UUID REFERENCES users(id),\n action TEXT NOT NULL,\n entity_type TEXT NOT NULL,\n entity_id TEXT NOT NULL,\n old_value JSONB,\n new_value JSONB,\n ip_address INET,\n created_at TIMESTAMPTZ DEFAULT now()\n);\n```",
144
+ tags: ["database", "audit", "schema", "sql"],
145
+ workspaceId: "proj-alpha",
146
+ createdAt: "2026-02-26T22:45:15Z",
147
+ updatedAt: "2026-02-26T22:45:15Z",
148
+ val: 2,
149
+ },
150
+
151
+ // ── Insight nodes ──
152
+ {
153
+ id: "kn-n1-query",
154
+ label: "N+1 Query in User List",
155
+ kind: "knowledge",
156
+ category: "insight",
157
+ content: "GET /api/users performs a separate query for each user's role metadata, resulting in N+1 queries. For 500 users this adds ~2 seconds of latency. Solution: use a JOIN or batch lookup to fetch all role data in a single query.",
158
+ tags: ["performance", "database", "n+1"],
159
+ workspaceId: "proj-alpha",
160
+ createdAt: "2026-02-22T09:30:00Z",
161
+ updatedAt: "2026-02-22T09:30:00Z",
162
+ val: 2,
163
+ },
164
+ {
165
+ id: "kn-session-race",
166
+ label: "Session Cleanup Race Condition",
167
+ kind: "knowledge",
168
+ category: "insight",
169
+ content: "When two concurrent requests hit /api/logout, the second call throws a 500 because the session row has already been deleted. Fix: use DELETE ... RETURNING or add IF EXISTS guard to make the operation idempotent.",
170
+ tags: ["bug", "concurrency", "sessions"],
171
+ workspaceId: "proj-alpha",
172
+ createdAt: "2026-02-26T22:50:00Z",
173
+ updatedAt: "2026-02-26T22:50:00Z",
174
+ val: 2,
175
+ },
176
+
177
+ // ── Reference nodes (link to tasks/sessions) ──
178
+ {
179
+ id: "kn-ref-task-001",
180
+ label: "JWT Auth Task",
181
+ kind: "reference",
182
+ sourceType: "task",
183
+ sourceId: "task-001",
184
+ content: "Implement JWT authentication across all protected routes, replacing session-based auth.",
185
+ workspaceId: "proj-alpha",
186
+ createdAt: "2026-02-25T10:00:00Z",
187
+ updatedAt: "2026-02-27T08:15:00Z",
188
+ val: 3,
189
+ },
190
+ {
191
+ id: "kn-ref-task-006",
192
+ label: "Parquet Export Task",
193
+ kind: "reference",
194
+ sourceType: "task",
195
+ sourceId: "task-006",
196
+ content: "Add Parquet export support for pipeline outputs, enabling downstream Spark consumption.",
197
+ workspaceId: "proj-beta",
198
+ createdAt: "2026-02-26T08:00:00Z",
199
+ updatedAt: "2026-02-27T09:00:00Z",
200
+ val: 3,
201
+ },
202
+ {
203
+ id: "kn-ref-sess-001",
204
+ label: "Auth Middleware Session",
205
+ kind: "reference",
206
+ sourceType: "session",
207
+ sourceId: "sess-001",
208
+ content: "Active session implementing JWT auth middleware, rewrote auth.ts, login.ts, and test suite.",
209
+ workspaceId: "proj-alpha",
210
+ createdAt: "2026-02-27T08:15:00Z",
211
+ updatedAt: "2026-02-27T08:15:42Z",
212
+ val: 2,
213
+ },
214
+ ];
215
+
216
+ /** Mock knowledge graph edges connecting nodes. */
217
+ export const MOCK_KNOWLEDGE_LINKS: GraphLink[] = [
218
+ // Auth flow connections
219
+ { source: "kn-auth-flow", target: "kn-jwt-over-session", type: "decided_by" },
220
+ { source: "kn-auth-flow", target: "kn-jwt-middleware", type: "implemented_by" },
221
+ { source: "kn-auth-flow", target: "kn-ref-task-001", type: "tracked_in" },
222
+ { source: "kn-auth-flow", target: "kn-error-handling", type: "relates_to" },
223
+ { source: "kn-jwt-over-session", target: "kn-ref-task-001", type: "motivated_by" },
224
+
225
+ // Database connections
226
+ { source: "kn-db-schema", target: "kn-pg-pool-decision", type: "decided_by" },
227
+ { source: "kn-db-schema", target: "kn-audit-schema", type: "contains" },
228
+ { source: "kn-db-schema", target: "kn-n1-query", type: "affected_by" },
229
+ { source: "kn-db-schema", target: "kn-session-race", type: "affected_by" },
230
+
231
+ // Rate limiting connections
232
+ { source: "kn-rate-limiting", target: "kn-error-handling", type: "relates_to" },
233
+ { source: "kn-rate-limiting", target: "kn-auth-flow", type: "depends_on" },
234
+
235
+ // ETL pipeline connections
236
+ { source: "kn-etl-pipeline", target: "kn-parquet-format", type: "outputs_to" },
237
+ { source: "kn-etl-pipeline", target: "kn-watermark-decision", type: "decided_by" },
238
+ { source: "kn-etl-pipeline", target: "kn-ref-task-006", type: "tracked_in" },
239
+ { source: "kn-parquet-format", target: "kn-ref-task-006", type: "tracked_in" },
240
+ { source: "kn-watermark-decision", target: "kn-etl-pipeline", type: "relates_to" },
241
+
242
+ // Reference connections
243
+ { source: "kn-ref-task-001", target: "kn-ref-sess-001", type: "has_session" },
244
+ { source: "kn-jwt-middleware", target: "kn-ref-sess-001", type: "created_in" },
245
+ { source: "kn-audit-schema", target: "kn-db-schema", type: "part_of" },
246
+ ];
247
+
248
+ /** Lookup map for knowledge nodes by ID. */
249
+ const knowledgeNodeById: Map<string, GraphNode> = new Map(MOCK_KNOWLEDGE_NODES.map((n) => [n.id, n]));
250
+
251
+ /** Helper to get a knowledge node by ID, throwing if not found (catches typos at startup). */
252
+ function getNode(id: string): GraphNode {
253
+ const node = knowledgeNodeById.get(id);
254
+ if (!node) {
255
+ throw new Error(`MOCK_KNOWLEDGE_NODES is missing node "${id}"`);
256
+ }
257
+ return node;
258
+ }
259
+
260
+ /**
261
+ * Pre-built detail data for knowledge nodes, keyed by node ID.
262
+ * Used by the mock provider to populate the detail panel on node selection.
263
+ */
264
+ export const MOCK_KNOWLEDGE_DETAILS: Record<string, NodeDetail> = {
265
+ "kn-auth-flow": {
266
+ node: getNode("kn-auth-flow"),
267
+ edges: [
268
+ { fromId: "kn-auth-flow", toId: "kn-jwt-over-session", type: "decided_by" },
269
+ { fromId: "kn-auth-flow", toId: "kn-jwt-middleware", type: "implemented_by" },
270
+ { fromId: "kn-auth-flow", toId: "kn-ref-task-001", type: "tracked_in" },
271
+ { fromId: "kn-auth-flow", toId: "kn-error-handling", type: "relates_to" },
272
+ { fromId: "kn-rate-limiting", toId: "kn-auth-flow", type: "depends_on" },
273
+ ],
274
+ },
275
+ "kn-db-schema": {
276
+ node: getNode("kn-db-schema"),
277
+ edges: [
278
+ { fromId: "kn-db-schema", toId: "kn-pg-pool-decision", type: "decided_by" },
279
+ { fromId: "kn-db-schema", toId: "kn-audit-schema", type: "contains" },
280
+ { fromId: "kn-db-schema", toId: "kn-n1-query", type: "affected_by" },
281
+ { fromId: "kn-db-schema", toId: "kn-session-race", type: "affected_by" },
282
+ { fromId: "kn-audit-schema", toId: "kn-db-schema", type: "part_of" },
283
+ ],
284
+ },
285
+ "kn-etl-pipeline": {
286
+ node: getNode("kn-etl-pipeline"),
287
+ edges: [
288
+ { fromId: "kn-etl-pipeline", toId: "kn-parquet-format", type: "outputs_to" },
289
+ { fromId: "kn-etl-pipeline", toId: "kn-watermark-decision", type: "decided_by" },
290
+ { fromId: "kn-etl-pipeline", toId: "kn-ref-task-006", type: "tracked_in" },
291
+ { fromId: "kn-watermark-decision", toId: "kn-etl-pipeline", type: "relates_to" },
292
+ ],
293
+ },
294
+ };
package/src/scss.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /** Type declarations for SCSS module imports. */
2
+ declare module "*.module.scss" {
3
+ /** Map of local class names to their CSS module-scoped equivalents. */
4
+ const classes: { readonly [key: string]: string };
5
+ export default classes;
6
+ }
7
+
8
+ /** Type declarations for plain SCSS imports (side-effect only). */
9
+ declare module "*.scss" {
10
+ const content: string;
11
+ export default content;
12
+ }
@@ -0,0 +1,244 @@
1
+ // ============================================================================
2
+ // Global Styles — Grackle Web UI
3
+ // ============================================================================
4
+ // Reset, base styles, scrollbars, keyframe animations, and accessibility
5
+ // overrides. Imported once in main.tsx; theme tokens come from theme.scss.
6
+ // ============================================================================
7
+
8
+ @use './theme.scss';
9
+ @use './prism-theme.scss';
10
+ @import url('https://cdn.jsdelivr.net/npm/firacode@6.2.0/distr/fira_code.css');
11
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700;800&display=swap');
12
+ @import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,700;1,9..40,400&display=swap');
13
+
14
+ // =============================================================================
15
+ // Suppress transitions during theme changes (T3 pattern)
16
+ // =============================================================================
17
+
18
+ .no-transitions,
19
+ .no-transitions *,
20
+ .no-transitions *::before,
21
+ .no-transitions *::after {
22
+ transition-duration: 0s !important;
23
+ animation-duration: 0s !important;
24
+ }
25
+
26
+ // =============================================================================
27
+ // Reset
28
+ // =============================================================================
29
+
30
+ *,
31
+ *::before,
32
+ *::after {
33
+ box-sizing: border-box;
34
+ margin: 0;
35
+ padding: 0;
36
+ }
37
+
38
+ html,
39
+ body,
40
+ #root {
41
+ height: 100%;
42
+ overflow: hidden;
43
+ }
44
+
45
+ body {
46
+ background: var(--bg-base);
47
+ color: var(--text-primary);
48
+ font-family: var(--font-ui);
49
+ font-size: var(--font-size-md);
50
+ font-weight: var(--font-weight-regular);
51
+ line-height: var(--line-height);
52
+ -webkit-font-smoothing: antialiased;
53
+ -moz-osx-font-smoothing: grayscale;
54
+ }
55
+
56
+ // Subtle noise texture overlay (T3-inspired tactile feel)
57
+ body::after {
58
+ content: '';
59
+ position: fixed;
60
+ inset: 0;
61
+ pointer-events: none;
62
+ opacity: var(--noise-opacity);
63
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
64
+ background-repeat: repeat;
65
+ z-index: 99999;
66
+ }
67
+
68
+ // =============================================================================
69
+ // Selection
70
+ // =============================================================================
71
+
72
+ ::selection {
73
+ background: var(--accent-green-selection);
74
+ color: var(--text-primary);
75
+ }
76
+
77
+ // =============================================================================
78
+ // Scrollbars
79
+ // =============================================================================
80
+
81
+ // WebKit (Chrome, Edge, Safari)
82
+ ::-webkit-scrollbar {
83
+ width: 6px;
84
+ height: 6px;
85
+ }
86
+
87
+ ::-webkit-scrollbar-track {
88
+ background: transparent;
89
+ }
90
+
91
+ ::-webkit-scrollbar-thumb {
92
+ background: var(--text-disabled);
93
+ border-radius: var(--radius-full);
94
+
95
+ &:hover {
96
+ background: var(--text-tertiary);
97
+ }
98
+ }
99
+
100
+ // Firefox
101
+ * {
102
+ scrollbar-width: thin;
103
+ scrollbar-color: var(--text-disabled) transparent;
104
+ }
105
+
106
+ // =============================================================================
107
+ // Focus Ring (Accessibility)
108
+ // =============================================================================
109
+
110
+ :focus-visible {
111
+ outline: 2px solid var(--ring);
112
+ outline-offset: 2px;
113
+ }
114
+
115
+ // Enable OpenType ligatures and contextual alternates globally
116
+ :root {
117
+ font-feature-settings: 'liga' 1, 'calt' 1;
118
+ }
119
+
120
+ // =============================================================================
121
+ // Keyframe Animations
122
+ // =============================================================================
123
+
124
+ @keyframes pulse {
125
+ 0%,
126
+ 100% {
127
+ opacity: 1;
128
+ }
129
+ 50% {
130
+ opacity: 0.5;
131
+ }
132
+ }
133
+
134
+ @keyframes fadeIn {
135
+ from {
136
+ opacity: 0;
137
+ transform: translateY(4px);
138
+ }
139
+ to {
140
+ opacity: 1;
141
+ transform: translateY(0);
142
+ }
143
+ }
144
+
145
+ @keyframes slideInLeft {
146
+ from {
147
+ opacity: 0;
148
+ transform: translateX(-8px);
149
+ }
150
+ to {
151
+ opacity: 1;
152
+ transform: translateX(0);
153
+ }
154
+ }
155
+
156
+ @keyframes spin {
157
+ from {
158
+ transform: rotate(0deg);
159
+ }
160
+ to {
161
+ transform: rotate(360deg);
162
+ }
163
+ }
164
+
165
+ // =============================================================================
166
+ // Matrix — CRT scanline overlay + text glow
167
+ // =============================================================================
168
+
169
+ [data-theme="matrix"] {
170
+ // Tunable scanline intensity — defaults to atmospheric, override via DevTools
171
+ --matrix-scanline-opacity: 0.04;
172
+
173
+ // Override the noise overlay with CRT scanlines
174
+ body::after {
175
+ opacity: var(--matrix-scanline-opacity);
176
+ background-image: repeating-linear-gradient(
177
+ 0deg,
178
+ rgba(0, 255, 65, 0.06) 0px,
179
+ rgba(0, 255, 65, 0.06) 1px,
180
+ transparent 1px,
181
+ transparent 3px
182
+ );
183
+ background-size: 100% 3px;
184
+ }
185
+
186
+ // CRT text glow — subtle green halo
187
+ body {
188
+ text-shadow: 0 0 2px rgba(0, 255, 65, 0.12);
189
+ }
190
+
191
+ // Suppress glow on focused text inputs for readability
192
+ input:focus,
193
+ textarea:focus,
194
+ [contenteditable="true"]:focus {
195
+ text-shadow: none;
196
+ }
197
+ }
198
+
199
+ // =============================================================================
200
+ // Accessibility: High Contrast
201
+ // =============================================================================
202
+ // Increase border visibility and text contrast for high-contrast mode.
203
+
204
+ @media (prefers-contrast: more) {
205
+ [data-theme="grackle-light"],
206
+ [data-theme="brutalist-light"],
207
+ [data-theme="monokai-light"] {
208
+ --text-secondary: #4b5563;
209
+ --text-tertiary: #6b7280;
210
+ --text-disabled: #9ca3af;
211
+ --border-subtle: rgba(0, 0, 0, 0.20);
212
+ --border-input: rgba(0, 0, 0, 0.30);
213
+ }
214
+
215
+ [data-theme="grackle-dark"],
216
+ [data-theme="glass"],
217
+ [data-theme="matrix"],
218
+ [data-theme="monokai-dark"],
219
+ [data-theme="brutalist-dark"],
220
+ [data-theme="ubuntu"],
221
+ [data-theme="sandstone"],
222
+ [data-theme="verdigris"],
223
+ [data-theme="primer"] {
224
+ --text-secondary: #d1d5db;
225
+ --text-tertiary: #9ca3af;
226
+ --text-disabled: #6b7280;
227
+ --border-subtle: rgba(255, 255, 255, 0.15);
228
+ --border-input: rgba(255, 255, 255, 0.25);
229
+ }
230
+ }
231
+
232
+ // =============================================================================
233
+ // Accessibility: Reduced Motion
234
+ // =============================================================================
235
+
236
+ @media (prefers-reduced-motion: reduce) {
237
+ *,
238
+ *::before,
239
+ *::after {
240
+ animation-duration: 0.01ms !important;
241
+ animation-iteration-count: 1 !important;
242
+ transition-duration: 0.01ms !important;
243
+ }
244
+ }