@kortix/ui 0.14.11 → 0.14.13
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 +1 -1
- package/dist/_vendor/kortix-shared.js +521 -7045
- package/dist/_vendor/shared/app-config.d.ts +8 -0
- package/dist/_vendor/shared/artifact-annotations.d.ts +708 -0
- package/dist/_vendor/shared/artifact-comments.d.ts +327 -0
- package/dist/_vendor/shared/index.d.ts +3 -1
- package/dist/_vendor/shared/my-kortix-agent.d.ts +40 -0
- package/dist/_vendor/shared/peer-message-prompt.d.ts +35 -0
- package/dist/_vendor/shared/pixel-mark.d.ts +11 -0
- package/dist/_vendor/shared/prompt-attachments.d.ts +1 -0
- package/dist/_vendor/shared/reminder-prompt.d.ts +8 -2
- package/dist/_vendor/shared/runtime-versions.d.ts +8 -0
- package/dist/artifacts/artifact-frame.d.ts +1 -0
- package/dist/artifacts/artifact-frame.js +18 -5
- package/dist/artifacts/frame-policy.d.ts +1 -1
- package/dist/artifacts/frame-policy.js +10 -5
- package/dist/browser/browser-panel.d.ts +2 -1
- package/dist/browser/browser-panel.js +12 -2
- package/dist/customize/agents/agent-access-text.d.ts +16 -0
- package/dist/customize/agents/agent-access-text.js +54 -0
- package/dist/customize/agents/agent-approval-rules.d.ts +8 -0
- package/dist/customize/agents/agent-approval-rules.js +26 -0
- package/dist/customize/agents/agent-authority-card.js +4 -1
- package/dist/customize/agents/agent-cover-card.d.ts +4 -1
- package/dist/customize/agents/agent-cover-card.js +2 -2
- package/dist/customize/agents/agent-detail-aside.d.ts +1 -2
- package/dist/customize/agents/agent-detail-aside.js +8 -11
- package/dist/customize/agents/agent-drives-section.d.ts +23 -7
- package/dist/customize/agents/agent-drives-section.js +107 -41
- package/dist/customize/agents/agent-instructions.d.ts +11 -0
- package/dist/customize/agents/agent-instructions.js +114 -0
- package/dist/customize/agents/agent-model-view.d.ts +17 -0
- package/dist/customize/agents/agent-model-view.js +67 -0
- package/dist/customize/agents/agent-overview.d.ts +53 -0
- package/dist/customize/agents/agent-overview.js +242 -0
- package/dist/customize/agents/agent-page-chrome.d.ts +128 -0
- package/dist/customize/agents/agent-page-chrome.js +145 -0
- package/dist/customize/agents/agent-page.d.ts +13 -1
- package/dist/customize/agents/agent-page.js +478 -367
- package/dist/customize/agents/agent-pin-button.d.ts +10 -0
- package/dist/customize/agents/agent-pin-button.js +20 -0
- package/dist/customize/agents/agent-policy-sets-section.d.ts +16 -0
- package/dist/customize/agents/agent-policy-sets-section.js +80 -0
- package/dist/customize/agents/agent-policy-sets.js +1 -1
- package/dist/customize/agents/agent-section-rail.d.ts +21 -0
- package/dist/customize/agents/agent-section-rail.js +23 -0
- package/dist/customize/agents/agent-share-control.d.ts +4 -3
- package/dist/customize/agents/agent-share-control.js +15 -16
- package/dist/customize/agents/{agent-people-section.d.ts → agent-share-dialog.d.ts} +3 -1
- package/dist/customize/agents/{agent-people-section.js → agent-share-dialog.js} +21 -21
- package/dist/customize/agents/agent-tabs.d.ts +95 -0
- package/dist/customize/agents/agent-tabs.js +199 -0
- package/dist/customize/agents/agents-page.d.ts +0 -21
- package/dist/customize/agents/agents-page.js +104 -118
- package/dist/customize/agents/connectors-required.d.ts +16 -0
- package/dist/customize/agents/connectors-required.js +19 -0
- package/dist/customize/agents/create-agent-modal.d.ts +19 -0
- package/dist/customize/agents/create-agent-modal.js +94 -0
- package/dist/customize/connectors/agent-access.d.ts +4 -4
- package/dist/customize/connectors/agent-access.js +7 -10
- package/dist/customize/connectors/connector-identity.d.ts +12 -0
- package/dist/customize/connectors/connector-identity.js +15 -2
- package/dist/customize/connectors/connector-routes.js +2 -2
- package/dist/customize/connectors/connectors-page.d.ts +14 -1
- package/dist/customize/connectors/connectors-page.js +101 -32
- package/dist/customize/connectors/detail/app-page.js +1 -1
- package/dist/customize/connectors/detail/connector-agents.js +0 -3
- package/dist/customize/connectors/detail/connector-page.d.ts +1 -1
- package/dist/customize/connectors/detail/connector-page.js +5 -2
- package/dist/customize/connectors/detail/connector-policy-sets.js +1 -1
- package/dist/customize/connectors/detail/connector-triggers.js +2 -2
- package/dist/customize/connectors/use-agent-access.d.ts +7 -5
- package/dist/customize/connectors/use-agent-access.js +2 -6
- package/dist/customize/models/models-page.d.ts +7 -1
- package/dist/customize/models/models-page.js +2 -2
- package/dist/customize/project-settings/project-admin-sections.d.ts +63 -0
- package/dist/customize/project-settings/project-admin-sections.js +80 -0
- package/dist/customize/project-settings/project-settings-page.d.ts +1 -1
- package/dist/customize/project-settings/project-settings-page.js +4 -13
- package/dist/customize/project-settings/project-settings-sections.d.ts +5 -5
- package/dist/customize/project-settings/project-settings-sections.js +6 -20
- package/dist/customize/providers/provider-accordion.js +29 -17
- package/dist/customize/providers/provider-connect.js +1 -1
- package/dist/customize/providers/provider-sheet.d.ts +4 -1
- package/dist/customize/providers/provider-sheet.js +15 -5
- package/dist/customize/secrets/secrets-page.d.ts +5 -1
- package/dist/customize/secrets/secrets-page.js +2 -2
- package/dist/customize/sections/gateway-view.d.ts +10 -2
- package/dist/customize/sections/gateway-view.js +16 -4
- package/dist/customize/sections/llm-provider/chatgpt-subscription-connect.d.ts +12 -5
- package/dist/customize/sections/llm-provider/chatgpt-subscription-connect.js +131 -8
- package/dist/customize/sections/llm-provider/claude-code-step.d.ts +10 -0
- package/dist/customize/sections/llm-provider/claude-code-step.js +32 -0
- package/dist/customize/sections/llm-provider/models-tab.js +5 -1
- package/dist/customize/sections/view/account-secret-resources-panel.d.ts +5 -3
- package/dist/customize/sections/view/account-secret-resources-panel.js +122 -19
- package/dist/customize/sections/view/agent-editor-access-fields.d.ts +1 -1
- package/dist/customize/sections/view/agent-editor-access-fields.js +8 -4
- package/dist/customize/sections/view/agent-editor-basics-fields.d.ts +4 -1
- package/dist/customize/sections/view/agent-editor-basics-fields.js +33 -4
- package/dist/customize/sections/view/agent-editor-catalog.d.ts +2 -2
- package/dist/customize/sections/view/agent-editor-catalog.js +10 -12
- package/dist/customize/sections/view/agent-editor-primitives.d.ts +1 -1
- package/dist/customize/sections/view/agent-editor-primitives.js +4 -4
- package/dist/customize/sections/view/agent-editor.d.ts +37 -26
- package/dist/customize/sections/view/agent-editor.js +19 -19
- package/dist/customize/sections/view/grant-mode-field.d.ts +8 -20
- package/dist/customize/sections/view/grant-mode-field.js +31 -57
- package/dist/customize/sections/view/permission-editor.d.ts +3 -1
- package/dist/customize/sections/view/permission-editor.js +19 -10
- package/dist/customize/sections/view/review-view.d.ts +8 -0
- package/dist/customize/sections/view/review-view.js +12 -1
- package/dist/customize/sections/view/secret-delivery.js +1 -4
- package/dist/customize/sections/view/secrets-view.d.ts +7 -1
- package/dist/customize/sections/view/secrets-view.js +42 -6
- package/dist/customize/settings/rail.js +2 -8
- package/dist/customize/settings/settings-tabs.d.ts +2 -2
- package/dist/customize/settings/settings-tabs.js +17 -19
- package/dist/customize/settings/tabs/experimental-tab.d.ts +3 -0
- package/dist/customize/settings/tabs/experimental-tab.js +6 -1
- package/dist/customize/settings/tabs/sandbox-tab.d.ts +4 -6
- package/dist/customize/settings/tabs/sandbox-tab.js +9 -9
- package/dist/customize/shared/access-list.d.ts +39 -0
- package/dist/customize/shared/access-list.js +62 -0
- package/dist/customize/shared/agent-resource-scope.d.ts +87 -0
- package/dist/customize/shared/agent-resource-scope.js +123 -0
- package/dist/customize/shared/capability-library.d.ts +41 -0
- package/dist/customize/shared/capability-library.js +271 -0
- package/dist/customize/shared/capability-page-shell.d.ts +18 -1
- package/dist/customize/shared/capability-page-shell.js +21 -1
- package/dist/customize/shared/catalog/catalog-space-tabs.d.ts +14 -0
- package/dist/customize/shared/catalog/catalog-space-tabs.js +20 -0
- package/dist/customize/shared/customize-tab-bar.d.ts +13 -0
- package/dist/customize/shared/customize-tab-bar.js +95 -0
- package/dist/customize/shared/entity/entity-modal.d.ts +17 -1
- package/dist/customize/shared/entity/entity-modal.js +10 -9
- package/dist/customize/shared/leave-guard.d.ts +23 -0
- package/dist/customize/shared/leave-guard.js +87 -0
- package/dist/customize/shared/standalone-settings-nav.js +4 -1
- package/dist/customize/shared/tool-rules.d.ts +11 -0
- package/dist/customize/shared/tool-rules.js +29 -0
- package/dist/customize/skills/builtin-skill-modal.d.ts +6 -0
- package/dist/customize/skills/builtin-skill-modal.js +41 -0
- package/dist/customize/skills/skills-page.d.ts +21 -18
- package/dist/customize/skills/skills-page.js +16 -110
- package/dist/customize/triggers/runtime-triggers.d.ts +17 -0
- package/dist/customize/triggers/runtime-triggers.js +57 -0
- package/dist/customize/triggers/schedule/event-trigger-copy.js +2 -2
- package/dist/customize/triggers/schedule/post-to-field.js +2 -2
- package/dist/customize/triggers/schedule/schedule-copy.d.ts +11 -6
- package/dist/customize/triggers/schedule/schedule-copy.js +29 -8
- package/dist/customize/triggers/schedule/schedule-detail-sheet.js +7 -3
- package/dist/customize/triggers/schedule/trigger-composer-logic.d.ts +26 -1
- package/dist/customize/triggers/schedule/trigger-composer-logic.js +64 -3
- package/dist/customize/triggers/schedule/trigger-composer.js +57 -20
- package/dist/customize/triggers/schedule/trigger-edit-logic.js +18 -5
- package/dist/customize/triggers/schedule/trigger-filter.d.ts +10 -0
- package/dist/customize/triggers/schedule/trigger-filter.js +16 -0
- 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/use-trigger-mutations.d.ts +1 -1
- package/dist/customize/triggers/schedule/use-trigger-mutations.js +1 -1
- package/dist/customize/triggers/schedule/when-app.d.ts +15 -0
- package/dist/customize/triggers/schedule/when-app.js +21 -0
- package/dist/customize/triggers/schedule/when-change-request.d.ts +10 -0
- package/dist/customize/triggers/schedule/when-change-request.js +15 -0
- package/dist/customize/triggers/schedule-view.d.ts +17 -3
- package/dist/customize/triggers/schedule-view.js +46 -16
- package/dist/customize/triggers/triggers-page.d.ts +3 -3
- package/dist/customize/triggers/triggers-page.js +2 -2
- package/dist/customize/use-configure-thread.d.ts +8 -2
- package/dist/customize/use-configure-thread.js +30 -18
- package/dist/files/project/components/change-request-detail-dialog.js +2 -3
- package/dist/files/project/components/drive-explorer.js +6 -5
- package/dist/files/project/explorer-source.d.ts +3 -0
- package/dist/files/project/upload-batch.d.ts +3 -3
- package/dist/files/project/upload-batch.js +7 -6
- package/dist/files/runtime/sandbox-explorer-source.js +3 -3
- package/dist/i18n/en.d.ts +1331 -53
- package/dist/i18n/en.js +1423 -145
- package/dist/i18n/ui-catalog/remaining-ui-translation-keys.generated.js +16 -7
- package/dist/internal/auth/auth-primitives.d.ts +1 -3
- package/dist/internal/auth/auth-primitives.js +2 -2
- package/dist/internal/billing/session-cost-format.d.ts +1 -0
- package/dist/internal/billing/session-cost-format.js +11 -0
- package/dist/internal/components/agent-mark.d.ts +12 -1
- package/dist/internal/components/agent-mark.js +34 -11
- package/dist/internal/components/nav-rail.d.ts +22 -0
- package/dist/internal/components/nav-rail.js +16 -0
- package/dist/internal/components/repository-disconnected.js +2 -2
- package/dist/internal/goals/goal-meta.d.ts +15 -1
- package/dist/internal/goals/goal-meta.js +42 -2
- package/dist/internal/hooks/projects/use-agent-config.d.ts +11 -7
- package/dist/internal/hooks/projects/use-agent-config.js +28 -11
- package/dist/internal/hooks/use-slash-focus.d.ts +7 -1
- package/dist/internal/hooks/use-slash-focus.js +9 -3
- package/dist/internal/layout/project-capability-nav.d.ts +24 -0
- package/dist/internal/layout/project-capability-nav.js +86 -0
- package/dist/internal/layout/project-page-header.d.ts +1 -1
- package/dist/internal/layout/project-page-header.js +1 -1
- package/dist/internal/layout/project-settings-nav.d.ts +3 -2
- package/dist/internal/layout/project-settings-nav.js +5 -3
- package/dist/internal/lib/browser-noise/rules/extensions.js +3 -0
- package/dist/internal/lib/browser-noise/rules/old-browsers.js +1 -1
- package/dist/internal/lib/capability-tab-routes.d.ts +34 -3
- package/dist/internal/lib/capability-tab-routes.js +76 -8
- package/dist/internal/lib/manifest-health.d.ts +10 -0
- package/dist/internal/lib/manifest-health.js +20 -0
- package/dist/internal/lib/pixel-mark.d.ts +4 -1
- package/dist/internal/lib/pixel-mark.js +33 -6
- package/dist/internal/lib/project-actions.d.ts +1 -1
- package/dist/internal/lib/project-actions.js +0 -4
- package/dist/internal/lib/provider-branding.js +2 -0
- package/dist/internal/lib/space-scope.d.ts +29 -0
- package/dist/internal/lib/space-scope.js +28 -0
- package/dist/internal/lib/use-project-feature-flags.js +3 -3
- package/dist/internal/lib/web-notifications.d.ts +74 -8
- package/dist/internal/lib/web-notifications.js +243 -117
- package/dist/internal/notifications/notification-rows.d.ts +14 -7
- package/dist/internal/notifications/notification-rows.js +21 -14
- package/dist/internal/notifications/session-toast-cards.d.ts +2 -2
- package/dist/internal/reminders/reminder-format.d.ts +6 -2
- package/dist/internal/reminders/reminder-format.js +7 -1
- package/dist/internal/stores/active-space-store.d.ts +35 -0
- package/dist/internal/stores/active-space-store.js +29 -0
- package/dist/internal/stores/kortix-computer-store.d.ts +2 -1
- package/dist/internal/stores/kortix-computer-store.js +18 -7
- package/dist/internal/stores/pinned-agents-store.d.ts +26 -0
- package/dist/internal/stores/pinned-agents-store.js +20 -0
- package/dist/internal/stores/session-panel-memory-store.js +3 -0
- package/dist/internal/stores/turn-attention-store.d.ts +5 -4
- package/dist/lib/routes.d.ts +16 -1
- package/dist/lib/routes.js +15 -3
- package/dist/markdown/doc-editor/doc-embed.d.ts +31 -0
- package/dist/markdown/doc-editor/doc-embed.js +168 -0
- package/dist/markdown/doc-editor/doc-extensions.d.ts +26 -0
- package/dist/markdown/doc-editor/doc-extensions.js +149 -0
- package/dist/markdown/doc-editor/doc-menus.d.ts +9 -0
- package/dist/markdown/doc-editor/doc-menus.js +56 -0
- package/dist/markdown/doc-editor/markdown.d.ts +12 -0
- package/dist/markdown/doc-editor/markdown.js +140 -0
- package/dist/markdown/genui/components/inline.d.ts +1 -1
- package/dist/primitives/badge.d.ts +1 -1
- package/dist/primitives/button.d.ts +1 -1
- package/dist/primitives/pixel-kortix-mark.d.ts +5 -4
- package/dist/primitives/pixel-kortix-mark.js +5 -15
- package/dist/primitives/tag.d.ts +1 -1
- package/dist/primitives/textarea.js +14 -0
- package/dist/primitives/toast.d.ts +2 -0
- package/dist/primitives/toast.js +4 -2
- package/dist/providers/ui-provider.d.ts +16 -0
- package/dist/session/actions/session-label.d.ts +1 -1
- package/dist/session/actions/session-label.js +3 -3
- package/dist/session/agents/agent-model.d.ts +92 -0
- package/dist/session/agents/agent-model.js +123 -0
- package/dist/session/agents/agent-state-mark.d.ts +10 -0
- package/dist/session/agents/agent-state-mark.js +22 -0
- package/dist/session/agents/agent-strip.d.ts +58 -0
- package/dist/session/agents/agent-strip.js +259 -0
- package/dist/session/agents/held-messages.d.ts +33 -0
- package/dist/session/agents/held-messages.js +50 -0
- package/dist/session/agents/legacy-subagent-chat.d.ts +11 -0
- package/dist/session/agents/legacy-subagent-chat.js +19 -0
- package/dist/session/agents/session-peek.d.ts +20 -0
- package/dist/session/agents/session-peek.js +67 -0
- package/dist/session/agents/session-prompt.d.ts +13 -0
- package/dist/session/agents/session-prompt.js +18 -0
- package/dist/session/agents/steer-session.d.ts +13 -0
- package/dist/session/agents/steer-session.js +29 -0
- package/dist/session/agents/subagent-dialog-content.d.ts +11 -0
- package/dist/session/agents/subagent-dialog-content.js +115 -0
- package/dist/session/agents/subagent-view.d.ts +8 -0
- package/dist/session/agents/subagent-view.js +18 -0
- package/dist/session/agents/tasks-panel.d.ts +13 -0
- package/dist/session/agents/tasks-panel.js +41 -0
- package/dist/session/agents/workflow-run-controls.d.ts +43 -0
- package/dist/session/agents/workflow-run-controls.js +141 -0
- package/dist/session/composer/ComposerCard.d.ts +1 -1
- package/dist/session/composer/ComposerCard.js +3 -3
- package/dist/session/composer/agent-selector.js +13 -19
- package/dist/session/composer/composer-underbar.d.ts +3 -1
- package/dist/session/composer/composer-underbar.js +2 -2
- package/dist/session/composer/composer.d.ts +5 -0
- package/dist/session/composer/composer.js +16 -10
- package/dist/session/composer/editor/composer-editor.js +19 -8
- package/dist/session/composer/editor/ultracode.d.ts +34 -0
- package/dist/session/composer/editor/ultracode.js +127 -0
- package/dist/session/composer/index.d.ts +1 -0
- package/dist/session/composer/index.js +1 -0
- package/dist/session/composer/send-blockers.d.ts +1 -11
- package/dist/session/composer/send-blockers.js +1 -11
- package/dist/session/composer/session-composer-readiness.d.ts +1 -28
- package/dist/session/composer/session-composer-readiness.js +5 -16
- package/dist/session/header/reminder-parts.d.ts +1 -1
- package/dist/session/header/session-site-header.js +6 -3
- package/dist/session/header/subagent-hover-card.d.ts +0 -2
- package/dist/session/header/subagent-hover-card.js +1 -4
- package/dist/session/models/claude-connection-slot.d.ts +11 -0
- package/dist/session/models/claude-connection-slot.js +30 -0
- package/dist/session/models/model-availability.d.ts +3 -1
- package/dist/session/models/model-availability.js +3 -0
- package/dist/session/models/model-selector.js +11 -12
- package/dist/session/models/model-tags.d.ts +9 -0
- package/dist/session/models/model-tags.js +8 -0
- package/dist/session/panel/easy/detail-view.js +7 -0
- package/dist/session/panel/easy/easy-panel.js +1 -1
- package/dist/session/panel/easy/step-icon.js +5 -1
- package/dist/session/panel/mobile-tool-drawer.js +7 -3
- package/dist/session/panel/open-session-quick-view.js +1 -1
- package/dist/session/panel/session-action-panel-column.js +1 -1
- package/dist/session/panel/session-desktop.js +41 -14
- package/dist/session/panel/session-panel-provider.d.ts +1 -1
- package/dist/session/panel/session-panel-provider.js +7 -11
- package/dist/session/prompts/question-prompt.js +3 -1
- package/dist/session/status/session-error-banner.js +4 -1
- package/dist/session/thread/session-chat.js +286 -296
- package/dist/session/thread/session-context-modal.js +29 -10
- package/dist/session/thread/session-context-spawned-sessions.d.ts +13 -0
- package/dist/session/thread/session-context-spawned-sessions.js +44 -0
- package/dist/session/thread/session-context-sub-sessions.js +3 -8
- package/dist/session/thread/transcript.d.ts +3 -0
- package/dist/session/thread/transcript.js +32 -8
- package/dist/session/tool/shared/full-view-action.d.ts +29 -0
- package/dist/session/tool/shared/full-view-action.js +43 -0
- package/dist/session/tool/tool-part-renderer.js +10 -2
- package/dist/session/tool/tools/agent-message-tool.js +2 -2
- package/dist/session/tool/tools/agent-spawn-tool.js +2 -2
- package/dist/session/tool/tools/agent-status-tool.js +2 -2
- package/dist/session/tool/tools/kortix-action-tool.d.ts +2 -0
- package/dist/session/tool/tools/kortix-action-tool.js +148 -0
- package/dist/session/tool/tools/kortix-tool-card.d.ts +83 -0
- package/dist/session/tool/tools/kortix-tool-card.js +186 -0
- package/dist/session/tool/tools/multi-agent-tool-bodies.d.ts +11 -0
- package/dist/session/tool/tools/multi-agent-tool-bodies.js +141 -0
- package/dist/session/tool/tools/multi-agent-tool-data.d.ts +63 -0
- package/dist/session/tool/tools/multi-agent-tool-data.js +118 -0
- package/dist/session/tool/tools/multi-agent-tools.d.ts +9 -0
- package/dist/session/tool/tools/multi-agent-tools.js +38 -0
- package/dist/session/tool/tools/question-tool.js +1 -1
- package/dist/session/tool/tools/register.d.ts +3 -0
- package/dist/session/tool/tools/register.js +3 -0
- package/dist/session/tool/tools/session-spawn-tool.js +2 -2
- package/dist/session/tool/tools/task-tool.d.ts +1 -1
- package/dist/session/tool/tools/task-tool.js +29 -41
- package/dist/session/tool/tools/workflow-progress.d.ts +34 -0
- package/dist/session/tool/tools/workflow-progress.js +186 -0
- package/dist/session/tool/tools/workflow-run.d.ts +128 -0
- package/dist/session/tool/tools/workflow-run.js +251 -0
- package/dist/session/tool/tools/workflow-tool.d.ts +9 -0
- package/dist/session/tool/tools/workflow-tool.js +253 -0
- package/dist/session/turn/notice-batch-group.d.ts +12 -0
- package/dist/session/turn/notice-batch-group.js +17 -0
- package/dist/session/turn/peer-message-row.d.ts +14 -0
- package/dist/session/turn/peer-message-row.js +57 -0
- package/dist/session/turn/subagent-notice-row.d.ts +4 -0
- package/dist/session/turn/subagent-notice-row.js +50 -0
- package/dist/session/turn/subagent-notice.d.ts +58 -0
- package/dist/session/turn/subagent-notice.js +111 -0
- package/dist/session/turn/user-message.d.ts +5 -4
- package/dist/session/turn/user-message.js +31 -10
- package/dist/styles/tokens.css +2 -0
- package/dist/styles.css +1 -1
- package/dist/terminal/session-terminal-connect-bar.js +1 -1
- package/dist/workspace/admin/project-admin-dashboard.d.ts +53 -0
- package/dist/workspace/admin/project-admin-dashboard.js +252 -0
- package/dist/workspace/admin/project-admin-nav.d.ts +20 -0
- package/dist/workspace/admin/project-admin-nav.js +41 -0
- package/dist/workspace/home/welcome-body.js +25 -3
- package/dist/workspace/index.d.ts +6 -2
- package/dist/workspace/index.js +12 -2
- package/dist/workspace/layout/new-session-create.js +3 -3
- package/dist/workspace/layout/project-home.js +3 -3
- package/dist/workspace/memory/memory-labels.js +5 -0
- package/dist/workspace/repository-disconnected.js +2 -2
- package/dist/workspace/sessions/board-dispatch.d.ts +52 -0
- package/dist/workspace/sessions/board-dispatch.js +110 -0
- package/dist/workspace/sessions/board-grouping.d.ts +63 -0
- package/dist/workspace/sessions/board-grouping.js +141 -0
- package/dist/workspace/sessions/board-peek.d.ts +15 -0
- package/dist/workspace/sessions/board-peek.js +54 -0
- package/dist/workspace/sessions/board-state-mark.d.ts +15 -0
- package/dist/workspace/sessions/board-state-mark.js +24 -0
- package/dist/workspace/sessions/project-sessions-view.js +42 -31
- package/dist/workspace/sessions/sessions-board.d.ts +12 -0
- package/dist/workspace/sessions/sessions-board.js +214 -0
- package/dist/workspace/sidebar/footer/project-manifest-issues-alert.d.ts +46 -0
- package/dist/workspace/sidebar/footer/project-manifest-issues-alert.js +85 -0
- package/dist/workspace/sidebar/footer/sidebar-alert.js +1 -1
- package/dist/workspace/sidebar/new-agent-modal-provider.d.ts +12 -0
- package/dist/workspace/sidebar/new-agent-modal-provider.js +19 -0
- package/dist/workspace/sidebar/project-nav-items.d.ts +3 -1
- package/dist/workspace/sidebar/project-nav-items.js +53 -5
- package/dist/workspace/sidebar/project-session-list.js +35 -12
- package/dist/workspace/sidebar/project-sidebar.js +6 -3
- package/dist/workspace/sidebar/session-filter-menu.js +2 -1
- package/dist/workspace/space/space-blocks.d.ts +25 -0
- package/dist/workspace/space/space-blocks.js +124 -0
- package/dist/workspace/space/space-filter-tabs.d.ts +17 -0
- package/dist/workspace/space/space-filter-tabs.js +31 -0
- package/dist/workspace/space/space-page.d.ts +24 -0
- package/dist/workspace/space/space-page.js +157 -0
- package/dist/workspace/space/space-room.d.ts +20 -0
- package/dist/workspace/space/space-room.js +27 -0
- package/dist/workspace/space/space-tab-menu.d.ts +14 -0
- package/dist/workspace/space/space-tab-menu.js +127 -0
- package/dist/workspace/space/space-tab-panels.d.ts +9 -0
- package/dist/workspace/space/space-tab-panels.js +203 -0
- package/dist/workspace/space/space-templates.d.ts +34 -0
- package/dist/workspace/space/space-templates.js +71 -0
- package/dist/workspace/space/use-space-filter.d.ts +10 -0
- package/dist/workspace/space/use-space-filter.js +40 -0
- package/dist/workspace/space/use-space-manifest.d.ts +8 -0
- package/dist/workspace/space/use-space-manifest.js +27 -0
- package/dist/workspace/spaces/space-timeline.js +2 -2
- package/package.json +56 -53
- package/skills/kortix-ui/SKILL.md +1 -1
- package/skills/kortix-ui/references/custom-dashboard.md +10 -4
- package/skills/kortix-ui/references/modules.md +11 -9
- package/dist/_vendor/shared/meta-agent.d.ts +0 -7
- package/dist/customize/agents/agent-grant-pages.d.ts +0 -37
- package/dist/customize/agents/agent-grant-pages.js +0 -226
- package/dist/customize/agents/agent-triggers-section.d.ts +0 -17
- package/dist/customize/agents/agent-triggers-section.js +0 -109
- package/dist/customize/migrate-to-v2/index.d.ts +0 -5
- package/dist/customize/migrate-to-v2/index.js +0 -5
- package/dist/customize/migrate-to-v2/migration-prompt.d.ts +0 -16
- package/dist/customize/migrate-to-v2/migration-prompt.js +0 -59
- package/dist/customize/migrate-to-v2/upgrade-defs.d.ts +0 -30
- package/dist/customize/migrate-to-v2/upgrade-defs.js +0 -43
- package/dist/customize/migrate-to-v2/upgrade-view.d.ts +0 -32
- package/dist/customize/migrate-to-v2/upgrade-view.js +0 -152
- package/dist/customize/migrate-to-v2/use-run-upgrade.d.ts +0 -18
- package/dist/customize/migrate-to-v2/use-run-upgrade.js +0 -16
- package/dist/customize/shared/capability-tabs.d.ts +0 -3
- package/dist/customize/shared/capability-tabs.js +0 -137
- package/dist/customize/skills/skill-scope.d.ts +0 -14
- package/dist/customize/skills/skill-scope.js +0 -18
- package/dist/internal/lib/manifest-version.d.ts +0 -21
- package/dist/internal/lib/manifest-version.js +0 -55
- package/dist/session/composer/hooks/use-composer-escape-stop.d.ts +0 -6
- package/dist/session/composer/hooks/use-composer-escape-stop.js +0 -28
- package/dist/session/thread/sub-session-modal-content.d.ts +0 -8
- package/dist/session/thread/sub-session-modal-content.js +0 -23
- package/dist/session/thread/sub-session-modal.d.ts +0 -2
- package/dist/session/thread/sub-session-modal.js +0 -14
- package/dist/workspace/sidebar/footer/project-manifest-upgrade-alert.d.ts +0 -13
- package/dist/workspace/sidebar/footer/project-manifest-upgrade-alert.js +0 -48
|
@@ -1,126 +1,99 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { agentStatus } from './agent-status.js';
|
|
6
|
-
import { useDefaultAgent } from './use-default-agent.js';
|
|
7
|
-
import { useTranslations as useI18nTranslations } from '../../i18n/index.js';
|
|
3
|
+
import { MY_KORTIX_AGENT_NAME } from '../../_vendor/kortix-shared.js';
|
|
4
|
+
import { adminPath } from '../../lib/routes.js';
|
|
8
5
|
/**
|
|
9
|
-
* /projects/[id]/
|
|
10
|
-
* screen of Customize.
|
|
6
|
+
* /projects/[id]/customize/agents/[name]: one agent, as a page with a rail.
|
|
11
7
|
*
|
|
12
|
-
* Customize is agent-
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* secrets, when it runs — hangs off it. This page is built like the Settings
|
|
16
|
-
* page (Marko, 2026-09-03: "make it a regular full page Agent Editor"): a
|
|
17
|
-
* header, a left rail of topics, and one full-width pane per topic.
|
|
8
|
+
* Customize is agent-first. My Kortix is the one agent a person talks to; every
|
|
9
|
+
* other agent is a work product with only the access its work needs. So the
|
|
10
|
+
* page is the agent: one identity header, one rail, and room to edit.
|
|
18
11
|
*
|
|
19
|
-
* ┌
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* │
|
|
23
|
-
* │ Access
|
|
24
|
-
* │
|
|
25
|
-
*
|
|
26
|
-
* │ Workspace │ │
|
|
27
|
-
* │ Tools │ │
|
|
28
|
-
* │ Basics │ │
|
|
29
|
-
* ├──────────────┴──────────────────────────────────────────────────────┤
|
|
30
|
-
* │ Unsaved changes · commits to the repo [Discard] [Save ⌘S] │
|
|
31
|
-
* └─────────────────────────────────────────────────────────────────────┘
|
|
12
|
+
* ┌ ▣ researcher [Share] [Start session] [⋯] ┐
|
|
13
|
+
* │ ● Enabled · Space: workspace · People start it │
|
|
14
|
+
* ├ Overview ┬ the row, full width ┤
|
|
15
|
+
* │ Triggers │ │
|
|
16
|
+
* │ Access: Connectors None · Secrets All · Skills All · Tools … │
|
|
17
|
+
* │ Runtime: Model · Workspace │
|
|
18
|
+
* └────────────────── [ ● Unsaved changes Skills Discard Save ⌘S ]
|
|
32
19
|
*
|
|
33
|
-
* The
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
20
|
+
* The URL names the tab and its view (`agent-tabs.ts`); every old
|
|
21
|
+
* `?section=` link still resolves. The rail lists every view as its own row
|
|
22
|
+
* (2026-10-28: Access and Runtime are group labels, not a second level), each
|
|
23
|
+
* with its grant state. A view renders the full resource screen in agent
|
|
24
|
+
* scope (one component, two variants), embedded without its own title
|
|
25
|
+
* (`CapabilityShellEmbedProvider`).
|
|
38
26
|
*
|
|
39
|
-
*
|
|
27
|
+
* The draft is shared across rows, so a row switch never drops an edit; the
|
|
28
|
+
* row with an edit carries a dot, and the save bar names the changed rows. A
|
|
29
|
+
* link off the page while dirty asks Stay / Leave / Save and leave.
|
|
40
30
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* `agents.<name>` block through the agent-config
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* Triggers and Model (the gateway pin) remain. We degrade, never blank.
|
|
31
|
+
* Two bodies under one frame:
|
|
32
|
+
* - **Editable**: a v2+ project and a caller with `project.agent.write`.
|
|
33
|
+
* Save round-trips the whole `agents.<name>` block through the agent-config
|
|
34
|
+
* route, which commits it to the project repo.
|
|
35
|
+
* - **Read-only**: a v1 project or a caller without write. The same tabs and
|
|
36
|
+
* the same Overview, with values in place of controls and a lock banner.
|
|
37
|
+
* My Kortix (a platform agent) has no page here: the project home starts it,
|
|
38
|
+
* and its route reads as not found.
|
|
50
39
|
*
|
|
51
40
|
* The page is keyed on the agent name by its route, so switching agents
|
|
52
|
-
* remounts every draft
|
|
41
|
+
* remounts every draft.
|
|
53
42
|
*/
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
43
|
+
import { getProjectDetail, listProjectResourceGrants, readProjectFile, } from '@kortix/sdk';
|
|
44
|
+
import { contract, qk, useFeatureFlag, useProjectAccountId, useUnifiedTriggers } from '@kortix/sdk/react';
|
|
45
|
+
import { DotsThreeIcon, LockSimpleIcon, PlayIcon, StarIcon, TrashIcon } from '@phosphor-icons/react';
|
|
46
|
+
import { useQueries, useQuery } from '@tanstack/react-query';
|
|
47
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
48
|
+
import { useLocale, useTranslations as useI18nTranslations } from '../../i18n/index.js';
|
|
49
|
+
import { AgentMark, agentDisplayName } from '../../internal/components/agent-mark.js';
|
|
50
|
+
import { useAgentConfig, useUpdateAgentConfig, useProjectCapabilities, } from '../../internal/hooks/projects/use-agent-config.js';
|
|
51
|
+
import { useNewProjectSession } from '../../internal/hooks/projects/use-new-project-session.js';
|
|
52
|
+
import { agentHref, capabilityTabHref } from '../../internal/lib/capability-tab-routes.js';
|
|
53
|
+
import { PROJECT_ACTIONS } from '../../internal/lib/project-actions.js';
|
|
54
|
+
import { useProjectCan } from '../../internal/lib/use-project-can.js';
|
|
56
55
|
import { Button } from '../../primitives/button.js';
|
|
57
56
|
import { ConfirmDialog } from '../../primitives/confirm-dialog.js';
|
|
58
57
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from '../../primitives/dropdown-menu.js';
|
|
58
|
+
import { EmptyState } from '../../primitives/empty-state.js';
|
|
59
|
+
import { ErrorState } from '../../primitives/error-state.js';
|
|
59
60
|
import Hint from '../../primitives/hint.js';
|
|
60
61
|
import { InfoBanner } from '../../primitives/info-banner.js';
|
|
61
|
-
import { Kbd } from '../../primitives/kbd.js';
|
|
62
|
-
import Loading from '../../primitives/loading.js';
|
|
63
|
-
import { Skeleton } from '../../primitives/skeleton.js';
|
|
64
|
-
import { Tabs, TabsList, TabsTrigger } from '../../primitives/tabs.js';
|
|
65
|
-
import { Textarea } from '../../primitives/textarea.js';
|
|
66
62
|
import { errorToast, successToast } from '../../primitives/toast.js';
|
|
67
|
-
import { EmptyState } from '../../primitives/empty-state.js';
|
|
68
|
-
import { ErrorState } from '../../primitives/error-state.js';
|
|
69
|
-
import { configEntitySourcePath } from '../sections/component/config-entity-source-path.js';
|
|
70
|
-
import { AgentConfigSections, agentConfigSectionKeys, agentEditorOptionQueries, DEFAULT_AGENT_CONFIG_SECTION, isAgentConfigSectionKey, registryGrantOptions, useAgentDraft, useAgentEditorOptions, useLocalizedAgentConfigCatalog, } from '../sections/view/agent-editor.js';
|
|
71
|
-
import { formatMode, toArray } from '../shared/utils.js';
|
|
72
|
-
import { editConfigPrompt, useConfigureThread, } from '../use-configure-thread.js';
|
|
73
|
-
import { agentConfigNeedsUpgrade, useAgentConfig, useUpdateAgentConfig, } from '../../internal/hooks/projects/use-agent-config.js';
|
|
74
|
-
import { useNewProjectSession } from '../../internal/hooks/projects/use-new-project-session.js';
|
|
75
|
-
import { PROJECT_ACTIONS } from '../../internal/lib/project-actions.js';
|
|
76
|
-
import { useProjectCan } from '../../internal/lib/use-project-can.js';
|
|
77
|
-
import { cn } from '../../internal/lib/utils.js';
|
|
78
|
-
import { getProjectDetail, readProjectFile, } from '@kortix/sdk';
|
|
79
|
-
import { contract, qk, useFeatureFlag, useProjectAccountId } from '@kortix/sdk/react';
|
|
80
|
-
import { capitalizeWords, isMetaAgentName, META_AGENT_DISPLAY_NAME } from '../../_vendor/kortix-shared.js';
|
|
81
|
-
import { BookOpenTextIcon, CaretRightIcon, CommandIcon, CpuIcon, CubeIcon, DotsThreeIcon, FileTextIcon, GlobeIcon, HardDriveIcon, KeyIcon, PlayIcon, PlugsConnectedIcon, PuzzlePieceIcon, RobotIcon, SlidersHorizontalIcon, StarIcon, TerminalWindowIcon, TimerIcon, TreeStructureIcon, UsersIcon, WrenchIcon, } from '@phosphor-icons/react';
|
|
82
|
-
import { useQueries, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
83
|
-
import { AnimatePresence, m } from 'motion/react';
|
|
84
63
|
import { UiLink as Link, useUiPathname, useUiRouter, useUiSearchParams } from '../../providers/ui-provider.js';
|
|
85
|
-
import {
|
|
86
|
-
import {
|
|
87
|
-
import {
|
|
88
|
-
import {
|
|
89
|
-
import {
|
|
90
|
-
import {
|
|
91
|
-
import {
|
|
92
|
-
import {
|
|
64
|
+
import { configEntitySourcePath } from '../sections/component/config-entity-source-path.js';
|
|
65
|
+
import { AGENT_CONFIG_SECTIONS, AgentConfigSections, agentEditorOptionQueries, registryGrantOptions, useAgentDraft, useAgentEditorOptions, useLocalizedAgentConfigCatalog, } from '../sections/view/agent-editor.js';
|
|
66
|
+
import { EditorSectionStyleProvider } from '../sections/view/agent-editor-primitives.js';
|
|
67
|
+
import { ToolsSection } from '../sections/view/permission-editor.js';
|
|
68
|
+
import { useAgentGrant } from '../shared/agent-resource-scope.js';
|
|
69
|
+
import { CapabilityShellEmbedProvider } from '../shared/capability-page-shell.js';
|
|
70
|
+
import { LeaveGuardProvider, useUnsavedChangesGuard } from '../shared/leave-guard.js';
|
|
71
|
+
import { toArray } from '../shared/utils.js';
|
|
72
|
+
import { ExtensionsPage, SkillsPage, ToolsPage } from '../skills/skills-page.js';
|
|
73
|
+
import { ConnectorsPage } from '../connectors/connectors-page.js';
|
|
74
|
+
import { SecretsPage } from '../secrets/secrets-page.js';
|
|
75
|
+
import { TriggersPage } from '../triggers/triggers-page.js';
|
|
76
|
+
import { editConfigPrompt, useConfigureThread } from '../use-configure-thread.js';
|
|
93
77
|
import { AgentAuthorityCard } from './agent-authority-card.js';
|
|
94
78
|
import { AgentModel, AgentScope } from './agent-detail-aside.js';
|
|
95
|
-
import {
|
|
96
|
-
import {
|
|
97
|
-
import {
|
|
79
|
+
import { AgentDrivesSection } from './agent-drives-section.js';
|
|
80
|
+
import { pruneRequiredConnectors } from './connectors-required.js';
|
|
81
|
+
import { useGrantLabel } from './agent-access-text.js';
|
|
82
|
+
import { AgentOverview, grantExcluded, grantOf } from './agent-overview.js';
|
|
83
|
+
import { AgentIdentityHeader, AgentPageSkeleton, AgentStatePage, AgentTabBar, AgentTabBody, LeaveDialog, SaveBar, } from './agent-page-chrome.js';
|
|
84
|
+
import { AgentModelView } from './agent-model-view.js';
|
|
85
|
+
import { AgentApprovalRules } from './agent-approval-rules.js';
|
|
86
|
+
import { AgentSectionRail, railGroupOf } from './agent-section-rail.js';
|
|
87
|
+
import { AgentPinButton } from './agent-pin-button.js';
|
|
98
88
|
import { AgentShareControl } from './agent-share-control.js';
|
|
99
|
-
import {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
triggers: TimerIcon,
|
|
107
|
-
skills: BookOpenTextIcon,
|
|
108
|
-
subagents: TreeStructureIcon,
|
|
109
|
-
commands: CommandIcon,
|
|
110
|
-
extensions: PuzzlePieceIcon,
|
|
111
|
-
connectors: PlugsConnectedIcon,
|
|
112
|
-
secrets: KeyIcon,
|
|
113
|
-
apps: GlobeIcon,
|
|
114
|
-
drives: HardDriveIcon,
|
|
115
|
-
actions: TerminalWindowIcon,
|
|
116
|
-
model: CpuIcon,
|
|
117
|
-
tools: WrenchIcon,
|
|
118
|
-
workspace: CubeIcon,
|
|
119
|
-
};
|
|
120
|
-
export function AgentPage({ projectId, agentName }) {
|
|
89
|
+
import { ACCESS_VIEWS, AGENT_TABS, agentLocationHref, changedItems, closestAgentName, resolveAgentLocation, railKeyOf, sectionLocationHref, } from './agent-tabs.js';
|
|
90
|
+
import { useSpacesEnabled } from '../../internal/lib/space-scope.js';
|
|
91
|
+
import { connectorPolicySetOptions } from './agent-policy-sets.js';
|
|
92
|
+
import { AgentPolicySetsPanel, useAgentPolicySetControls } from './agent-policy-sets-section.js';
|
|
93
|
+
import { useDefaultAgent } from './use-default-agent.js';
|
|
94
|
+
export function AgentPage({ projectId, agentName, renderApps, }) {
|
|
95
|
+
const t = useI18nTranslations('agentEditor.tabs');
|
|
121
96
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
122
|
-
// `accountId` skips useProjectCan's own getProject and lets the IAM probe
|
|
123
|
-
// run on the first render instead of waiting a round-trip for it.
|
|
124
97
|
const accountId = useProjectAccountId(projectId);
|
|
125
98
|
const canWrite = useProjectCan(projectId, PROJECT_ACTIONS.PROJECT_AGENT_WRITE, { accountId }).allowed === true;
|
|
126
99
|
const detailQuery = useQuery({
|
|
@@ -129,336 +102,474 @@ export function AgentPage({ projectId, agentName }) {
|
|
|
129
102
|
...contract('config'),
|
|
130
103
|
});
|
|
131
104
|
const config = detailQuery.data?.config ?? null;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
// All reads start on the first render, in parallel. The agent-config read
|
|
137
|
-
// used to wait for detail to list the agent, and the editor's option reads
|
|
138
|
-
// for the editor to mount: three round trips in a row, each a Git read on
|
|
139
|
-
// the API. Now the skeleton lasts as long as the slowest single read.
|
|
105
|
+
// A platform agent (My Kortix) has nothing to edit here: not found.
|
|
106
|
+
const agent = toArray(config?.agents).find((a) => a.name === agentName && !a.platform) ?? null;
|
|
107
|
+
// Every read starts on the first render, in parallel: the skeleton lasts as
|
|
108
|
+
// long as the slowest single read, not three in a row.
|
|
140
109
|
const configQuery = useAgentConfig(projectId, agentName);
|
|
141
110
|
const editorOptionQueries = agentEditorOptionQueries(projectId);
|
|
142
111
|
useQueries({
|
|
143
|
-
queries: [
|
|
144
|
-
editorOptionQueries.secrets,
|
|
145
|
-
editorOptionQueries.connectors,
|
|
146
|
-
editorOptionQueries.sandboxes,
|
|
147
|
-
].map((query) => ({ ...query, enabled: canWrite })),
|
|
112
|
+
queries: [editorOptionQueries.secrets, editorOptionQueries.connectors, editorOptionQueries.sandboxes].map((query) => ({ ...query, enabled: canWrite })),
|
|
148
113
|
});
|
|
149
|
-
if (detailQuery.isLoading || (agent &&
|
|
114
|
+
if (detailQuery.isLoading || (agent && configQuery.isLoading)) {
|
|
150
115
|
return _jsx(AgentPageSkeleton, {});
|
|
151
116
|
}
|
|
117
|
+
const retry = (_jsx(Button, { variant: "outline", size: "sm", onClick: () => void detailQuery.refetch(), children: tI18nComplete.raw('text942087cc2d41') }));
|
|
152
118
|
if (detailQuery.isError || !config) {
|
|
153
|
-
return (_jsx(
|
|
119
|
+
return (_jsx(AgentStatePage, { title: agentDisplayName(agentName), children: _jsx(ErrorState, { size: "sm", title: t('loadError'), description: _jsx(ErrorDetails, { error: detailQuery.error }), action: retry }) }));
|
|
154
120
|
}
|
|
155
121
|
if (!agent) {
|
|
156
|
-
|
|
122
|
+
// Only agents this page opens: a platform agent (My Kortix) is not found here either.
|
|
123
|
+
const suggestion = closestAgentName(agentName, toArray(config.agents)
|
|
124
|
+
.filter((a) => !a.platform)
|
|
125
|
+
.map((a) => a.name));
|
|
126
|
+
return (_jsx(AgentStatePage, { title: t('notFoundHeader'), children: _jsx(EmptyState, { size: "sm", title: t('notFoundTitle'), description: _jsxs("span", { className: "space-y-1", children: [_jsx("span", { className: "block", children: t.rich('notFoundBody', { name: () => _jsx("span", { className: "font-mono", children: agentName }) }) }), suggestion ? (_jsx("span", { className: "block", children: t.rich('didYouMean', {
|
|
127
|
+
link: () => (_jsx(Link, { href: agentHref(projectId, suggestion), className: "text-foreground underline underline-offset-4", children: agentDisplayName(suggestion) })),
|
|
128
|
+
}) })) : null] }), action: _jsx(Button, { asChild: true, variant: "outline", size: "sm", children: _jsx(Link, { href: capabilityTabHref(projectId, 'agent'), children: t('allAgents') }) }) }) }));
|
|
129
|
+
}
|
|
130
|
+
// A writer whose agent-config read failed would otherwise land on the
|
|
131
|
+
// read-only page with no word on why: say what failed, offer the retry.
|
|
132
|
+
if (canWrite && configQuery.isError) {
|
|
133
|
+
return (_jsx(AgentStatePage, { title: agentDisplayName(agent.name), children: _jsx(ErrorState, { size: "sm", title: t('configLoadError', { name: agentDisplayName(agent.name) }), description: _jsx(ErrorDetails, { error: configQuery.error }), action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => void configQuery.refetch(), children: tI18nComplete.raw('text942087cc2d41') }) }) }));
|
|
157
134
|
}
|
|
158
|
-
const editable =
|
|
159
|
-
|
|
160
|
-
|
|
135
|
+
const editable = canWrite && configQuery.data?.editable === true;
|
|
136
|
+
return editable ? (_jsx(EditableAgentPage, { projectId: projectId, agent: agent, config: config, initial: configQuery.data?.block ?? {}, renderApps: renderApps })) : (_jsx(ReadOnlyAgentPage, { projectId: projectId, agent: agent, config: config, block: configQuery.data?.block ?? blockFromScope(agent), canWrite: canWrite }));
|
|
137
|
+
}
|
|
138
|
+
/** The raw failure, folded, in mono. No fold when there is nothing to show. */
|
|
139
|
+
function ErrorDetails({ error }) {
|
|
140
|
+
const t = useI18nTranslations('agentEditor.tabs');
|
|
141
|
+
const message = error instanceof Error ? error.message : typeof error === 'string' ? error : '';
|
|
142
|
+
if (!message)
|
|
143
|
+
return null;
|
|
144
|
+
return (_jsxs("details", { className: "mt-2 text-left", children: [_jsx("summary", { className: "text-muted-foreground hover:text-foreground cursor-pointer text-xs transition-colors", children: t('details') }), _jsx("p", { className: "text-muted-foreground mt-2 font-mono text-xs break-words", children: message })] }));
|
|
145
|
+
}
|
|
146
|
+
/** The block a reader sees when the agent-config read returned nothing. */
|
|
147
|
+
function blockFromScope(agent) {
|
|
148
|
+
const scope = agent.scope;
|
|
149
|
+
return {
|
|
150
|
+
enabled: agent.enabled,
|
|
151
|
+
space: agent.space ?? undefined,
|
|
152
|
+
sandbox: agent.sandbox ?? undefined,
|
|
153
|
+
connectors: scope?.connectors,
|
|
154
|
+
secrets: scope?.env,
|
|
155
|
+
apps: scope?.apps,
|
|
156
|
+
kortix_permissions: scope?.kortix_permissions ?? scope?.kortix_cli,
|
|
157
|
+
behavior: {
|
|
158
|
+
description: agent.description ?? undefined,
|
|
159
|
+
model: agent.model ?? undefined,
|
|
160
|
+
mode: agent.mode ?? undefined,
|
|
161
|
+
hidden: agent.hidden,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
// ─── Shared hooks ────────────────────────────────────────────────────────────
|
|
166
|
+
function useAgentLocation(tabs, views) {
|
|
167
|
+
const params = useUiSearchParams();
|
|
168
|
+
return resolveAgentLocation({ tab: params.get('tab'), view: params.get('view'), section: params.get('section') }, tabs, views);
|
|
169
|
+
}
|
|
170
|
+
/** How many triggers start this agent (kortix.yaml and runtime), and how
|
|
171
|
+
* many grants name it. `GET /triggers/all` leaves out what the caller may not read. */
|
|
172
|
+
function useAgentUseCounts(projectId, agentName, config) {
|
|
173
|
+
const accountId = useProjectAccountId(projectId);
|
|
174
|
+
const canManageMembers = useProjectCan(projectId, PROJECT_ACTIONS.PROJECT_MEMBERS_MANAGE, { accountId }).allowed === true;
|
|
175
|
+
const triggers = useUnifiedTriggers(projectId);
|
|
176
|
+
const grants = useQuery({
|
|
177
|
+
queryKey: qk.project.resourceGrants(projectId),
|
|
178
|
+
queryFn: () => listProjectResourceGrants(projectId),
|
|
179
|
+
enabled: canManageMembers,
|
|
180
|
+
retry: false,
|
|
181
|
+
...contract('inventory'),
|
|
182
|
+
});
|
|
183
|
+
// A trigger stored as `default` starts the project's default agent.
|
|
184
|
+
const fallback = config.default_agent ?? config.open_code_default_agent ?? null;
|
|
185
|
+
return {
|
|
186
|
+
triggerCount: triggers.data
|
|
187
|
+
? triggers.data.triggers.filter((a) => a.target.kind === 'agent' && (a.target.agent === 'default' && fallback ? fallback : a.target.agent) === agentName).length
|
|
188
|
+
: undefined,
|
|
189
|
+
peopleCount: grants.data
|
|
190
|
+
? grants.data.grants.filter((g) => g.resource_type === 'agent' && g.resource_id === agentName).length
|
|
191
|
+
: undefined,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/** The Overview's catalog totals and the connectors that need a sign-in. */
|
|
195
|
+
function useOverviewFacts(projectId, agentName, config, block) {
|
|
196
|
+
const queries = agentEditorOptionQueries(projectId);
|
|
197
|
+
const connectors = useQuery(queries.connectors);
|
|
198
|
+
const secrets = useQuery(queries.secrets);
|
|
199
|
+
const counts = useAgentUseCounts(projectId, agentName, config);
|
|
200
|
+
const all = connectors.data?.connectors ?? [];
|
|
201
|
+
const granted = block.connectors;
|
|
202
|
+
const needsSignIn = all
|
|
203
|
+
.filter((c) => c.status === 'needs_auth' && (granted === 'all' || (Array.isArray(granted) && granted.includes(c.slug))))
|
|
204
|
+
.map((c) => c.slug);
|
|
205
|
+
const secretIds = new Set((secrets.data?.items ?? []).map((s) => s.identifier));
|
|
206
|
+
return {
|
|
207
|
+
totals: {
|
|
208
|
+
skills: toArray(config.skills).length,
|
|
209
|
+
...(connectors.data ? { connectors: all.length } : {}),
|
|
210
|
+
...(secrets.data ? { secrets: secretIds.size } : {}),
|
|
211
|
+
},
|
|
212
|
+
needsSignIn,
|
|
213
|
+
...counts,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/** The header's meta line: status, space (only with spaces on), who starts it, default. */
|
|
217
|
+
function useHeaderFacts(projectId, agent, config, block, editable) {
|
|
218
|
+
const t = useI18nTranslations('agentEditor.tabs');
|
|
219
|
+
const tPage = useI18nTranslations('agentEditor.page');
|
|
220
|
+
const enabled = block.enabled !== false;
|
|
221
|
+
// Editable pages pass the draft: read it alone, so Project-wide reads as
|
|
222
|
+
// Project-wide before the save. A reader's block already carries the space.
|
|
223
|
+
const space = (editable ? block.space : (block.space ?? agent.space)) || null;
|
|
224
|
+
const mode = (block.behavior?.mode ?? agent.mode ?? 'primary').toLowerCase();
|
|
225
|
+
const isDefault = (config.default_agent ?? config.open_code_default_agent) === agent.name;
|
|
226
|
+
// Spaces are Work in progress (`project_channels`): off, no Space fact.
|
|
227
|
+
const spacesOn = useSpacesEnabled(projectId);
|
|
228
|
+
return [
|
|
229
|
+
{ label: enabled ? t('enabled') : t('off'), tone: enabled ? 'success' : 'neutral' },
|
|
230
|
+
...(spacesOn ? [{ label: space ? t('spaceValue', { space }) : t('projectWide') }] : []),
|
|
231
|
+
{ label: mode === 'subagent' ? t('startSubagent') : mode === 'all' ? t('startBoth') : t('startPrimary') },
|
|
232
|
+
...(isDefault ? [{ label: tPage('default') }] : []),
|
|
233
|
+
];
|
|
161
234
|
}
|
|
162
|
-
// ─── Frame ─────────────────────────────────────────────────────────────────
|
|
163
235
|
/**
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* (`project-settings-page.tsx`), row for row.
|
|
236
|
+
* The header's Share dialog. The old `?tab=people` link opens it; closing it
|
|
237
|
+
* drops that query, so a reload or a later tab click does not reopen it.
|
|
167
238
|
*/
|
|
168
|
-
function
|
|
169
|
-
const
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
items: items.filter((s) => s.group === group),
|
|
179
|
-
}))
|
|
180
|
-
.filter((g) => g.items.length > 0);
|
|
181
|
-
const showGroupLabels = groups.length > 1;
|
|
182
|
-
const trigger = (item, horizontal) => {
|
|
183
|
-
const SectionIcon = SECTION_ICON[item.key];
|
|
184
|
-
return (_jsx(TabsTrigger, { value: item.key, asChild: true, size: horizontal ? undefined : 'md', className: horizontal
|
|
185
|
-
? 'w-auto shrink-0 gap-2.5 px-3 py-0.75 whitespace-nowrap'
|
|
186
|
-
: cn(
|
|
187
|
-
// The Settings rail's row dialect (`project-settings-page.tsx`).
|
|
188
|
-
'gap-2 px-2.5 py-1 font-normal transition-none has-[>svg]:px-2.5', 'text-foreground data-[state=inactive]:text-foreground hover:bg-hover hover:text-foreground', 'data-[state=active]:bg-active data-[state=active]:font-medium', '[&_svg]:text-muted-foreground data-[state=active]:[&_svg]:text-foreground'), children: _jsxs(Link, { href: sectionHref(item.key), prefetch: true, children: [_jsx(SectionIcon, { className: "size-4 shrink-0" }), _jsx("span", { className: cn(!horizontal && 'truncate'), children: item.label })] }) }, item.key));
|
|
189
|
-
};
|
|
190
|
-
return (_jsxs("div", { className: "relative flex h-full min-h-0 flex-1 flex-col", children: [_jsx("div", { className: "border-border/60 shrink-0 border-b px-5 py-3", children: header }), _jsxs("div", { className: cn('min-h-0 flex-1', isMobile ? 'flex flex-col overflow-hidden' : 'grid overflow-hidden'), style: isMobile ? undefined : { gridTemplateColumns: `${SETTINGS_SIDEBAR_WIDTH_PX}px 1fr` }, children: [isMobile ? (_jsx("nav", { "aria-label": tI18nComplete.raw('text7be318295927'), className: "border-border/60 flex h-auto shrink-0 items-center border-b", children: _jsx(FadedScrollArea, { orientation: "horizontal", fadeColor: "from-background", className: "min-w-0 flex-1 py-2", children: _jsx(Tabs, { value: section, className: "w-fit", children: _jsx(TabsList, { orientation: "horizontal", className: "w-fit", children: items.map((item) => trigger(item, true)) }) }) }) })) : (_jsx("aside", { className: "flex min-h-0 flex-col border-r bg-inherit", children: _jsx("nav", { "aria-label": tI18nComplete.raw('text7be318295927'), className: "flex min-h-0 flex-1 [scrollbar-width:none] flex-col gap-4 overflow-y-auto px-2 pt-3 pb-2 [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden", children: _jsx(Tabs, { value: section, orientation: "vertical", className: "space-y-3", children: groups.map((g) => (_jsxs("div", { children: [showGroupLabels ? (_jsx("div", { className: "text-muted-foreground flex h-7 items-center px-2.5 text-xs font-medium", children: g.group })) : null, _jsx(TabsList, { orientation: "vertical", className: "w-full", children: g.items.map((item) => trigger(item, false)) })] }, g.group))) }) }) })), _jsx("main", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-y-auto", children: _jsx("div", { className: "mx-auto w-full max-w-2xl px-4 py-10 pb-32 lg:py-14 lg:pb-32", children: pane }) })] }), footer] }));
|
|
239
|
+
function useShareDialog(openedByLink) {
|
|
240
|
+
const pathname = useUiPathname();
|
|
241
|
+
const router = useUiRouter();
|
|
242
|
+
const [open, setOpenState] = useState(openedByLink);
|
|
243
|
+
const setOpen = useCallback((next) => {
|
|
244
|
+
setOpenState(next);
|
|
245
|
+
if (!next && openedByLink)
|
|
246
|
+
router.replace(pathname);
|
|
247
|
+
}, [openedByLink, router, pathname]);
|
|
248
|
+
return { open, setOpen };
|
|
191
249
|
}
|
|
192
|
-
|
|
193
|
-
|
|
250
|
+
/**
|
|
251
|
+
* Mod+S saves the agent, only while the draft holds an edit. With nothing to
|
|
252
|
+
* save the key keeps the browser's own behavior. A key pressed inside an open
|
|
253
|
+
* dialog (an embedded screen's own editor, the secret form) belongs to that
|
|
254
|
+
* dialog, never to the agent's draft.
|
|
255
|
+
*/
|
|
256
|
+
function useSaveShortcut(dirty, onSave) {
|
|
257
|
+
useEffect(() => {
|
|
258
|
+
if (!dirty)
|
|
259
|
+
return;
|
|
260
|
+
const handler = (event) => {
|
|
261
|
+
if (!(event.metaKey || event.ctrlKey) || event.shiftKey || event.altKey || event.key !== 's')
|
|
262
|
+
return;
|
|
263
|
+
const target = event.target instanceof Element ? event.target : null;
|
|
264
|
+
if (target?.closest('[role="dialog"], [role="alertdialog"]'))
|
|
265
|
+
return;
|
|
266
|
+
event.preventDefault();
|
|
267
|
+
onSave();
|
|
268
|
+
};
|
|
269
|
+
window.addEventListener('keydown', handler);
|
|
270
|
+
return () => window.removeEventListener('keydown', handler);
|
|
271
|
+
}, [dirty, onSave]);
|
|
194
272
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
273
|
+
/**
|
|
274
|
+
* The rail's rows, one flat list in the order of `agents.<name>` in
|
|
275
|
+
* kortix.yaml: Overview, Model, every grant (`countOf` gives its state),
|
|
276
|
+
* Workspace, then Triggers and Drives, which live outside the block. Model and
|
|
277
|
+
* Workspace show their value, or "Project default" when the block sets none.
|
|
278
|
+
*/
|
|
279
|
+
function useRailItems(pathname, views, counts, countOf, values = {}) {
|
|
280
|
+
const t = useI18nTranslations('agentEditor.tabs');
|
|
281
|
+
const tPage = useI18nTranslations('agentEditor.page');
|
|
282
|
+
const catalog = useLocalizedAgentConfigCatalog();
|
|
283
|
+
const labelOf = (key) => catalog.sections.find((s) => s.key === key)?.label ?? key;
|
|
284
|
+
const viewRow = (view, count) => views.includes(view) ? [{ key: view, label: labelOf(view), href: sectionLocationHref(pathname, view), count }] : [];
|
|
285
|
+
const grants = ACCESS_VIEWS.filter((view) => view !== 'drives').flatMap((view) => viewRow(view, countOf?.(view) ?? undefined));
|
|
286
|
+
return [
|
|
287
|
+
{ key: 'overview', label: t('tabOverview'), href: agentLocationHref(pathname, 'overview') },
|
|
288
|
+
...viewRow('model', values.model ?? tPage('projectDefault')),
|
|
289
|
+
...grants,
|
|
290
|
+
...viewRow('workspace', values.workspace ?? tPage('projectDefault')),
|
|
291
|
+
{
|
|
292
|
+
key: 'triggers',
|
|
293
|
+
label: t('tabTriggers'),
|
|
294
|
+
href: agentLocationHref(pathname, 'triggers'),
|
|
295
|
+
count: counts.triggerCount || undefined,
|
|
296
|
+
},
|
|
297
|
+
...viewRow('drives'),
|
|
298
|
+
];
|
|
199
299
|
}
|
|
200
|
-
// ─── Section routing ───────────────────────────────────────────────────────
|
|
201
300
|
/**
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
301
|
+
* The rail rows as the page's top tabs: Overview, Model, Capabilities (the
|
|
302
|
+
* grants of what the agent can do), Access (what it can reach), Workspace,
|
|
303
|
+
* Triggers. A tab with several views shows them as pills.
|
|
205
304
|
*/
|
|
206
|
-
function
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
305
|
+
function useTabGroups(items) {
|
|
306
|
+
const t = useI18nTranslations('agentEditor.tabs');
|
|
307
|
+
const pick = (keys) => keys.flatMap((key) => items.filter((item) => item.key === key));
|
|
308
|
+
const one = (key) => ({ key, label: items.find((item) => item.key === key)?.label ?? key, items: pick([key]) });
|
|
309
|
+
return [
|
|
310
|
+
one('overview'),
|
|
311
|
+
one('model'),
|
|
312
|
+
{ key: 'capabilities', label: t('tabCapabilities'), items: pick(['tools', 'skills', 'subagents', 'commands', 'extensions']) },
|
|
313
|
+
{ key: 'access', label: t('tabAccess'), items: pick(['connectors', 'secrets', 'apps', 'actions', 'drives']) },
|
|
314
|
+
one('workspace'),
|
|
315
|
+
one('triggers'),
|
|
316
|
+
];
|
|
212
317
|
}
|
|
213
|
-
|
|
214
|
-
|
|
318
|
+
/** The tabs over the one scroller. */
|
|
319
|
+
function TabLayout({ tabs, children }) {
|
|
320
|
+
return (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [tabs, _jsx("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: children })] }));
|
|
215
321
|
}
|
|
216
|
-
// ─── Header
|
|
322
|
+
// ─── Header actions ──────────────────────────────────────────────────────────
|
|
217
323
|
/**
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
* primary action because an agent exists to be run. A subagent is called by
|
|
225
|
-
* other agents, never picked for a session — the composer hides it — so the
|
|
226
|
-
* button is disabled with the reason, not offered.
|
|
324
|
+
* Share, Start session, and the ⋯ menu. Share renders for everyone and gates
|
|
325
|
+
* itself on `project.members.manage`. The ⋯ menu needs `project.agent.write`.
|
|
326
|
+
* Start session boots a session
|
|
327
|
+
* on THIS agent through the sidebar's New session hook. A subagent is called
|
|
328
|
+
* by other agents, never picked for a session, so its button is disabled with
|
|
329
|
+
* the reason. Below `sm` Start session is an icon button.
|
|
227
330
|
*/
|
|
228
|
-
function AgentActions({ projectId, agent, config, canWrite, }) {
|
|
331
|
+
function AgentActions({ projectId, agent, config, canWrite, share, }) {
|
|
332
|
+
const t = useI18nTranslations('agentEditor.tabs');
|
|
229
333
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
230
|
-
const queryClient = useQueryClient();
|
|
231
334
|
const startSession = useNewProjectSession(projectId);
|
|
232
335
|
const configure = useConfigureThread(projectId);
|
|
233
|
-
const
|
|
336
|
+
const makeDefault = useDefaultAgent(projectId);
|
|
337
|
+
const [confirm, setConfirm] = useState(null);
|
|
234
338
|
const isDefault = (config.default_agent ?? config.open_code_default_agent) === agent.name;
|
|
235
339
|
const mode = agent.mode?.toLowerCase();
|
|
236
340
|
const startBlocked = agent.enabled === false
|
|
237
|
-
? '
|
|
341
|
+
? t('startDisabled')
|
|
238
342
|
: mode === 'subagent'
|
|
239
|
-
? '
|
|
343
|
+
? t('startSubagentBlocked')
|
|
240
344
|
: null;
|
|
241
|
-
const
|
|
242
|
-
const
|
|
243
|
-
return (_jsxs(
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
345
|
+
const startLabel = tI18nComplete.raw('textb1c52ee3677d');
|
|
346
|
+
const start = (_jsxs(_Fragment, { children: [_jsxs(Button, { size: "sm", disabled: startBlocked !== null, onClick: () => startSession({ create: { agent_name: agent.name } }), className: "hidden sm:inline-flex", children: [_jsx(PlayIcon, { weight: "fill", className: "size-3.5 shrink-0" }), startLabel] }), _jsx(Button, { size: "icon-base", "aria-label": startLabel, disabled: startBlocked !== null, onClick: () => startSession({ create: { agent_name: agent.name } }), className: "sm:hidden", children: _jsx(PlayIcon, { weight: "fill", className: "size-3.5" }) })] }));
|
|
347
|
+
return (_jsxs(_Fragment, { children: [_jsx(AgentPinButton, { projectId: projectId, agent: agent.name }), _jsx(AgentShareControl, { projectId: projectId, agentName: agent.name, open: share.open, onOpenChange: share.setOpen }), startBlocked ? (_jsx(Hint, { label: startBlocked, children: _jsx("span", { className: "inline-flex", children: start }) })) : (start), canWrite ? (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon-base", "aria-label": tI18nComplete.raw('textf8d46c2570e7'), children: _jsx(DotsThreeIcon, { className: "size-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsxs(DropdownMenuItem, { disabled: isDefault || agent.enabled === false || makeDefault.isPending, onSelect: () => makeDefault.mutate(agent.name), children: [_jsx(StarIcon, { className: "size-4" }), isDefault ? tI18nComplete.raw('texte8cb80e5c5cb') : tI18nComplete.raw('texte8f43f910a4e')] }), _jsxs(DropdownMenuItem, { disabled: configure.pending, onSelect: () => setConfirm('edit'), children: [_jsx(AgentMark, { slug: MY_KORTIX_AGENT_NAME }), t('askToEditAgent')] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { variant: "destructive", disabled: configure.pending, onSelect: () => setConfirm('delete'), children: [_jsx(TrashIcon, { className: "size-4" }), t('deleteAgent', { name: agentDisplayName(agent.name) })] })] })] })) : null, _jsx(ConfirmDialog, { open: confirm !== null, onOpenChange: (open) => (open ? undefined : setConfirm(null)), title: confirm === 'delete' ? t('deleteTitle', { name: agentDisplayName(agent.name) }) : tI18nComplete.raw('text24ba36a8ec86'), description: confirm === 'delete'
|
|
348
|
+
? t('deleteBody')
|
|
349
|
+
: tI18nComplete('text13324ae62b23', { value0: agent.name }), confirmLabel: tI18nComplete.raw('text0bce1a892dec'), cancelLabel: tI18nComplete.raw('text19766ed6ccb2'), confirmVariant: confirm === 'delete' ? 'destructive' : 'default', onConfirm: () => {
|
|
350
|
+
const kind = confirm;
|
|
351
|
+
setConfirm(null);
|
|
352
|
+
configure.start(kind === 'delete'
|
|
353
|
+
? t('deletePrompt', { name: agent.name, path: agent.path })
|
|
354
|
+
: editConfigPrompt('agent', agent.name, agent.path));
|
|
248
355
|
} })] }));
|
|
249
356
|
}
|
|
250
|
-
/** The status chips beside the name. Only states worth flagging. */
|
|
251
|
-
function AgentChips({ agent, config, size, }) {
|
|
252
|
-
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
253
|
-
const { showMode, isDefault, disabled } = agentStatus(agent, config);
|
|
254
|
-
return (_jsxs("span", { className: "flex items-center gap-1.5", children: [showMode ? (_jsx(Badge, { variant: "secondary", size: size, children: formatMode(agent.mode ?? '') })) : null, isDefault ? (_jsx(Badge, { variant: "secondary", size: size, children: tI18nComplete.raw('text21b111cbfe6e') })) : null, disabled ? (_jsx(Badge, { variant: "muted", size: size, children: tI18nComplete.raw('text75081b593d15') })) : null] }));
|
|
255
|
-
}
|
|
256
357
|
/**
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
358
|
+
* The one column every Access and Runtime view sits in, embedded resource
|
|
359
|
+
* screen or settings form alike: the same width, the same top offset.
|
|
360
|
+
* Triggers is not a view: it keeps the full width its list
|
|
361
|
+
* and detail split needs.
|
|
260
362
|
*/
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
363
|
+
/** A view beside the Capabilities or Access rail, centered in the space right of the rail. */
|
|
364
|
+
const RAIL_COLUMN = 'mx-auto max-w-3xl';
|
|
365
|
+
/** A one-view tab (Workspace, Model): centered, the Overview's column. */
|
|
366
|
+
const CENTER_COLUMN = 'mx-auto max-w-3xl';
|
|
367
|
+
/** Frames a full resource screen in agent scope, with `lead` atop its scroller. */
|
|
368
|
+
function Embedded({ agentName, lead, column, children, }) {
|
|
369
|
+
return (
|
|
370
|
+
// A view in a column sits beside the rail, which names no view: the screen shows its own title.
|
|
371
|
+
_jsx(CapabilityShellEmbedProvider, { value: { agentName, lead, className: column, titled: column !== undefined }, children: _jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: children }) }));
|
|
264
372
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const
|
|
268
|
-
'
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
* Its people, triggers, model and permissions are platform-managed, not project
|
|
276
|
-
* settings to inspect here. */
|
|
277
|
-
const PLATFORM_SECTIONS = ['overview'];
|
|
278
|
-
function EditableAgentPage({ projectId, agent, config, initial, schemaVersion, }) {
|
|
373
|
+
/** Runtime > Model's one way out to the project-wide model screens. */
|
|
374
|
+
function ProjectModelsLink({ projectId }) {
|
|
375
|
+
const t = useI18nTranslations('agentEditor.tabs');
|
|
376
|
+
return (_jsx("p", { className: "text-muted-foreground text-sm text-pretty", children: t.rich('projectModelsLink', {
|
|
377
|
+
link: (chunks) => (_jsx(Link, { href: adminPath(projectId, 'models'), className: "text-foreground decoration-border hover:decoration-foreground underline underline-offset-4 transition-colors", children: chunks })),
|
|
378
|
+
}) }));
|
|
379
|
+
}
|
|
380
|
+
// ─── Editable body ───────────────────────────────────────────────────────────
|
|
381
|
+
function EditableAgentPage({ projectId, agent, config, initial, renderApps, }) {
|
|
382
|
+
const tCapabilities = useI18nTranslations('agentCapabilities');
|
|
279
383
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
384
|
+
const locale = useLocale();
|
|
280
385
|
const editor = useAgentDraft(initial);
|
|
281
386
|
const options = useAgentEditorOptions(projectId);
|
|
387
|
+
const capabilities = useProjectCapabilities(projectId);
|
|
282
388
|
const update = useUpdateAgentConfig(projectId, agent.name);
|
|
389
|
+
const configure = useConfigureThread(projectId);
|
|
283
390
|
const [confirmDiscard, setConfirmDiscard] = useState(false);
|
|
391
|
+
const pathname = useUiPathname();
|
|
392
|
+
const drivesOn = useFeatureFlag(projectId, 'drives').enabled;
|
|
393
|
+
const views = useMemo(() => AGENT_CONFIG_SECTIONS.map((s) => s.key).filter((k) => drivesOn || k !== 'drives'), [drivesOn]);
|
|
394
|
+
const location = useAgentLocation(AGENT_TABS, views);
|
|
395
|
+
const share = useShareDialog(location.open === 'share');
|
|
396
|
+
const registryOptions = useMemo(() => registryGrantOptions({ manifest_raw: config.manifest_raw, agents: toArray(config.agents) }, agent.name), [config.manifest_raw, config.agents, agent.name]);
|
|
284
397
|
const skillsOptions = toArray(config.skills).map((skill) => ({
|
|
285
398
|
id: skill.name,
|
|
286
399
|
label: skill.name,
|
|
287
400
|
description: skill.description ?? undefined,
|
|
288
401
|
}));
|
|
289
|
-
const pathname = useUiPathname();
|
|
290
|
-
// Drives exists only with Volumes on (the project's derived `drives` flag).
|
|
291
|
-
const drivesOn = useFeatureFlag(projectId, 'drives').enabled;
|
|
292
|
-
const sections = useMemo(() => agentConfigSectionKeys(schemaVersion).filter((k) => drivesOn || k !== 'drives'), [schemaVersion, drivesOn]);
|
|
293
|
-
const registryOptions = useMemo(() => registryGrantOptions({ manifest_raw: config.manifest_raw, agents: toArray(config.agents) }, agent.name), [config.manifest_raw, config.agents, agent.name]);
|
|
294
402
|
const policySetOptions = useMemo(() => connectorPolicySetOptions(config.manifest_raw), [config.manifest_raw]);
|
|
295
|
-
const
|
|
403
|
+
const policySetControl = useAgentPolicySetControls(projectId, editor, policySetOptions);
|
|
404
|
+
const surface = { kind: 'agent', agentName: agent.name };
|
|
405
|
+
const defaultAgent = config.default_agent ?? config.open_code_default_agent;
|
|
406
|
+
const name = agentDisplayName(agent.name);
|
|
407
|
+
const sourcePath = editor.draft.file ?? configEntitySourcePath(agent.path);
|
|
408
|
+
const { draft, set } = editor;
|
|
409
|
+
const connectorsGrant = useAgentGrant(draft.connectors, (v) => {
|
|
410
|
+
set('connectors', v);
|
|
411
|
+
// `connectors_required` is no longer enforced: keep it inside the grant.
|
|
412
|
+
const kept = pruneRequiredConnectors(draft.connectors_required, v);
|
|
413
|
+
if (kept !== draft.connectors_required)
|
|
414
|
+
set('connectors_required', kept);
|
|
415
|
+
});
|
|
416
|
+
const secretsGrant = useAgentGrant(draft.secrets, (v) => set('secrets', v));
|
|
417
|
+
const appsGrant = useAgentGrant(draft.apps, (v) => set('apps', v));
|
|
418
|
+
const facts = useOverviewFacts(projectId, agent.name, config, draft);
|
|
419
|
+
const headerFacts = useHeaderFacts(projectId, agent, config, draft, true);
|
|
420
|
+
const spacesOn = useSpacesEnabled(projectId);
|
|
296
421
|
const onSave = useCallback(async () => {
|
|
297
422
|
if (!editor.isDirty || update.isPending)
|
|
298
|
-
return;
|
|
423
|
+
return !editor.isDirty;
|
|
299
424
|
try {
|
|
300
425
|
const response = await update.mutateAsync(editor.draft);
|
|
301
426
|
editor.commit(response.block ?? editor.draft);
|
|
302
|
-
successToast(tI18nComplete('text6b0bbffdbd6e', { value0:
|
|
427
|
+
successToast(tI18nComplete('text6b0bbffdbd6e', { value0: name }));
|
|
428
|
+
return true;
|
|
303
429
|
}
|
|
304
430
|
catch (e) {
|
|
305
431
|
errorToast(e?.message ?? tI18nComplete.raw('text166442c65e8e'));
|
|
432
|
+
return false;
|
|
306
433
|
}
|
|
307
|
-
}, [editor, update,
|
|
308
|
-
|
|
309
|
-
//
|
|
310
|
-
//
|
|
434
|
+
}, [editor, update, name, tI18nComplete]);
|
|
435
|
+
const saveNow = useCallback(() => void onSave(), [onSave]);
|
|
436
|
+
// Tab links change only the query on this path: the draft survives them, so
|
|
437
|
+
// the guard lets them through.
|
|
311
438
|
const leaveGuard = useUnsavedChangesGuard(editor.isDirty, pathname);
|
|
312
|
-
useSaveShortcut(
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
439
|
+
useSaveShortcut(editor.isDirty, saveNow);
|
|
440
|
+
const grantLabel = useGrantLabel();
|
|
441
|
+
// A tool's aliases go off with it (`agent` takes `task`): the tab counts tools, not names.
|
|
442
|
+
const toolAliases = new Set((capabilities.data?.tools ?? []).flatMap((tool) => tool.aliases));
|
|
443
|
+
const countOf = (view) => {
|
|
444
|
+
if (view === 'drives')
|
|
445
|
+
return null;
|
|
446
|
+
const value = grantOf(draft, view);
|
|
447
|
+
const excluded = grantExcluded(value);
|
|
448
|
+
return view === 'tools' && excluded.length > 0
|
|
449
|
+
? grantLabel({ exclude: excluded.filter((id) => !toolAliases.has(id)) })
|
|
450
|
+
: grantLabel(value);
|
|
451
|
+
};
|
|
452
|
+
const railItems = useRailItems(pathname, views, facts, countOf, {
|
|
453
|
+
model: modelName(editor.oc.model),
|
|
454
|
+
workspace: draft.sandbox,
|
|
455
|
+
});
|
|
456
|
+
const tabGroups = useTabGroups(railItems);
|
|
457
|
+
const dirtyItems = useMemo(() => changedItems(editor.draft, editor.baseline), [editor.draft, editor.baseline]);
|
|
458
|
+
const changed = new Intl.ListFormat(locale, { type: 'conjunction' }).format(dirtyItems.map((key) => railItems.find((item) => item.key === key)?.label ?? key));
|
|
459
|
+
const editorSection = (view) => (_jsx(AgentConfigSections, { section: view, editor: editor, options: options, skillsOptions: skillsOptions, registryOptions: registryOptions, apps: null, drives: _jsx(AgentDrivesSection, { projectId: projectId, agentName: agent.name, repositoryAccess: draft.repository_access !== false }), sectionStyle: "tab" }));
|
|
460
|
+
const body = (() => {
|
|
461
|
+
const view = location.view;
|
|
462
|
+
switch (location.tab) {
|
|
463
|
+
case 'overview':
|
|
464
|
+
return (_jsx(AgentTabBody, { children: _jsx(AgentOverview, { agent: agent, config: config, block: draft, prompt: editor.oc.prompt ?? '', editor: editor, sourcePath: sourcePath, showSpace: spacesOn, onAskMyKortix: () => configure.start(editConfigPrompt('agent', agent.name, agent.path)), focusInstructions: location.open === 'instructions' }) }));
|
|
465
|
+
case 'access':
|
|
466
|
+
case 'runtime': {
|
|
467
|
+
if (!view)
|
|
468
|
+
return null;
|
|
469
|
+
// Every Access view is the ONE component Project admin shows for the
|
|
470
|
+
// same library, in agent mode: the agent's grant row and a switch per
|
|
471
|
+
// item over the project's catalog (Marko, 2026-10-27).
|
|
472
|
+
if (view === 'skills' || view === 'tools' || view === 'extensions') {
|
|
473
|
+
const Page = view === 'skills' ? SkillsPage : view === 'tools' ? ToolsPage : ExtensionsPage;
|
|
474
|
+
return (_jsx(Embedded, { agentName: agent.name, column: RAIL_COLUMN, children: _jsx(Page, { projectId: projectId, agent: { name: agent.name, editor }, footer: view === 'tools' ? (_jsx(AgentApprovalRules, { projectId: projectId, editor: editor, rules: _jsx(EditorSectionStyleProvider, { value: "panel", children: _jsx(ToolsSection, { permission: editor.oc.permission, onChange: (next) => editor.setOc('permission', next), title: tCapabilities('rulesTitle') }) }) })) : undefined }) }));
|
|
475
|
+
}
|
|
476
|
+
if (view === 'connectors')
|
|
477
|
+
return (_jsx(Embedded, { agentName: agent.name, column: RAIL_COLUMN, children: _jsx(ConnectorsPage, { projectId: projectId, surface: surface, grant: connectorsGrant, rowControl: policySetControl, agentPanel: _jsxs(_Fragment, { children: [_jsx(AgentPolicySetsPanel, { projectId: projectId, editor: editor, catalog: policySetOptions, unlistedOnly: true }), _jsx(RequiredConnectorsNote, { names: draft.connectors_required })] }) }) }));
|
|
478
|
+
if (view === 'secrets')
|
|
479
|
+
return (_jsx(Embedded, { agentName: agent.name, column: RAIL_COLUMN, children: _jsx(SecretsPage, { projectId: projectId, surface: surface, grant: secretsGrant }) }));
|
|
480
|
+
if (view === 'apps' && renderApps)
|
|
481
|
+
return (_jsx(Embedded, { agentName: agent.name, column: RAIL_COLUMN, children: renderApps({ agentName: agent.name, grant: appsGrant, needsAppRead: !grantsAppRead(draft.kortix_permissions ?? draft.kortix_cli) }) }));
|
|
482
|
+
if (view === 'drives')
|
|
483
|
+
return (_jsx(Embedded, { agentName: agent.name, column: RAIL_COLUMN, children: _jsx(AgentDrivesSection, { projectId: projectId, agentName: agent.name, repositoryAccess: draft.repository_access !== false }) }));
|
|
484
|
+
// Model is this agent's model only. The project-wide gateway screens
|
|
485
|
+
// (providers, routing, costs, logs) live once, in Project admin.
|
|
486
|
+
if (view === 'model')
|
|
487
|
+
return (_jsx(AgentTabBody, { children: _jsx(AgentModelView, { oc: editor.oc, setOc: editor.setOc, footer: _jsx(ProjectModelsLink, { projectId: projectId }) }) }));
|
|
488
|
+
return (_jsx(AgentTabBody, { className: `${view === 'workspace' ? CENTER_COLUMN : RAIL_COLUMN} space-y-5`, children: _jsx(CapabilityShellEmbedProvider, { value: { agentName: agent.name }, children: editorSection(view) }) }));
|
|
489
|
+
}
|
|
490
|
+
case 'triggers':
|
|
491
|
+
return (_jsx(Embedded, { agentName: agent.name, children: _jsx(TriggersPage, { projectId: projectId, surface: surface, defaultAgent: defaultAgent }) }));
|
|
492
|
+
}
|
|
493
|
+
})();
|
|
494
|
+
return (
|
|
495
|
+
// Embedded screens leave through the router too (a configure session):
|
|
496
|
+
// they ask the same question as a link click.
|
|
497
|
+
_jsx(LeaveGuardProvider, { value: leaveGuard.confirmLeave, children: _jsxs("div", { className: "relative flex h-full min-h-0 flex-1 flex-col", children: [_jsx(AgentIdentityHeader, { slug: agent.name, title: name, facts: headerFacts, actions: _jsx(AgentActions, { projectId: projectId, agent: agent, config: config, canWrite: true, share: share }) }), _jsx(TabLayout, { tabs: _jsx(AgentTabBar, { groups: tabGroups, active: railKeyOf(location), dirty: dirtyItems }), children: _jsx(AgentSectionRail, { group: railGroupOf(tabGroups, railKeyOf(location)), active: railKeyOf(location), dirty: dirtyItems, children: body }) }), _jsx(SaveBar, { dirty: editor.isDirty, pending: update.isPending, changed: changed, onDiscard: () => setConfirmDiscard(true), onSave: saveNow }), _jsx(ConfirmDialog, { open: confirmDiscard, onOpenChange: setConfirmDiscard, title: tI18nComplete.raw('text3b13192b9d88'), description: tI18nComplete('text8a36cce34f68', { value0: name }), confirmLabel: tI18nComplete.raw('texteb1a70e39274'), cancelLabel: tI18nComplete.raw('texte76fd2add010'), confirmVariant: "destructive", onConfirm: () => {
|
|
316
498
|
setConfirmDiscard(false);
|
|
317
499
|
editor.discard();
|
|
318
|
-
} }), _jsx(
|
|
319
|
-
if (
|
|
320
|
-
leaveGuard.
|
|
321
|
-
}
|
|
500
|
+
} }), _jsx(LeaveDialog, { open: leaveGuard.asking, changed: changed, pending: update.isPending, onStay: leaveGuard.stay, onLeave: leaveGuard.leave, onSaveAndLeave: async () => {
|
|
501
|
+
if (await onSave())
|
|
502
|
+
leaveGuard.leave();
|
|
503
|
+
} })] }) }));
|
|
322
504
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
*/
|
|
329
|
-
function OverviewPane({ description, onDescriptionChange, descriptionHelp, prompt, onPromptChange, }) {
|
|
505
|
+
// ─── Read-only body ──────────────────────────────────────────────────────────
|
|
506
|
+
/** A reader's tabs and views: what can be shown without the editor. */
|
|
507
|
+
const READ_ONLY_VIEWS = ['actions', 'model'];
|
|
508
|
+
function ReadOnlyAgentPage({ projectId, agent, config, block, canWrite, }) {
|
|
509
|
+
const t = useI18nTranslations('agentEditor.tabs');
|
|
330
510
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
331
|
-
const
|
|
332
|
-
return (_jsxs(_Fragment, { children: [_jsx(SettingsSectionHeader, { title: tEditor('overviewTitle'), className: "pb-1" }), _jsx(EditorSection, { title: tI18nComplete.raw('text526e0087cc3f'), description: descriptionHelp, bare: true, children: _jsx(Textarea, { "aria-label": tI18nComplete.raw('text526e0087cc3f'), value: description, placeholder: tI18nComplete.raw('text446f4eabf99f'), minHeight: 44, className: "text-sm", onChange: (e) => onDescriptionChange(e.target.value) }) }), _jsx(InstructionsSection, { value: prompt, onChange: onPromptChange })] }));
|
|
333
|
-
}
|
|
334
|
-
/**
|
|
335
|
-
* The instructions — the agent's system prompt, and the thing that most IS
|
|
336
|
-
* the agent. Two views of one field: Edit is the textarea, Preview renders
|
|
337
|
-
* the markdown the way the agent's source file reads. It opens on Preview
|
|
338
|
-
* when there is something to read and on Edit when there is not; the toggle
|
|
339
|
-
* is the segmented `TabsList` at the section heading's right edge.
|
|
340
|
-
*/
|
|
341
|
-
function InstructionsSection({ value, onChange, }) {
|
|
342
|
-
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
343
|
-
const [view, setView] = useState(value.trim() ? 'preview' : 'edit');
|
|
344
|
-
return (_jsx(EditorSection, { title: tI18nComplete.raw('text934652dce41d'), description: tI18nComplete.raw('text5fe8921b712c'), trailing: _jsx(Tabs, { value: view, onValueChange: (next) => setView(next), children: _jsxs(TabsList, { "aria-label": tI18nComplete.raw('texte75bb2d0d554'), children: [_jsx(TabsTrigger, { value: "edit", children: tI18nComplete.raw('text464c4ffd019e') }), _jsx(TabsTrigger, { value: "preview", children: tI18nComplete.raw('text324b134f57c7') })] }) }), bare: true, children: view === 'edit' ? (_jsx(Textarea, { "aria-label": tI18nComplete.raw('text934652dce41d'), value: value, placeholder: tI18nComplete.raw('text1436469ad07f'), minHeight: 420, autoFocus: value.trim().length > 0, className: "font-mono text-xs leading-relaxed", onChange: (e) => onChange(e.target.value) })) : (_jsx("div", { className: "bg-popover min-h-[420px] rounded-md border px-5 py-4", children: _jsx(MarkdownWithFrontmatter, { content: value }) })) }));
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* The save bar. Exists only while there is something to save — an always-on
|
|
348
|
-
* disabled pair of buttons is chrome that never earns its row. It floats at
|
|
349
|
-
* the bottom centre of the page in the Drive selection bar's shape
|
|
350
|
-
* (`project-files/components/drive-selection-bar.tsx`): a `bg-popover` card
|
|
351
|
-
* as wide as its content — the state as a title over one muted line, then
|
|
352
|
-
* Discard and Save as a spaced pair (a confirm is never glued to its cancel).
|
|
353
|
-
* It sits outside both scrollers, so it is reachable
|
|
354
|
-
* from any point in a long instruction set.
|
|
355
|
-
*/
|
|
356
|
-
function SaveBar({ dirty, pending, onDiscard, onSave, }) {
|
|
357
|
-
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
358
|
-
return (_jsx(AnimatePresence, { initial: false, children: dirty ? (_jsx(m.div, { initial: { opacity: 0, y: 8 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: 8 }, transition: { type: 'spring', duration: 0.3, bounce: 0 }, className: "pointer-events-none absolute inset-x-0 bottom-4 z-30 flex justify-center px-4", children: _jsxs("div", { className: "bg-popover text-popover-foreground border-border pointer-events-auto flex max-w-full items-center gap-3 rounded-lg border p-2 pl-3.5 shadow-md", children: [_jsxs("div", { className: "min-w-0", "aria-live": "polite", children: [_jsx("p", { className: "text-foreground truncate text-sm font-medium", children: tI18nComplete.raw('textefa5855ff509') }), _jsx("p", { className: "text-muted-foreground truncate text-xs", children: tI18nComplete.raw('textc8134fda3694') })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx(Button, { variant: "secondary", size: "sm", onClick: onDiscard, disabled: pending, children: tI18nComplete.raw('texteb1a70e39274') }), _jsxs(Button, { variant: "secondary", size: "sm", className: "gap-1.5", onClick: onSave, disabled: pending, children: [pending ? _jsx(Loading, { className: "size-3.5 shrink-0" }) : null, tI18nComplete.raw('text1509f561f241'), _jsx(Kbd, { children: tI18nComplete.raw('text8cd003e6301b') })] })] })] }) }, "save-bar")) : null }));
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Mod+S saves. The page is a document you edit, and every editor a person
|
|
362
|
-
* has used saves on that chord; without it the browser offers to save the
|
|
363
|
-
* HTML, which is never what anyone meant.
|
|
364
|
-
*/
|
|
365
|
-
function useSaveShortcut(onSave) {
|
|
366
|
-
useEffect(() => {
|
|
367
|
-
const handler = (event) => {
|
|
368
|
-
if ((event.metaKey || event.ctrlKey) &&
|
|
369
|
-
!event.shiftKey &&
|
|
370
|
-
!event.altKey &&
|
|
371
|
-
event.key === 's') {
|
|
372
|
-
event.preventDefault();
|
|
373
|
-
onSave();
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
window.addEventListener('keydown', handler);
|
|
377
|
-
return () => window.removeEventListener('keydown', handler);
|
|
378
|
-
}, [onSave]);
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Holds a dirty page on the page until the person decides.
|
|
382
|
-
*
|
|
383
|
-
* Two exits, two guards. A tab close or a reload reaches only `beforeunload`,
|
|
384
|
-
* so that is armed while dirty. An in-app link — the sidebar, a tab, the
|
|
385
|
-
* breadcrumb — never fires it, and the App Router has no navigation event to
|
|
386
|
-
* cancel, so anchor clicks are intercepted in the capture phase instead: the
|
|
387
|
-
* click is swallowed, the target href is parked, and the page asks. `leave`
|
|
388
|
-
* pushes the parked href; `stay` drops it. Modified clicks (new tab) and
|
|
389
|
-
* external links pass through — nothing is lost by opening a second tab.
|
|
390
|
-
*/
|
|
391
|
-
function useUnsavedChangesGuard(isDirty, currentPath) {
|
|
392
|
-
const router = useUiRouter();
|
|
393
|
-
const [pendingHref, setPendingHref] = useState(null);
|
|
394
|
-
useEffect(() => {
|
|
395
|
-
if (!isDirty)
|
|
396
|
-
return;
|
|
397
|
-
const onBeforeUnload = (event) => {
|
|
398
|
-
event.preventDefault();
|
|
399
|
-
};
|
|
400
|
-
const onClick = (event) => {
|
|
401
|
-
if (event.defaultPrevented || event.button !== 0)
|
|
402
|
-
return;
|
|
403
|
-
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
|
|
404
|
-
return;
|
|
405
|
-
const anchor = event.target?.closest?.('a[href]');
|
|
406
|
-
if (!(anchor instanceof HTMLAnchorElement))
|
|
407
|
-
return;
|
|
408
|
-
if (anchor.target && anchor.target !== '_self')
|
|
409
|
-
return;
|
|
410
|
-
if (anchor.origin !== window.location.origin)
|
|
411
|
-
return;
|
|
412
|
-
const href = anchor.pathname + anchor.search + anchor.hash;
|
|
413
|
-
if (href === window.location.pathname + window.location.search + window.location.hash)
|
|
414
|
-
return;
|
|
415
|
-
// A link that only changes `?section=` on this page switches topic; the
|
|
416
|
-
// draft survives that, so it never needs the question.
|
|
417
|
-
if (currentPath && anchor.pathname === currentPath)
|
|
418
|
-
return;
|
|
419
|
-
event.preventDefault();
|
|
420
|
-
event.stopPropagation();
|
|
421
|
-
setPendingHref(href);
|
|
422
|
-
};
|
|
423
|
-
window.addEventListener('beforeunload', onBeforeUnload);
|
|
424
|
-
document.addEventListener('click', onClick, true);
|
|
425
|
-
return () => {
|
|
426
|
-
window.removeEventListener('beforeunload', onBeforeUnload);
|
|
427
|
-
document.removeEventListener('click', onClick, true);
|
|
428
|
-
};
|
|
429
|
-
}, [isDirty, currentPath]);
|
|
430
|
-
return {
|
|
431
|
-
pendingHref,
|
|
432
|
-
stay: () => setPendingHref(null),
|
|
433
|
-
leave: () => {
|
|
434
|
-
const href = pendingHref;
|
|
435
|
-
setPendingHref(null);
|
|
436
|
-
if (href)
|
|
437
|
-
router.push(href);
|
|
438
|
-
},
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
// ─── Read-only body ────────────────────────────────────────────────────────
|
|
442
|
-
function ReadOnlyAgentPage({ projectId, agent, config, canWrite, showUpgradeHint, isPlatform, }) {
|
|
443
|
-
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
444
|
-
const tUpgrades = useI18nTranslations('settings.upgrades');
|
|
445
|
-
// The real repo path, with any manifest anchor stripped. Agents declared in
|
|
446
|
-
// the manifest rather than as their own file carry one
|
|
447
|
-
// (`kortix.yaml#agents.<name>`), and reading that verbatim is a 404.
|
|
511
|
+
const pathname = useUiPathname();
|
|
448
512
|
const sourcePath = configEntitySourcePath(agent.path);
|
|
513
|
+
// The served block carries the prompt when the read returned it; otherwise
|
|
514
|
+
// read the agent's source file.
|
|
449
515
|
const fileQuery = useQuery({
|
|
450
516
|
queryKey: ['entity-file-content', projectId, sourcePath],
|
|
451
517
|
queryFn: () => readProjectFile(projectId, sourcePath),
|
|
452
518
|
staleTime: 30_000,
|
|
453
|
-
|
|
454
|
-
enabled: !isPlatform,
|
|
519
|
+
enabled: block.behavior?.prompt === undefined,
|
|
455
520
|
});
|
|
456
|
-
const
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
521
|
+
const prompt = block.behavior?.prompt ?? (fileQuery.data ? stripFrontmatter(fileQuery.data.content) : null);
|
|
522
|
+
const views = useMemo(() => {
|
|
523
|
+
const own = ACCESS_VIEWS.filter((v) => v === 'skills' || v === 'connectors' || v === 'secrets' || v === 'apps' || v === 'actions');
|
|
524
|
+
return [...own, 'model'];
|
|
525
|
+
}, []);
|
|
526
|
+
const location = useAgentLocation(AGENT_TABS, READ_ONLY_VIEWS);
|
|
527
|
+
const share = useShareDialog(location.open === 'share');
|
|
528
|
+
const facts = useOverviewFacts(projectId, agent.name, config, block);
|
|
529
|
+
const headerFacts = useHeaderFacts(projectId, agent, config, block, false);
|
|
530
|
+
const spacesOn = useSpacesEnabled(projectId);
|
|
531
|
+
const railItems = useRailItems(pathname, READ_ONLY_VIEWS, facts, undefined, {
|
|
532
|
+
model: modelName(block.behavior?.model),
|
|
533
|
+
workspace: block.sandbox,
|
|
534
|
+
});
|
|
535
|
+
const tabGroups = useTabGroups(railItems);
|
|
536
|
+
const name = agentDisplayName(agent.name);
|
|
537
|
+
// A reader has a page for Kortix permissions and Model only. Every other
|
|
538
|
+
// Access row shows its grant by name on the Overview and links nowhere.
|
|
539
|
+
const banner = (_jsx(InfoBanner, { tone: "neutral", icon: LockSimpleIcon, title: t('readOnlyTitle'), children: t.rich('readOnlyBody', { code: (chunks) => _jsx("span", { className: "font-mono", children: chunks }) }) }));
|
|
540
|
+
const body = (() => {
|
|
541
|
+
switch (location.tab) {
|
|
542
|
+
case 'overview':
|
|
543
|
+
return (_jsxs(AgentTabBody, { className: "space-y-6", children: [banner, _jsx(AgentOverview, { agent: agent, config: config, block: block, prompt: prompt, sourcePath: sourcePath, showSpace: spacesOn })] }));
|
|
544
|
+
case 'access':
|
|
545
|
+
case 'runtime':
|
|
546
|
+
return (_jsxs(AgentTabBody, { className: `${location.view === 'model' || location.view === 'workspace' ? CENTER_COLUMN : RAIL_COLUMN} space-y-6`, children: [banner, _jsx(EditorSectionStyleProvider, { value: "panel", children: location.view === 'model' ? (_jsxs("div", { className: "space-y-3", children: [_jsx(AgentModel, { projectId: projectId, agentName: agent.name }), _jsx("p", { className: "text-muted-foreground text-xs text-pretty", children: tI18nComplete.raw('text9dee2a1acfd9') })] })) : (_jsxs("div", { className: "space-y-8", children: [_jsx(AgentScope, { projectId: projectId, agentName: agent.name, scope: agent.scope }), _jsx(AgentAuthorityCard, { projectId: projectId, agentName: agent.name, grant: block.kortix_permissions ?? block.kortix_cli })] })) })] }));
|
|
547
|
+
case 'triggers':
|
|
548
|
+
// The same Triggers screen; its own controls decide what a reader may change.
|
|
549
|
+
return (_jsx(Embedded, { agentName: agent.name, children: _jsx(TriggersPage, { projectId: projectId, surface: { kind: 'agent', agentName: agent.name }, defaultAgent: config.default_agent ?? config.open_code_default_agent }) }));
|
|
550
|
+
}
|
|
551
|
+
})();
|
|
552
|
+
return (_jsxs("div", { className: "relative flex h-full min-h-0 flex-1 flex-col", children: [_jsx(AgentIdentityHeader, { slug: agent.name, title: name, facts: headerFacts, actions: _jsx(AgentActions, { projectId: projectId, agent: agent, config: config, canWrite: canWrite, share: share }) }), _jsx(TabLayout, { tabs: _jsx(AgentTabBar, { groups: tabGroups, active: railKeyOf(location) }), children: _jsx(AgentSectionRail, { group: railGroupOf(tabGroups, railKeyOf(location)), active: railKeyOf(location), children: body }) })] }));
|
|
553
|
+
}
|
|
554
|
+
/** A markdown file's body without its frontmatter. */
|
|
555
|
+
function stripFrontmatter(content) {
|
|
556
|
+
return content.replace(/^---\n[\s\S]*?\n---\n?/, '');
|
|
557
|
+
}
|
|
558
|
+
/** Whether a Kortix permissions grant lets the agent open project Apps. */
|
|
559
|
+
function grantsAppRead(grant) {
|
|
560
|
+
return grant === 'all' || (Array.isArray(grant) && grant.includes('project.app.read'));
|
|
561
|
+
}
|
|
562
|
+
/** The Model row's value: the model id after its provider (`kortix/kimi-k2` → `kimi-k2`). */
|
|
563
|
+
function modelName(model) {
|
|
564
|
+
return model ? model.slice(model.lastIndexOf('/') + 1) : undefined;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* `connectors_required` (kortix.yaml), when the block sets it: read-only,
|
|
568
|
+
* because sessions no longer wait for these connectors.
|
|
569
|
+
*/
|
|
570
|
+
function RequiredConnectorsNote({ names }) {
|
|
571
|
+
const t = useI18nTranslations('agentEditor.tabs');
|
|
572
|
+
if (!names || names.length === 0)
|
|
573
|
+
return null;
|
|
574
|
+
return (_jsxs("section", { className: "space-y-1", children: [_jsx("h2", { className: "text-sm font-medium", children: t('requiredConnectors') }), _jsx("p", { className: "text-foreground font-mono text-sm", children: names.join(', ') }), _jsx("p", { className: "text-muted-foreground text-xs text-pretty", children: t('requiredConnectorsHelp') })] }));
|
|
464
575
|
}
|