@kortix/ui 0.14.5 → 0.14.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/dist/_vendor/kortix-shared.js +489 -381
  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-authority-card.js +1 -2
  12. package/dist/customize/agents/agent-detail-aside.js +15 -14
  13. package/dist/customize/agents/agent-drives-section.js +5 -6
  14. package/dist/customize/agents/agent-grant-pages.js +73 -76
  15. package/dist/customize/agents/agent-nav.prototype.d.ts +35 -0
  16. package/dist/customize/agents/agent-nav.prototype.js +95 -0
  17. package/dist/customize/agents/agent-page.js +59 -23
  18. package/dist/customize/agents/agent-people-section.js +18 -17
  19. package/dist/customize/agents/agent-triggers-section.js +6 -5
  20. package/dist/customize/agents/agents-page.js +18 -1
  21. package/dist/customize/connectors/add-mcp/add-mcp-server.js +4 -2
  22. package/dist/customize/connectors/catalog/catalog-entry.d.ts +14 -0
  23. package/dist/customize/connectors/catalog/catalog-entry.js +18 -1
  24. package/dist/customize/connectors/catalog/connector-browse.d.ts +28 -0
  25. package/dist/customize/connectors/catalog/connector-browse.js +18 -5
  26. package/dist/customize/connectors/connector-routes.d.ts +3 -1
  27. package/dist/customize/connectors/connector-routes.js +18 -0
  28. package/dist/customize/connectors/connectors-page.js +23 -4
  29. package/dist/customize/connectors/detail/app-page.js +19 -5
  30. package/dist/customize/connectors/detail/connector-advanced-tools.js +4 -6
  31. package/dist/customize/connectors/detail/connector-modal.d.ts +10 -13
  32. package/dist/customize/connectors/detail/connector-modal.js +18 -101
  33. package/dist/customize/connectors/detail/connector-notice.js +6 -2
  34. package/dist/customize/connectors/detail/connector-page.d.ts +30 -0
  35. package/dist/customize/connectors/detail/connector-page.js +26 -13
  36. package/dist/customize/providers/provider-accordion.js +2 -1
  37. package/dist/customize/providers/provider-connect.js +2 -1
  38. package/dist/customize/sections/component/telegram-channel-row.js +1 -1
  39. package/dist/customize/sections/connector-connection-modal.js +11 -9
  40. package/dist/customize/sections/connectors-view.js +11 -13
  41. package/dist/customize/sections/llm-provider/custom-provider-form.js +24 -7
  42. package/dist/customize/sections/llm-provider/custom-provider-panel.js +44 -8
  43. package/dist/customize/sections/llm-provider/types.d.ts +3 -0
  44. package/dist/customize/sections/llm-provider/utils.js +2 -2
  45. package/dist/customize/sections/view/agent-editor-access-fields.d.ts +9 -16
  46. package/dist/customize/sections/view/agent-editor-access-fields.js +30 -30
  47. package/dist/customize/sections/view/agent-editor-basics-fields.js +3 -10
  48. package/dist/customize/sections/view/agent-editor-primitives.d.ts +28 -10
  49. package/dist/customize/sections/view/agent-editor-primitives.js +32 -19
  50. package/dist/customize/sections/view/agent-editor.js +3 -3
  51. package/dist/customize/sections/view/gateway/gateway-routing.js +18 -21
  52. package/dist/customize/sections/view/grant-mode-field.d.ts +2 -5
  53. package/dist/customize/sections/view/grant-mode-field.js +10 -18
  54. package/dist/customize/sections/view/permission-editor.js +11 -8
  55. package/dist/customize/sections/view/secrets-view.js +2 -1
  56. package/dist/customize/settings/rail-copy-context.js +5 -3
  57. package/dist/customize/settings/tabs/general-tab.d.ts +9 -2
  58. package/dist/customize/settings/tabs/general-tab.js +33 -11
  59. package/dist/customize/settings/tabs/sandbox-template-form.js +9 -12
  60. package/dist/customize/settings/tabs/transfer-workspace-dialog.d.ts +4 -0
  61. package/dist/customize/settings/tabs/transfer-workspace-dialog.js +82 -0
  62. package/dist/customize/shared/capability-tabs.js +2 -1
  63. package/dist/customize/skills/skills-page.js +3 -5
  64. package/dist/customize/triggers/schedule/event-trigger-copy.js +3 -2
  65. package/dist/customize/triggers/schedule/schedule-builder.js +7 -4
  66. package/dist/customize/triggers/schedule/trigger-composer.js +5 -2
  67. package/dist/customize/triggers/schedule/when-event.js +1 -1
  68. package/dist/diff/diff-view.js +9 -10
  69. package/dist/files/editor/code-editor.js +2 -3
  70. package/dist/files/project/api/runtime-files.js +3 -2
  71. package/dist/files/project/components/change-request-detail-dialog.d.ts +3 -1
  72. package/dist/files/project/components/change-request-detail-dialog.js +3 -5
  73. package/dist/files/project/components/change-request-status-badge.d.ts +12 -0
  74. package/dist/files/project/components/change-request-status-badge.js +27 -0
  75. package/dist/files/project/components/change-requests-panel.js +1 -1
  76. package/dist/files/project/components/drive-explorer.js +2 -1
  77. package/dist/files/project/components/drive-grid-view.js +11 -7
  78. package/dist/files/project/components/drive-list-view.js +4 -4
  79. package/dist/files/project/components/file-breadcrumbs.js +1 -1
  80. package/dist/files/project/components/file-explorer-page.js +1 -1
  81. package/dist/files/project/components/file-history-popover.js +1 -6
  82. package/dist/files/project/components/file-search.js +6 -1
  83. package/dist/files/project/components/open-change-request-dialog.js +2 -1
  84. package/dist/files/project/components/version-selector-logic.d.ts +11 -0
  85. package/dist/files/project/components/version-selector-logic.js +26 -0
  86. package/dist/files/project/components/version-selector.js +11 -20
  87. package/dist/files/project/file-source.js +18 -1
  88. package/dist/files/project/hooks/use-file-content.js +2 -0
  89. package/dist/files/project/hooks/use-server-health.js +17 -15
  90. package/dist/files/renderers/docx/docx-viewer.js +0 -5
  91. package/dist/files/renderers/image-renderer.js +6 -24
  92. package/dist/files/renderers/pdf/pdf-viewer.js +1 -1
  93. package/dist/files/renderers/presentation/FullScreenPresentationViewer.js +2 -11
  94. package/dist/files/renderers/show-content-renderer.js +1 -1
  95. package/dist/files/renderers/sqlite-renderer.js +8 -3
  96. package/dist/files/renderers/xlsx/xlsx-viewer.js +15 -16
  97. package/dist/files/tree/components/file-tree-item.js +1 -1
  98. package/dist/files/viewer/file-header.js +1 -1
  99. package/dist/files/viewer/file-preview-modal.d.ts +1 -1
  100. package/dist/files/viewer/file-preview-modal.js +13 -3
  101. package/dist/files/viewer/file-source.d.ts +3 -1
  102. package/dist/files/viewer/use-file-content-state.js +27 -8
  103. package/dist/files/viewer/viewer-actions.js +2 -2
  104. package/dist/i18n/en.d.ts +355 -12
  105. package/dist/i18n/en.js +360 -17
  106. package/dist/internal/desktop/desktop-back-button.js +5 -3
  107. package/dist/internal/files/types.d.ts +2 -0
  108. package/dist/internal/goals/goal-meta.d.ts +30 -0
  109. package/dist/internal/goals/goal-meta.js +55 -0
  110. package/dist/internal/hooks/use-auto-scroll.js +5 -3
  111. package/dist/internal/lib/query-client-singleton.d.ts +9 -3
  112. package/dist/internal/lib/query-client-singleton.js +18 -12
  113. package/dist/internal/notifications/notification-rows.js +2 -1
  114. package/dist/internal/outcomes/outcome-types.d.ts +5 -0
  115. package/dist/internal/share/session-shares-modal.js +3 -7
  116. package/dist/internal/stores/kortix-computer-store.js +14 -2
  117. package/dist/internal/stores/session-hover-store.d.ts +32 -0
  118. package/dist/internal/stores/session-hover-store.js +38 -0
  119. package/dist/internal/stores/sidebar-nav-store.d.ts +1 -1
  120. package/dist/internal/stores/sidebar-nav-store.js +3 -1
  121. package/dist/lib/routes.d.ts +2 -0
  122. package/dist/lib/routes.js +1 -0
  123. package/dist/markdown/code/inline-code.js +8 -0
  124. package/dist/markdown/code/output-paths-context.d.ts +18 -0
  125. package/dist/markdown/code/output-paths-context.js +35 -0
  126. package/dist/markdown/genui/components/charts.js +6 -5
  127. package/dist/primitives/map.js +2 -1
  128. package/dist/primitives/preview-image.js +4 -2
  129. package/dist/primitives/settings-section-header.d.ts +1 -1
  130. package/dist/primitives/textarea.js +1 -1
  131. package/dist/primitives/typed-title.js +12 -14
  132. package/dist/primitives/typing-animation.js +4 -2
  133. package/dist/session/composer/agent-selector.js +6 -1
  134. package/dist/session/composer/attachment-tile.d.ts +0 -2
  135. package/dist/session/composer/attachment-tile.js +0 -8
  136. package/dist/session/composer/clipboard-files.d.ts +2 -1
  137. package/dist/session/composer/composer-chat-input.js +5 -3
  138. package/dist/session/composer/composer-draft-recovery.d.ts +1 -2
  139. package/dist/session/composer/composer-draft-recovery.js +0 -13
  140. package/dist/session/composer/composer-logic.js +8 -7
  141. package/dist/session/composer/context-ring.d.ts +1 -1
  142. package/dist/session/composer/context-ring.js +2 -2
  143. package/dist/session/composer/context-usage.d.ts +3 -6
  144. package/dist/session/composer/context-usage.js +3 -6
  145. package/dist/session/composer/draft/composer-draft.js +4 -4
  146. package/dist/session/composer/inbox-row-claims.d.ts +2 -2
  147. package/dist/session/composer/inbox-row-claims.js +1 -1
  148. package/dist/session/composer/pasted-text.js +3 -2
  149. package/dist/session/composer/queue-projection.d.ts +3 -2
  150. package/dist/session/composer/queued-prompt-edit.d.ts +1 -1
  151. package/dist/session/composer/reasoning-effort-selector.d.ts +2 -1
  152. package/dist/session/composer/session-composer-readiness.d.ts +7 -22
  153. package/dist/session/composer/session-composer-readiness.js +12 -40
  154. package/dist/session/composer/stores/queued-draft-store.js +3 -2
  155. package/dist/session/composer/token-progress.d.ts +1 -1
  156. package/dist/session/composer/token-progress.js +2 -2
  157. package/dist/session/header/reminder-parts.d.ts +11 -2
  158. package/dist/session/header/reminder-parts.js +9 -4
  159. package/dist/session/header/session-goal-indicator.d.ts +1 -0
  160. package/dist/session/header/session-goal-indicator.js +41 -0
  161. package/dist/session/header/session-site-header.js +2 -1
  162. package/dist/session/media/sandbox-url-detector.js +0 -7
  163. package/dist/session/outcomes/change-request-outcomes.js +24 -3
  164. package/dist/session/overrides/provider-secret-pool-editor.js +2 -1
  165. package/dist/session/panel/advanced/advanced-panel.js +3 -7
  166. package/dist/session/panel/easy/app-preview.js +12 -2
  167. package/dist/session/panel/easy/easy-panel-logic.d.ts +1 -1
  168. package/dist/session/panel/easy/easy-panel-logic.js +1 -1
  169. package/dist/session/panel/easy/outputs-card.js +2 -1
  170. package/dist/session/panel/easy/panel-card.js +5 -3
  171. package/dist/session/panel/easy/preview-load.d.ts +14 -0
  172. package/dist/session/panel/easy/preview-load.js +15 -0
  173. package/dist/session/panel/easy/step-detail-body.js +2 -7
  174. package/dist/session/panel/session-action-panel-column.js +11 -1
  175. package/dist/session/panel/session-audit-shared.d.ts +0 -4
  176. package/dist/session/panel/session-audit-shared.js +1 -1
  177. package/dist/session/panel/session-changes-shared.d.ts +2 -1
  178. package/dist/session/panel/session-panel-provider.js +6 -2
  179. package/dist/session/panel/shared/use-panel-derivations.js +6 -4
  180. package/dist/session/panel/use-session-panel-layout.js +7 -5
  181. package/dist/session/print/session-print-header.js +9 -8
  182. package/dist/session/prompts/session-permission-prompt.js +6 -3
  183. package/dist/session/status/provisioning-failure.d.ts +2 -1
  184. package/dist/session/status/session-error-banner.js +8 -6
  185. package/dist/session/status/session-starting-loader.d.ts +24 -31
  186. package/dist/session/status/session-starting-loader.js +32 -81
  187. package/dist/session/thread/chat-minimap-items.d.ts +4 -4
  188. package/dist/session/thread/first-prompt-handover.d.ts +3 -2
  189. package/dist/session/thread/message-parsing.d.ts +3 -3
  190. package/dist/session/thread/session-chat.js +15 -19
  191. package/dist/session/thread/session-history-scroll.d.ts +2 -1
  192. package/dist/session/thread/session-history.js +3 -1
  193. package/dist/session/thread/session-thread.js +1 -1
  194. package/dist/session/thread/transcript.js +13 -7
  195. package/dist/session/tool/shared/file-list.js +19 -2
  196. package/dist/session/tool/shared/infrastructure-contexts.d.ts +7 -0
  197. package/dist/session/tool/shared/infrastructure-contexts.js +7 -0
  198. package/dist/session/tool/shared/infrastructure-output.js +9 -5
  199. package/dist/session/tool/shared/infrastructure-row-header.js +9 -1
  200. package/dist/session/tool/shared/infrastructure-rows.js +7 -5
  201. package/dist/session/tool/tools/bash-tool.js +10 -6
  202. package/dist/session/tool/tools/web-search-tool.js +25 -3
  203. package/dist/session/turn/recovered-failures.d.ts +8 -0
  204. package/dist/session/turn/recovered-failures.js +32 -0
  205. package/dist/session/turn/streaming-cadence.js +5 -8
  206. package/dist/styles.css +1 -1
  207. package/dist/terminal/pty-connection.d.ts +5 -4
  208. package/dist/terminal/session-terminal-panel.js +3 -5
  209. package/dist/theme/theme.js +2 -1
  210. package/dist/workspace/index.d.ts +1 -0
  211. package/dist/workspace/index.js +1 -0
  212. package/dist/workspace/projects/modal/github-import-pickers.js +7 -6
  213. package/dist/workspace/review/review-center.js +13 -10
  214. package/dist/workspace/saved-session-skeleton-shape.d.ts +4 -3
  215. package/dist/workspace/saved-session-skeleton.d.ts +5 -1
  216. package/dist/workspace/saved-session-skeleton.js +5 -4
  217. package/dist/workspace/session-workspace.js +9 -14
  218. package/dist/workspace/sessions/deleted-session-row.js +5 -2
  219. package/dist/workspace/sidebar/footer/project-computer-nav.js +6 -4
  220. package/dist/workspace/sidebar/footer/project-goals-nav.d.ts +6 -0
  221. package/dist/workspace/sidebar/footer/project-goals-nav.js +26 -0
  222. package/dist/workspace/sidebar/footer/project-mcp-nav.js +6 -2
  223. package/dist/workspace/sidebar/modal/rename-session-modal.js +8 -3
  224. package/dist/workspace/sidebar/modal/session-embed-section.d.ts +25 -0
  225. package/dist/workspace/sidebar/modal/session-embed-section.js +71 -0
  226. package/dist/workspace/sidebar/modal/share-session-modal.js +2 -2
  227. package/dist/workspace/sidebar/nav-row-meta.js +14 -2
  228. package/dist/workspace/sidebar/project-nav-items.js +3 -0
  229. package/dist/workspace/sidebar/project-session-list.js +12 -3
  230. package/dist/workspace/sidebar/session-brief-hover-card.js +5 -8
  231. package/package.json +4 -4
  232. package/skills/kortix-ui/references/modules.md +2 -0
  233. package/dist/session/status/use-readiness-settling.d.ts +0 -18
  234. package/dist/session/status/use-readiness-settling.js +0 -43
  235. package/dist/workspace/sidebar/modal/session-public-link-section.d.ts +0 -13
  236. package/dist/workspace/sidebar/modal/session-public-link-section.js +0 -66
@@ -86,9 +86,11 @@ export function diffAgentGrants(current, next) {
86
86
  if (next.mode === 'all')
87
87
  return { add: [], remove: [...currentIds] };
88
88
  const nextIds = next.ids;
89
+ const currentSet = new Set(currentIds);
90
+ const nextSet = new Set(nextIds);
89
91
  return {
90
- add: nextIds.filter((id) => !currentIds.includes(id)),
91
- remove: currentIds.filter((id) => !nextIds.includes(id)),
92
+ add: nextIds.filter((id) => !currentSet.has(id)),
93
+ remove: currentIds.filter((id) => !nextSet.has(id)),
92
94
  };
93
95
  }
94
96
  /**
@@ -339,10 +341,11 @@ function PrincipalAccessDialog({ open, onOpenChange, accountId, scope, mode, acc
339
341
  ...contract('inventory'),
340
342
  });
341
343
  const projectAgents = useMemo(() => resourceGrantsQuery.data?.resources.agents ?? [], [resourceGrantsQuery.data]);
344
+ const selectedAgentIdSet = useMemo(() => new Set(agents.ids), [agents.ids]);
342
345
  const selectedAgentDeclares = useMemo(() => {
343
346
  if (agents.mode !== 'subset' || agents.ids.length === 0)
344
347
  return null;
345
- const picked = projectAgents.filter((a) => agents.ids.includes(a.id));
348
+ const picked = projectAgents.filter((a) => selectedAgentIdSet.has(a.id));
346
349
  if (picked.length === 0)
347
350
  return null;
348
351
  const union = (key) => {
@@ -351,7 +354,7 @@ function PrincipalAccessDialog({ open, onOpenChange, accountId, scope, mode, acc
351
354
  return [...new Set(picked.flatMap((a) => a.declares?.[key] ?? []))];
352
355
  };
353
356
  return { secrets: union('secrets'), connectors: union('connectors') };
354
- }, [agents, projectAgents]);
357
+ }, [agents, projectAgents, selectedAgentIdSet]);
355
358
  // ── Expiry ────────────────────────────────────────────────────────────
356
359
  // `expires_at` is a column on every assignment, so every grant this dialog
357
360
  // writes can carry one. It used to be offered only where the underlying store
@@ -879,7 +882,7 @@ function PrincipalAccessDialog({ open, onOpenChange, accountId, scope, mode, acc
879
882
  ? ['member', 'admin']
880
883
  : undefined }), scope.kind === 'project' && principals.groupIds.length > 0 ? (_jsx(FieldDescription, { children: tI18nComplete.raw('text237f1a28cf06') })) : null] })) : null, scope.kind === 'project' && everyoneSelected ? (_jsx(InfoBanner, { tone: "neutral", icon: UsersThreeIcon, children: tSharing('everyoneRoleNote', { project: scope.projectName }) })) : null, scope.kind === 'project' && showAgentCeilingNote ? (_jsx(InfoBanner, { tone: "neutral", icon: RobotIcon, title: tAgents('ceilingNoteTitle'), children: _jsx("span", { "data-testid": "agent-ceiling-note", children: tAgents('ceilingNote') }) })) : null, showAgents ? (_jsxs(Field, { className: "gap-1.5", children: [_jsx(FieldLabel, { children: tI18nComplete.raw('text279b44d2ab4b') }), resourceGrantsQuery.isError ? (_jsx(InfoBanner, { tone: "destructive", action: _jsx(Button, { size: "sm", variant: "outline", onClick: () => void resourceGrantsQuery.refetch(), children: tCommon('retry') }), children: resourceGrantsQuery.error.message })) : resourceGrantsQuery.isLoading ? (_jsx(Skeleton, { className: "h-6 w-full rounded-md" })) : null, _jsx(Tabs, { value: agents.mode, onValueChange: (next) => setAgents(next === 'all' ? ALL_AGENTS : { mode: 'subset', ids: agents.ids }), children: _jsxs(TabsListCompact, { children: [_jsx(TabsTriggerCompact, { value: "all", children: tI18nComplete.raw('text54c32d3e2cfa') }), _jsx(TabsTriggerCompact, { value: "subset", children: tI18nComplete.raw('textb080141d6840') })] }) }), agents.mode === 'all' ? (_jsx(FieldDescription, { children: projectAgents.length === 0
881
884
  ? tI18nComplete.raw('text7bf9d07dcb99')
882
- : tI18nComplete('textc5bb9fda9711', { value0: projectAgents.length }) })) : null, agents.mode === 'subset' ? (resourceGrantsQuery.isLoading ? (_jsx(Skeleton, { className: "h-24 w-full rounded-md" })) : projectAgents.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-xs", children: tI18nComplete.raw('text7bf9d07dcb99') })) : (_jsx("div", { className: "border-border max-h-40 overflow-y-auto rounded-md border p-1", children: projectAgents.map((agent) => (_jsx(Checkbox, { label: agent.name, checked: agents.ids.includes(agent.id), disabled: pending, onCheckedChange: () => setAgents((prev) => ({
885
+ : tI18nComplete('textc5bb9fda9711', { value0: projectAgents.length }) })) : null, agents.mode === 'subset' ? (resourceGrantsQuery.isLoading ? (_jsx(Skeleton, { className: "h-24 w-full rounded-md" })) : projectAgents.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-xs", children: tI18nComplete.raw('text7bf9d07dcb99') })) : (_jsx("div", { className: "border-border max-h-40 overflow-y-auto rounded-md border p-1", children: projectAgents.map((agent) => (_jsx(Checkbox, { label: agent.name, checked: selectedAgentIdSet.has(agent.id), disabled: pending, onCheckedChange: () => setAgents((prev) => ({
883
886
  mode: 'subset',
884
887
  ids: prev.ids.includes(agent.id)
885
888
  ? prev.ids.filter((x) => x !== agent.id)
@@ -13,7 +13,7 @@ import { errorToast, successToast } from '../../primitives/toast.js';
13
13
  import { useCopy } from '../../internal/hooks/use-copy.js';
14
14
  import { cn } from '../../internal/lib/utils.js';
15
15
  import { CheckIcon, CopyIcon } from '@phosphor-icons/react';
16
- import { AnimatePresence, motion } from 'motion/react';
16
+ import { AnimatePresence, m } from 'motion/react';
17
17
  /**
18
18
  * Imperative copy for call sites that are not a `CopyRow` (a kebab item, a
19
19
  * toast action button). Same toast pair the three private copies used.
@@ -37,5 +37,5 @@ export function CopyRow({ value, label, display, successMessage, actions, classN
37
37
  const copyLabel = copied
38
38
  ? tI18nComplete.raw('text8d525e5f158b')
39
39
  : tI18nComplete.raw('texte21f935f11d7');
40
- return (_jsxs("div", { className: cn('space-y-1.5', className), children: [label ? _jsx("span", { className: "text-muted-foreground text-xs font-medium", children: label }) : null, _jsxs("div", { className: "bg-popover flex items-center gap-2 rounded-md border px-3 py-2", children: [_jsx("code", { className: "text-foreground min-w-0 flex-1 truncate font-mono text-xs", children: display ?? value }), actions, _jsx(Hint, { label: copyLabel, children: _jsx(Button, { type: "button", variant: "ghost", size: "icon-xs", "aria-label": copyLabel, onClick: () => void copy(value), className: "text-muted-foreground hover:text-foreground shrink-0", children: _jsx("span", { className: "relative inline-flex size-3.5 items-center justify-center", children: _jsx(AnimatePresence, { initial: false, mode: "popLayout", children: _jsx(motion.span, { initial: { scale: 0.25, opacity: 0, filter: 'blur(4px)' }, animate: { scale: 1, opacity: 1, filter: 'blur(0px)' }, exit: { scale: 0.25, opacity: 0, filter: 'blur(4px)' }, transition: { type: 'spring', duration: 0.3, bounce: 0 }, className: "absolute inset-0 inline-flex items-center justify-center", children: copied ? (_jsx(CheckIcon, { className: "text-kortix-green size-3.5" })) : (_jsx(CopyIcon, { className: "size-3.5" })) }, copied ? 'check' : 'copy') }) }) }) })] })] }));
40
+ return (_jsxs("div", { className: cn('space-y-1.5', className), children: [label ? _jsx("span", { className: "text-muted-foreground text-xs font-medium", children: label }) : null, _jsxs("div", { className: "bg-popover flex items-center gap-2 rounded-md border px-3 py-2", children: [_jsx("code", { className: "text-foreground min-w-0 flex-1 truncate font-mono text-xs", children: display ?? value }), actions, _jsx(Hint, { label: copyLabel, children: _jsx(Button, { type: "button", variant: "ghost", size: "icon-xs", "aria-label": copyLabel, onClick: () => void copy(value), className: "text-muted-foreground hover:text-foreground shrink-0", children: _jsx("span", { className: "relative inline-flex size-3.5 items-center justify-center", children: _jsx(AnimatePresence, { initial: false, mode: "popLayout", children: _jsx(m.span, { initial: { scale: 0.25, opacity: 0, filter: 'blur(4px)' }, animate: { scale: 1, opacity: 1, filter: 'blur(0px)' }, exit: { scale: 0.25, opacity: 0, filter: 'blur(4px)' }, transition: { type: 'spring', duration: 0.3, bounce: 0 }, className: "absolute inset-0 inline-flex items-center justify-center", children: copied ? (_jsx(CheckIcon, { className: "text-kortix-green size-3.5" })) : (_jsx(CopyIcon, { className: "size-3.5" })) }, copied ? 'check' : 'copy') }) }) }) })] })] }));
41
41
  }
@@ -42,6 +42,7 @@ export function SharingPicker({ projectId, value, onChange, copy, showHeading =
42
42
  const offerMembers = !hideMembers && (accountApiEnabled || value.mode === 'members');
43
43
  return (_jsxs("div", { className: "space-y-3", children: [showHeading && _jsx(Label, { children: c.heading }), _jsxs(RadioGroup, { value: value.mode, onValueChange: (v) => onChange({ ...value, mode: v }), className: "space-y-2", children: [_jsx(ShareOption, { value: "project", label: c.project.label, desc: c.project.desc, disabled: isDisabled('project') }), _jsx(ShareOption, { value: "private", label: c.private.label, desc: c.private.desc, disabled: isDisabled('private') }), offerMembers && (_jsx(ShareOption, { value: "members", label: c.members.label, desc: c.members.desc, disabled: isDisabled('members') }))] }), offerMembers && value.mode === 'members' && (_jsx(SubjectPicker, { projectId: projectId, memberIds: value.memberIds, groupIds: value.groupIds, onChange: (memberIds, groupIds) => onChange({ ...value, memberIds, groupIds }) })), hideMembers && !legacyMembers && (_jsxs("p", { className: "text-muted-foreground text-xs leading-relaxed", children: [tI18nComplete.raw('text558b36e065df'), ' ', _jsx("span", { className: "text-foreground/80 font-medium", children: tI18nComplete.raw('textd4f0bc5a29de') }), ' ', tI18nComplete.raw('text3a71ebb2d593')] })), legacyMembers && (_jsx("p", { className: "text-xs leading-relaxed text-amber-600 dark:text-amber-400", children: tI18nComplete.raw('text64f4c4bd39c9') }))] }));
44
44
  }
45
+ const NO_INVITE_EMAILS = [];
45
46
  /**
46
47
  * Legacy adapter over {@link PrincipalPicker}, kept ONLY for the
47
48
  * non-access callers of this module (`features/apps/apps-view.tsx` and
@@ -52,7 +53,7 @@ export function SharingPicker({ projectId, value, onChange, copy, showHeading =
52
53
  * @deprecated Use `PrincipalPicker` from
53
54
  * `@/features/workspace/shared/access`.
54
55
  */
55
- export function SubjectPicker({ projectId, accountId, memberIds, groupIds, inviteEmails = [], onChange, allowInvite = false, kinds = ['member', 'group'], excludeUserIds, emptyLabel = 'No members or groups in this project yet.', allExcludedLabel = 'Everyone is already added.', }) {
56
+ export function SubjectPicker({ projectId, accountId, memberIds, groupIds, inviteEmails = NO_INVITE_EMAILS, onChange, allowInvite = false, kinds = ['member', 'group'], excludeUserIds, emptyLabel = 'No members or groups in this project yet.', allExcludedLabel = 'Everyone is already added.', }) {
56
57
  const value = useMemo(() => ({ memberIds, groupIds, inviteEmails }), [memberIds, groupIds, inviteEmails]);
57
58
  const scope = projectId
58
59
  ? { kind: 'project', projectId }
@@ -11,7 +11,7 @@
11
11
  import { isKortixAppUrl } from '../apps/kortix-app-url.js';
12
12
  import { APP_ACCESS_PARAM, withoutAppAccessToken } from '../internal/lib/utils/app-access-token.js';
13
13
  import { useAppAccess, useProjectApps } from '@kortix/sdk/react';
14
- import { useRef } from 'react';
14
+ import { useLayoutEffect, useRef } from 'react';
15
15
  import { appCan } from '../apps/app-shared.js';
16
16
  export { withoutAppAccessToken };
17
17
  function hostOf(url) {
@@ -72,8 +72,10 @@ export function useAppInBrowser(projectId, url) {
72
72
  }
73
73
  }
74
74
  const pinned = useRef(null);
75
- if (url && resolved && pinned.current?.url !== url)
76
- pinned.current = { url, src: resolved };
77
75
  const src = url && pinned.current?.url === url ? pinned.current.src : resolved;
76
+ useLayoutEffect(() => {
77
+ if (url && src && pinned.current?.url !== url)
78
+ pinned.current = { url, src };
79
+ });
78
80
  return { app, apps: apps.data ?? [], src };
79
81
  }
@@ -23,7 +23,7 @@ import { buildWebProxyUrl, isExternalUrl, isWebProxyUrl, normalizeExternalInput,
23
23
  import { useBrowserRecentsStore } from '../internal/stores/browser-recents-store.js';
24
24
  import { useTabStore } from '../internal/stores/tab-store.js';
25
25
  import { WarningIcon as AlertTriangle, ArrowSquareOutIcon, GlobeIcon as Globe, LinkSimpleIcon as Link2, DotsThreeIcon as MoreHorizontal, ArrowClockwiseIcon as RefreshCw, GearSixIcon as Settings2, } from '@phosphor-icons/react';
26
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
26
+ import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
27
27
  import { BrowserLanding } from './browser-landing.js';
28
28
  import { PreviewLoadingOverlay, SandboxAddressBar } from './sandbox-browser-chrome.js';
29
29
  function normalizePreviewLabel(value, fallback) {
@@ -34,6 +34,7 @@ function normalizePreviewLabel(value, fallback) {
34
34
  return fallback;
35
35
  return trimmed;
36
36
  }
37
+ const subscribeNoop = () => () => { };
37
38
  /**
38
39
  * Preview tab content — renders a proxied sandbox URL in an iframe
39
40
  * with a browser-like toolbar: editable address bar, refresh, back/forward, open externally.
@@ -56,8 +57,7 @@ export function BrowserPanel({ tabId, projectId, projectSessionId }) {
56
57
  const loadTimeoutRef = useRef(null);
57
58
  // Recents come from a persisted store — render them only after mount so the
58
59
  // server and first client render agree.
59
- const [mounted, setMounted] = useState(false);
60
- useEffect(() => setMounted(true), []);
60
+ const mounted = useSyncExternalStore(subscribeNoop, () => true, () => false);
61
61
  // Extract metadata from tab
62
62
  const rawPreviewUrl = tab?.metadata?.url || '';
63
63
  const port = tab?.metadata?.port || 0;
@@ -199,7 +199,7 @@ export function BrowserPanel({ tabId, projectId, projectSessionId }) {
199
199
  });
200
200
  pushHistory(newProxyUrl);
201
201
  handleRefresh();
202
- }, [subdomainOpts, rewritePortPath, tabId, updateTabMetadata, pushHistory, handleRefresh]);
202
+ }, [subdomainOpts, rewritePortPath, tabId, appPreviewTitle, updateTabMetadata, pushHistory, handleRefresh]);
203
203
  const canGoBack = historyIndex > 0;
204
204
  const canGoForward = historyIndex < history.length - 1;
205
205
  /** Walk the history stack in either direction; the two directions were two
@@ -248,7 +248,7 @@ export function BrowserPanel({ tabId, projectId, projectSessionId }) {
248
248
  handleRefresh();
249
249
  }
250
250
  }
251
- }, [canGoBack, canGoForward, historyIndex, history, tabId, updateTabMetadata, handleRefresh]);
251
+ }, [canGoBack, canGoForward, historyIndex, history, tabId, appPreviewTitle, updateTabMetadata, handleRefresh]);
252
252
  /** Home: the landing (Apps + recents). An empty url is what renders it. */
253
253
  const handleHome = useCallback(() => {
254
254
  updateTabMetadata({
@@ -290,7 +290,7 @@ export function BrowserPanel({ tabId, projectId, projectSessionId }) {
290
290
  path,
291
291
  },
292
292
  };
293
- }, [fullUrl, isExternalBrowsing, originalUrl, port, tab?.metadata?.path, tab?.title]);
293
+ }, [fullUrl, isExternalBrowsing, originalUrl, port, tab?.metadata?.path, tab?.title, appPreviewTitle]);
294
294
  const hasPreview = !!previewUrl || hostPreview.failed;
295
295
  const emptyState = (_jsx(EmptyState, { icon: Globe, className: "h-full", title: tHardcodedUi.raw('autoComponentsTabsPreviewTabContentJsxTextPreviewBrowser8136da05'), description: _jsxs(_Fragment, { children: [tHardcodedUi.raw('autoComponentsTabsPreviewTabContentJsxTextOpenAnAppda305669'), ' ', _jsx("span", { className: "text-foreground/80 font-mono", children: "3000" }), ' ', tHardcodedUi.raw('autoComponentsTabsPreviewTabContentJsxTextIfYouKnow6745fa88')] }) }));
296
296
  // Copy-public-link action, surfaced from the "⋯" overflow menu.
@@ -64,6 +64,9 @@ export declare function SandboxAddressBar({ displayValue, hasPreview, isLoading,
64
64
  * Cross-origin iframes frequently never fire onLoad, so neither surface may
65
65
  * trust the event alone — the parent decides when to show and dismiss this.
66
66
  */
67
- export declare function PreviewLoadingOverlay({ label }: {
67
+ export declare function PreviewLoadingOverlay({ label, detail, action, }: {
68
68
  label: string;
69
+ /** A second line once the load is slow: why, and the way out. */
70
+ detail?: string;
71
+ action?: React.ReactNode;
69
72
  }): import("react").JSX.Element;
@@ -80,6 +80,7 @@ export function parseAddressInput(value) {
80
80
  return null;
81
81
  return toInternalUrl(parsed.port, parsed.path);
82
82
  }
83
+ const NO_SUGGESTIONS = [];
83
84
  /**
84
85
  * The back / forward buttons and the home / address / reload group every
85
86
  * sandbox preview surface renders, with the hostname highlighted at rest. The bar
@@ -88,7 +89,7 @@ export function parseAddressInput(value) {
88
89
  * controls around it (`BrowserPanel`'s overflow menu, `AppPreview`'s viewer
89
90
  * actions and close) — the component is a fragment, so it slots between them.
90
91
  */
91
- export function SandboxAddressBar({ displayValue, hasPreview, isLoading, canGoBack, canGoForward, onBack, onForward, onReload, onHome, onNavigate, suggestions = [], placeholder, ariaLabel, inputRef, resetOnEscape = true, trailing, }) {
92
+ export function SandboxAddressBar({ displayValue, hasPreview, isLoading, canGoBack, canGoForward, onBack, onForward, onReload, onHome, onNavigate, suggestions = NO_SUGGESTIONS, placeholder, ariaLabel, inputRef, resetOnEscape = true, trailing, }) {
92
93
  const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
93
94
  const [addressValue, setAddressValue] = useState(displayValue);
94
95
  const [isEditing, setIsEditing] = useState(false);
@@ -144,6 +145,6 @@ export function SandboxAddressBar({ displayValue, hasPreview, isLoading, canGoBa
144
145
  * Cross-origin iframes frequently never fire onLoad, so neither surface may
145
146
  * trust the event alone — the parent decides when to show and dismiss this.
146
147
  */
147
- export function PreviewLoadingOverlay({ label }) {
148
- return (_jsx("div", { className: "bg-background/80 absolute inset-0 z-10 flex items-center justify-center", children: _jsxs("div", { className: "text-muted-foreground flex flex-col items-center gap-2", children: [_jsx(Loading, { className: "size-4" }), _jsx("p", { className: "text-xs", children: label })] }) }));
148
+ export function PreviewLoadingOverlay({ label, detail, action, }) {
149
+ return (_jsx("div", { className: "bg-background/80 absolute inset-0 z-10 flex items-center justify-center", children: _jsxs("div", { className: "text-muted-foreground flex max-w-xs flex-col items-center gap-2 px-4 text-center", children: [_jsx(Loading, { className: "size-4" }), _jsx("p", { className: "text-xs", children: label }), detail && _jsx("p", { className: "text-xs text-pretty", children: detail }), action] }) }));
149
150
  }
@@ -0,0 +1,20 @@
1
+ import type { ProjectConfigSummary } from '@kortix/sdk';
2
+ type AgentScope = NonNullable<ProjectConfigSummary['agents'][number]['scope']>;
3
+ /** One grant on the card: everything (`'all'`) or how many are listed. */
4
+ export interface AgentAccessPart {
5
+ kind: 'connectors' | 'secrets' | 'actions';
6
+ value: 'all' | number;
7
+ }
8
+ /**
9
+ * What an agent's configuration grants, for its card. The card used to show
10
+ * only the agent's own description, and the starter's says "full tool access"
11
+ * whatever the configuration grants (KRTX-3025). Null for an agent that
12
+ * kortix.yaml does not govern: there is nothing to summarize.
13
+ */
14
+ export declare function agentAccess(scope: AgentScope | undefined): {
15
+ kind: 'full';
16
+ } | {
17
+ kind: 'scoped';
18
+ parts: AgentAccessPart[];
19
+ } | null;
20
+ export {};
@@ -0,0 +1,17 @@
1
+ /**
2
+ * What an agent's configuration grants, for its card. The card used to show
3
+ * only the agent's own description, and the starter's says "full tool access"
4
+ * whatever the configuration grants (KRTX-3025). Null for an agent that
5
+ * kortix.yaml does not govern: there is nothing to summarize.
6
+ */
7
+ export function agentAccess(scope) {
8
+ if (!scope)
9
+ return null;
10
+ const grant = (value) => value === 'all' ? 'all' : (value?.length ?? 0);
11
+ const parts = [
12
+ { kind: 'connectors', value: grant(scope.connectors) },
13
+ { kind: 'secrets', value: grant(scope.env) },
14
+ { kind: 'actions', value: grant(scope.kortix_permissions ?? scope.kortix_cli) },
15
+ ];
16
+ return parts.every((part) => part.value === 'all') ? { kind: 'full' } : { kind: 'scoped', parts };
17
+ }
@@ -22,7 +22,6 @@ import { useAgentAuthority, } from '../../access/access/agent-principals.js';
22
22
  import { useTranslations as useI18nTranslations } from '../../i18n/index.js';
23
23
  import { getProjectDetail } from '@kortix/sdk';
24
24
  import { contract, qk } from '@kortix/sdk/react';
25
- import { ArrowUpRightIcon } from '@phosphor-icons/react';
26
25
  import { useQuery } from '@tanstack/react-query';
27
26
  export function AgentAuthorityCard({ projectId, agentName, grant, }) {
28
27
  const t = useI18nTranslations('agentPrincipals');
@@ -39,7 +38,7 @@ export function AgentAuthorityCard({ projectId, agentName, grant, }) {
39
38
  : authority.declared.length === 0
40
39
  ? t('declaredNone')
41
40
  : t('declaredCount', { count: authority.declared.length });
42
- return (_jsx("div", { "data-testid": "agent-authority", children: _jsxs(EditorSection, { title: t('title'), description: t('description'), trailing: _jsx(Badge, { variant: "outline", size: "sm", className: "tabular-nums", children: t('effectiveCount', { count: authority.effective.length }) }), children: [_jsx(SettingRow, { label: t('kortixPermissions'), help: t('kortixPermissionsHelp', { agent: agentName }), children: _jsx("span", { className: "text-foreground block text-sm sm:text-right", children: declaredLabel }) }), _jsx(SettingRow, { label: t('ceiling'), help: t('ceilingHelp'), children: _jsxs("div", { className: "flex flex-wrap items-center gap-1.5 sm:justify-end", "data-testid": "agent-ceiling", children: [ceiling.kind === 'loading' ? (_jsx(Skeleton, { className: "h-5 w-32" })) : ceiling.kind === 'hidden' ? (_jsx("span", { className: "text-muted-foreground text-sm", children: t('ceilingHidden') })) : ceiling.kind === 'default' ? (_jsx("span", { className: "text-foreground text-sm", children: t('ceilingDefault') })) : (ceiling.roleKeys.map((key) => (_jsx(Badge, { variant: "outline", size: "sm", className: "capitalize", children: key }, key)))), accountId && ceiling.kind !== 'hidden' && ceiling.kind !== 'loading' ? (_jsx(Button, { asChild: true, variant: "ghost", size: "sm", className: "gap-1 px-2", children: _jsxs(HubLink, { to: hubTarget(accountId, { tab: 'access-projects', project: projectId }), children: [t('changeCeiling'), _jsx(ArrowUpRightIcon, { className: "size-3.5 shrink-0" })] }) })) : null] }) }), _jsx(SettingRow, { label: t('humanOnly'), help: t('humanOnlyHelp'), children: _jsx("span", { className: "text-foreground block text-sm sm:text-right", children: t('humanOnlyValue') }) }), _jsxs(SettingBlock, { label: t('effective'), help: t('effectiveHelp'), children: [_jsx("ul", { className: "flex flex-wrap gap-1", "data-testid": "agent-effective-permissions", children: authority.effective.map((permission) => (_jsx("li", { children: _jsx(Badge, { variant: "outline", size: "xs", className: "font-mono", children: permission }) }, permission))) }), authority.outsideCeiling.length > 0 ? (_jsx(DroppedList, { label: t('outsideCeiling'), permissions: authority.outsideCeiling, testId: "agent-outside-ceiling" })) : null, authority.humanOnly.length > 0 ? (_jsx(DroppedList, { label: t('droppedHumanOnly'), permissions: authority.humanOnly, testId: "agent-dropped-human-only" })) : null] })] }) }));
41
+ return (_jsx("div", { "data-testid": "agent-authority", children: _jsxs(EditorSection, { title: t('title'), description: t('description'), children: [_jsx(SettingRow, { label: t('kortixPermissions'), help: t('kortixPermissionsHelp', { agent: agentName }), children: _jsx("span", { className: "text-foreground block text-sm sm:text-right", children: declaredLabel }) }), _jsx(SettingRow, { label: t('ceiling'), help: t('ceilingHelp'), children: _jsxs("div", { className: "flex flex-wrap items-center gap-1.5 sm:justify-end", "data-testid": "agent-ceiling", children: [ceiling.kind === 'loading' ? (_jsx(Skeleton, { className: "h-5 w-32" })) : ceiling.kind === 'hidden' ? (_jsx("span", { className: "text-muted-foreground text-sm", children: t('ceilingHidden') })) : ceiling.kind === 'default' ? (_jsx("span", { className: "text-foreground text-sm", children: t('ceilingDefault') })) : (ceiling.roleKeys.map((key) => (_jsx(Badge, { variant: "outline", size: "sm", className: "capitalize", children: key }, key)))), accountId && ceiling.kind !== 'hidden' && ceiling.kind !== 'loading' ? (_jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: _jsx(HubLink, { to: hubTarget(accountId, { tab: 'access-projects', project: projectId }), children: t('changeCeiling') }) })) : null] }) }), _jsx(SettingRow, { label: t('humanOnly'), help: t('humanOnlyHelp'), children: _jsx("span", { className: "text-foreground block text-sm sm:text-right", children: t('humanOnlyValue') }) }), _jsxs(SettingBlock, { label: t('effective'), help: t('effectiveHelp'), children: [_jsx("ul", { className: "flex flex-wrap gap-1", "data-testid": "agent-effective-permissions", children: authority.effective.map((permission) => (_jsx("li", { children: _jsx(Badge, { variant: "outline", size: "xs", className: "font-mono", children: permission }) }, permission))) }), authority.outsideCeiling.length > 0 ? (_jsx(DroppedList, { label: t('outsideCeiling'), permissions: authority.outsideCeiling, testId: "agent-outside-ceiling" })) : null, authority.humanOnly.length > 0 ? (_jsx(DroppedList, { label: t('droppedHumanOnly'), permissions: authority.humanOnly, testId: "agent-dropped-human-only" })) : null] })] }) }));
43
42
  }
44
43
  function DroppedList({ label, permissions, testId, }) {
45
44
  return (_jsxs("div", { className: "space-y-1.5", "data-testid": testId, children: [_jsx("p", { className: "text-muted-foreground text-xs", children: label }), _jsx("ul", { className: "flex flex-wrap gap-1", children: permissions.map((permission) => (_jsx("li", { children: _jsx(Badge, { variant: "muted", size: "xs", className: "font-mono line-through", children: permission }) }, permission))) })] }));
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useTranslations as useI18nTranslations } from '../../i18n/index.js';
4
4
  /**
5
5
  * The v1 fallback cards of the agent page, plus the scope-checklist helpers
@@ -19,10 +19,10 @@ import { useTranslations as useI18nTranslations } from '../../i18n/index.js';
19
19
  */
20
20
  import { Badge } from '../../primitives/badge.js';
21
21
  import { Button } from '../../primitives/button.js';
22
- import { Label } from '../../primitives/label.js';
23
22
  import Loading from '../../primitives/loading.js';
24
23
  import { errorToast, successToast } from '../../primitives/toast.js';
25
24
  import { ModelSelector } from '../../session/models/model-selector.js';
25
+ import { EditorSection, SettingRow } from '../sections/view/agent-editor-primitives.js';
26
26
  import { PROJECT_ACTIONS } from '../../internal/lib/project-actions.js';
27
27
  import { useProjectCan } from '../../internal/lib/use-project-can.js';
28
28
  import { cn } from '../../internal/lib/utils.js';
@@ -51,7 +51,11 @@ export function AgentModel({ projectId, agentName }) {
51
51
  ? (models.find((x) => x.providerID === m.providerID && x.modelID === m.modelID)?.modelName ??
52
52
  `${m.providerID}/${m.modelID}`)
53
53
  : null;
54
- return (_jsxs("div", { className: "bg-popover space-y-3 rounded-md border px-4 py-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Label, { children: tI18nComplete.raw('text5e2c614c23f0') }), explicit ? (_jsx(Badge, { variant: "muted", size: "xs", children: tI18nComplete.raw('textf20c87946555') })) : null] }), canManage ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(ModelSelector, { models: models, providers: providers, selectedModel: explicit, onSelect: (m) => {
54
+ const help = explicit ? (_jsxs(_Fragment, { children: [tI18nComplete.raw('text40124896532d'), ' ', _jsx("span", { className: "text-foreground font-medium", children: nameOf(explicit) }), "."] })) : (_jsxs(_Fragment, { children: [tI18nComplete.raw('text46e3bd02feee'), resolved ? (_jsxs(_Fragment, { children: [' ', "(", _jsx("span", { className: "text-foreground font-medium", children: nameOf(resolved) }), ")"] })) : null, tI18nComplete.raw('textd5bf3036405d')] }));
55
+ return (_jsx(EditorSection, { title: tI18nComplete.raw('text5e2c614c23f0'), description: help, lead: true, children: _jsx(SettingRow, { label: tI18nComplete.raw('text34455bf1d857'), children: canManage ? (_jsxs("div", { className: "flex items-center gap-2 sm:justify-end", children: [explicit ? (_jsx(Button, { variant: "ghost", size: "sm", onClick: () => {
56
+ void defaults.clearAgentDefault(agentName);
57
+ successToast(tI18nComplete('text86781ce4c5b4', { value0: agentName }));
58
+ }, children: tI18nComplete.raw('textbc5b45ae7b60') })) : null, _jsx(ModelSelector, { models: models, providers: providers, selectedModel: explicit, onSelect: (m) => {
55
59
  if (m) {
56
60
  void defaults.setAgentDefault(agentName, m);
57
61
  successToast(`${agentName} → ${nameOf(m)}`);
@@ -59,10 +63,7 @@ export function AgentModel({ projectId, agentName }) {
59
63
  else {
60
64
  void defaults.clearAgentDefault(agentName);
61
65
  }
62
- } }), explicit ? (_jsx(Button, { variant: "ghost", size: "sm", className: "h-7 px-2 text-xs", onClick: () => {
63
- void defaults.clearAgentDefault(agentName);
64
- successToast(tI18nComplete('text86781ce4c5b4', { value0: agentName }));
65
- }, children: tI18nComplete.raw('textbc5b45ae7b60') })) : null] })) : (_jsx(Badge, { variant: "outline", size: "sm", className: "font-mono", children: nameOf(resolved) ?? tI18nComplete.raw('text1f0a5246c481') })), _jsx("p", { className: "text-muted-foreground text-xs leading-relaxed text-pretty", children: explicit ? (_jsxs(_Fragment, { children: [tI18nComplete.raw('text40124896532d'), ' ', _jsx("span", { className: "text-foreground font-medium", children: nameOf(explicit) }), "."] })) : (_jsxs(_Fragment, { children: [tI18nComplete.raw('text46e3bd02feee'), resolved ? (_jsxs(_Fragment, { children: [' ', "(", _jsx("span", { className: "text-foreground font-medium", children: nameOf(resolved) }), ")"] })) : null, tI18nComplete.raw('textd5bf3036405d')] })) })] }));
66
+ } })] })) : (_jsx("span", { className: "text-foreground block truncate text-sm sm:text-right", children: nameOf(resolved) ?? tI18nComplete.raw('text1f0a5246c481') })) }) }));
66
67
  }
67
68
  /**
68
69
  * An agent's manifest allowlist (`agents:` in kortix.yaml, or the legacy
@@ -125,13 +126,13 @@ function AgentScopeCard({ projectId, agentName, scope, }) {
125
126
  });
126
127
  // Non-managers get the read-only mirror (the old presentation).
127
128
  if (!canManage) {
128
- return (_jsxs("div", { className: "bg-popover space-y-3 rounded-md border px-4 py-4", children: [_jsx(Label, { children: tI18nComplete.raw('textec5ba0abb717') }), _jsxs("dl", { className: "space-y-2", children: [_jsx(ScopeRow, { label: tI18nComplete.raw('textd8707d411d99'), value: scope.env }), _jsx(ScopeRow, { label: tI18nComplete.raw('textc3d2e79ebdd0'), value: scope.connectors }), _jsx(ScopeRow, { label: tI18nComplete.raw('text8f12a6e05e6d'), value: scope.kortix_permissions ?? scope.kortix_cli })] }), _jsx("p", { className: "text-muted-foreground text-xs leading-relaxed text-pretty", children: tI18nComplete.raw('textac4c418e412f') })] }));
129
+ return (_jsx(EditorSection, { title: tI18nComplete.raw('textec5ba0abb717'), bare: true, children: _jsxs("div", { className: "bg-popover space-y-3 rounded-md border px-4 py-4", children: [_jsxs("dl", { className: "space-y-2", children: [_jsx(ScopeRow, { label: tI18nComplete.raw('textd8707d411d99'), value: scope.env }), _jsx(ScopeRow, { label: tI18nComplete.raw('textc3d2e79ebdd0'), value: scope.connectors }), _jsx(ScopeRow, { label: tI18nComplete.raw('text8f12a6e05e6d'), value: scope.kortix_permissions ?? scope.kortix_cli })] }), _jsx("p", { className: "text-muted-foreground text-xs leading-relaxed text-pretty", children: tI18nComplete.raw('textac4c418e412f') })] }) }));
129
130
  }
130
- return (_jsxs("div", { className: "bg-popover space-y-4 rounded-md border px-4 py-4", children: [_jsx(Label, { children: tI18nComplete.raw('textec5ba0abb717') }), _jsx(ScopeEditor, { label: tI18nComplete.raw('textd8707d411d99'), allLabel: tI18nComplete.raw('text922315177668'), emptyLabel: tI18nComplete.raw('text82a37b8c2266'), value: env, options: secretOptions, match: "case-insensitive", onChange: setEnv }, `env-${editorNonce}`), _jsx(ScopeEditor, { label: tI18nComplete.raw('textc3d2e79ebdd0'), allLabel: tI18nComplete.raw('texta2e8754e4899'), emptyLabel: tI18nComplete.raw('text389fb5217392'), value: connectors, options: connectorOptions, onChange: setConnectors }, `connectors-${editorNonce}`), _jsx("dl", { children: _jsx(ScopeRow, { label: tI18nComplete.raw('text8f12a6e05e6d'), value: scope.kortix_permissions ?? scope.kortix_cli }) }), dirty ? (_jsxs("div", { className: "border-border/50 flex items-center justify-end gap-2 border-t pt-3", children: [_jsx(Button, { variant: "ghost", size: "sm", disabled: save.isPending, onClick: () => {
131
- setEnv(scope.env);
132
- setConnectors(scope.connectors);
133
- setEditorNonce((n) => n + 1);
134
- }, children: tI18nComplete.raw('textdaee7606b339') }), _jsxs(Button, { size: "sm", disabled: save.isPending, onClick: () => save.mutate(), children: [save.isPending && _jsx(Loading, { className: "size-3.5 shrink-0" }), tI18nComplete.raw('text1509f561f241')] })] })) : null] }));
131
+ return (_jsx(EditorSection, { title: tI18nComplete.raw('textec5ba0abb717'), bare: true, children: _jsxs("div", { className: "bg-popover space-y-4 rounded-md border px-4 py-4", children: [_jsx(ScopeEditor, { label: tI18nComplete.raw('textd8707d411d99'), allLabel: tI18nComplete.raw('text922315177668'), emptyLabel: tI18nComplete.raw('text82a37b8c2266'), value: env, options: secretOptions, match: "case-insensitive", onChange: setEnv }, `env-${editorNonce}`), _jsx(ScopeEditor, { label: tI18nComplete.raw('textc3d2e79ebdd0'), allLabel: tI18nComplete.raw('texta2e8754e4899'), emptyLabel: tI18nComplete.raw('text389fb5217392'), value: connectors, options: connectorOptions, onChange: setConnectors }, `connectors-${editorNonce}`), _jsx("dl", { children: _jsx(ScopeRow, { label: tI18nComplete.raw('text8f12a6e05e6d'), value: scope.kortix_permissions ?? scope.kortix_cli }) }), dirty ? (_jsxs("div", { className: "border-border/50 flex items-center justify-end gap-2 border-t pt-3", children: [_jsx(Button, { variant: "ghost", size: "sm", disabled: save.isPending, onClick: () => {
132
+ setEnv(scope.env);
133
+ setConnectors(scope.connectors);
134
+ setEditorNonce((n) => n + 1);
135
+ }, children: tI18nComplete.raw('textdaee7606b339') }), _jsxs(Button, { size: "sm", disabled: save.isPending, onClick: () => save.mutate(), children: [save.isPending && _jsx(Loading, { className: "size-3.5 shrink-0" }), tI18nComplete.raw('text1509f561f241')] })] })) : null] }) }));
135
136
  }
136
137
  /**
137
138
  * The Secrets checklist, built from the project's secrets.
@@ -233,7 +234,7 @@ function ScopeEditor({ label, allLabel, emptyLabel, value, options, match = 'exa
233
234
  return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-muted-foreground text-xs", children: label }), _jsx("div", { className: "border-border/70 inline-flex shrink-0 overflow-hidden rounded-md border", children: ['all', 'specific', 'none'].map((m) => (_jsx("button", { type: "button", onClick: () => pick(m), className: cn('px-2.5 py-1 text-xs capitalize', 'transition-[color,background-color] active:scale-[0.96]', mode === m
234
235
  ? 'bg-secondary text-foreground font-medium'
235
236
  : 'text-muted-foreground hover:bg-muted/50'), children: m }, m))) })] }), mode === 'all' ? (_jsx("p", { className: "text-muted-foreground text-xs text-pretty", children: allLabel })) : null, mode === 'specific' &&
236
- (rows.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-xs", children: emptyLabel })) : (_jsx("div", { className: "border-border/60 max-h-44 overflow-y-auto rounded-md border p-1", children: rows.map((o) => (_jsxs("button", { type: "button", "aria-pressed": o.selected, onClick: () => toggle(o.id), className: cn('flex w-full items-center gap-2 rounded px-2 py-1 text-left text-xs transition-colors', o.selected ? 'bg-secondary' : 'hover:bg-muted/50'), children: [_jsx("span", { className: cn('flex size-4 shrink-0 items-center justify-center rounded border', o.selected
237
+ (rows.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-xs", children: emptyLabel })) : (_jsx("div", { className: "border-border/60 max-h-44 overflow-y-auto rounded-md border p-1", children: rows.map((o) => (_jsxs("button", { type: "button", "aria-pressed": o.selected, onClick: () => toggle(o.id), className: cn('flex w-full items-center gap-2 rounded-sm px-2 py-1 text-left text-xs transition-colors', o.selected ? 'bg-secondary' : 'hover:bg-muted/50'), children: [_jsx("span", { className: cn('flex size-4 shrink-0 items-center justify-center rounded-sm border', o.selected
237
238
  ? 'border-foreground bg-foreground text-background'
238
239
  : 'border-border/70'), children: o.selected && _jsx(Check, { className: "size-3" }) }), _jsx("span", { className: "min-w-0 flex-1 truncate font-mono", children: o.label }), o.hint ? (_jsx("span", { className: "text-muted-foreground max-w-[40%] shrink-0 truncate font-mono", children: o.hint })) : null, o.orphan && (_jsx("span", { className: "text-kortix-orange", children: tI18nComplete.raw('textffa63583dfa6') }))] }, o.id))) })))] }));
239
240
  }
@@ -3,14 +3,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { uiRoutes } from '../../lib/routes.js';
4
4
  import { EmptyState } from '../../primitives/empty-state.js';
5
5
  import { ErrorState } from '../../primitives/error-state.js';
6
- import { EditorSection } from '../sections/view/agent-editor-primitives.js';
6
+ import { EditorList, EditorSection } from '../sections/view/agent-editor-primitives.js';
7
7
  import { Button } from '../../primitives/button.js';
8
8
  import { Skeleton } from '../../primitives/skeleton.js';
9
9
  import { Switch } from '../../primitives/switch.js';
10
10
  import { errorToast } from '../../primitives/toast.js';
11
11
  import { useDriveFolder, useFolderAccess, useProjectDrive, useShareFolder, useUnshareFolder, } from '../../files/drives/use-drives.js';
12
12
  import { useTranslations } from '../../i18n/index.js';
13
- import { HardDriveIcon } from '@phosphor-icons/react';
14
13
  import { UiLink as Link } from '../../providers/ui-provider.js';
15
14
  /**
16
15
  * Which shared drives an agent gets, on the agent's page, beside Apps and
@@ -27,7 +26,7 @@ export function AgentDrivesSection({ projectId, agentName }) {
27
26
  const drives = (root.data?.entries ?? []).filter((e) => e.type === 'dir' && !/^\/?Users(\/|$)/.test(e.path));
28
27
  let body;
29
28
  if (drive.isLoading || root.isLoading) {
30
- body = (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-13 w-full rounded-md" }), _jsx(Skeleton, { className: "h-13 w-full rounded-md" })] }));
29
+ body = (_jsx(EditorList, { children: [0, 1].map((i) => (_jsx("li", { className: "flex items-center gap-3 px-4 py-3", children: _jsx(Skeleton, { className: "h-4 w-40 rounded-sm" }) }, i))) }));
31
30
  }
32
31
  else if (drive.isError || root.isError || !drive.data) {
33
32
  body = (_jsx(ErrorState, { size: "sm", title: t('loadError'), action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => void root.refetch(), children: t('retry') }) }));
@@ -36,9 +35,9 @@ export function AgentDrivesSection({ projectId, agentName }) {
36
35
  body = _jsx(EmptyState, { size: "sm", title: t('noCompanyDrives') });
37
36
  }
38
37
  else {
39
- body = (_jsx("ul", { className: "space-y-2", children: drives.map((entry) => (_jsx(AgentDriveRow, { driveId: drive.data.driveId, entry: entry, agentName: agentName }, entry.path))) }));
38
+ body = (_jsx(EditorList, { children: drives.map((entry) => (_jsx(AgentDriveRow, { driveId: drive.data.driveId, entry: entry, agentName: agentName }, entry.path))) }));
40
39
  }
41
- return (_jsx(EditorSection, { title: t('customizeTitle'), description: t('accessAgentsCompanyHint'), trailing: driveHref ? (_jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsx(Link, { href: driveHref, children: t('driveLabel') }) })) : undefined, children: _jsx("div", { className: "py-4", children: body }) }));
40
+ return (_jsx(EditorSection, { title: t('customizeTitle'), description: t('accessAgentsCompanyHint'), trailing: driveHref ? (_jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: _jsx(Link, { href: driveHref, children: t('driveLabel') }) })) : undefined, lead: true, bare: true, children: body }));
42
41
  }
43
42
  function AgentDriveRow({ driveId, entry, agentName }) {
44
43
  const t = useTranslations('drives');
@@ -63,5 +62,5 @@ function AgentDriveRow({ driveId, entry, agentName }) {
63
62
  errorToast(t('shareFailed'));
64
63
  }
65
64
  };
66
- return (_jsxs("li", { className: "bg-popover flex items-center gap-3 rounded-md border px-4 py-2", children: [_jsx("span", { className: "bg-muted text-muted-foreground flex size-9 shrink-0 items-center justify-center rounded-md", children: _jsx(HardDriveIcon, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "text-foreground truncate text-sm font-medium", children: entry.name }), _jsx("p", { className: "text-muted-foreground truncate font-mono text-xs", children: inherited ? t('everyoneInProject') : `/drives${path}` })] }), access.isLoading ? (_jsx(Skeleton, { className: "h-5 w-9 rounded-full" })) : (_jsx(Switch, { checked: !!own || inherited, disabled: !canManage || inherited || pending, onCheckedChange: (v) => void toggle(v), "aria-label": t('levelFor', { name: entry.name }) }))] }));
65
+ return (_jsxs("li", { className: "flex items-center gap-3 px-4 py-2.5", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "text-foreground truncate text-sm font-medium", children: entry.name }), _jsx("p", { className: "text-muted-foreground truncate font-mono text-xs", children: inherited ? t('everyoneInProject') : `/drives${path}` })] }), access.isLoading ? (_jsx(Skeleton, { className: "h-5 w-9 rounded-full" })) : (_jsx(Switch, { checked: !!own || inherited, disabled: !canManage || inherited || pending, onCheckedChange: (v) => void toggle(v), "aria-label": t('levelFor', { name: entry.name }) }))] }));
67
66
  }