@kortix/ui 0.14.4 → 0.14.6

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 (228) hide show
  1. package/README.md +8 -4
  2. package/dist/access/access/access-dialog.js +8 -5
  3. package/dist/access/access/copy-row.js +2 -2
  4. package/dist/access/sharing-picker.js +2 -1
  5. package/dist/browser/app-in-browser.js +5 -3
  6. package/dist/browser/browser-panel.js +6 -6
  7. package/dist/browser/sandbox-browser-chrome.d.ts +4 -1
  8. package/dist/browser/sandbox-browser-chrome.js +4 -3
  9. package/dist/customize/agents/agent-access.d.ts +20 -0
  10. package/dist/customize/agents/agent-access.js +17 -0
  11. package/dist/customize/agents/agent-grant-pages.js +5 -6
  12. package/dist/customize/agents/agent-page.js +2 -1
  13. package/dist/customize/agents/agents-page.js +18 -1
  14. package/dist/customize/connectors/add-mcp/add-mcp-server.js +4 -2
  15. package/dist/customize/connectors/connector-routes.d.ts +3 -1
  16. package/dist/customize/connectors/connector-routes.js +18 -0
  17. package/dist/customize/connectors/connectors-page.js +23 -4
  18. package/dist/customize/connectors/detail/connector-advanced-tools.js +4 -6
  19. package/dist/customize/providers/provider-accordion.js +2 -1
  20. package/dist/customize/providers/provider-connect.js +2 -1
  21. package/dist/customize/sections/component/telegram-channel-row.js +1 -1
  22. package/dist/customize/sections/connector-connection-modal.js +11 -9
  23. package/dist/customize/sections/connectors-view.js +11 -13
  24. package/dist/customize/sections/llm-provider/constants.d.ts +0 -1
  25. package/dist/customize/sections/llm-provider/constants.js +0 -2
  26. package/dist/customize/sections/llm-provider/models-tab-group.d.ts +1 -1
  27. package/dist/customize/sections/llm-provider/models-tab-group.js +7 -4
  28. package/dist/customize/sections/llm-provider/models-tab-row.d.ts +2 -18
  29. package/dist/customize/sections/llm-provider/models-tab-row.js +6 -30
  30. package/dist/customize/sections/llm-provider/models-tab.d.ts +0 -1
  31. package/dist/customize/sections/llm-provider/models-tab.js +1 -10
  32. package/dist/customize/sections/llm-provider/use-connected-providers.js +2 -2
  33. package/dist/customize/sections/llm-provider/utils.d.ts +1 -1
  34. package/dist/customize/sections/llm-provider/utils.js +7 -14
  35. package/dist/customize/sections/view/gateway/_shared.js +1 -2
  36. package/dist/customize/sections/view/gateway/gateway-routing.js +18 -20
  37. package/dist/customize/sections/view/sandbox-provider-coverage.d.ts +3 -18
  38. package/dist/customize/sections/view/sandbox-provider-coverage.js +7 -27
  39. package/dist/customize/settings/rail-copy-context.js +5 -3
  40. package/dist/customize/settings/tabs/sandbox-tab.d.ts +2 -27
  41. package/dist/customize/settings/tabs/sandbox-tab.js +13 -112
  42. package/dist/customize/settings/tabs/sandbox-template-form.js +9 -12
  43. package/dist/customize/shared/capability-tabs.js +2 -1
  44. package/dist/customize/shared/entity/entity-modal.d.ts +5 -1
  45. package/dist/customize/shared/entity/entity-modal.js +7 -4
  46. package/dist/customize/skills/remove-skill-button.d.ts +16 -0
  47. package/dist/customize/skills/remove-skill-button.js +42 -0
  48. package/dist/customize/skills/skills-page.js +4 -6
  49. package/dist/customize/triggers/schedule/event-trigger-copy.js +3 -2
  50. package/dist/customize/triggers/schedule/schedule-builder.js +7 -4
  51. package/dist/customize/triggers/schedule/trigger-composer.js +5 -2
  52. package/dist/customize/triggers/schedule/trigger-list.d.ts +0 -2
  53. package/dist/customize/triggers/schedule/trigger-list.js +1 -18
  54. package/dist/customize/triggers/schedule/trigger-tile.d.ts +1 -32
  55. package/dist/customize/triggers/schedule/trigger-tile.js +1 -16
  56. package/dist/customize/triggers/schedule/when-event.js +1 -1
  57. package/dist/diff/diff-view.js +9 -10
  58. package/dist/files/editor/code-editor.js +2 -3
  59. package/dist/files/project/components/change-request-detail-dialog.d.ts +3 -1
  60. package/dist/files/project/components/change-request-detail-dialog.js +3 -5
  61. package/dist/files/project/components/change-request-status-badge.d.ts +12 -0
  62. package/dist/files/project/components/change-request-status-badge.js +27 -0
  63. package/dist/files/project/components/change-requests-panel.js +1 -1
  64. package/dist/files/project/components/drive-explorer.js +2 -1
  65. package/dist/files/project/components/drive-grid-view.js +11 -7
  66. package/dist/files/project/components/drive-list-view.js +4 -4
  67. package/dist/files/project/components/file-breadcrumbs.js +1 -1
  68. package/dist/files/project/components/file-explorer-page.js +1 -1
  69. package/dist/files/project/components/file-history-popover.js +1 -6
  70. package/dist/files/project/components/file-search.js +6 -1
  71. package/dist/files/project/components/open-change-request-dialog.js +2 -1
  72. package/dist/files/project/components/version-selector-logic.d.ts +11 -0
  73. package/dist/files/project/components/version-selector-logic.js +26 -0
  74. package/dist/files/project/components/version-selector.js +11 -20
  75. package/dist/files/project/hooks/use-change-requests.d.ts +14 -1
  76. package/dist/files/project/hooks/use-change-requests.js +44 -25
  77. package/dist/files/project/hooks/use-server-health.js +17 -15
  78. package/dist/files/renderers/docx/docx-viewer.js +4 -6
  79. package/dist/files/renderers/image-renderer.js +6 -24
  80. package/dist/files/renderers/pdf/pdf-renderer.d.ts +3 -1
  81. package/dist/files/renderers/pdf/pdf-renderer.js +2 -2
  82. package/dist/files/renderers/pdf/pdf-viewer.d.ts +3 -0
  83. package/dist/files/renderers/pdf/pdf-viewer.js +16 -7
  84. package/dist/files/renderers/presentation/FullScreenPresentationViewer.js +2 -11
  85. package/dist/files/renderers/show-content-renderer.js +1 -1
  86. package/dist/files/renderers/sqlite-renderer.js +8 -3
  87. package/dist/files/renderers/xlsx/xlsx-viewer.js +15 -16
  88. package/dist/files/tree/components/file-tree-item.js +1 -1
  89. package/dist/files/viewer/file-content-renderer.d.ts +4 -1
  90. package/dist/files/viewer/file-content-renderer.js +2 -2
  91. package/dist/files/viewer/file-preview-modal.js +1 -1
  92. package/dist/files/viewer/use-file-content-state.js +1 -1
  93. package/dist/i18n/en.d.ts +36 -35
  94. package/dist/i18n/en.js +45 -44
  95. package/dist/index.d.ts +1 -1
  96. package/dist/internal/desktop/desktop-back-button.js +5 -3
  97. package/dist/internal/hooks/use-auto-scroll.js +5 -3
  98. package/dist/internal/hooks/use-notification-center.js +21 -15
  99. package/dist/internal/hooks/use-review-session-summary.d.ts +6 -0
  100. package/dist/internal/hooks/use-review-session-summary.js +11 -0
  101. package/dist/internal/lib/browser-error-noise.d.ts +1 -1
  102. package/dist/internal/lib/browser-error-noise.js +1 -1
  103. package/dist/internal/lib/browser-noise/rules/rejections.d.ts +10 -0
  104. package/dist/internal/lib/browser-noise/rules/rejections.js +27 -1
  105. package/dist/internal/lib/provider-branding.js +14 -3
  106. package/dist/internal/lib/trigger-clock.d.ts +42 -0
  107. package/dist/internal/lib/trigger-clock.js +34 -0
  108. package/dist/internal/lib/web-notifications.d.ts +6 -0
  109. package/dist/internal/lib/web-notifications.js +57 -7
  110. package/dist/internal/notifications/notification-bell.d.ts +13 -0
  111. package/dist/internal/notifications/notification-bell.js +1 -1
  112. package/dist/internal/notifications/notification-rows.js +2 -1
  113. package/dist/internal/outcomes/outcome-types.d.ts +5 -0
  114. package/dist/internal/reminders/reminder-filter.d.ts +12 -0
  115. package/dist/internal/reminders/reminder-filter.js +34 -0
  116. package/dist/internal/reminders/reminder-format.d.ts +6 -0
  117. package/dist/internal/reminders/reminder-format.js +20 -2
  118. package/dist/internal/stores/kortix-computer-store.d.ts +1 -1
  119. package/dist/internal/stores/session-hover-store.d.ts +20 -5
  120. package/dist/internal/stores/session-hover-store.js +31 -13
  121. package/dist/internal/stores/session-panel-memory-store.js +2 -0
  122. package/dist/markdown/code/inline-code.js +8 -0
  123. package/dist/markdown/code/output-paths-context.d.ts +18 -0
  124. package/dist/markdown/code/output-paths-context.js +35 -0
  125. package/dist/markdown/genui/components/charts.js +6 -5
  126. package/dist/primitives/count-badge.d.ts +3 -1
  127. package/dist/primitives/count-badge.js +3 -3
  128. package/dist/primitives/glyph-paths-source.js +1 -1
  129. package/dist/primitives/glyph-paths.generated.js +1 -1
  130. package/dist/primitives/map.js +2 -1
  131. package/dist/primitives/preview-image.js +4 -2
  132. package/dist/primitives/textarea.js +1 -1
  133. package/dist/primitives/typed-title.js +12 -14
  134. package/dist/primitives/typing-animation.js +4 -2
  135. package/dist/providers/ui-provider.d.ts +57 -0
  136. package/dist/providers/ui-provider.js +4 -0
  137. package/dist/session/composer/ComposerCard.d.ts +2 -0
  138. package/dist/session/composer/ComposerCard.js +5 -1
  139. package/dist/session/composer/agent-selector.js +17 -5
  140. package/dist/session/composer/composer-chat-input.js +5 -3
  141. package/dist/session/composer/composer-logic.js +8 -7
  142. package/dist/session/composer/composer-toolbar.js +4 -2
  143. package/dist/session/composer/composer-underbar.js +3 -1
  144. package/dist/session/composer/composer.js +34 -5
  145. package/dist/session/composer/draft/composer-draft.js +4 -4
  146. package/dist/session/composer/menus/slash-actions.d.ts +22 -2
  147. package/dist/session/composer/menus/slash-actions.js +20 -0
  148. package/dist/session/composer/menus/slash-items.js +19 -3
  149. package/dist/session/composer/pasted-text.js +3 -2
  150. package/dist/session/composer/stores/queued-draft-store.js +3 -2
  151. package/dist/session/header/reminder-parts.d.ts +294 -0
  152. package/dist/session/header/reminder-parts.js +120 -0
  153. package/dist/session/header/session-reminders-indicator.d.ts +13 -0
  154. package/dist/session/header/session-reminders-indicator.js +142 -35
  155. package/dist/session/media/sandbox-url-detector.js +0 -7
  156. package/dist/session/models/model-availability.d.ts +23 -0
  157. package/dist/session/models/model-availability.js +20 -0
  158. package/dist/session/models/model-grouping.js +1 -4
  159. package/dist/session/models/model-selector.js +23 -14
  160. package/dist/session/models/use-model-connection-gate.js +4 -1
  161. package/dist/session/outcomes/change-request-outcomes.js +24 -3
  162. package/dist/session/outcomes/session-outcomes-provider.d.ts +3 -1
  163. package/dist/session/outcomes/session-outcomes-provider.js +31 -3
  164. package/dist/session/overrides/provider-secret-pool-editor.js +2 -1
  165. package/dist/session/overrides/session-overrides-composer.d.ts +1 -1
  166. package/dist/session/overrides/session-overrides-composer.js +5 -1
  167. package/dist/session/panel/advanced/advanced-panel.js +3 -7
  168. package/dist/session/panel/easy/app-preview.js +12 -2
  169. package/dist/session/panel/easy/easy-panel-logic.d.ts +1 -1
  170. package/dist/session/panel/easy/easy-panel-logic.js +1 -1
  171. package/dist/session/panel/easy/outputs-card.js +2 -1
  172. package/dist/session/panel/easy/panel-card.js +5 -3
  173. package/dist/session/panel/easy/preview-load.d.ts +14 -0
  174. package/dist/session/panel/easy/preview-load.js +15 -0
  175. package/dist/session/panel/easy/step-detail-body.js +2 -7
  176. package/dist/session/panel/mobile-tool-drawer.js +4 -2
  177. package/dist/session/panel/open-session-quick-view.js +2 -1
  178. package/dist/session/panel/panel-fallback.js +8 -4
  179. package/dist/session/panel/session-panel-provider.d.ts +1 -0
  180. package/dist/session/panel/session-panel-provider.js +19 -3
  181. package/dist/session/panel/session-reminders-panel.d.ts +4 -0
  182. package/dist/session/panel/session-reminders-panel.js +109 -0
  183. package/dist/session/panel/shared/use-panel-derivations.js +6 -4
  184. package/dist/session/panel/shared/use-panel-handoffs.d.ts +2 -2
  185. package/dist/session/panel/shared/use-panel-handoffs.js +5 -1
  186. package/dist/session/panel/use-session-panel-layout.js +7 -5
  187. package/dist/session/print/session-print-header.d.ts +0 -10
  188. package/dist/session/print/session-print-header.js +25 -9
  189. package/dist/session/status/session-surface.js +1 -1
  190. package/dist/session/thread/optimistic-turn.d.ts +5 -1
  191. package/dist/session/thread/optimistic-turn.js +8 -6
  192. package/dist/session/thread/session-chat.d.ts +6 -1
  193. package/dist/session/thread/session-chat.js +34 -12
  194. package/dist/session/thread/session-history.js +3 -1
  195. package/dist/session/thread/session-thread.d.ts +10 -1
  196. package/dist/session/thread/session-thread.js +2 -2
  197. package/dist/session/thread/transcript.js +13 -7
  198. package/dist/session/tool/shared/file-list.js +19 -2
  199. package/dist/session/tool/shared/infrastructure-contexts.d.ts +7 -0
  200. package/dist/session/tool/shared/infrastructure-contexts.js +7 -0
  201. package/dist/session/tool/shared/infrastructure-output.js +9 -5
  202. package/dist/session/tool/shared/infrastructure-row-header.js +9 -1
  203. package/dist/session/tool/shared/infrastructure-rows.js +7 -5
  204. package/dist/session/tool/tools/bash-tool.js +10 -6
  205. package/dist/session/tool/tools/web-search-tool.js +25 -3
  206. package/dist/session/turn/burst-step-body.js +4 -0
  207. package/dist/session/turn/recovered-failures.d.ts +8 -0
  208. package/dist/session/turn/recovered-failures.js +32 -0
  209. package/dist/session/turn/streaming-cadence.js +5 -8
  210. package/dist/styles.css +1 -1
  211. package/dist/terminal/session-terminal-panel.js +3 -5
  212. package/dist/theme/theme.js +2 -1
  213. package/dist/workspace/projects/modal/github-import-pickers.js +7 -6
  214. package/dist/workspace/review/review-center.js +13 -10
  215. package/dist/workspace/session-workspace.js +5 -9
  216. package/dist/workspace/sessions/deleted-session-row.js +5 -2
  217. package/dist/workspace/sidebar/footer/project-computer-nav.js +6 -4
  218. package/dist/workspace/sidebar/footer/project-mcp-nav.js +6 -2
  219. package/dist/workspace/sidebar/modal/rename-session-modal.js +8 -3
  220. package/dist/workspace/sidebar/project-session-list.js +52 -55
  221. package/dist/workspace/sidebar/session-brief-hover-card.d.ts +35 -18
  222. package/dist/workspace/sidebar/session-brief-hover-card.js +114 -37
  223. package/dist/workspace/sidebar/session-status-mark.d.ts +15 -1
  224. package/dist/workspace/sidebar/session-status-mark.js +63 -17
  225. package/package.json +7 -3
  226. package/skills/kortix-ui/SKILL.md +1 -1
  227. package/dist/customize/sections/view/sandbox-provider-result.d.ts +0 -47
  228. package/dist/customize/sections/view/sandbox-provider-result.js +0 -79
@@ -96,7 +96,7 @@ export function buildSlashSections({ commands, actions = SLASH_ACTIONS, files =
96
96
  const filteredActions = filterSlashActions(actions, query);
97
97
  const filteredFiles = filterSlashFiles(files, query);
98
98
  const fileCap = q ? FILE_LIMIT : FILE_PREVIEW_LIMIT;
99
- // Render order: Actions, Outputs, Context, Skills, Commands, MCP.
99
+ // Render order: Actions, the host's groups, Outputs, Context, Skills, Commands, MCP.
100
100
  //
101
101
  // Actions moved from last to first. They are the fixed, always-present rows
102
102
  // (switch model, attach a file, …) — the same six every time, in the same
@@ -112,11 +112,12 @@ export function buildSlashSections({ commands, actions = SLASH_ACTIONS, files =
112
112
  // in would desync the highlight from the keyboard.
113
113
  let index = 0;
114
114
  const sections = [];
115
- if (filteredActions.length) {
115
+ const builtIn = filteredActions.filter((a) => !a.group);
116
+ if (builtIn.length) {
116
117
  sections.push({
117
118
  heading: actionsHeading,
118
119
  hideHeading: true,
119
- rows: filteredActions.map((action) => ({
120
+ rows: builtIn.map((action) => ({
120
121
  index: index++,
121
122
  type: 'action',
122
123
  name: action.label,
@@ -127,6 +128,21 @@ export function buildSlashSections({ commands, actions = SLASH_ACTIONS, files =
127
128
  })),
128
129
  });
129
130
  }
131
+ // The host's rows (`UiHostConfig.useSlashActions`), under their own headings, in the order given.
132
+ const hostGroups = [...new Set(filteredActions.filter((a) => a.group).map((a) => a.group))];
133
+ for (const heading of hostGroups) {
134
+ sections.push({
135
+ heading,
136
+ rows: filteredActions.filter((a) => a.group === heading).map((action) => ({
137
+ index: index++,
138
+ type: 'action',
139
+ name: action.label,
140
+ description: action.description,
141
+ hint: action.hint,
142
+ action,
143
+ })),
144
+ });
145
+ }
130
146
  // Outputs, then Context, then the command buckets.
131
147
  //
132
148
  // Above the commands because this is the one part of the palette that is
@@ -19,12 +19,13 @@ export function PastedTextCopy({ text }) {
19
19
  // The toolbar `ButtonGroup`'s look: `size-7` on the `secondary` fill, as `CloseButton`.
20
20
  return (_jsx(CopyButton, { code: text, size: "md", className: "bg-secondary hover:bg-secondary/90 shrink-0", label: t.raw('texte21f935f11d7') }));
21
21
  }
22
+ const graphemeSegmenter = typeof Intl !== 'undefined' && 'Segmenter' in Intl ? new Intl.Segmenter() : null;
22
23
  /** Word and character counts for the header. Characters are what the user sees: graphemes, else code points. */
23
24
  export function pastedTextCounts(text) {
24
25
  const words = text.trim() ? text.trim().split(/\s+/).length : 0;
25
26
  let chars = 0;
26
- if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {
27
- for (const _segment of new Intl.Segmenter().segment(text))
27
+ if (graphemeSegmenter) {
28
+ for (const _segment of graphemeSegmenter.segment(text))
28
29
  chars++;
29
30
  }
30
31
  else
@@ -18,9 +18,10 @@ export const useQueuedDraftStore = create((set) => ({
18
18
  }),
19
19
  remove: (sessionId, clientMessageIds) => set((s) => {
20
20
  const drafts = s.bySession[sessionId];
21
- if (!drafts?.some((d) => clientMessageIds.includes(d.clientMessageId)))
21
+ const ids = new Set(clientMessageIds);
22
+ if (!drafts?.some((d) => ids.has(d.clientMessageId)))
22
23
  return s;
23
- return withSession(s, sessionId, drafts.filter((d) => !clientMessageIds.includes(d.clientMessageId)));
24
+ return withSession(s, sessionId, drafts.filter((d) => !ids.has(d.clientMessageId)));
24
25
  }),
25
26
  prune: (sessionId, listedClientMessageIds) => set((s) => {
26
27
  const drafts = s.bySession[sessionId];
@@ -0,0 +1,294 @@
1
+ import type { SessionReminder } from '@kortix/sdk';
2
+ import { type ReactNode } from 'react';
3
+ export declare const isFailedReminder: (reminder: SessionReminder) => boolean;
4
+ /** Soonest next fire first; paused ones, which have no next fire, last. */
5
+ export declare function sortReminders(reminders: SessionReminder[]): SessionReminder[];
6
+ /** A ring filled clockwise from the top by `share`; an empty track around a pause glyph while paused. */
7
+ export declare function CountdownRing({ share, size, stroke, tone, paused, children, }: {
8
+ share: number | null;
9
+ size: number;
10
+ stroke: number;
11
+ tone: 'purple' | 'red';
12
+ paused: boolean;
13
+ children?: ReactNode;
14
+ }): import("react").JSX.Element;
15
+ /** "6h" over "12m": the time left in its two largest units, narrow and localized. */
16
+ export declare function countdownParts(ms: number, locale: string): [string, string | null];
17
+ /** What a row and its details show for one reminder at `now`. */
18
+ export declare function useReminderView(now: number): (reminder: SessionReminder) => {
19
+ paused: boolean;
20
+ isFailed: boolean;
21
+ next: string | null;
22
+ nextAt: number;
23
+ countdown: [string, string | null];
24
+ share: number | null;
25
+ tone: "purple" | "red";
26
+ pauseLabel: string;
27
+ schedule: string;
28
+ meta: string;
29
+ };
30
+ /** Repeats, time zone, last run, and the last error when the run failed. */
31
+ export declare function ReminderFacts({ reminder, now, className, }: {
32
+ reminder: SessionReminder;
33
+ now: number;
34
+ className?: string;
35
+ }): import("react").JSX.Element;
36
+ /** Retry a failed run, pause or resume, remove, and the link into the Reminders tab. */
37
+ export declare function ReminderActions({ reminder, controls, manageHref, onNavigate, className, }: {
38
+ reminder: SessionReminder;
39
+ controls: ReminderControls;
40
+ manageHref: string | null;
41
+ onNavigate?: () => void;
42
+ className?: string;
43
+ }): import("react").JSX.Element;
44
+ export interface ReminderControls {
45
+ pending: boolean;
46
+ running: boolean;
47
+ /** Fire the reminder once now. */
48
+ run: (reminder: SessionReminder) => void;
49
+ setEnabled: (reminder: SessionReminder, enabled: boolean) => void;
50
+ requestRemove: (reminder: SessionReminder) => void;
51
+ }
52
+ /**
53
+ * The session's reminders with run, pause, resume and remove. Remove asks first:
54
+ * render `confirm` once next to whatever calls `requestRemove`.
55
+ */
56
+ export declare function useReminderControls(projectId: string | null, sessionId: string | null | undefined): {
57
+ reminders: {
58
+ update: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, {
59
+ reminderId: string;
60
+ enabled: boolean;
61
+ }, unknown>;
62
+ remove: import("@tanstack/react-query").UseMutationResult<{
63
+ ok: boolean;
64
+ }, Error, string, unknown>;
65
+ run: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, string, unknown>;
66
+ data: {
67
+ reminders: SessionReminder[];
68
+ };
69
+ error: Error;
70
+ isError: true;
71
+ isPending: false;
72
+ isLoading: false;
73
+ isLoadingError: false;
74
+ isRefetchError: true;
75
+ isSuccess: false;
76
+ isPlaceholderData: false;
77
+ status: "error";
78
+ dataUpdatedAt: number;
79
+ errorUpdatedAt: number;
80
+ failureCount: number;
81
+ failureReason: Error | null;
82
+ errorUpdateCount: number;
83
+ isFetched: boolean;
84
+ isFetchedAfterMount: boolean;
85
+ isFetching: boolean;
86
+ isInitialLoading: boolean;
87
+ isPaused: boolean;
88
+ isRefetching: boolean;
89
+ isStale: boolean;
90
+ isEnabled: boolean;
91
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
92
+ reminders: SessionReminder[];
93
+ }, Error>>;
94
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
95
+ } | {
96
+ update: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, {
97
+ reminderId: string;
98
+ enabled: boolean;
99
+ }, unknown>;
100
+ remove: import("@tanstack/react-query").UseMutationResult<{
101
+ ok: boolean;
102
+ }, Error, string, unknown>;
103
+ run: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, string, unknown>;
104
+ data: {
105
+ reminders: SessionReminder[];
106
+ };
107
+ error: null;
108
+ isError: false;
109
+ isPending: false;
110
+ isLoading: false;
111
+ isLoadingError: false;
112
+ isRefetchError: false;
113
+ isSuccess: true;
114
+ isPlaceholderData: false;
115
+ status: "success";
116
+ dataUpdatedAt: number;
117
+ errorUpdatedAt: number;
118
+ failureCount: number;
119
+ failureReason: Error | null;
120
+ errorUpdateCount: number;
121
+ isFetched: boolean;
122
+ isFetchedAfterMount: boolean;
123
+ isFetching: boolean;
124
+ isInitialLoading: boolean;
125
+ isPaused: boolean;
126
+ isRefetching: boolean;
127
+ isStale: boolean;
128
+ isEnabled: boolean;
129
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
130
+ reminders: SessionReminder[];
131
+ }, Error>>;
132
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
133
+ } | {
134
+ update: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, {
135
+ reminderId: string;
136
+ enabled: boolean;
137
+ }, unknown>;
138
+ remove: import("@tanstack/react-query").UseMutationResult<{
139
+ ok: boolean;
140
+ }, Error, string, unknown>;
141
+ run: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, string, unknown>;
142
+ data: undefined;
143
+ error: Error;
144
+ isError: true;
145
+ isPending: false;
146
+ isLoading: false;
147
+ isLoadingError: true;
148
+ isRefetchError: false;
149
+ isSuccess: false;
150
+ isPlaceholderData: false;
151
+ status: "error";
152
+ dataUpdatedAt: number;
153
+ errorUpdatedAt: number;
154
+ failureCount: number;
155
+ failureReason: Error | null;
156
+ errorUpdateCount: number;
157
+ isFetched: boolean;
158
+ isFetchedAfterMount: boolean;
159
+ isFetching: boolean;
160
+ isInitialLoading: boolean;
161
+ isPaused: boolean;
162
+ isRefetching: boolean;
163
+ isStale: boolean;
164
+ isEnabled: boolean;
165
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
166
+ reminders: SessionReminder[];
167
+ }, Error>>;
168
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
169
+ } | {
170
+ update: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, {
171
+ reminderId: string;
172
+ enabled: boolean;
173
+ }, unknown>;
174
+ remove: import("@tanstack/react-query").UseMutationResult<{
175
+ ok: boolean;
176
+ }, Error, string, unknown>;
177
+ run: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, string, unknown>;
178
+ data: undefined;
179
+ error: null;
180
+ isError: false;
181
+ isPending: true;
182
+ isLoading: true;
183
+ isLoadingError: false;
184
+ isRefetchError: false;
185
+ isSuccess: false;
186
+ isPlaceholderData: false;
187
+ status: "pending";
188
+ dataUpdatedAt: number;
189
+ errorUpdatedAt: number;
190
+ failureCount: number;
191
+ failureReason: Error | null;
192
+ errorUpdateCount: number;
193
+ isFetched: boolean;
194
+ isFetchedAfterMount: boolean;
195
+ isFetching: boolean;
196
+ isInitialLoading: boolean;
197
+ isPaused: boolean;
198
+ isRefetching: boolean;
199
+ isStale: boolean;
200
+ isEnabled: boolean;
201
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
202
+ reminders: SessionReminder[];
203
+ }, Error>>;
204
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
205
+ } | {
206
+ update: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, {
207
+ reminderId: string;
208
+ enabled: boolean;
209
+ }, unknown>;
210
+ remove: import("@tanstack/react-query").UseMutationResult<{
211
+ ok: boolean;
212
+ }, Error, string, unknown>;
213
+ run: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, string, unknown>;
214
+ data: undefined;
215
+ error: null;
216
+ isError: false;
217
+ isPending: true;
218
+ isLoadingError: false;
219
+ isRefetchError: false;
220
+ isSuccess: false;
221
+ isPlaceholderData: false;
222
+ status: "pending";
223
+ dataUpdatedAt: number;
224
+ errorUpdatedAt: number;
225
+ failureCount: number;
226
+ failureReason: Error | null;
227
+ errorUpdateCount: number;
228
+ isFetched: boolean;
229
+ isFetchedAfterMount: boolean;
230
+ isFetching: boolean;
231
+ isLoading: boolean;
232
+ isInitialLoading: boolean;
233
+ isPaused: boolean;
234
+ isRefetching: boolean;
235
+ isStale: boolean;
236
+ isEnabled: boolean;
237
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
238
+ reminders: SessionReminder[];
239
+ }, Error>>;
240
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
241
+ } | {
242
+ update: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, {
243
+ reminderId: string;
244
+ enabled: boolean;
245
+ }, unknown>;
246
+ remove: import("@tanstack/react-query").UseMutationResult<{
247
+ ok: boolean;
248
+ }, Error, string, unknown>;
249
+ run: import("@tanstack/react-query").UseMutationResult<SessionReminder, Error, string, unknown>;
250
+ data: {
251
+ reminders: SessionReminder[];
252
+ };
253
+ isError: false;
254
+ error: null;
255
+ isPending: false;
256
+ isLoading: false;
257
+ isLoadingError: false;
258
+ isRefetchError: false;
259
+ isSuccess: true;
260
+ isPlaceholderData: true;
261
+ status: "success";
262
+ dataUpdatedAt: number;
263
+ errorUpdatedAt: number;
264
+ failureCount: number;
265
+ failureReason: Error | null;
266
+ errorUpdateCount: number;
267
+ isFetched: boolean;
268
+ isFetchedAfterMount: boolean;
269
+ isFetching: boolean;
270
+ isInitialLoading: boolean;
271
+ isPaused: boolean;
272
+ isRefetching: boolean;
273
+ isStale: boolean;
274
+ isEnabled: boolean;
275
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
276
+ reminders: SessionReminder[];
277
+ }, Error>>;
278
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
279
+ };
280
+ controls: ReminderControls;
281
+ confirm: import("react").JSX.Element;
282
+ };
283
+ /**
284
+ * A reminder row's cells, for a `REMINDER_ROW_GRID` container: the ring and
285
+ * the title share the first grid row, so the ring centres on the title line;
286
+ * the next run sits at the end of that line, the schedule under the title.
287
+ */
288
+ export declare const REMINDER_ROW_GRID = "grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-x-2.5";
289
+ export declare function ReminderRowCells({ reminder, view, trailing, }: {
290
+ reminder: SessionReminder;
291
+ view: ReturnType<ReturnType<typeof useReminderView>>;
292
+ /** Replaces the next-run time in the end column, e.g. a disclosure caret. */
293
+ trailing?: ReactNode;
294
+ }): import("react").JSX.Element;
@@ -0,0 +1,120 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * The pieces a session reminder is drawn with, shared by the header popover's
5
+ * hover card and the panel's Reminders view (`session-reminders-panel.tsx`):
6
+ * the countdown ring, the facts block, the action row, and the pause/remove
7
+ * mutations with their confirm dialog.
8
+ */
9
+ import { HoverPrefetchLink } from '../../internal/components/hover-prefetch-link.js';
10
+ import { Button } from '../../primitives/button.js';
11
+ import { ConfirmDialog } from '../../primitives/confirm-dialog.js';
12
+ import Hint from '../../primitives/hint.js';
13
+ import { errorToast, successToast } from '../../primitives/toast.js';
14
+ import { elapsedShare, formatFireTime, reminderTitle, scheduleLabel } from '../../internal/reminders/reminder-format.js';
15
+ import { cn } from '../../internal/lib/utils.js';
16
+ import { useLocale, useTranslations } from '../../i18n/index.js';
17
+ import { useSessionReminders } from '@kortix/sdk/react';
18
+ import { ArrowClockwiseIcon, ArrowUpRightIcon, PauseIcon, PlayIcon } from '@phosphor-icons/react';
19
+ import { useState } from 'react';
20
+ export const isFailedReminder = (reminder) => reminder.last_status === 'failed';
21
+ /** Soonest next fire first; paused ones, which have no next fire, last. */
22
+ export function sortReminders(reminders) {
23
+ const key = (reminder) => reminder.state === 'active' && reminder.next_fire_at ? Date.parse(reminder.next_fire_at) : Infinity;
24
+ return [...reminders].sort((a, b) => key(a) - key(b));
25
+ }
26
+ /** A ring filled clockwise from the top by `share`; an empty track around a pause glyph while paused. */
27
+ export function CountdownRing({ share, size, stroke, tone, paused, children, }) {
28
+ const r = (size - stroke) / 2;
29
+ const length = 2 * Math.PI * r;
30
+ return (_jsxs("span", { className: "relative flex shrink-0 items-center justify-center", style: { width: size, height: size }, children: [_jsxs("svg", { "aria-hidden": true, width: size, height: size, className: "absolute inset-0 -rotate-90", children: [_jsx("circle", { cx: size / 2, cy: size / 2, r: r, fill: "none", stroke: "currentColor", strokeWidth: stroke, className: "text-border" }), !paused && share !== null ? (_jsx("circle", { cx: size / 2, cy: size / 2, r: r, fill: "none", stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", strokeDasharray: `${length * share} ${length}`, className: tone === 'red' ? 'text-kortix-red' : 'text-kortix-purple' })) : null] }), paused ? (_jsx(PauseIcon, { "aria-hidden": true, weight: "fill", className: "text-muted-foreground", style: { width: Math.round(size * 0.4), height: Math.round(size * 0.4) } })) : (children)] }));
31
+ }
32
+ /** "6h" over "12m": the time left in its two largest units, narrow and localized. */
33
+ export function countdownParts(ms, locale) {
34
+ const min = Math.max(0, Math.round(ms / 60_000));
35
+ const unit = (value, name) => new Intl.NumberFormat(locale, { style: 'unit', unit: name, unitDisplay: 'narrow' }).format(value);
36
+ if (min >= 24 * 60)
37
+ return [unit(Math.floor(min / (24 * 60)), 'day'), unit(Math.floor((min % (24 * 60)) / 60), 'hour')];
38
+ if (min >= 60)
39
+ return [unit(Math.floor(min / 60), 'hour'), unit(min % 60, 'minute')];
40
+ return [unit(min, 'minute'), null];
41
+ }
42
+ /** What a row and its details show for one reminder at `now`. */
43
+ export function useReminderView(now) {
44
+ const t = useTranslations('reminders');
45
+ const locale = useLocale();
46
+ return (reminder) => {
47
+ const paused = reminder.state !== 'active';
48
+ const nextAt = reminder.next_fire_at ? Date.parse(reminder.next_fire_at) : NaN;
49
+ const failed = isFailedReminder(reminder);
50
+ return {
51
+ paused,
52
+ isFailed: failed,
53
+ next: !paused && reminder.next_fire_at ? formatFireTime(reminder.next_fire_at, locale, now) : null,
54
+ nextAt,
55
+ countdown: countdownParts(nextAt - now, locale),
56
+ share: elapsedShare(reminder, now),
57
+ tone: failed ? 'red' : 'purple',
58
+ pauseLabel: paused ? t('resume') : t('pause'),
59
+ schedule: scheduleLabel(reminder, (key, values) => t(key, values)),
60
+ meta: [failed ? t('lastRunFailed') : paused ? t('pausedLabel') : null, scheduleLabel(reminder, (key, values) => t(key, values))]
61
+ .filter(Boolean)
62
+ .join(' · '),
63
+ };
64
+ };
65
+ }
66
+ /** Repeats, time zone, last run, and the last error when the run failed. */
67
+ export function ReminderFacts({ reminder, now, className, }) {
68
+ const t = useTranslations('reminders');
69
+ const locale = useLocale();
70
+ const failed = isFailedReminder(reminder);
71
+ return (_jsxs("dl", { className: cn('space-y-1.5 text-xs', className), children: [_jsxs("div", { className: "flex justify-between gap-3", children: [_jsx("dt", { className: "text-muted-foreground", children: t('repeats') }), _jsx("dd", { className: "text-foreground truncate", children: scheduleLabel(reminder, (key, values) => t(key, values)) })] }), _jsxs("div", { className: "flex justify-between gap-3", children: [_jsx("dt", { className: "text-muted-foreground", children: t('timeZone') }), _jsx("dd", { className: "text-foreground truncate", children: reminder.timezone })] }), _jsxs("div", { className: "flex justify-between gap-3", children: [_jsx("dt", { className: "text-muted-foreground", children: t('lastRun') }), _jsx("dd", { className: "text-foreground flex items-center gap-1.5", children: reminder.last_fired_at ? (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": true, className: cn('size-1.5 rounded-full', failed ? 'bg-kortix-red' : 'bg-kortix-green') }), formatFireTime(reminder.last_fired_at, locale, now)] })) : (t('neverRun')) })] }), failed && reminder.last_error ? (_jsx("p", { className: "text-foreground bg-kortix-red/15 mt-2 rounded-md px-2 py-1.5 font-mono break-words", children: reminder.last_error })) : null] }));
72
+ }
73
+ /** Retry a failed run, pause or resume, remove, and the link into the Reminders tab. */
74
+ export function ReminderActions({ reminder, controls, manageHref, onNavigate, className, }) {
75
+ const t = useTranslations('reminders');
76
+ const paused = reminder.state !== 'active';
77
+ return (_jsxs("div", { className: cn('flex items-center gap-1', className), children: [isFailedReminder(reminder) ? (_jsxs(Button, { variant: "secondary", size: "xs", disabled: controls.running, onClick: () => controls.run(reminder), children: [_jsx(ArrowClockwiseIcon, { className: "size-3.5" }), t('retry')] })) : null, _jsxs(Button, { variant: "secondary", size: "xs", disabled: controls.pending, onClick: () => controls.setEnabled(reminder, paused), children: [paused ? _jsx(PlayIcon, { className: "size-3.5" }) : _jsx(PauseIcon, { className: "size-3.5" }), paused ? t('resume') : t('pause')] }), _jsx(Button, { variant: "ghost", size: "xs", className: "text-destructive", onClick: () => controls.requestRemove(reminder), children: t('remove') }), manageHref ? (
78
+ // An icon, not a label: three text buttons overflow the 288px card.
79
+ _jsx(Hint, { label: t('openInReminders'), side: "top", sideOffset: 6, alignOffset: 0, children: _jsx(Button, { asChild: true, variant: "ghost", size: "icon-xs", className: "text-muted-foreground ml-auto", "aria-label": t('openInReminders'), children: _jsx(HoverPrefetchLink, { href: manageHref, onClick: onNavigate, children: _jsx(ArrowUpRightIcon, { className: "size-3.5" }) }) }) })) : null] }));
80
+ }
81
+ /**
82
+ * The session's reminders with run, pause, resume and remove. Remove asks first:
83
+ * render `confirm` once next to whatever calls `requestRemove`.
84
+ */
85
+ export function useReminderControls(projectId, sessionId) {
86
+ const t = useTranslations('reminders');
87
+ const reminders = useSessionReminders(projectId, sessionId);
88
+ const [removing, setRemoving] = useState(null);
89
+ const controls = {
90
+ pending: reminders.update.isPending,
91
+ running: reminders.run.isPending,
92
+ run: (reminder) => reminders.run.mutate(reminder.id, {
93
+ onSuccess: () => successToast(t('runQueued')),
94
+ onError: (error) => errorToast(error instanceof Error ? error.message : t('runFailed')),
95
+ }),
96
+ setEnabled: (reminder, enabled) => reminders.update.mutate({ reminderId: reminder.id, enabled }, {
97
+ onSuccess: () => successToast(enabled ? t('resumed') : t('paused')),
98
+ onError: (error) => errorToast(error instanceof Error ? error.message : t('updateFailed')),
99
+ }),
100
+ requestRemove: setRemoving,
101
+ };
102
+ const confirm = (_jsx(ConfirmDialog, { open: !!removing, onOpenChange: (next) => !next && setRemoving(null), title: t('removeTitle'), description: t('removeDescription'), confirmLabel: t('remove'), confirmVariant: "destructive", isPending: reminders.remove.isPending, onConfirm: () => removing &&
103
+ reminders.remove.mutate(removing.id, {
104
+ onSuccess: () => {
105
+ successToast(t('removed'));
106
+ setRemoving(null);
107
+ },
108
+ onError: (error) => errorToast(error instanceof Error ? error.message : t('updateFailed')),
109
+ }) }));
110
+ return { reminders, controls, confirm };
111
+ }
112
+ /**
113
+ * A reminder row's cells, for a `REMINDER_ROW_GRID` container: the ring and
114
+ * the title share the first grid row, so the ring centres on the title line;
115
+ * the next run sits at the end of that line, the schedule under the title.
116
+ */
117
+ export const REMINDER_ROW_GRID = 'grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-x-2.5';
118
+ export function ReminderRowCells({ reminder, view, trailing, }) {
119
+ return (_jsxs(_Fragment, { children: [_jsx(CountdownRing, { share: view.share, size: 14, stroke: 2, tone: view.tone, paused: view.paused }), _jsx("span", { className: cn('truncate text-sm leading-5', view.paused ? 'text-muted-foreground' : 'text-foreground font-medium'), children: reminderTitle(reminder) }), trailing ?? (view.next ? (_jsx("span", { className: "text-muted-foreground col-start-3 row-start-1 text-xs tabular-nums pointer-coarse:hidden", children: view.next })) : null), _jsx("span", { className: "text-muted-foreground col-start-2 truncate text-xs leading-4", children: view.meta })] }));
120
+ }
@@ -1,3 +1,16 @@
1
+ /** More live reminders than this open in the side panel, not the popover. */
2
+ export declare const REMINDERS_POPOVER_MAX = 30;
3
+ /**
4
+ * The clock in `BellMark`'s badge-glow style: the glyph, then again in the
5
+ * count's colour under the bell's corner mask, so the colour reaches in from
6
+ * the corner the count sits on. Purple for active reminders, red while one's
7
+ * last run failed. With nothing active the glyph is muted and has no count.
8
+ */
9
+ export declare function ReminderMark({ count, failed: anyFailed, surface, }: {
10
+ count: number;
11
+ failed: boolean;
12
+ surface?: 'bg-background' | 'bg-sidebar';
13
+ }): import("react").JSX.Element;
1
14
  export declare function SessionRemindersIndicator({ runtimeSessionId }: {
2
15
  runtimeSessionId: string;
3
16
  }): import("react").JSX.Element | null;