@kortix/ui 0.14.8 → 0.14.9
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.
- package/README.md +2 -2
- package/dist/_vendor/kortix-shared.js +63 -3
- package/dist/_vendor/shared/app-config.d.ts +175 -0
- package/dist/_vendor/shared/channel-message.d.ts +34 -5
- package/dist/_vendor/shared/index.d.ts +1 -0
- package/dist/_vendor/shared/space-slug.d.ts +37 -0
- package/dist/access/access/access-detail-shell.js +1 -1
- package/dist/access/access/principal-picker.d.ts +11 -0
- package/dist/access/access/principal-picker.js +3 -2
- package/dist/apps/app-preview-pool.d.ts +7 -2
- package/dist/apps/app-preview-pool.js +11 -5
- package/dist/apps/app-shared.d.ts +22 -15
- package/dist/apps/app-shared.js +37 -19
- package/dist/apps/index.d.ts +2 -2
- package/dist/apps/index.js +2 -2
- package/dist/artifacts/artifact-frame.d.ts +16 -0
- package/dist/artifacts/artifact-frame.js +51 -0
- package/dist/artifacts/artifact-session.d.ts +18 -0
- package/dist/artifacts/artifact-session.js +101 -0
- package/dist/artifacts/frame-policy.d.ts +30 -0
- package/dist/artifacts/frame-policy.js +61 -0
- package/dist/artifacts/index.d.ts +3 -0
- package/dist/artifacts/index.js +5 -0
- package/dist/browser/sandbox-browser-chrome.d.ts +4 -1
- package/dist/browser/sandbox-browser-chrome.js +2 -2
- package/dist/customize/agents/agent-grant-pages.d.ts +5 -1
- package/dist/customize/agents/agent-grant-pages.js +30 -4
- package/dist/customize/agents/agent-page.js +3 -1
- package/dist/customize/agents/agent-policy-sets.d.ts +43 -0
- package/dist/customize/agents/agent-policy-sets.js +72 -0
- package/dist/customize/agents/agent-triggers-section.js +2 -1
- package/dist/customize/connectors/add-mcp/add-mcp-server-dialog.d.ts +6 -1
- package/dist/customize/connectors/add-mcp/add-mcp-server-dialog.js +10 -4
- package/dist/customize/connectors/agent-access.d.ts +35 -0
- package/dist/customize/connectors/agent-access.js +77 -0
- package/dist/customize/connectors/catalog/browse-sections.d.ts +2 -29
- package/dist/customize/connectors/catalog/browse-sections.js +7 -74
- package/dist/customize/connectors/catalog/catalog-entry.d.ts +18 -37
- package/dist/customize/connectors/catalog/catalog-entry.js +28 -40
- package/dist/customize/connectors/catalog/connector-browse.d.ts +3 -32
- package/dist/customize/connectors/catalog/connector-browse.js +19 -50
- package/dist/customize/connectors/catalog/use-catalog.d.ts +20 -59
- package/dist/customize/connectors/catalog/use-catalog.js +48 -175
- package/dist/customize/connectors/connector-identity.d.ts +9 -11
- package/dist/customize/connectors/connector-identity.js +13 -42
- package/dist/customize/connectors/connector-moves-banner.d.ts +2 -1
- package/dist/customize/connectors/connector-moves-banner.js +4 -6
- package/dist/customize/connectors/connector-routes.d.ts +21 -9
- package/dist/customize/connectors/connector-routes.js +29 -20
- package/dist/customize/connectors/connectors-page.js +53 -82
- package/dist/customize/connectors/detail/app-page.js +226 -98
- package/dist/customize/connectors/detail/computer-app-page.d.ts +16 -0
- package/dist/customize/connectors/detail/computer-app-page.js +39 -0
- package/dist/customize/connectors/detail/connector-accounts.js +3 -1
- package/dist/customize/connectors/detail/connector-advanced-tools.d.ts +4 -1
- package/dist/customize/connectors/detail/connector-advanced-tools.js +2 -2
- package/dist/customize/connectors/detail/connector-agents.d.ts +14 -0
- package/dist/customize/connectors/detail/connector-agents.js +69 -0
- package/dist/customize/connectors/detail/connector-detail-tabs.js +2 -1
- package/dist/customize/connectors/detail/connector-move-row.d.ts +8 -5
- package/dist/customize/connectors/detail/connector-move-row.js +23 -14
- package/dist/customize/connectors/detail/connector-page.d.ts +4 -1
- package/dist/customize/connectors/detail/connector-page.js +14 -10
- package/dist/customize/connectors/detail/connector-policy-sets.d.ts +28 -0
- package/dist/customize/connectors/detail/connector-policy-sets.js +203 -0
- package/dist/customize/connectors/detail/connector-settings.d.ts +4 -1
- package/dist/customize/connectors/detail/connector-settings.js +7 -3
- package/dist/customize/connectors/detail/connector-status.d.ts +19 -6
- package/dist/customize/connectors/detail/connector-status.js +34 -10
- package/dist/customize/connectors/detail/connector-tabs.d.ts +4 -1
- package/dist/customize/connectors/detail/connector-tabs.js +8 -2
- package/dist/customize/connectors/detail/connector-tools.d.ts +3 -3
- package/dist/customize/connectors/detail/connector-tools.js +105 -48
- package/dist/customize/connectors/detail/email-inboxes.d.ts +43 -0
- package/dist/customize/connectors/detail/email-inboxes.js +184 -0
- package/dist/customize/connectors/detail/provider-info.d.ts +1 -1
- package/dist/customize/connectors/detail/provider-info.js +2 -2
- package/dist/customize/connectors/detail/status-badge.d.ts +1 -1
- package/dist/customize/connectors/detail/status-badge.js +4 -5
- package/dist/customize/connectors/detail/use-connector-detail.d.ts +6 -0
- package/dist/customize/connectors/detail/use-connector-detail.js +14 -4
- package/dist/customize/connectors/install/install-dialog.d.ts +23 -0
- package/dist/customize/connectors/install/install-dialog.js +40 -0
- package/dist/customize/connectors/install/install.d.ts +13 -2
- package/dist/customize/connectors/install/install.js +9 -4
- package/dist/customize/connectors/install/use-install.d.ts +19 -2
- package/dist/customize/connectors/install/use-install.js +65 -37
- package/dist/customize/connectors/install/way-kind.d.ts +5 -0
- package/dist/customize/connectors/install/way-kind.js +16 -0
- package/dist/customize/connectors/provider-label.d.ts +2 -1
- package/dist/customize/connectors/provider-label.js +13 -3
- package/dist/customize/connectors/tools/pattern-rule-draft.d.ts +4 -0
- package/dist/customize/connectors/tools/pattern-rule-draft.js +12 -3
- package/dist/customize/connectors/tools/policy-sets.d.ts +27 -0
- package/dist/customize/connectors/tools/policy-sets.js +41 -0
- package/dist/customize/connectors/tools/tool-groups.d.ts +32 -9
- package/dist/customize/connectors/tools/tool-groups.js +78 -16
- package/dist/customize/connectors/tools/tool-policy-control.d.ts +11 -10
- package/dist/customize/connectors/tools/tool-policy-control.js +15 -16
- package/dist/customize/connectors/tools/tool-policy-labels.d.ts +6 -5
- package/dist/customize/connectors/tools/tool-policy-labels.js +17 -16
- package/dist/customize/connectors/tools/tool-policy.d.ts +50 -4
- package/dist/customize/connectors/tools/tool-policy.js +74 -8
- package/dist/customize/connectors/use-agent-access.d.ts +85 -0
- package/dist/customize/connectors/use-agent-access.js +72 -0
- package/dist/customize/migrate-to-v2/index.d.ts +1 -2
- package/dist/customize/migrate-to-v2/index.js +1 -2
- package/dist/customize/migrate-to-v2/migration-prompt.d.ts +12 -25
- package/dist/customize/migrate-to-v2/migration-prompt.js +34 -236
- package/dist/customize/migrate-to-v2/upgrade-defs.d.ts +1 -1
- package/dist/customize/migrate-to-v2/upgrade-defs.js +7 -6
- package/dist/customize/migrate-to-v2/upgrade-view.js +7 -7
- package/dist/customize/migrate-to-v2/use-run-upgrade.d.ts +3 -3
- package/dist/customize/providers/provider-accordion.js +17 -2
- package/dist/customize/sections/component/channel-access-panel.d.ts +16 -0
- package/dist/customize/sections/component/channel-access-panel.js +146 -0
- package/dist/customize/sections/component/channel-connect-hero.d.ts +3 -2
- package/dist/customize/sections/component/channel-connect-hero.js +3 -2
- package/dist/customize/sections/component/channel-hero-frame.d.ts +31 -0
- package/dist/customize/sections/component/channel-hero-frame.js +40 -0
- package/dist/customize/sections/component/channel-mocks.d.ts +6 -0
- package/dist/customize/sections/component/channel-mocks.js +46 -0
- package/dist/customize/sections/component/channel-row.d.ts +13 -3
- package/dist/customize/sections/component/channel-row.js +10 -4
- package/dist/customize/sections/component/email-connect-form.d.ts +27 -0
- package/dist/customize/sections/component/email-connect-form.js +183 -0
- package/dist/customize/sections/component/slack-connect-card.d.ts +7 -0
- package/dist/customize/sections/component/slack-connect-card.js +2 -3
- package/dist/customize/sections/component/teams-connect-card.d.ts +7 -0
- package/dist/customize/sections/component/teams-connect-card.js +2 -3
- package/dist/customize/sections/component/telegram-channel-row.js +16 -25
- package/dist/customize/sections/connectors-view.d.ts +1 -15
- package/dist/customize/sections/connectors-view.js +81 -314
- package/dist/customize/sections/view/agent-editor-catalog.js +5 -0
- package/dist/customize/sections/view/channels-view.d.ts +5 -1
- package/dist/customize/sections/view/channels-view.js +61 -75
- package/dist/customize/sections/view/gateway/gateway-overview.js +10 -2
- package/dist/customize/settings/tabs/experimental-tab.js +35 -16
- package/dist/customize/shared/catalog/catalog-empty-state.d.ts +1 -12
- package/dist/customize/shared/catalog/catalog-empty-state.js +3 -3
- package/dist/customize/shared/channels-switch-dialog.d.ts +18 -0
- package/dist/customize/shared/channels-switch-dialog.js +30 -0
- package/dist/customize/shared/feature-gate-screen.js +27 -9
- package/dist/customize/shared/use-customize-prefetch.d.ts +2 -3
- package/dist/customize/shared/use-customize-prefetch.js +9 -27
- package/dist/customize/triggers/schedule/post-to-field.d.ts +18 -0
- package/dist/customize/triggers/schedule/post-to-field.js +49 -0
- package/dist/customize/triggers/schedule/schedule-copy.d.ts +10 -6
- package/dist/customize/triggers/schedule/schedule-copy.js +42 -11
- package/dist/customize/triggers/schedule/schedule-detail-sheet.js +2 -1
- package/dist/customize/triggers/schedule/trigger-composer-logic.d.ts +22 -0
- package/dist/customize/triggers/schedule/trigger-composer-logic.js +25 -0
- package/dist/customize/triggers/schedule/trigger-composer.d.ts +5 -0
- package/dist/customize/triggers/schedule/trigger-composer.js +23 -14
- package/dist/customize/triggers/schedule/trigger-edit-logic.js +3 -0
- package/dist/customize/triggers/schedule/trigger-filter.js +1 -1
- package/dist/customize/triggers/schedule/trigger-runs-logic.d.ts +2 -2
- package/dist/customize/triggers/schedule/trigger-runs-panel.js +1 -0
- package/dist/customize/triggers/schedule/trigger-toast.js +2 -1
- package/dist/customize/triggers/schedule-view.js +5 -2
- package/dist/files/index.d.ts +1 -0
- package/dist/files/index.js +1 -0
- package/dist/files/project/change-request-recovery.d.ts +1 -26
- package/dist/files/project/change-request-recovery.js +1 -59
- package/dist/files/project/components/change-request-detail-dialog.js +13 -3
- package/dist/files/project/components/drive-explorer.js +15 -15
- package/dist/files/project/components/drive-toolbar.d.ts +16 -2
- package/dist/files/project/components/drive-toolbar.js +14 -5
- package/dist/files/project/hooks/use-change-request-recovery.js +3 -19
- package/dist/files/project/hooks/use-change-requests.d.ts +1 -0
- package/dist/files/project/hooks/use-change-requests.js +11 -2
- package/dist/files/renderers/image-frame.d.ts +46 -0
- package/dist/files/renderers/image-frame.js +59 -0
- package/dist/files/renderers/image-renderer.d.ts +11 -1
- package/dist/files/renderers/image-renderer.js +13 -3
- package/dist/files/renderers/pdf/pdf-clipboard.d.ts +2 -0
- package/dist/files/renderers/pdf/pdf-clipboard.js +21 -0
- package/dist/files/renderers/pdf/pdf-viewer.js +4 -2
- package/dist/files/renderers/show-content-renderer.d.ts +9 -1
- package/dist/files/renderers/show-content-renderer.js +56 -14
- package/dist/files/runtime/file-source.js +2 -0
- package/dist/files/runtime/hooks/use-binary-blob.d.ts +10 -1
- package/dist/files/runtime/hooks/use-binary-blob.js +10 -4
- package/dist/files/runtime/hooks/use-shared-image.d.ts +41 -0
- package/dist/files/runtime/hooks/use-shared-image.js +177 -0
- package/dist/files/viewer/file-content-renderer.d.ts +22 -1
- package/dist/files/viewer/file-content-renderer.js +50 -7
- package/dist/files/viewer/file-header.d.ts +7 -3
- package/dist/files/viewer/file-header.js +20 -11
- package/dist/files/viewer/file-preview-modal.d.ts +1 -1
- package/dist/files/viewer/file-preview-modal.js +10 -22
- package/dist/files/viewer/file-source.d.ts +13 -0
- package/dist/files/viewer/use-file-content-state.d.ts +2 -0
- package/dist/files/viewer/use-file-content-state.js +28 -10
- package/dist/files/viewer/viewer-actions.d.ts +3 -1
- package/dist/files/viewer/viewer-actions.js +2 -2
- package/dist/hooks/use-media-query.d.ts +1 -0
- package/dist/hooks/use-mobile.d.ts +5 -0
- package/dist/hooks/use-mobile.js +8 -0
- package/dist/i18n/en.d.ts +873 -85
- package/dist/i18n/en.js +888 -100
- package/dist/i18n/ui-catalog/localize-ui-catalog.js +4 -0
- package/dist/i18n/ui-catalog/remaining-ui-translation-keys.generated.js +15 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/internal/account-hub/account-settings-sidebar.js +1 -1
- package/dist/internal/account-hub/hub-sheet.d.ts +9 -1
- package/dist/internal/account-hub/hub-sheet.js +21 -5
- package/dist/internal/account-hub/sections.d.ts +1 -1
- package/dist/internal/account-hub/sections.js +2 -1
- package/dist/internal/auth/auth-card-shell.js +3 -3
- package/dist/internal/components/agent-mark.js +5 -2
- package/dist/internal/connector-logo/connector-logo-source.d.ts +63 -0
- package/dist/internal/connector-logo/connector-logo-source.js +48 -0
- package/dist/internal/connector-logo/connector-logo.d.ts +39 -0
- package/dist/internal/connector-logo/connector-logo.js +56 -0
- package/dist/internal/connector-logo/connector-mark-files.d.ts +11 -0
- package/dist/internal/connector-logo/connector-mark-files.js +35 -0
- package/dist/internal/files/file-read-retry.d.ts +13 -0
- package/dist/internal/files/file-read-retry.js +23 -3
- package/dist/internal/files/session-drive-files.d.ts +5 -1
- package/dist/internal/files/session-drive-files.js +7 -2
- package/dist/internal/hooks/channels/use-channels-installations.d.ts +32 -5
- package/dist/internal/hooks/channels/use-channels-installations.js +55 -7
- package/dist/internal/hooks/channels/use-email-inboxes.d.ts +19 -0
- package/dist/internal/hooks/channels/use-email-inboxes.js +48 -0
- package/dist/internal/hooks/connectors/use-add-account.js +1 -1
- package/dist/internal/hooks/index.d.ts +1 -1
- package/dist/internal/hooks/index.js +1 -1
- package/dist/internal/hooks/projects/use-new-project-session.d.ts +9 -0
- package/dist/internal/hooks/projects/use-new-project-session.js +28 -12
- package/dist/internal/hooks/use-auto-scroll.d.ts +8 -1
- package/dist/internal/hooks/use-auto-scroll.js +4 -4
- package/dist/internal/icons/telegram.d.ts +5 -0
- package/dist/internal/icons/telegram.js +6 -1
- package/dist/internal/layout/nav-hover-card.d.ts +35 -0
- package/dist/internal/layout/nav-hover-card.js +84 -0
- package/dist/internal/layout/project-nav-row.d.ts +3 -1
- package/dist/internal/layout/project-nav-row.js +3 -2
- package/dist/internal/layout/project-page-header.d.ts +4 -2
- package/dist/internal/layout/project-page-header.js +4 -3
- package/dist/internal/layout/project-settings-nav.js +59 -2
- package/dist/internal/lib/browser-error-noise.d.ts +1 -1
- package/dist/internal/lib/browser-error-noise.js +1 -1
- package/dist/internal/lib/browser-noise/rules/injected-scripts.d.ts +7 -0
- package/dist/internal/lib/browser-noise/rules/injected-scripts.js +15 -0
- package/dist/internal/lib/manifest-version.d.ts +1 -1
- package/dist/internal/lib/manifest-version.js +2 -2
- package/dist/internal/lib/memory-href.d.ts +16 -0
- package/dist/internal/lib/memory-href.js +46 -0
- package/dist/internal/lib/use-project-feature-flags.js +9 -9
- package/dist/internal/lib/utils/heic-convert.d.ts +1 -1
- package/dist/internal/lib/utils/heic-convert.js +3 -4
- package/dist/internal/lib/web-notifications.d.ts +20 -0
- package/dist/internal/lib/web-notifications.js +48 -4
- package/dist/internal/notifications/notification-bell.d.ts +4 -1
- package/dist/internal/notifications/notification-bell.js +2 -2
- package/dist/internal/selection/selection-bar.d.ts +2 -1
- package/dist/internal/selection/selection-bar.js +1 -1
- package/dist/internal/stores/file-preview-store.d.ts +29 -2
- package/dist/internal/stores/file-preview-store.js +19 -1
- package/dist/internal/stores/kortix-computer-store.js +3 -0
- package/dist/internal/stores/sidebar-nav-store.d.ts +1 -1
- package/dist/internal/stores/sidebar-nav-store.js +3 -1
- package/dist/lib/routes.d.ts +13 -1
- package/dist/lib/routes.js +13 -0
- package/dist/markdown/index.d.ts +2 -1
- package/dist/markdown/index.js +2 -1
- package/dist/markdown/setup-links/approval-decision.d.ts +1 -0
- package/dist/markdown/setup-links/approval-decision.js +6 -2
- package/dist/markdown/setup-links/connector-handshake.d.ts +3 -1
- package/dist/markdown/setup-links/connector-handshake.js +12 -10
- package/dist/markdown/setup-links/secret-intake-form.d.ts +0 -10
- package/dist/markdown/setup-links/secret-intake-form.js +1 -1
- package/dist/markdown/setup-links/show-connect-hero.d.ts +28 -0
- package/dist/markdown/setup-links/show-connect-hero.js +91 -0
- package/dist/markdown/unified-markdown.js +5 -5
- package/dist/primitives/badge.d.ts +1 -1
- package/dist/primitives/badge.js +2 -0
- package/dist/primitives/disclosure.js +14 -2
- package/dist/primitives/empty-art.d.ts +12 -0
- package/dist/primitives/empty-art.js +11 -0
- package/dist/primitives/mermaid-renderer.d.ts +2 -0
- package/dist/primitives/mermaid-renderer.js +21 -15
- package/dist/primitives/resizable.js +6 -1
- package/dist/primitives/resize-seam.d.ts +11 -0
- package/dist/primitives/resize-seam.js +12 -0
- package/dist/primitives/sidebar-panel.js +4 -7
- package/dist/primitives/tabs.d.ts +14 -1
- package/dist/primitives/tabs.js +1 -1
- package/dist/providers/ui-provider.d.ts +9 -0
- package/dist/session/composer/ComposerAboveCard.d.ts +1 -1
- package/dist/session/composer/ComposerAboveCard.js +2 -2
- package/dist/session/composer/ComposerCard.d.ts +1 -1
- package/dist/session/composer/ComposerCard.js +3 -3
- package/dist/session/composer/agent-selector.d.ts +13 -1
- package/dist/session/composer/agent-selector.js +25 -5
- package/dist/session/composer/composer-agent-access.d.ts +15 -0
- package/dist/session/composer/composer-agent-access.js +27 -0
- package/dist/session/composer/composer-chat-input.d.ts +8 -2
- package/dist/session/composer/composer-chat-input.js +8 -6
- package/dist/session/composer/composer-logic.d.ts +16 -0
- package/dist/session/composer/composer-logic.js +12 -0
- package/dist/session/composer/composer-underbar.d.ts +3 -1
- package/dist/session/composer/composer-underbar.js +4 -3
- package/dist/session/composer/composer.d.ts +15 -1
- package/dist/session/composer/composer.js +19 -1
- package/dist/session/composer/draft/composer-draft.d.ts +6 -2
- package/dist/session/composer/draft/composer-draft.js +5 -1
- package/dist/session/composer/reasoning-effort-selector.js +1 -1
- package/dist/session/models/chatgpt-connection-button.d.ts +11 -0
- package/dist/session/models/chatgpt-connection-button.js +54 -0
- package/dist/session/models/model-selector.js +5 -2
- package/dist/session/models/use-model-connection-gate.d.ts +5 -5
- package/dist/session/models/use-model-connection-gate.js +5 -5
- package/dist/session/outcomes/jump-to-outcome.d.ts +10 -0
- package/dist/session/outcomes/jump-to-outcome.js +11 -0
- package/dist/session/outcomes/session-outcomes-bridge.d.ts +14 -0
- package/dist/session/outcomes/session-outcomes-bridge.js +12 -0
- package/dist/session/outcomes/session-outcomes-provider.d.ts +3 -1
- package/dist/session/outcomes/session-outcomes-provider.js +33 -3
- package/dist/session/panel/easy/app-preview.d.ts +10 -0
- package/dist/session/panel/easy/app-preview.js +31 -12
- package/dist/session/panel/easy/change-requests-card.d.ts +7 -0
- package/dist/session/panel/easy/change-requests-card.js +17 -0
- package/dist/session/panel/easy/easy-panel-logic.js +7 -1
- package/dist/session/panel/easy/easy-panel.js +5 -2
- package/dist/session/panel/easy/file-preview.js +1 -1
- package/dist/session/panel/easy/outputs-card.d.ts +2 -1
- package/dist/session/panel/easy/outputs-card.js +3 -2
- package/dist/session/panel/mobile-tool-drawer.js +7 -1
- package/dist/session/panel/session-audit-panel.js +9 -2
- package/dist/session/panel/session-detail-panel.js +9 -3
- package/dist/session/panel/session-files-explorer.d.ts +9 -0
- package/dist/session/panel/session-files-explorer.js +12 -3
- package/dist/session/panel/session-panel-provider.d.ts +15 -1
- package/dist/session/panel/session-panel-provider.js +32 -7
- package/dist/session/panel/shared/derive-panels.d.ts +8 -1
- package/dist/session/panel/shared/derive-panels.js +12 -2
- package/dist/session/panel/shared/output-priority.js +2 -0
- package/dist/session/participants/session-participants.d.ts +5 -1
- package/dist/session/participants/session-participants.js +9 -2
- package/dist/session/prompts/approval-request.d.ts +5 -0
- package/dist/session/prompts/approval-request.js +7 -1
- package/dist/session/prompts/session-approval-review.d.ts +9 -0
- package/dist/session/prompts/session-approval-review.js +18 -0
- package/dist/session/status/session-error-banner.js +2 -49
- package/dist/session/status/session-starting-loader.d.ts +14 -2
- package/dist/session/status/session-starting-loader.js +16 -4
- package/dist/session/thread/after-first-prompt.d.ts +7 -0
- package/dist/session/thread/after-first-prompt.js +8 -0
- package/dist/session/thread/detect-command.d.ts +12 -0
- package/dist/session/thread/detect-command.js +20 -0
- package/dist/session/thread/session-chat.d.ts +3 -1
- package/dist/session/thread/session-chat.js +377 -252
- package/dist/session/thread/session-thread.d.ts +3 -1
- package/dist/session/thread/session-thread.js +9 -2
- package/dist/session/thread/thread-boot-rows.d.ts +36 -0
- package/dist/session/thread/thread-boot-rows.js +89 -0
- package/dist/session/thread/transcript-rows.d.ts +31 -0
- package/dist/session/thread/transcript-rows.js +3 -0
- package/dist/session/thread/transcript.d.ts +0 -9
- package/dist/session/thread/transcript.js +104 -19
- package/dist/session/tool/shared/infrastructure-contexts.d.ts +28 -0
- package/dist/session/tool/shared/infrastructure-contexts.js +31 -3
- package/dist/session/tool/tool-part-renderer.d.ts +5 -4
- package/dist/session/tool/tool-part-renderer.js +8 -3
- package/dist/session/tool/tools/bash-tool.js +7 -6
- package/dist/session/tool/tools/channel-send-card.d.ts +1 -2
- package/dist/session/tool/tools/channel-send.d.ts +2 -1
- package/dist/session/tool/tools/codemode-tool.js +1 -1
- package/dist/session/tool/tools/connector-tools.js +1 -1
- package/dist/session/tool/tools/image-gen-tool.d.ts +1 -1
- package/dist/session/tool/tools/image-gen-tool.js +240 -53
- package/dist/session/tool/tools/show-tool.js +19 -8
- package/dist/session/turn/channel-brand.d.ts +8 -3
- package/dist/session/turn/channel-brand.js +20 -4
- package/dist/session/turn/message-author.d.ts +8 -0
- package/dist/session/turn/message-author.js +24 -0
- package/dist/session/turn/message-row.d.ts +52 -0
- package/dist/session/turn/message-row.js +44 -0
- package/dist/session/turn/plan-anchor.d.ts +1 -1
- package/dist/session/turn/plan-anchor.js +1 -1
- package/dist/session/turn/user-message.d.ts +7 -1
- package/dist/session/turn/user-message.js +21 -7
- package/dist/styles.css +1 -1
- package/dist/workspace/home/access-requests-bell.d.ts +9 -2
- package/dist/workspace/home/access-requests-bell.js +20 -6
- package/dist/workspace/home/first-chat.d.ts +8 -21
- package/dist/workspace/home/first-chat.js +22 -72
- package/dist/workspace/index.d.ts +6 -0
- package/dist/workspace/index.js +6 -0
- package/dist/workspace/layout/project-home.d.ts +14 -2
- package/dist/workspace/layout/project-home.js +60 -21
- package/dist/workspace/layout/use-project-home-send.d.ts +9 -1
- package/dist/workspace/layout/use-project-home-send.js +82 -3
- package/dist/workspace/memory/body-doc.d.ts +17 -0
- package/dist/workspace/memory/body-doc.js +208 -0
- package/dist/workspace/memory/body-extensions.d.ts +38 -0
- package/dist/workspace/memory/body-extensions.js +103 -0
- package/dist/workspace/memory/company-memory-page.d.ts +8 -0
- package/dist/workspace/memory/company-memory-page.js +16 -0
- package/dist/workspace/memory/memory-all.d.ts +20 -0
- package/dist/workspace/memory/memory-all.js +27 -0
- package/dist/workspace/memory/memory-body.d.ts +19 -0
- package/dist/workspace/memory/memory-body.js +139 -0
- package/dist/workspace/memory/memory-empty.d.ts +13 -0
- package/dist/workspace/memory/memory-empty.js +28 -0
- package/dist/workspace/memory/memory-history.d.ts +27 -0
- package/dist/workspace/memory/memory-history.js +108 -0
- package/dist/workspace/memory/memory-labels.d.ts +16 -0
- package/dist/workspace/memory/memory-labels.js +47 -0
- package/dist/workspace/memory/memory-page-list.d.ts +34 -0
- package/dist/workspace/memory/memory-page-list.js +156 -0
- package/dist/workspace/memory/memory-reader.d.ts +58 -0
- package/dist/workspace/memory/memory-reader.js +123 -0
- package/dist/workspace/memory/memory-view.d.ts +21 -0
- package/dist/workspace/memory/memory-view.js +124 -0
- package/dist/workspace/memory/remember-popover.d.ts +19 -0
- package/dist/workspace/memory/remember-popover.js +61 -0
- package/dist/workspace/memory/remember-this.d.ts +12 -0
- package/dist/workspace/memory/remember-this.js +89 -0
- package/dist/workspace/memory/source-mark.d.ts +18 -0
- package/dist/workspace/memory/source-mark.js +79 -0
- package/dist/workspace/memory/used-memory-chip.d.ts +14 -0
- package/dist/workspace/memory/used-memory-chip.js +61 -0
- package/dist/workspace/new/advanced-fields.d.ts +2 -1
- package/dist/workspace/new/advanced-fields.js +2 -2
- package/dist/workspace/new/source-param.d.ts +1 -1
- package/dist/workspace/new/source-param.js +3 -1
- package/dist/workspace/new/use-create-workspace.d.ts +8 -10
- package/dist/workspace/new/use-create-workspace.js +3 -3
- package/dist/workspace/projects/onboarding/app-logo.d.ts +7 -2
- package/dist/workspace/projects/onboarding/app-logo.js +6 -13
- package/dist/workspace/projects/policies-panel.js +5 -3
- package/dist/workspace/review/review-actions.d.ts +4 -2
- package/dist/workspace/review/review-actions.js +8 -2
- package/dist/workspace/review/review-center.js +11 -7
- package/dist/workspace/review/review-detail.d.ts +10 -0
- package/dist/workspace/review/review-detail.js +101 -13
- package/dist/workspace/saved-session-skeleton.d.ts +2 -2
- package/dist/workspace/saved-session-skeleton.js +3 -3
- package/dist/workspace/session-workspace.js +15 -13
- package/dist/workspace/sessions/project-sessions-view.js +3 -2
- package/dist/workspace/sessions/sessions-toolbar.d.ts +3 -1
- package/dist/workspace/sessions/sessions-toolbar.js +2 -2
- package/dist/workspace/sidebar/footer/project-apps-nav.d.ts +5 -0
- package/dist/workspace/sidebar/footer/project-apps-nav.js +41 -2
- package/dist/workspace/sidebar/footer/project-artifacts-nav.d.ts +6 -0
- package/dist/workspace/sidebar/footer/project-artifacts-nav.js +22 -0
- package/dist/workspace/sidebar/footer/project-manifest-upgrade-alert.js +13 -13
- package/dist/workspace/sidebar/footer/project-memory-nav.d.ts +7 -0
- package/dist/workspace/sidebar/footer/project-memory-nav.js +19 -0
- package/dist/workspace/sidebar/nav-row-meta.js +14 -2
- package/dist/workspace/sidebar/project-nav-items.js +3 -0
- package/dist/workspace/sidebar/project-session-list.js +68 -56
- package/dist/workspace/sidebar/project-sidebar.js +9 -2
- package/dist/workspace/sidebar/project-spaces-nav.d.ts +8 -0
- package/dist/workspace/sidebar/project-spaces-nav.js +69 -0
- package/dist/workspace/sidebar/session-group-order.d.ts +9 -0
- package/dist/workspace/sidebar/session-group-order.js +25 -0
- package/dist/workspace/sidebar/session-group-sections.d.ts +62 -0
- package/dist/workspace/sidebar/session-group-sections.js +267 -0
- package/dist/workspace/sidebar/session-list-chrome.d.ts +28 -0
- package/dist/workspace/sidebar/session-list-chrome.js +50 -0
- package/dist/workspace/spaces/channel-glyph.d.ts +5 -0
- package/dist/workspace/spaces/channel-glyph.js +6 -0
- package/dist/workspace/spaces/channel-setup.d.ts +16 -0
- package/dist/workspace/spaces/channel-setup.js +105 -0
- package/dist/workspace/spaces/channels-onboarding.d.ts +13 -0
- package/dist/workspace/spaces/channels-onboarding.js +37 -0
- package/dist/workspace/spaces/create-channel-dialog.d.ts +16 -0
- package/dist/workspace/spaces/create-channel-dialog.js +158 -0
- package/dist/workspace/spaces/private-channels-not-in.d.ts +9 -0
- package/dist/workspace/spaces/private-channels-not-in.js +69 -0
- package/dist/workspace/spaces/space-agents.d.ts +10 -0
- package/dist/workspace/spaces/space-agents.js +10 -0
- package/dist/workspace/spaces/space-details-dialog.d.ts +20 -0
- package/dist/workspace/spaces/space-details-dialog.js +176 -0
- package/dist/workspace/spaces/space-link-label.d.ts +49 -0
- package/dist/workspace/spaces/space-link-label.js +73 -0
- package/dist/workspace/spaces/space-links.d.ts +19 -0
- package/dist/workspace/spaces/space-links.js +230 -0
- package/dist/workspace/spaces/space-members.d.ts +46 -0
- package/dist/workspace/spaces/space-members.js +182 -0
- package/dist/workspace/spaces/space-roster.d.ts +15 -0
- package/dist/workspace/spaces/space-roster.js +44 -0
- package/dist/workspace/spaces/space-threads-tab.d.ts +56 -0
- package/dist/workspace/spaces/space-threads-tab.js +156 -0
- package/dist/workspace/spaces/space-timeline-view.d.ts +254 -0
- package/dist/workspace/spaces/space-timeline-view.js +235 -0
- package/dist/workspace/spaces/space-timeline.d.ts +106 -0
- package/dist/workspace/spaces/space-timeline.js +183 -0
- package/dist/workspace/spaces/space-triggers.d.ts +13 -0
- package/dist/workspace/spaces/space-triggers.js +78 -0
- package/dist/workspace/spaces/space-view.d.ts +37 -0
- package/dist/workspace/spaces/space-view.js +436 -0
- package/package.json +27 -36
- package/skills/kortix-ui/SKILL.md +3 -3
- package/skills/kortix-ui/references/custom-dashboard.md +3 -3
- package/skills/kortix-ui/references/modules.md +28 -4
- package/skills/kortix-ui/references/theming.md +1 -1
- package/dist/customize/connectors/catalog/merge-search.d.ts +0 -10
- package/dist/customize/connectors/catalog/merge-search.js +0 -26
- package/dist/customize/connectors/detail/find-easy-connect-app.d.ts +0 -29
- package/dist/customize/connectors/detail/find-easy-connect-app.js +0 -22
- package/dist/customize/migrate-to-v2/use-migrate-to-v2.d.ts +0 -9
- package/dist/customize/migrate-to-v2/use-migrate-to-v2.js +0 -24
- package/dist/customize/sections/connector-connection-header.d.ts +0 -36
- package/dist/customize/sections/connector-connection-header.js +0 -33
- package/dist/customize/sections/connector-connection-modal.d.ts +0 -34
- package/dist/customize/sections/connector-connection-modal.js +0 -72
- package/dist/customize/sections/discover-catalogue-card.d.ts +0 -19
- package/dist/customize/sections/discover-catalogue-card.js +0 -26
- package/dist/customize/sections/discover-catalogue-detail.d.ts +0 -15
- package/dist/customize/sections/discover-catalogue-detail.js +0 -24
- package/dist/customize/sections/discover-catalogue.d.ts +0 -17
- package/dist/customize/sections/discover-catalogue.js +0 -132
- package/dist/customize/sections/llm-provider/provider-access-menu.d.ts +0 -10
- package/dist/customize/sections/llm-provider/provider-access-menu.js +0 -23
- package/dist/files/project/components/drive-empty-art.d.ts +0 -2
- package/dist/files/project/components/drive-empty-art.js +0 -5
- package/dist/internal/hooks/use-media-query.d.ts +0 -2
- package/dist/internal/share/public-share-link-button.d.ts +0 -14
- package/dist/internal/share/public-share-link-button.js +0 -17
- package/dist/markdown/setup-links/app-credentials-form.d.ts +0 -12
- package/dist/markdown/setup-links/app-credentials-form.js +0 -115
- /package/dist/{internal/hooks → hooks}/use-media-query.js +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type ProjectSpace } from '@kortix/sdk';
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
/** A channel by slug, or the caller's DM with one agent. */
|
|
4
|
+
export type SpaceTarget = {
|
|
5
|
+
kind: 'channel';
|
|
6
|
+
slug: string;
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'dm';
|
|
9
|
+
agentName: string;
|
|
10
|
+
};
|
|
11
|
+
export interface SpaceViewProps {
|
|
12
|
+
projectId: string;
|
|
13
|
+
target: SpaceTarget;
|
|
14
|
+
/** Runs first on every send. Throw to refuse it: the composer keeps the draft (apps/web checks billing here). */
|
|
15
|
+
beforeSend?: () => Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* The Files tab: the host's Drive folder view for the space (apps/web
|
|
18
|
+
* passes its Drive explorer). Absent: the tab shows its empty state. The
|
|
19
|
+
* Memory tab is the space's memory pages (`MemoryView`).
|
|
20
|
+
*/
|
|
21
|
+
renderFolder?: (folder: SpaceFolder) => ReactNode;
|
|
22
|
+
/** A channel's Apps tab: the host's App gallery for the channel. Absent: its empty state. */
|
|
23
|
+
renderApps?: (space: ProjectSpace) => ReactNode;
|
|
24
|
+
}
|
|
25
|
+
/** What a host's folder view draws: one space's Files tab. `place` is "#general" or the DM's agent. */
|
|
26
|
+
export interface SpaceFolder {
|
|
27
|
+
space: ProjectSpace;
|
|
28
|
+
tab: 'files' | 'memory';
|
|
29
|
+
place: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A channel or DM page under `project_channels`: the header, the tab row
|
|
33
|
+
* (Chat, Threads, and the space's files, memory, apps, links and triggers),
|
|
34
|
+
* and the open thread in a panel on the right. Every message starts a new
|
|
35
|
+
* thread.
|
|
36
|
+
*/
|
|
37
|
+
export declare function SpaceView(props: SpaceViewProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { ApiError } from '@kortix/sdk';
|
|
4
|
+
import { updateCachedProjectSessions, useOpenProjectDm, useProjectConfig, useProjectSpaces, useSession, useSessionPrompts, useProjectSpaceMembers, useUpdateProjectSpace, useVisibleAgents, } from '@kortix/sdk/react';
|
|
5
|
+
import { CaretDownIcon, SquaresFourIcon } from '@phosphor-icons/react';
|
|
6
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
7
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
8
|
+
import { useTranslations } from '../../i18n/index.js';
|
|
9
|
+
import { Close } from '../../icons/close.js';
|
|
10
|
+
import { AgentMark } from '../../internal/components/agent-mark.js';
|
|
11
|
+
import { SidebarToggle } from '../../internal/layout/sidebar-toggle.js';
|
|
12
|
+
import { MemoryView } from '../memory/memory-view.js';
|
|
13
|
+
import { UsedMemoryChip } from '../memory/used-memory-chip.js';
|
|
14
|
+
import { useIsPhone } from '../../hooks/use-mobile.js';
|
|
15
|
+
import { PROJECT_ACTIONS } from '../../internal/lib/project-actions.js';
|
|
16
|
+
import { useProjectCan, useProjectPageCans } from '../../internal/lib/use-project-can.js';
|
|
17
|
+
import { ProjectScope } from '../../internal/project-scope.js';
|
|
18
|
+
import { useComposerPrefillStore } from '../../internal/stores/composer-prefill-store.js';
|
|
19
|
+
import { cn } from '../../lib/utils.js';
|
|
20
|
+
import { uiRoutes } from '../../lib/routes.js';
|
|
21
|
+
import { Button } from '../../primitives/button.js';
|
|
22
|
+
import { ConfirmDialog } from '../../primitives/confirm-dialog.js';
|
|
23
|
+
import { EmptyArt } from '../../primitives/empty-art.js';
|
|
24
|
+
import { EmptyState } from '../../primitives/empty-state.js';
|
|
25
|
+
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../primitives/resizable.js';
|
|
26
|
+
import { ErrorState } from '../../primitives/error-state.js';
|
|
27
|
+
import Hint from '../../primitives/hint.js';
|
|
28
|
+
import { useOptionalSidebar } from '../../primitives/sidebar.js';
|
|
29
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../primitives/tabs.js';
|
|
30
|
+
import { errorToast, successToast } from '../../primitives/toast.js';
|
|
31
|
+
import { UiLink as Link, useUiPathname, useUiRouter, useUiSearchParams } from '../../providers/ui-provider.js';
|
|
32
|
+
import { ComposerChatInput } from '../../session/composer/composer-chat-input.js';
|
|
33
|
+
import { FeaturedAgentsContext } from '../../session/composer/agent-selector.js';
|
|
34
|
+
import { ComposerDropZone } from '../../session/composer/composer-drop-zone.js';
|
|
35
|
+
import { AfterFirstPromptContext } from '../../session/thread/after-first-prompt.js';
|
|
36
|
+
import { SessionThread } from '../../session/thread/session-thread.js';
|
|
37
|
+
import { TranscriptRowsContext } from '../../session/thread/transcript-rows.js';
|
|
38
|
+
import { useProjectHomeSend } from '../layout/use-project-home-send.js';
|
|
39
|
+
import { ChannelSetup } from './channel-setup.js';
|
|
40
|
+
import { ChannelsIntro, GeneralChatHead } from './channels-onboarding.js';
|
|
41
|
+
import { CreateChannelDialog } from './create-channel-dialog.js';
|
|
42
|
+
import { channelRunnableAgents, offeredChannelAgents } from './space-agents.js';
|
|
43
|
+
import { SpaceLinks } from './space-links.js';
|
|
44
|
+
import { SpaceTriggers } from './space-triggers.js';
|
|
45
|
+
import { SpaceDetailsDialog } from './space-details-dialog.js';
|
|
46
|
+
import { ChannelGlyph } from './channel-glyph.js';
|
|
47
|
+
import { JoinChannelButton } from './space-members.js';
|
|
48
|
+
import { SpaceRosterButton } from './space-roster.js';
|
|
49
|
+
import { agentLabel, liveReplyCount, spaceRoster, spaceTabFromParam, spaceTabs, threadIsWorking, } from './space-timeline.js';
|
|
50
|
+
import { SpaceTimeline, useSpaceThreads } from './space-timeline-view.js';
|
|
51
|
+
import { SpaceThreadsTab } from './space-threads-tab.js';
|
|
52
|
+
/** The search and filter keys of the Threads and Links tabs. */
|
|
53
|
+
const TAB_FILTER_PARAMS = ['q', 'status', 'by', 'agent', 'active', 'pinned', 'added'];
|
|
54
|
+
/** The query key of the open thread: it survives a reload and can be linked. */
|
|
55
|
+
const THREAD_PARAM = 'thread';
|
|
56
|
+
/** The open tab. Absent on Chat. */
|
|
57
|
+
const TAB_PARAM = 'tab';
|
|
58
|
+
/** Set by the archive action and by the create dialog's "already exists" link: the archived channel's id. */
|
|
59
|
+
const ARCHIVED_PARAM = 'archived';
|
|
60
|
+
/** `1` when the viewer may not unarchive that channel (the create dialog's 409 said `can_edit: false`). */
|
|
61
|
+
const ARCHIVED_LOCKED_PARAM = 'locked';
|
|
62
|
+
/**
|
|
63
|
+
* The space's tabs, less Apps and Triggers for a caller known to lack their
|
|
64
|
+
* read permission: those lists would answer 403. Shown while the answer loads.
|
|
65
|
+
*/
|
|
66
|
+
function useReadableSpaceTabs(projectId, kind) {
|
|
67
|
+
const triggers = useProjectPageCans(projectId)[PROJECT_ACTIONS.PROJECT_TRIGGER_READ];
|
|
68
|
+
const apps = useProjectCan(projectId, PROJECT_ACTIONS.PROJECT_APP_READ);
|
|
69
|
+
const denied = (can) => !!can && !can.isLoading && !can.isError && !can.allowed;
|
|
70
|
+
const hideApps = denied(apps);
|
|
71
|
+
const hideTriggers = denied(triggers);
|
|
72
|
+
return useMemo(() => spaceTabs(kind).filter((tab) => !(tab === 'apps' && hideApps) && !(tab === 'triggers' && hideTriggers)), [kind, hideApps, hideTriggers]);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A channel or DM page under `project_channels`: the header, the tab row
|
|
76
|
+
* (Chat, Threads, and the space's files, memory, apps, links and triggers),
|
|
77
|
+
* and the open thread in a panel on the right. Every message starts a new
|
|
78
|
+
* thread.
|
|
79
|
+
*/
|
|
80
|
+
export function SpaceView(props) {
|
|
81
|
+
return (_jsx(ProjectScope, { projectId: props.projectId, children: _jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden", children: [_jsx("div", { className: "absolute inset-0 flex flex-col", children: _jsx(SpaceViewBody, { ...props }) }), _jsx(ChannelsIntro, { projectId: props.projectId })] }) }));
|
|
82
|
+
}
|
|
83
|
+
function SpaceViewBody({ projectId, target, beforeSend, renderFolder, renderApps }) {
|
|
84
|
+
const t = useTranslations('spaces.view');
|
|
85
|
+
const router = useUiRouter();
|
|
86
|
+
const pathname = useUiPathname();
|
|
87
|
+
const searchParams = useUiSearchParams();
|
|
88
|
+
const spaces = useProjectSpaces(projectId);
|
|
89
|
+
const openDm = useOpenProjectDm(projectId);
|
|
90
|
+
const channel = target.kind === 'channel'
|
|
91
|
+
? spaces.data?.find((space) => space.kind === 'channel' && space.slug === target.slug)
|
|
92
|
+
: undefined;
|
|
93
|
+
const listedDm = target.kind === 'dm'
|
|
94
|
+
? spaces.data?.find((space) => space.kind === 'dm' && space.dm_agent_name === target.agentName)
|
|
95
|
+
: undefined;
|
|
96
|
+
const openedDm = target.kind === 'dm' && openDm.data?.dm_agent_name === target.agentName ? openDm.data : undefined;
|
|
97
|
+
const space = channel ?? listedDm ?? openedDm;
|
|
98
|
+
// A DM the caller never opened does not exist yet: create it once.
|
|
99
|
+
const dmAgent = target.kind === 'dm' ? target.agentName : null;
|
|
100
|
+
const requestedDm = useRef(null);
|
|
101
|
+
const { mutate: openDmMutate } = openDm;
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (!dmAgent || !spaces.data || listedDm || requestedDm.current === dmAgent)
|
|
104
|
+
return;
|
|
105
|
+
requestedDm.current = dmAgent;
|
|
106
|
+
openDmMutate(dmAgent);
|
|
107
|
+
}, [dmAgent, spaces.data, listedDm, openDmMutate]);
|
|
108
|
+
const threads = useSpaceThreads(projectId, space?.space_id);
|
|
109
|
+
const threadId = searchParams.get(THREAD_PARAM);
|
|
110
|
+
const tabs = useReadableSpaceTabs(projectId, target.kind);
|
|
111
|
+
const requestedTab = spaceTabFromParam(searchParams.get(TAB_PARAM), target.kind);
|
|
112
|
+
const tab = tabs.includes(requestedTab) ? requestedTab : 'chat';
|
|
113
|
+
// `push` adds a history entry, so the browser's Back walks it: a tab, and
|
|
114
|
+
// opening the thread panel. Filters and switching threads replace the entry.
|
|
115
|
+
const setParams = useCallback((change, mode = 'replace') => {
|
|
116
|
+
const params = new URLSearchParams(searchParams);
|
|
117
|
+
change(params);
|
|
118
|
+
const query = params.toString();
|
|
119
|
+
router[mode](query ? `${pathname}?${query}` : pathname, { scroll: false });
|
|
120
|
+
}, [pathname, router, searchParams]);
|
|
121
|
+
// The current history entry is the one this view pushed to open the thread:
|
|
122
|
+
// closing goes Back to the entry under it. A reload, a link or a later tab
|
|
123
|
+
// push makes it someone else's entry, so closing replaces it instead.
|
|
124
|
+
const ownThreadEntry = useRef(false);
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (!threadId)
|
|
127
|
+
ownThreadEntry.current = false;
|
|
128
|
+
}, [threadId]);
|
|
129
|
+
const openThread = useCallback((sessionId) => {
|
|
130
|
+
if (threadId)
|
|
131
|
+
return setParams((params) => params.set(THREAD_PARAM, sessionId));
|
|
132
|
+
ownThreadEntry.current = true;
|
|
133
|
+
setParams((params) => params.set(THREAD_PARAM, sessionId), 'push');
|
|
134
|
+
}, [setParams, threadId]);
|
|
135
|
+
const closeThread = useCallback(() => {
|
|
136
|
+
if (ownThreadEntry.current) {
|
|
137
|
+
ownThreadEntry.current = false;
|
|
138
|
+
return router.back();
|
|
139
|
+
}
|
|
140
|
+
setParams((params) => params.delete(THREAD_PARAM));
|
|
141
|
+
}, [router, setParams]);
|
|
142
|
+
const setTab = useCallback((next) => {
|
|
143
|
+
ownThreadEntry.current = false;
|
|
144
|
+
setParams((params) => {
|
|
145
|
+
// Threads and Links share `q` and `by`: a tab starts unfiltered.
|
|
146
|
+
for (const key of TAB_FILTER_PARAMS)
|
|
147
|
+
params.delete(key);
|
|
148
|
+
if (next === 'chat')
|
|
149
|
+
params.delete(TAB_PARAM);
|
|
150
|
+
else
|
|
151
|
+
params.set(TAB_PARAM, next);
|
|
152
|
+
}, 'push');
|
|
153
|
+
}, [setParams]);
|
|
154
|
+
const title = target.kind === 'channel' ? target.slug : agentLabel(target.agentName);
|
|
155
|
+
// The channel details dialog: the header opens it, and so does the setup block for a viewer who may add no one.
|
|
156
|
+
const [details, setDetails] = useState(null);
|
|
157
|
+
const header = (_jsx(SpaceHeader, { projectId: projectId, target: target, title: title, space: space, sessions: threads.sessions, details: details, setDetails: setDetails }));
|
|
158
|
+
if (!space) {
|
|
159
|
+
let body = null;
|
|
160
|
+
if (spaces.isError && !spaces.data) {
|
|
161
|
+
body = (_jsx(ErrorState, { size: "sm", title: t('loadError'), action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => spaces.refetch(), children: t('retry') }) }));
|
|
162
|
+
}
|
|
163
|
+
else if (target.kind === 'dm' && openDm.isError) {
|
|
164
|
+
body = (_jsx(ErrorState, { size: "sm", title: t('dmFailed'), action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => openDm.mutate(target.agentName), disabled: openDm.isPending, children: t('retry') }) }));
|
|
165
|
+
}
|
|
166
|
+
else if (target.kind === 'channel' && spaces.data) {
|
|
167
|
+
const archivedId = searchParams.get(ARCHIVED_PARAM);
|
|
168
|
+
const fallback = spaces.data.find((candidate) => candidate.is_default);
|
|
169
|
+
body = archivedId ? (_jsx(ArchivedChannel, { projectId: projectId, slug: target.slug, spaceId: archivedId, canEdit: searchParams.get(ARCHIVED_LOCKED_PARAM) !== '1' })) : (_jsx(EmptyState, { size: "sm", title: t('notFound'), description: t('notFoundHint'), action: fallback?.slug ? (_jsx(Button, { asChild: true, variant: "outline", size: "sm", children: _jsx(Link, { href: uiRoutes().channel(projectId, fallback.slug), children: t('openDefault', { name: fallback.slug }) }) })) : null }));
|
|
170
|
+
}
|
|
171
|
+
// Still loading: the header from the URL, an empty body (navigation shows no skeleton).
|
|
172
|
+
return (_jsxs("div", { className: "bg-background flex min-h-0 flex-1 flex-col overflow-hidden", children: [header, _jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center px-5 py-8", children: body })] }));
|
|
173
|
+
}
|
|
174
|
+
const place = space.kind === 'channel' ? `#${space.slug}` : title;
|
|
175
|
+
return (
|
|
176
|
+
// One panel group, always mounted, so opening a thread never remounts the
|
|
177
|
+
// timeline (its scroll and the composer's draft stay). The thread joins
|
|
178
|
+
// the group while one is open; the divider drags, and `autoSaveId` keeps
|
|
179
|
+
// the width per browser. Below `xl` the thread takes the whole width: the
|
|
180
|
+
// timeline panel and the divider hide, and the thread panel's flex-grow
|
|
181
|
+
// fills the row.
|
|
182
|
+
_jsxs(ResizablePanelGroup, { direction: "horizontal", autoSaveId: "kortix:space-thread-split", className: "bg-background min-h-0 flex-1 overflow-hidden", children: [_jsx(ResizablePanel, { id: "space-timeline", order: 1, minSize: 35, defaultSize: 60, className: cn('flex min-w-0 flex-col', threadId && 'max-xl:hidden'), children: _jsxs(ComposerDropZone, { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [header, _jsxs(Tabs, { value: tab, onValueChange: setTab, className: "min-h-0 flex-1 gap-0", children: [_jsx(TabsList, { type: "underline", size: "sm", className: "w-full shrink-0 justify-start gap-4 overflow-x-auto px-5", children: tabs.map((value) => (_jsx(TabsTrigger, { value: value, className: "w-fit flex-none", children: t(`tab.${value}`) }, value))) }), _jsx(SpaceTabs, { projectId: projectId, space: space, place: place, threads: threads, threadId: threadId, onOpenThread: openThread, onOpenMembers: () => setDetails('members'), beforeSend: beforeSend, renderFolder: renderFolder, renderApps: renderApps, tabs: tabs, params: searchParams, setParams: setParams })] })] }) }), threadId ? (_jsxs(_Fragment, { children: [_jsx(ResizableHandle, { className: "bg-border w-px after:absolute after:inset-y-0 after:-left-1.5 after:w-3 max-xl:hidden" }), _jsx(ResizablePanel, { id: "space-thread", order: 2, minSize: 25, maxSize: 65, defaultSize: 40, className: "flex min-w-0 flex-col", children: _jsx(ThreadPanel, { projectId: projectId, sessionId: threadId, context: place, thread: threads.sessions.find((session) => session.session_id === threadId), agentFallback: space.dm_agent_name, onClose: closeThread }, threadId) })] })) : null] }));
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* The tab panels. Chat and Threads read the space's threads; Files is the
|
|
186
|
+
* host's folder view, Memory the space's memory pages, Apps the host's App
|
|
187
|
+
* gallery, Links the channel's links, Triggers the triggers that post here.
|
|
188
|
+
* Files without a host view draws its empty state with the action disabled.
|
|
189
|
+
*/
|
|
190
|
+
function SpaceTabs({ projectId, space, place, threads, threadId, onOpenThread, onOpenMembers, beforeSend, renderFolder, renderApps, tabs, params, setParams, }) {
|
|
191
|
+
const t = useTranslations('spaces.view');
|
|
192
|
+
return (_jsxs(_Fragment, { children: [_jsxs(TabsContent, { value: "chat", className: "flex min-h-0 flex-col", children: [space.is_default ? _jsx(GeneralChatHead, { projectId: projectId }) : null, space.kind === 'channel' ? _jsx(ChannelSetup, { projectId: projectId, space: space, onOpenMembers: onOpenMembers }) : null, _jsx(SpaceTimeline, { projectId: projectId, space: space, threads: threads, selectedId: threadId, onOpenThread: onOpenThread }), _jsx(SpaceComposer, { projectId: projectId, space: space, onOpenThread: onOpenThread, beforeSend: beforeSend })] }), _jsx(TabsContent, { value: "threads", className: "flex min-h-0 flex-col", children: _jsx(SpaceThreadsTab, { projectId: projectId, space: space, threads: threads, selectedId: threadId, onOpenThread: onOpenThread, params: params, setParams: setParams }) }), tabs
|
|
193
|
+
.filter((tab) => tab !== 'chat' && tab !== 'threads')
|
|
194
|
+
.map((tab) => tab === 'memory' ? (_jsx(TabsContent, { value: tab, className: "flex min-h-0 flex-col", children: _jsx(MemoryView, { projectId: projectId, layerKey: space.space_id, place: place }) }, tab)) : renderFolder && tab === 'files' ? (_jsx(TabsContent, { value: tab, className: "flex min-h-0 flex-col", children: renderFolder({ space, tab, place }) }, tab)) : tab === 'links' ? (_jsx(TabsContent, { value: tab, className: "flex min-h-0 flex-col", children: _jsx(SpaceLinks, { projectId: projectId, space: space, place: place, onOpenThread: onOpenThread, params: params, setParams: setParams }) }, tab)) : tab === 'triggers' ? (_jsx(TabsContent, { value: tab, className: "min-h-0 overflow-y-auto", children: _jsx(SpaceTriggers, { projectId: projectId, space: space, place: place }) }, tab)) : tab === 'apps' ? (_jsx(TabsContent, { value: tab, className: "min-h-0 overflow-y-auto", children: renderApps?.(space) ?? (_jsx(EmptyState, { className: "min-h-full", media: _jsx(EmptyArt, { icon: SquaresFourIcon }), title: t('empty.apps.title'), description: t('empty.apps.description', { place }) })) }, tab)) : (_jsx(TabsContent, { value: tab, className: "min-h-0 overflow-y-auto", children: _jsx(EmptyState, { className: "min-h-full", media: _jsx(EmptyArt, {}), title: t(`empty.${tab}.title`), description: t(`empty.${tab}.description`, { place }), action: _jsx(Button, { variant: "outline", size: "sm", disabled: true, children: t(`empty.${tab}.action`) }) }) }, tab)))] }));
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* The header row: `# name ⌄` (the channel's details) and its description,
|
|
198
|
+
* then its members and agents; a DM shows its agent. Same
|
|
199
|
+
* title-bar classes as `ProjectPageHeader`, so it clears the desktop window
|
|
200
|
+
* controls the same way.
|
|
201
|
+
*/
|
|
202
|
+
function SpaceHeader({ projectId, target, title, space, sessions, details, setDetails, }) {
|
|
203
|
+
const t = useTranslations('spaces.view');
|
|
204
|
+
const sidebar = useOptionalSidebar();
|
|
205
|
+
const router = useUiRouter();
|
|
206
|
+
const update = useUpdateProjectSpace(projectId);
|
|
207
|
+
const [renameOpen, setRenameOpen] = useState(false);
|
|
208
|
+
const [archiveOpen, setArchiveOpen] = useState(false);
|
|
209
|
+
const channel = target.kind === 'channel' && space ? space : null;
|
|
210
|
+
// The channel's members and its agent list: the same roster for every
|
|
211
|
+
// viewer. The threads a viewer can load only add their thread counts.
|
|
212
|
+
const members = useProjectSpaceMembers(projectId, channel?.space_id);
|
|
213
|
+
const roster = useMemo(() => {
|
|
214
|
+
const found = spaceRoster(sessions, space?.dm_agent_name);
|
|
215
|
+
const threads = new Map(found.people.map((person) => [person.id, person.threads]));
|
|
216
|
+
const people = (members.data?.members ?? []).map((member) => ({
|
|
217
|
+
id: member.user_id,
|
|
218
|
+
name: member.name,
|
|
219
|
+
email: null,
|
|
220
|
+
avatarUrl: member.avatar_url,
|
|
221
|
+
threads: threads.get(member.user_id) ?? 0,
|
|
222
|
+
}));
|
|
223
|
+
return { people, agents: space?.agents ?? [], agentThreads: found.agentThreads };
|
|
224
|
+
}, [sessions, space?.dm_agent_name, space?.agents, members.data]);
|
|
225
|
+
const archive = () => {
|
|
226
|
+
if (!channel)
|
|
227
|
+
return;
|
|
228
|
+
update.mutate({ spaceId: channel.space_id, input: { archived: true } }, {
|
|
229
|
+
onSuccess: () => {
|
|
230
|
+
setArchiveOpen(false);
|
|
231
|
+
successToast(t('archived'));
|
|
232
|
+
// The page stays on the channel, now archived, with its Unarchive action.
|
|
233
|
+
router.replace(`${uiRoutes().channel(projectId, channel.slug ?? title)}?${ARCHIVED_PARAM}=${encodeURIComponent(channel.space_id)}`);
|
|
234
|
+
},
|
|
235
|
+
onError: () => errorToast(t('archiveFailed')),
|
|
236
|
+
});
|
|
237
|
+
};
|
|
238
|
+
return (_jsxs("div", { className: "kx-titlebar-row kx-capability-titlebar relative flex shrink-0 items-center gap-2 px-2", "data-sidebar-collapsed": sidebar?.state === 'collapsed' || undefined, children: [_jsx(SidebarToggle, {}), _jsxs("div", { className: "kx-titlebar-tabs flex h-12 min-w-0 flex-1 items-center gap-2", children: [target.kind === 'channel' ? (_jsx("h1", { className: "flex min-w-0 shrink-0", children: channel ? (
|
|
239
|
+
// `#name` reads as one token, the caret as a separate affordance:
|
|
240
|
+
// 2px between `#` and the name, 6px before the caret. The `#` is
|
|
241
|
+
// bold at `size-4.5`, so its strokes match the 600 name and its
|
|
242
|
+
// height matches the name's cap height. `has-[>svg]:px-1.5`, not
|
|
243
|
+
// `px-*`: the `sm` size's own `has-[>svg]:px-2.5` would win.
|
|
244
|
+
_jsxs(Button, { variant: "ghost", size: "sm", className: "max-w-60 gap-0 has-[>svg]:px-1.5", "aria-label": t('channelDetails', { name: title }), onClick: () => setDetails('about'), children: [_jsx(ChannelGlyph, { visibility: channel.visibility, weight: "bold", className: "size-4.5 shrink-0" }), _jsx("span", { className: "ml-0.5 truncate text-lg font-semibold", children: title }), _jsx(CaretDownIcon, { weight: "bold", className: "text-muted-foreground ml-1.5 size-3.5 shrink-0" })] })) : (_jsxs("span", { className: "flex h-8 items-center px-1.5", children: [_jsx(ChannelGlyph, { weight: "bold", className: "size-4.5 shrink-0" }), _jsx("span", { className: "ml-0.5 truncate text-lg font-semibold", children: title })] })) })) : (_jsxs("h1", { className: "flex min-w-0 shrink-0 items-center gap-2 px-2", children: [_jsx(AgentMark, { slug: target.agentName, size: 14 }), _jsx("span", { className: "truncate text-lg font-semibold", children: title })] })), channel?.description ? (_jsx("p", { className: "text-muted-foreground min-w-0 truncate text-xs", title: channel.description, children: channel.description })) : null] }), channel && channel.is_member === false && channel.visibility !== 'private' ? _jsx(JoinChannelButton, { projectId: projectId, space: channel }) : null, channel && (roster.people.length > 0 || roster.agents.length > 0) ? (_jsx(SpaceRosterButton, { roster: roster, onViewAll: () => setDetails('members') })) : null, channel ? (_jsxs(_Fragment, { children: [_jsx(SpaceDetailsDialog, { space: channel, tab: details, onTabChange: setDetails, onOpenChange: (open) => setDetails(open ? 'about' : null), onEdit: () => {
|
|
245
|
+
setDetails(null);
|
|
246
|
+
setRenameOpen(true);
|
|
247
|
+
}, onArchive: () => {
|
|
248
|
+
setDetails(null);
|
|
249
|
+
setArchiveOpen(true);
|
|
250
|
+
} }), _jsx(CreateChannelDialog, { projectId: projectId, open: renameOpen, onOpenChange: setRenameOpen, space: channel }), _jsx(ConfirmDialog, { open: archiveOpen, onOpenChange: setArchiveOpen, title: t('archiveTitle', { name: title }), description: t('archiveDescription'), confirmLabel: t('archive'), onConfirm: archive, isPending: update.isPending })] })) : null] }));
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* `/c/<slug>` of an archived channel whose id the link carried. Its creator or a
|
|
254
|
+
* project manager (`canEdit`) may bring it back; anyone else reads who can.
|
|
255
|
+
*/
|
|
256
|
+
function ArchivedChannel({ projectId, slug, spaceId, canEdit, }) {
|
|
257
|
+
const t = useTranslations('spaces.view');
|
|
258
|
+
const router = useUiRouter();
|
|
259
|
+
const update = useUpdateProjectSpace(projectId);
|
|
260
|
+
const unarchive = () => update.mutate({ spaceId, input: { archived: false } }, {
|
|
261
|
+
onSuccess: (space) => {
|
|
262
|
+
successToast(t('unarchived'));
|
|
263
|
+
router.replace(uiRoutes().channel(projectId, space.slug ?? slug));
|
|
264
|
+
},
|
|
265
|
+
onError: (err) => errorToast(t(err instanceof ApiError && err.status === 403 ? 'archivedLocked' : 'unarchiveFailed')),
|
|
266
|
+
});
|
|
267
|
+
if (!canEdit) {
|
|
268
|
+
return _jsx(EmptyState, { size: "sm", title: t('archivedTitle', { name: slug }), description: t('archivedLocked') });
|
|
269
|
+
}
|
|
270
|
+
return (_jsx(EmptyState, { size: "sm", title: t('archivedTitle', { name: slug }), description: t('archivedHint'), action: _jsx(Button, { variant: "outline", size: "sm", onClick: unarchive, disabled: update.isPending, "aria-busy": update.isPending || undefined, children: t('unarchive') }) }));
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* The composer under the timeline. Every send creates a new thread in this
|
|
274
|
+
* space (`useProjectHomeSend` with `space`): the billing gate, uploads and the
|
|
275
|
+
* first prompt work as on project home, and the new thread opens on the right.
|
|
276
|
+
*/
|
|
277
|
+
function SpaceComposer({ projectId, space, onOpenThread, beforeSend, }) {
|
|
278
|
+
const t = useTranslations('spaces.view');
|
|
279
|
+
const isPhone = useIsPhone();
|
|
280
|
+
const spaceSend = useMemo(() => ({ spaceId: space.space_id, onOpen: onOpenThread }), [space.space_id, onOpenThread]);
|
|
281
|
+
const { send, sending } = useProjectHomeSend(projectId, { beforeSend, space: spaceSend });
|
|
282
|
+
const draftScope = useMemo(() => ({ kind: 'space', spaceId: space.space_id }), [space.space_id]);
|
|
283
|
+
// A prompt handed to project home (`?q=`, "start in chat") lands here, since home opens the default channel.
|
|
284
|
+
const pendingPrefill = useComposerPrefillStore((s) => s.prefillByProject[projectId]);
|
|
285
|
+
const consumePrefill = useComposerPrefillStore((s) => s.consume);
|
|
286
|
+
const [prefill, setPrefill] = useState(null);
|
|
287
|
+
useEffect(() => {
|
|
288
|
+
if (!pendingPrefill)
|
|
289
|
+
return;
|
|
290
|
+
consumePrefill(projectId);
|
|
291
|
+
setPrefill({
|
|
292
|
+
text: pendingPrefill.text,
|
|
293
|
+
id: Date.now(),
|
|
294
|
+
submit: pendingPrefill.submit,
|
|
295
|
+
files: pendingPrefill.files,
|
|
296
|
+
options: pendingPrefill.options,
|
|
297
|
+
});
|
|
298
|
+
}, [pendingPrefill, projectId, consumePrefill]);
|
|
299
|
+
const onCommand = useCallback((command, args, options) => {
|
|
300
|
+
// The send rejects on failure; the hook already showed the error.
|
|
301
|
+
void Promise.resolve(send(`/${command.name}${args ? ` ${args}` : ''}`, undefined, options)).catch(() => undefined);
|
|
302
|
+
}, [send]);
|
|
303
|
+
const agent = space.dm_agent_name;
|
|
304
|
+
// A channel's agents lead its picker; the first one the project still offers starts a new thread.
|
|
305
|
+
const visible = useVisibleAgents({ projectId });
|
|
306
|
+
const projectConfig = useProjectConfig(projectId);
|
|
307
|
+
const projectDefault = projectConfig?.default_agent ?? projectConfig?.open_code_default_agent ?? null;
|
|
308
|
+
// A member with no agent grant still posts here with the channel's agents.
|
|
309
|
+
const runnable = useMemo(() => channelRunnableAgents(space, projectDefault), [space, projectDefault]);
|
|
310
|
+
const offered = useMemo(() => [...visible, ...runnable.filter((name) => !visible.some((a) => a.name === name)).map((name) => ({ name }))], [visible, runnable]);
|
|
311
|
+
const channelAgents = useMemo(() => offeredChannelAgents(space, offered), [space, offered]);
|
|
312
|
+
const channelName = space.slug ?? space.name;
|
|
313
|
+
const featured = useMemo(() => (channelAgents.length > 0 ? { label: `#${channelName}`, restLabel: t('allAgents'), names: channelAgents } : null), [channelAgents, channelName, t]);
|
|
314
|
+
return (_jsx("div", { className: "shrink-0 pt-1 pb-4", children: _jsx(FeaturedAgentsContext.Provider, { value: featured, children: _jsx(ComposerChatInput, { defaultAgentName: channelAgents[0] ?? null, channelAgentNames: runnable, onSend: send, onCommand: onCommand, projectId: projectId, draftScope: draftScope, isSending: sending, disabled: sending,
|
|
315
|
+
// The box empties at the keypress; the thread on the right draws the attachments.
|
|
316
|
+
clearOnSend: "text-only", boundAgentName: agent,
|
|
317
|
+
// `hint`, not `placeholder`: a placeholder is only the first frame of
|
|
318
|
+
// the rotating tips, and this box must always say where the message goes.
|
|
319
|
+
hint: agent ? t('messageAgent', { agent: agentLabel(agent) }) : t('messageChannel', { name: space.slug ?? space.name }), prefill: prefill,
|
|
320
|
+
// Attach, agent and settings inside the bordered box, down to a 720px
|
|
321
|
+
// window. A phone's toolbar is too narrow beside the model selector, so
|
|
322
|
+
// it keeps the row beneath.
|
|
323
|
+
underbarPlacement: isPhone ? 'below' : 'inline', slashMenuPlacement: "above",
|
|
324
|
+
// The timeline's width and side margins, not the centred session column.
|
|
325
|
+
parentClassName: "max-w-none px-5" }) }) }));
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* "N replies" with a hairline to the right. At 0 (the first answer pending)
|
|
329
|
+
* the hairline is drawn alone at the same place and height, and the count
|
|
330
|
+
* fades in when the answer lands: the answer row never moves.
|
|
331
|
+
*/
|
|
332
|
+
function RepliesDivider({ count, className }) {
|
|
333
|
+
const t = useTranslations('spaces.view');
|
|
334
|
+
return (_jsxs("div", { className: cn('flex items-center gap-3 px-5', className), children: [_jsx("span", { "aria-hidden": count === 0 || undefined, className: cn('text-muted-foreground shrink-0 text-xs tabular-nums transition-opacity duration-(--duration-normal) ease-out motion-reduce:transition-none', count === 0 && 'opacity-0'), children: t('replies', { count: Math.max(count, 1) }) }), _jsx("div", { className: "bg-border h-px flex-1" })] }));
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* The open thread, beside the timeline: its header, then the session's
|
|
338
|
+
* transcript drawn as message rows (`TranscriptRowsContext`) with the reply
|
|
339
|
+
* composer under it. Sending continues the same session.
|
|
340
|
+
*/
|
|
341
|
+
function ThreadPanel({ projectId, sessionId, context, thread, agentFallback, onClose, }) {
|
|
342
|
+
const t = useTranslations('spaces.view');
|
|
343
|
+
const session = useSession(projectId, sessionId);
|
|
344
|
+
useLiveThreadRow(projectId, sessionId, session);
|
|
345
|
+
// Null from an older API that does not count replies.
|
|
346
|
+
const replyCount = thread?.reply_count ?? null;
|
|
347
|
+
const dividerOnTop = Boolean(replyCount) && session.hasOlder;
|
|
348
|
+
const answered = session.messages.some((message) => message.info.role === 'assistant');
|
|
349
|
+
// A turn has finished: the thread's "Used memory" record can be read.
|
|
350
|
+
const turnDone = !session.isBusy && answered;
|
|
351
|
+
// The first answer is on its way (or landed a frame before its count):
|
|
352
|
+
// the divider is drawn without a count, so the answer does not push it in.
|
|
353
|
+
const answerPending = replyCount === 0 && (session.isBusy || answered || (!!thread && threadIsWorking(thread)));
|
|
354
|
+
// Stable across stream frames: every memoized turn reads this context.
|
|
355
|
+
// "Used memory" sits under the first prompt, or heads the panel with the divider.
|
|
356
|
+
const afterFirstPrompt = useMemo(() => dividerOnTop ? null : (_jsxs(_Fragment, { children: [replyCount || answerPending ? _jsx(RepliesDivider, { count: replyCount ?? 0, className: "py-2" }) : null, _jsx(UsedMemoryChip, { projectId: projectId, sessionId: sessionId, ready: turnDone, className: "px-5" })] })), [replyCount, answerPending, dividerOnTop, projectId, sessionId, turnDone]);
|
|
357
|
+
const agentName = session.agentName ?? thread?.agent_name ?? agentFallback;
|
|
358
|
+
const rows = useMemo(() => ({
|
|
359
|
+
agent: agentName ? agentLabel(agentName) : t('agentFallback'),
|
|
360
|
+
agentSlug: agentName ?? undefined,
|
|
361
|
+
owner: thread
|
|
362
|
+
? { name: thread.owner_name ?? null, email: thread.owner_email ?? null, avatarUrl: thread.owner_avatar_url ?? null }
|
|
363
|
+
: null,
|
|
364
|
+
unknownAuthor: t('authorFallback'),
|
|
365
|
+
// The composer's computer notices say "thread", never "session".
|
|
366
|
+
notices: {
|
|
367
|
+
unreachable: t('notice.unreachable'),
|
|
368
|
+
unreachableMidTurn: t('notice.unreachableMidTurn'),
|
|
369
|
+
stalled: t('notice.stalled'),
|
|
370
|
+
starting: t('notice.starting'),
|
|
371
|
+
idle: t('notice.idle'),
|
|
372
|
+
waking: t('notice.waking'),
|
|
373
|
+
},
|
|
374
|
+
labels: {
|
|
375
|
+
restart: t('boot.restart'),
|
|
376
|
+
},
|
|
377
|
+
}), [agentName, thread, t]);
|
|
378
|
+
return (_jsxs("aside", { "aria-label": t('threadTitle'), className: "bg-background flex min-h-0 w-full flex-1 flex-col", children: [_jsxs("div", { className: "kx-titlebar-row relative flex shrink-0 items-center gap-2 border-b px-2", children: [_jsx("div", { className: "kx-titlebar-tabs flex h-12 min-w-0 flex-1 items-center px-3", children: _jsxs("div", { className: "flex min-w-0 items-baseline gap-2", children: [_jsx("h2", { className: "text-base font-semibold", children: t('threadTitle') }), _jsx("span", { className: "text-muted-foreground truncate text-xs", children: context })] }) }), _jsx(Hint, { label: t('closeThread'), side: "bottom", children: _jsx(Button, { variant: "ghost", size: "icon-md", "aria-label": t('closeThread'), onClick: onClose, children: _jsx(Close, {}) }) })] }), replyCount && dividerOnTop ? (_jsxs("div", { className: "shrink-0 pt-3", children: [_jsx(RepliesDivider, { count: replyCount }), _jsx(UsedMemoryChip, { projectId: projectId, sessionId: sessionId, ready: turnDone, className: "px-5" })] })) : null, _jsx(TranscriptRowsContext.Provider, { value: rows, children: _jsx(AfterFirstPromptContext.Provider, { value: afterFirstPrompt, children: _jsx(SessionThread, { session: session, hideHeader: true, composerPlaceholder: t('replyPlaceholder'), className: "min-h-0 flex-1" }) }) })] }));
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* The open thread's live stream, written into its row in the space's cached
|
|
382
|
+
* list: the timeline's "N replies", "Last reply" and "is working" change the
|
|
383
|
+
* frame the panel does, not at the list's next poll (5 s working, 15 s idle).
|
|
384
|
+
* The count needs the whole transcript (`hasOlder` false); with older history
|
|
385
|
+
* unloaded only the working state is written. The poll still reconciles.
|
|
386
|
+
*/
|
|
387
|
+
function useLiveThreadRow(projectId, sessionId, session) {
|
|
388
|
+
const queryClient = useQueryClient();
|
|
389
|
+
const busy = session.isBusy;
|
|
390
|
+
// A reply counts from Enter: the prompt inbox holds it (optimistically)
|
|
391
|
+
// until the transcript has its message. The same query the panel's chat reads.
|
|
392
|
+
const inbox = useSessionPrompts(projectId, sessionId);
|
|
393
|
+
const ids = new Set(session.messages.map((message) => message.info.id));
|
|
394
|
+
const waiting = inbox.prompts.filter((prompt) => prompt.state !== 'failed' && !ids.has(prompt.message_id) && !(prompt.wire_message_id && ids.has(prompt.wire_message_id))).length;
|
|
395
|
+
const roles = [
|
|
396
|
+
...session.messages.map((message) => message.info.role),
|
|
397
|
+
...Array.from({ length: waiting }, () => 'user'),
|
|
398
|
+
];
|
|
399
|
+
const replies = session.hasOlder || roles.length === 0 ? null : liveReplyCount(roles);
|
|
400
|
+
// The stream has an answer: the computer is up, so a booting status is stale.
|
|
401
|
+
const answered = roles.includes('assistant');
|
|
402
|
+
// Sent, not yet running: the thread is working from Enter.
|
|
403
|
+
const working = busy || waiting > 0;
|
|
404
|
+
// Before the runtime is up the stream knows nothing: the list's own state stands.
|
|
405
|
+
const live = !!session.runtimeSessionId;
|
|
406
|
+
useEffect(() => {
|
|
407
|
+
if (!live)
|
|
408
|
+
return;
|
|
409
|
+
updateCachedProjectSessions(queryClient, projectId, (rows) => {
|
|
410
|
+
const index = rows.findIndex((row) => row.session_id === sessionId);
|
|
411
|
+
const row = rows[index];
|
|
412
|
+
if (!row)
|
|
413
|
+
return rows;
|
|
414
|
+
const grew = replies !== null && replies > (row.reply_count ?? 0);
|
|
415
|
+
const booting = row.status === 'provisioning' || row.status === 'queued' || row.status === 'branching';
|
|
416
|
+
const settle = (working || answered) && booting;
|
|
417
|
+
if (!grew && !settle && (row.working?.state === 'working') === working)
|
|
418
|
+
return rows;
|
|
419
|
+
const now = new Date().toISOString();
|
|
420
|
+
const next = rows.slice();
|
|
421
|
+
next[index] = {
|
|
422
|
+
...row,
|
|
423
|
+
...(grew ? { reply_count: replies, updated_at: now } : {}),
|
|
424
|
+
// `threadIsWorking` reads the status too: a thread the stream answers is up.
|
|
425
|
+
...(settle ? { status: 'running' } : {}),
|
|
426
|
+
working: {
|
|
427
|
+
state: working ? 'working' : 'idle',
|
|
428
|
+
since: working ? (row.working?.since ?? now) : null,
|
|
429
|
+
turn_token: row.working?.turn_token ?? null,
|
|
430
|
+
pending_delivery: false,
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
return next;
|
|
434
|
+
});
|
|
435
|
+
}, [queryClient, projectId, sessionId, live, working, replies, answered]);
|
|
436
|
+
}
|