@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,137 @@
1
+ /**
2
+ * Shared task-status metadata: labels, icons, colors, and column order.
3
+ *
4
+ * Every view (sidebar, DAG, board, task page) should import from here so that
5
+ * labels, icons, colors, and ordering stay consistent across the UI.
6
+ */
7
+
8
+ import type { ReactNode } from "react";
9
+ import { Ban, Check, Circle, Pause, X } from "lucide-react";
10
+ import { ICON_SM } from "./iconSize.js";
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // Core types
14
+ // ---------------------------------------------------------------------------
15
+
16
+ /** Canonical task statuses displayed in the UI. */
17
+ export type TaskStatusKey = "not_started" | "working" | "paused" | "complete" | "failed";
18
+
19
+ /** Virtual status for tasks with unresolved dependencies. Not stored on the task itself. */
20
+ export type VirtualStatus = "blocked";
21
+
22
+ /** All statuses the UI may display, including virtual ones. */
23
+ export type DisplayStatus = TaskStatusKey | VirtualStatus;
24
+
25
+ /** Visual metadata for a single task status. */
26
+ export interface TaskStatusStyle {
27
+ /** CSS color value (typically a custom-property reference). */
28
+ color: string;
29
+ /** Status icon element. */
30
+ icon: ReactNode;
31
+ /** Human-readable label. */
32
+ label: string;
33
+ }
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Style map
37
+ // ---------------------------------------------------------------------------
38
+
39
+ /** Complete style map for every displayable status (canonical + virtual). */
40
+ export const TASK_STATUS_STYLES: Record<DisplayStatus, TaskStatusStyle> = {
41
+ not_started: { color: "var(--text-tertiary)", icon: <Circle size={ICON_SM} />, label: "Not Started" },
42
+ working: { color: "var(--accent-green)", icon: <Circle size={ICON_SM} fill="currentColor" />, label: "Working" },
43
+ paused: { color: "var(--accent-yellow)", icon: <Pause size={ICON_SM} />, label: "Paused" },
44
+ complete: { color: "var(--accent-green)", icon: <Check size={ICON_SM} />, label: "Complete" },
45
+ failed: { color: "var(--accent-red)", icon: <X size={ICON_SM} />, label: "Failed" },
46
+ blocked: { color: "var(--accent-yellow)", icon: <Ban size={ICON_SM} />, label: "Blocked" },
47
+ };
48
+
49
+ /** Safe accessor — returns a style for any status string, falling back to `not_started`. */
50
+ export function getStatusStyle(status: string): TaskStatusStyle {
51
+ if (status === "blocked") {
52
+ return TASK_STATUS_STYLES.blocked;
53
+ }
54
+
55
+ return TASK_STATUS_STYLES[resolveStatus(status)];
56
+ }
57
+
58
+ // ---------------------------------------------------------------------------
59
+ // CSS-class map for badge-style rendering (TaskPage)
60
+ // ---------------------------------------------------------------------------
61
+
62
+ /** Maps a canonical status key to a CSS class suffix used for badge coloring. */
63
+ export const STATUS_BADGE_CLASS_MAP: Record<string, string> = {
64
+ not_started: "statusPending",
65
+ working: "statusInProgress",
66
+ paused: "statusWaitingInput",
67
+ complete: "statusDone",
68
+ failed: "statusFailed",
69
+ };
70
+
71
+ /** Resolve a task status to the corresponding badge class key. */
72
+ export function getStatusBadgeClassKey(status: string): string {
73
+ return STATUS_BADGE_CLASS_MAP[resolveStatus(status)] ?? "statusPending";
74
+ }
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // Ordering
78
+ // ---------------------------------------------------------------------------
79
+
80
+ /**
81
+ * Sidebar group order — includes virtual "blocked" group.
82
+ * This is the urgency-first ordering used by the sidebar grouped view.
83
+ */
84
+ export const SIDEBAR_STATUS_ORDER: DisplayStatus[] = [
85
+ "working", "paused", "failed", "not_started", "blocked", "complete",
86
+ ];
87
+
88
+ /**
89
+ * Board columns — the five concrete columns shown on the Kanban board.
90
+ * "blocked" is NOT a column; blocked tasks stay in their original column
91
+ * with a badge overlay.
92
+ */
93
+ export const BOARD_COLUMN_ORDER: TaskStatusKey[] = [
94
+ "not_started", "working", "paused", "complete", "failed",
95
+ ];
96
+
97
+ // ---------------------------------------------------------------------------
98
+ // Alias resolution (legacy proto names → canonical)
99
+ // ---------------------------------------------------------------------------
100
+
101
+ /** Maps legacy / proto status strings to canonical UI status keys. */
102
+ const STATUS_ALIASES: Record<string, TaskStatusKey> = {
103
+ pending: "not_started",
104
+ assigned: "not_started",
105
+ in_progress: "working",
106
+ waiting_input: "paused",
107
+ review: "paused",
108
+ done: "complete",
109
+ };
110
+
111
+ /** Resolve a raw status string to a canonical `TaskStatusKey`, treating unknown values as `not_started`. */
112
+ export function resolveStatus(raw: string): TaskStatusKey {
113
+ if (raw in TASK_STATUS_STYLES && raw !== "blocked") {
114
+ return raw as TaskStatusKey;
115
+ }
116
+ return STATUS_ALIASES[raw] ?? "not_started";
117
+ }
118
+
119
+ // ---------------------------------------------------------------------------
120
+ // MiniMap color resolution (DagView)
121
+ // ---------------------------------------------------------------------------
122
+
123
+ /** CSS variable names used for MiniMap node coloring by task status. */
124
+ export const STATUS_CSS_VAR_MAP: Record<string, string> = {
125
+ not_started: "--text-tertiary",
126
+ working: "--accent-green",
127
+ paused: "--accent-yellow",
128
+ complete: "--accent-green",
129
+ failed: "--accent-red",
130
+ // Legacy aliases
131
+ pending: "--text-tertiary",
132
+ assigned: "--text-tertiary",
133
+ in_progress: "--accent-green",
134
+ review: "--accent-yellow",
135
+ done: "--accent-green",
136
+ waiting_input: "--accent-yellow",
137
+ };
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Formats an ISO timestamp string as a human-readable relative time.
3
+ *
4
+ * Examples:
5
+ * "just now" (< 1 minute ago)
6
+ * "5m ago" (< 1 hour ago)
7
+ * "2h ago" (< 24 hours ago)
8
+ * "yesterday" (1–2 days ago)
9
+ * "3 days ago" (2–7 days ago)
10
+ * "Feb 27" (> 7 days ago, same year)
11
+ * "Feb 27 2025" (different year)
12
+ */
13
+ export function formatRelativeTime(isoString: string): string {
14
+ const date = new Date(isoString);
15
+ const now = new Date();
16
+ const diffMs = now.getTime() - date.getTime();
17
+ const diffSeconds = Math.floor(diffMs / 1000);
18
+ const diffMinutes = Math.floor(diffSeconds / 60);
19
+ const diffHours = Math.floor(diffMinutes / 60);
20
+ const diffDays = Math.floor(diffHours / 24);
21
+
22
+ if (diffSeconds < 60) {
23
+ return "just now";
24
+ }
25
+ if (diffMinutes < 60) {
26
+ return `${diffMinutes}m ago`;
27
+ }
28
+ if (diffHours < 24) {
29
+ return `${diffHours}h ago`;
30
+ }
31
+ if (diffDays === 1) {
32
+ return "yesterday";
33
+ }
34
+ if (diffDays < 7) {
35
+ return `${diffDays} days ago`;
36
+ }
37
+
38
+ // Older than a week — show a short date
39
+ const sameYear = date.getFullYear() === now.getFullYear();
40
+ const month = date.toLocaleString("en-US", { month: "short" });
41
+ const day = date.getDate();
42
+ return sameYear ? `${month} ${day}` : `${month} ${day} ${date.getFullYear()}`;
43
+ }
44
+
45
+ /**
46
+ * Formats an ISO timestamp string as a human-readable countdown to a future event.
47
+ *
48
+ * Examples:
49
+ * "in 45s" (< 1 minute away)
50
+ * "in 5m" (< 1 hour away)
51
+ * "in 2h" (< 24 hours away)
52
+ * "in 3 days" (< 7 days away)
53
+ * "Feb 27" (> 7 days away, same year)
54
+ *
55
+ * Returns "overdue" if the timestamp is in the past.
56
+ */
57
+ export function formatCountdown(isoString: string): string {
58
+ const date = new Date(isoString);
59
+ if (Number.isNaN(date.getTime())) {
60
+ return "\u2014";
61
+ }
62
+ const now = new Date();
63
+ const diffMs = date.getTime() - now.getTime();
64
+
65
+ if (diffMs <= 0) {
66
+ return "overdue";
67
+ }
68
+
69
+ const diffSeconds = Math.floor(diffMs / 1000);
70
+ const diffMinutes = Math.floor(diffSeconds / 60);
71
+ const diffHours = Math.floor(diffMinutes / 60);
72
+ const diffDays = Math.floor(diffHours / 24);
73
+
74
+ if (diffSeconds < 60) {
75
+ return `in ${diffSeconds}s`;
76
+ }
77
+ if (diffMinutes < 60) {
78
+ return `in ${diffMinutes}m`;
79
+ }
80
+ if (diffHours < 24) {
81
+ return `in ${diffHours}h`;
82
+ }
83
+ if (diffDays < 7) {
84
+ return `in ${diffDays} day${diffDays === 1 ? "" : "s"}`;
85
+ }
86
+
87
+ // Further out — show a short date
88
+ const sameYear = date.getFullYear() === now.getFullYear();
89
+ const month = date.toLocaleString("en-US", { month: "short" });
90
+ const day = date.getDate();
91
+ return sameYear ? `${month} ${day}` : `${month} ${day} ${date.getFullYear()}`;
92
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./node_modules/@grackle-ai/heft-rig/profiles/web/tsconfig-base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"]
8
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+ import { resolve } from "node:path";
4
+
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ build: {
8
+ lib: {
9
+ entry: resolve(__dirname, "src/index.ts"),
10
+ formats: ["es"],
11
+ fileName: "index",
12
+ },
13
+ rollupOptions: {
14
+ external: [
15
+ "react", "react-dom", "react-router", "react/jsx-runtime",
16
+ /^@grackle-ai\//,
17
+ ],
18
+ },
19
+ },
20
+ });
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ["src/**/*.test.ts", "src/**/*.test.tsx"],
6
+ environment: "node",
7
+ testTimeout: 10_000,
8
+ isolate: true,
9
+ },
10
+ });