clay-server 5.1.1-beta.1 → 5.2.0-beta.10
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/lib/account-auth-policy.js +21 -0
- package/lib/account-auth-socket.js +30 -0
- package/lib/account-auth-throttle.js +44 -0
- package/lib/account-auth-transport.js +48 -0
- package/lib/account-login-page.js +28 -0
- package/lib/account-passkey-challenges.js +31 -0
- package/lib/account-passkey-page.js +89 -0
- package/lib/account-passkey-policy.js +39 -0
- package/lib/account-password-page.js +69 -0
- package/lib/account-passwords.js +36 -0
- package/lib/account-remembered.js +77 -0
- package/lib/account-session-page.js +51 -0
- package/lib/account-session-store.js +82 -0
- package/lib/builtin-mates.js +19 -16
- package/lib/bundled-skills/clay-agent-browser/SKILL.md +6 -2
- package/lib/canonical-clay-record-authority.js +15 -0
- package/lib/canonical-clay-scheduling-authority.js +19 -0
- package/lib/claude-hook-installer.js +1 -239
- package/lib/claude-jsonl-watcher.js +1 -204
- package/lib/clay-control-presentation-binding.js +96 -0
- package/lib/clay-control-presentation.js +128 -0
- package/lib/clay-control-target-projection.js +26 -0
- package/lib/clay-mate-chat-receipts.js +26 -0
- package/lib/clay-mate-chat.js +88 -0
- package/lib/clay-mate-knowledge-input.js +26 -0
- package/lib/clay-mate-knowledge.js +95 -0
- package/lib/clay-mate-lifecycle.js +95 -0
- package/lib/clay-product-control-input.js +33 -0
- package/lib/clay-product-control-tools.js +51 -0
- package/lib/clay-product-control.js +247 -0
- package/lib/clay-project-lifecycle.js +154 -0
- package/lib/clay-project-record-input.js +44 -0
- package/lib/clay-project-records.js +84 -0
- package/lib/clay-scheduling-input.js +21 -0
- package/lib/clay-scheduling-receipts.js +26 -0
- package/lib/clay-scheduling.js +119 -0
- package/lib/clay-screen-controls.js +104 -0
- package/lib/clay-skill-install.js +1 -33
- package/lib/clay-workspace-controls.js +84 -0
- package/lib/clay-workspace-input.js +17 -0
- package/lib/clay-workspace-receipts.js +26 -0
- package/lib/cli-sessions.js +1 -300
- package/lib/codex-defaults.js +1 -28
- package/lib/context-usage.js +3 -2
- package/lib/contextual-screen-snapshot.js +38 -0
- package/lib/daemon-project-access.js +11 -0
- package/lib/daemon-project-lifecycle-callbacks.js +15 -0
- package/lib/daemon-project-lifecycle.js +262 -0
- package/lib/daemon-projects.js +1 -1
- package/lib/daemon.js +80 -276
- package/lib/default-ai-runtime.js +4 -8
- package/lib/dm-digest-cursor.js +120 -0
- package/lib/email-mcp-server.js +1 -1
- package/lib/issues-service.js +29 -15
- package/lib/kiro-defaults.js +1 -22
- package/lib/knowledge-db-import-validation.js +46 -0
- package/lib/knowledge-db-import.js +99 -0
- package/lib/knowledge-db-service.js +24 -33
- package/lib/knowledge-db-storage-nedb-maintenance.js +99 -0
- package/lib/knowledge-db-storage-nedb.js +66 -0
- package/lib/knowledge-db-storage.js +72 -0
- package/lib/knowledge-db-validation.js +0 -0
- package/lib/knowledge-document-index.js +2 -1
- package/lib/knowledge-file-store.js +7 -1
- package/lib/knowledge-product-operations.js +46 -0
- package/lib/mate-avatar-catalog.js +12 -0
- package/lib/mate-avatar-migration.js +41 -0
- package/lib/mate-context-service.js +138 -0
- package/lib/mate-context-tools.js +21 -0
- package/lib/mate-creation-mcp-server.js +2 -0
- package/lib/mate-knowledge-canonical-access.js +10 -0
- package/lib/mate-knowledge-mate-bound.js +53 -0
- package/lib/mate-knowledge-mcp-server.js +55 -8
- package/lib/mate-knowledge-service.js +16 -34
- package/lib/mate-knowledge-text-tools.js +106 -0
- package/lib/mate-lifecycle-service.js +94 -0
- package/lib/mate-message-delivery.js +43 -0
- package/lib/mate-ready-creation.js +9 -1
- package/lib/mate-schedule-input.js +29 -0
- package/lib/mate-schedule-lifecycle.js +151 -0
- package/lib/mate-scheduling.js +103 -0
- package/lib/mates.js +18 -6
- package/lib/mcp-agent-tools.js +117 -0
- package/lib/mcp-connection-store.js +119 -15
- package/lib/mcp-import-credentials.js +31 -0
- package/lib/mcp-local-transport.js +13 -0
- package/lib/mcp-oauth.js +8 -6
- package/lib/mcp-proxy.js +2 -32
- package/lib/mcp-query-bridge.js +30 -0
- package/lib/mcp-remote-connections.js +74 -20
- package/lib/mcp-source-adapters.js +1 -0
- package/lib/mcp-source-context.js +1 -0
- package/lib/mcp-source-discovery.js +1 -0
- package/lib/mcp-source-plugins.js +1 -0
- package/lib/mcp-source-restrictions.js +1 -0
- package/lib/mcp-tool-policy.js +9 -0
- package/lib/migrate-single-user.js +3 -23
- package/lib/notes-checklist.js +50 -0
- package/lib/notes.js +49 -3
- package/lib/os-user-diagnostics.js +2 -4
- package/lib/os-users.js +24 -70
- package/lib/pane-pending-interactions.js +20 -0
- package/lib/pane-session-activation.js +114 -0
- package/lib/pane-session-transport.js +26 -0
- package/lib/project-admin-overview.js +51 -0
- package/lib/project-ask-user.js +8 -4
- package/lib/project-connection.js +14 -10
- package/lib/project-control-git-view.js +12 -0
- package/lib/project-debate.js +1 -0
- package/lib/project-delegated-follow-up.js +2 -1
- package/lib/project-directory-claim.js +65 -0
- package/lib/project-file-operations.js +61 -0
- package/lib/project-filesystem.js +15 -85
- package/lib/project-full-access.js +23 -2
- package/lib/project-http.js +7 -4
- package/lib/project-knowledge.js +32 -18
- package/lib/project-lifecycle-operations.js +98 -0
- package/lib/project-lifecycle-process-witness.js +32 -0
- package/lib/project-lifecycle-runtime.js +50 -0
- package/lib/project-linux-access.js +22 -0
- package/lib/project-logs-canonical-clay.js +27 -0
- package/lib/project-logs-clay-query.js +16 -0
- package/lib/project-logs-schema.js +4 -2
- package/lib/project-logs-service.js +8 -7
- package/lib/project-logs.js +1 -0
- package/lib/project-loop.js +1 -0
- package/lib/project-mate-chat-control.js +55 -0
- package/lib/project-mate-creation-proposal.js +18 -3
- package/lib/project-mate-interaction.js +40 -62
- package/lib/project-mcp.js +54 -16
- package/lib/project-models.js +14 -31
- package/lib/project-notifications.js +76 -17
- package/lib/project-ownership.js +77 -0
- package/lib/project-pair-result-delivery.js +14 -3
- package/lib/project-pair-usage.js +12 -13
- package/lib/project-pending-message-queue.js +4 -1
- package/lib/project-product-control.js +89 -0
- package/lib/project-product-session-queue.js +46 -0
- package/lib/project-push-access.js +28 -0
- package/lib/project-scheduled-message-queue.js +30 -0
- package/lib/project-scheduled-messages.js +67 -68
- package/lib/project-scheduled-task-control.js +83 -0
- package/lib/project-scheduled-tasks.js +13 -2
- package/lib/project-scheduling-access.js +10 -0
- package/lib/project-server-settings.js +1 -0
- package/lib/project-session-actions.js +65 -0
- package/lib/project-session-delete.js +8 -1
- package/lib/project-session-document.js +27 -7
- package/lib/project-session-github.js +63 -19
- package/lib/project-session-history-actions.js +167 -0
- package/lib/project-session-linear.js +14 -6
- package/lib/project-session-notes.js +7 -3
- package/lib/project-session-pair.js +1 -1
- package/lib/project-session-runtime-actions.js +64 -0
- package/lib/project-session-spawn.js +2 -3
- package/lib/project-session-vendor.js +55 -0
- package/lib/project-sessions.js +103 -272
- package/lib/project-shared-browser.js +78 -17
- package/lib/project-studio-presentation.js +58 -0
- package/lib/project-user-knowledge.js +2 -1
- package/lib/project-user-message.js +67 -1
- package/lib/project-vendor-login.js +6 -36
- package/lib/project-workspace-operations.js +126 -0
- package/lib/project-workspace-query.js +19 -2
- package/lib/project.js +178 -45
- package/lib/public/app.js +46 -0
- package/lib/public/appearance-bootstrap.js +16 -0
- package/lib/public/auth/account-login.css +98 -0
- package/lib/public/auth/account-login.js +104 -0
- package/lib/public/css/clay-tool-activity.css +51 -0
- package/lib/public/css/clay-workspace.css +29 -0
- package/lib/public/css/command-palette.css +12 -33
- package/lib/public/css/contextual-clay.css +240 -0
- package/lib/public/css/home-debate-planning.css +2 -0
- package/lib/public/css/home-mate-creation.css +5 -0
- package/lib/public/css/input.css +6 -0
- package/lib/public/css/mate-avatar-gallery.css +12 -0
- package/lib/public/css/mate-conversation.css +10 -5
- package/lib/public/css/messages.css +6 -2
- package/lib/public/css/overlays.css +4 -2
- package/lib/public/css/project-admin-overview.css +13 -0
- package/lib/public/css/session-folders.css +11 -0
- package/lib/public/css/session-github.css +46 -1
- package/lib/public/css/shared-browser.css +35 -1
- package/lib/public/css/sticky-notes.css +87 -1
- package/lib/public/css/user-settings-sessions.css +42 -0
- package/lib/public/index.html +28 -10
- package/lib/public/mate-avatars/B01.png +0 -0
- package/lib/public/mate-avatars/B02.png +0 -0
- package/lib/public/mate-avatars/B03.png +0 -0
- package/lib/public/mate-avatars/B04.png +0 -0
- package/lib/public/mate-avatars/B05.png +0 -0
- package/lib/public/mate-avatars/B06.png +0 -0
- package/lib/public/mate-avatars/B07.png +0 -0
- package/lib/public/mate-avatars/B08.png +0 -0
- package/lib/public/mate-avatars/B09.png +0 -0
- package/lib/public/mate-avatars/B10.png +0 -0
- package/lib/public/mate-avatars/B11.png +0 -0
- package/lib/public/mate-avatars/B12.png +0 -0
- package/lib/public/mate-avatars/B13.png +0 -0
- package/lib/public/mate-avatars/B14.png +0 -0
- package/lib/public/mate-avatars/B15.png +0 -0
- package/lib/public/mate-avatars/B16.png +0 -0
- package/lib/public/mate-avatars/B17.png +0 -0
- package/lib/public/mate-avatars/B18.png +0 -0
- package/lib/public/mate-avatars/B19.png +0 -0
- package/lib/public/mate-avatars/B20.png +0 -0
- package/lib/public/mate-avatars/B21.png +0 -0
- package/lib/public/mate-avatars/B22.png +0 -0
- package/lib/public/mate-avatars/B23.png +0 -0
- package/lib/public/mate-avatars/B24.png +0 -0
- package/lib/public/mate-avatars/B25.png +0 -0
- package/lib/public/mate-avatars/B26.png +0 -0
- package/lib/public/mate-avatars/B27.png +0 -0
- package/lib/public/mate-avatars/B28.png +0 -0
- package/lib/public/mate-avatars/B29.png +0 -0
- package/lib/public/mate-avatars/B30.png +0 -0
- package/lib/public/mate-avatars/B31.png +0 -0
- package/lib/public/mate-avatars/B32.png +0 -0
- package/lib/public/mate-avatars/B33.png +0 -0
- package/lib/public/mate-avatars/B34.png +0 -0
- package/lib/public/mate-avatars/B35.png +0 -0
- package/lib/public/mate-avatars/B36.png +0 -0
- package/lib/public/mate-avatars/B37.png +0 -0
- package/lib/public/mate-avatars/B38.png +0 -0
- package/lib/public/mate-avatars/B39.png +0 -0
- package/lib/public/mate-avatars/B40.png +0 -0
- package/lib/public/mate-avatars/B41.png +0 -0
- package/lib/public/mate-avatars/B42.png +0 -0
- package/lib/public/mate-avatars/B43.png +0 -0
- package/lib/public/mate-avatars/B44.png +0 -0
- package/lib/public/mate-avatars/B45.png +0 -0
- package/lib/public/mate-avatars/B46.png +0 -0
- package/lib/public/mate-avatars/B47.png +0 -0
- package/lib/public/mate-avatars/B48.png +0 -0
- package/lib/public/mate-avatars/C01.png +0 -0
- package/lib/public/mate-avatars/C02.png +0 -0
- package/lib/public/mate-avatars/C03.png +0 -0
- package/lib/public/mate-avatars/C04.png +0 -0
- package/lib/public/mate-avatars/C05.png +0 -0
- package/lib/public/mate-avatars/C06.png +0 -0
- package/lib/public/mate-avatars/C07.png +0 -0
- package/lib/public/mate-avatars/C08.png +0 -0
- package/lib/public/mate-avatars/C09.png +0 -0
- package/lib/public/mate-avatars/C10.png +0 -0
- package/lib/public/mate-avatars/C11.png +0 -0
- package/lib/public/mate-avatars/C12.png +0 -0
- package/lib/public/mate-avatars/C13.png +0 -0
- package/lib/public/mate-avatars/C14.png +0 -0
- package/lib/public/mate-avatars/C15.png +0 -0
- package/lib/public/mate-avatars/C16.png +0 -0
- package/lib/public/mate-avatars/C17.png +0 -0
- package/lib/public/mate-avatars/C18.png +0 -0
- package/lib/public/mate-avatars/C19.png +0 -0
- package/lib/public/mate-avatars/C20.png +0 -0
- package/lib/public/mate-avatars/C21.png +0 -0
- package/lib/public/mate-avatars/C22.png +0 -0
- package/lib/public/mate-avatars/C23.png +0 -0
- package/lib/public/mate-avatars/C24.png +0 -0
- package/lib/public/mate-avatars/C25.png +0 -0
- package/lib/public/mate-avatars/C26.png +0 -0
- package/lib/public/mate-avatars/C27.png +0 -0
- package/lib/public/mate-avatars/C28.png +0 -0
- package/lib/public/mate-avatars/C29.png +0 -0
- package/lib/public/mate-avatars/C30.png +0 -0
- package/lib/public/mate-avatars/C31.png +0 -0
- package/lib/public/mate-avatars/C32.png +0 -0
- package/lib/public/mate-avatars/C33.png +0 -0
- package/lib/public/mate-avatars/C34.png +0 -0
- package/lib/public/mate-avatars/C35.png +0 -0
- package/lib/public/mate-avatars/C36.png +0 -0
- package/lib/public/mate-avatars/C37.png +0 -0
- package/lib/public/mate-avatars/C38.png +0 -0
- package/lib/public/mate-avatars/C39.png +0 -0
- package/lib/public/mate-avatars/C40.png +0 -0
- package/lib/public/mate-avatars/C41.png +0 -0
- package/lib/public/mate-avatars/C42.png +0 -0
- package/lib/public/mate-avatars/C43.png +0 -0
- package/lib/public/mate-avatars/C44.png +0 -0
- package/lib/public/mate-avatars/C45.png +0 -0
- package/lib/public/mate-avatars/C46.png +0 -0
- package/lib/public/mate-avatars/C47.png +0 -0
- package/lib/public/mate-avatars/C48.png +0 -0
- package/lib/public/mate-avatars/catalog.json +482 -0
- package/lib/public/mate-avatars/lead-clay.png +0 -0
- package/lib/public/modules/account-auth-settings.js +71 -0
- package/lib/public/modules/account-transport-settings.js +51 -0
- package/lib/public/modules/admin-settings-projects.js +6 -2
- package/lib/public/modules/app-connection.js +11 -1
- package/lib/public/modules/app-favicon.js +18 -9
- package/lib/public/modules/app-header.js +7 -4
- package/lib/public/modules/app-loop-ui.js +2 -0
- package/lib/public/modules/app-message-router.js +22 -1
- package/lib/public/modules/app-messages.js +119 -17
- package/lib/public/modules/app-misc.js +3 -1
- package/lib/public/modules/app-notifications.js +11 -5
- package/lib/public/modules/app-panels.js +61 -123
- package/lib/public/modules/app-projects.js +13 -0
- package/lib/public/modules/app-rate-limit.js +7 -27
- package/lib/public/modules/app-rendering.js +4 -3
- package/lib/public/modules/avatar.js +15 -41
- package/lib/public/modules/chat-render-runtime.js +20 -0
- package/lib/public/modules/clay-browser-links.js +47 -0
- package/lib/public/modules/clay-control-activity.js +214 -0
- package/lib/public/modules/clay-control-copy.js +36 -0
- package/lib/public/modules/clay-control-detail-targets.js +44 -0
- package/lib/public/modules/clay-control-object-targets.js +52 -0
- package/lib/public/modules/clay-control-target-visibility.js +12 -0
- package/lib/public/modules/clay-control-targets.js +44 -0
- package/lib/public/modules/clay-log-links.js +23 -0
- package/lib/public/modules/clay-navigation-render.js +52 -0
- package/lib/public/modules/clay-owner-navigation.js +33 -0
- package/lib/public/modules/clay-session-links.js +31 -0
- package/lib/public/modules/clay-studio-bridge.js +20 -0
- package/lib/public/modules/clay-studio-document.js +67 -0
- package/lib/public/modules/clay-studio-render.js +146 -0
- package/lib/public/modules/clay-tool-activity.js +140 -0
- package/lib/public/modules/clay-tool-presentation.js +342 -0
- package/lib/public/modules/command-palette.js +162 -40
- package/lib/public/modules/contextual-ask-session.js +26 -0
- package/lib/public/modules/contextual-clay-geometry.js +155 -0
- package/lib/public/modules/contextual-clay-session.js +130 -0
- package/lib/public/modules/contextual-clay-workspace.js +169 -0
- package/lib/public/modules/contextual-clay.js +250 -0
- package/lib/public/modules/contextual-composer.js +91 -0
- package/lib/public/modules/contextual-mate-context.js +117 -0
- package/lib/public/modules/contextual-mate-hint.js +40 -0
- package/lib/public/modules/contextual-mate-identity.js +23 -0
- package/lib/public/modules/contextual-mate-sessions.js +134 -0
- package/lib/public/modules/contextual-search.js +137 -0
- package/lib/public/modules/contextual-session-citations.js +58 -0
- package/lib/public/modules/debate.js +1 -0
- package/lib/public/modules/default-ai.js +11 -3
- package/lib/public/modules/elicitation-form.js +5 -0
- package/lib/public/modules/filebrowser.js +20 -1
- package/lib/public/modules/generation-stop.js +8 -5
- package/lib/public/modules/git-panel.js +3 -1
- package/lib/public/modules/history-replay-batch.js +13 -1
- package/lib/public/modules/home-debate-live.js +2 -0
- package/lib/public/modules/home-debate-planning.js +7 -7
- package/lib/public/modules/home-mate-avatar-editor.js +127 -208
- package/lib/public/modules/home-mate-chat.js +8 -6
- package/lib/public/modules/home-mate-creation.js +73 -1
- package/lib/public/modules/home-mate-settings.js +19 -12
- package/lib/public/modules/icon-strip-tooltip.js +2 -1
- package/lib/public/modules/input.js +88 -10
- package/lib/public/modules/issues-render.js +3 -2
- package/lib/public/modules/knowledge-db-workbench.js +4 -4
- package/lib/public/modules/markdown.js +6 -34
- package/lib/public/modules/mate-avatar-catalog.js +97 -0
- package/lib/public/modules/mate-knowledge-workbench.js +1 -1
- package/lib/public/modules/mate-management.js +40 -7
- package/lib/public/modules/mcp-connection-view.js +31 -13
- package/lib/public/modules/mcp-discovery-view.js +31 -0
- package/lib/public/modules/mcp-ui.js +23 -4
- package/lib/public/modules/mention.js +3 -0
- package/lib/public/modules/message-delivery.js +20 -2
- package/lib/public/modules/model-picker.js +2 -0
- package/lib/public/modules/pane-activation.js +214 -0
- package/lib/public/modules/pane-binding.js +82 -0
- package/lib/public/modules/pane-bridge.js +7 -4
- package/lib/public/modules/pane-browser-bridge.js +22 -0
- package/lib/public/modules/pane-file-bridge.js +4 -0
- package/lib/public/modules/pane-issue-bridge.js +4 -1
- package/lib/public/modules/passkey-browser.js +69 -0
- package/lib/public/modules/passkey-server-settings.js +57 -0
- package/lib/public/modules/pending-message-queue.js +1 -0
- package/lib/public/modules/permission-control.js +5 -4
- package/lib/public/modules/personal-settings-dialog.js +7 -1
- package/lib/public/modules/product-review.js +26 -0
- package/lib/public/modules/profile.js +1 -238
- package/lib/public/modules/project-access-recovery.js +17 -0
- package/lib/public/modules/project-admin-overview.js +21 -0
- package/lib/public/modules/project-chat-identity.js +13 -4
- package/lib/public/modules/project-logs-render.js +6 -2
- package/lib/public/modules/project-mate-navigation.js +144 -22
- package/lib/public/modules/rewind.js +5 -0
- package/lib/public/modules/scheduled-tasks.js +2 -0
- package/lib/public/modules/scheduler.js +2 -0
- package/lib/public/modules/search-clay-chat.js +5 -440
- package/lib/public/modules/server-settings-controls.js +10 -0
- package/lib/public/modules/server-settings.js +7 -2
- package/lib/public/modules/session-actions.js +5 -2
- package/lib/public/modules/session-context-menu.js +5 -0
- package/lib/public/modules/session-create-form.js +10 -10
- package/lib/public/modules/session-folder-layout.js +1 -1
- package/lib/public/modules/session-folder-view-menu.js +9 -0
- package/lib/public/modules/session-github.js +85 -14
- package/lib/public/modules/session-rich-drafts.js +21 -0
- package/lib/public/modules/session-switch-defer.js +67 -0
- package/lib/public/modules/session-work-primary.js +51 -0
- package/lib/public/modules/settings-defaults.js +27 -28
- package/lib/public/modules/shared-browser-settings.js +112 -0
- package/lib/public/modules/shared-browser-tabs.js +13 -3
- package/lib/public/modules/shared-browser.js +29 -6
- package/lib/public/modules/sidebar-mobile.js +4 -3
- package/lib/public/modules/sidebar-projects.js +1 -0
- package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
- package/lib/public/modules/sidebar-sessions.js +1 -0
- package/lib/public/modules/split-group-restore.js +68 -0
- package/lib/public/modules/split-pair-ui.js +1 -0
- package/lib/public/modules/split-pane-reconciler.js +15 -0
- package/lib/public/modules/split-pane-renderer.js +87 -6
- package/lib/public/modules/split-session-boundary.js +1 -1
- package/lib/public/modules/split-view.js +60 -68
- package/lib/public/modules/sticky-note-markdown.js +72 -6
- package/lib/public/modules/sticky-notes-actions.js +30 -0
- package/lib/public/modules/sticky-notes-browser.js +9 -2
- package/lib/public/modules/sticky-notes-card.js +23 -7
- package/lib/public/modules/sticky-notes-checklist.js +116 -0
- package/lib/public/modules/sticky-notes-editor.js +108 -44
- package/lib/public/modules/sticky-notes-shared.js +50 -2
- package/lib/public/modules/sticky-notes-state.js +66 -0
- package/lib/public/modules/sticky-notes.js +34 -51
- package/lib/public/modules/stt-controller.js +4 -1
- package/lib/public/modules/stt-recording.js +1 -1
- package/lib/public/modules/stt.js +7 -2
- package/lib/public/modules/terminal.js +9 -0
- package/lib/public/modules/theme.js +8 -1
- package/lib/public/modules/thinking-lifecycle.js +33 -3
- package/lib/public/modules/thinking-view.js +23 -1
- package/lib/public/modules/tools.js +60 -11
- package/lib/public/modules/tui-grab.js +1 -2
- package/lib/public/modules/user-settings-account.js +14 -1
- package/lib/public/modules/user-settings-appearance.js +10 -3
- package/lib/public/modules/user-settings-editors.js +1 -1
- package/lib/public/modules/user-settings-layout.js +11 -2
- package/lib/public/modules/user-settings-preferences.js +6 -2
- package/lib/public/modules/user-settings-profile.js +12 -2
- package/lib/public/modules/user-settings-sessions.js +120 -0
- package/lib/public/modules/user-settings.js +6 -2
- package/lib/public/modules/vendor-login-browser.js +5 -3
- package/lib/public/modules/vendor-login.js +2 -2
- package/lib/public/modules/vendor-priority.js +15 -1
- package/lib/public/modules/wireframe-workbench.js +5 -2
- package/lib/public/modules/you-activity.js +3 -1
- package/lib/public/modules/you.js +91 -6
- package/lib/public/muse-avatar.svg +4 -0
- package/lib/public/style.css +6 -0
- package/lib/public/sw.js +3 -1
- package/lib/safe-bash-commands.js +3 -45
- package/lib/scheduled-task-records.js +3 -1
- package/lib/scheduler.js +2 -0
- package/lib/sdk-bridge.js +342 -401
- package/lib/sdk-foreground-admission.js +16 -0
- package/lib/sdk-mcp-descriptors.js +2 -37
- package/lib/sdk-message-processor.js +52 -17
- package/lib/sdk-quota-snapshot.js +1 -1
- package/lib/sdk-response-recovery.js +1 -0
- package/lib/sdk-worker.js +2 -677
- package/lib/server-account-passkeys.js +186 -0
- package/lib/server-account-passwords.js +127 -0
- package/lib/server-account-security.js +53 -0
- package/lib/server-admin.js +63 -16
- package/lib/server-appearance-settings.js +13 -1
- package/lib/server-auth.js +107 -79
- package/lib/server-contextual-clay-settings.js +40 -0
- package/lib/server-contextual-mate-sessions.js +70 -0
- package/lib/server-dm.js +2 -1
- package/lib/server-global-ws.js +10 -20
- package/lib/server-home-chat-events.js +18 -4
- package/lib/server-home-chat.js +22 -20
- package/lib/server-home-clay-entry.js +23 -4
- package/lib/server-home-clay-session-links.js +29 -9
- package/lib/server-home-mate-creation.js +1 -0
- package/lib/server-home-mcp-consent.js +14 -0
- package/lib/server-mates.js +25 -62
- package/lib/server-owner-ui.js +118 -0
- package/lib/server-path-access.js +38 -0
- package/lib/server-project-removal.js +22 -0
- package/lib/server-settings.js +8 -2
- package/lib/server.js +165 -43
- package/lib/session-config-transition.js +45 -0
- package/lib/session-folders.js +7 -2
- package/lib/session-fork-history.js +21 -0
- package/lib/session-github.js +9 -2
- package/lib/session-hygiene.js +3 -35
- package/lib/session-permission-mode.js +4 -3
- package/lib/session-skill-scope.js +11 -0
- package/lib/session-visibility.js +5 -2
- package/lib/session-work-primary.js +50 -0
- package/lib/sessions.js +64 -99
- package/lib/shared-browser-cookie-sync.js +32 -0
- package/lib/shared-browser-cookies.js +79 -0
- package/lib/shared-browser-runtime.js +25 -9
- package/lib/shared-browser-storage-sync.js +43 -0
- package/lib/shared-browser-storage.js +101 -0
- package/lib/shared-browser-tools.js +2 -1
- package/lib/shared-browser-worker.js +46 -10
- package/lib/terminal-manager.js +65 -6
- package/lib/tool-llm.js +1 -1
- package/lib/tui-transcript-index.js +1 -132
- package/lib/user-knowledge-service.js +23 -1
- package/lib/users-auth.js +38 -3
- package/lib/users-contextual-clay-preferences.js +31 -0
- package/lib/users-create.js +97 -0
- package/lib/users-permissions.js +2 -8
- package/lib/users-server-pin.js +37 -0
- package/lib/users.js +18 -84
- package/lib/vendor-login-browser.js +1 -11
- package/lib/workspace-assignment-service.js +25 -0
- package/lib/workspace-query-access.js +4 -1
- package/lib/workspace-query-mcp-server.js +1 -1
- package/lib/workspace-query-service.js +13 -2
- package/lib/ws-request.js +1 -0
- package/lib/ws-schema.js +18 -2
- package/lib/yoke/acp-agent-profiles.js +7 -5
- package/lib/yoke/adapters/antigravity.js +3 -14
- package/lib/yoke/adapters/claude-query-contract.js +9 -0
- package/lib/yoke/adapters/claude.js +54 -50
- package/lib/yoke/adapters/codex-query-contract.js +24 -0
- package/lib/yoke/adapters/codex.js +53 -111
- package/lib/yoke/adapters/kiro.js +3 -1
- package/lib/yoke/adapters/muse-query-contract.js +7 -0
- package/lib/yoke/adapters/muse.js +122 -0
- package/lib/yoke/auth-events.js +17 -0
- package/lib/yoke/claude-hook-installer.js +271 -0
- package/lib/yoke/claude-jsonl-watcher.js +204 -0
- package/lib/yoke/claude-maintenance.js +55 -0
- package/lib/yoke/claude-permission-patterns.js +53 -0
- package/lib/yoke/claude-response-recovery.js +155 -0
- package/lib/yoke/claude-transcript-hygiene.js +34 -0
- package/lib/yoke/claude-worker-startup.js +28 -0
- package/lib/yoke/clay-skill-install.js +33 -0
- package/lib/yoke/cli-sessions.js +300 -0
- package/lib/yoke/codex-app-server.js +7 -12
- package/lib/yoke/codex-idle-recovery.js +81 -1
- package/lib/yoke/codex-recovery-admission.js +164 -0
- package/lib/yoke/configuration.js +13 -0
- package/lib/yoke/discovery.js +70 -0
- package/lib/yoke/errors.js +8 -0
- package/lib/yoke/host-environment.js +7 -0
- package/lib/yoke/index.js +9 -51
- package/lib/yoke/interface.js +116 -0
- package/lib/yoke/kiro-acp-server.js +5 -5
- package/lib/yoke/legacy-sessions.js +89 -0
- package/lib/yoke/login-protocol.js +25 -0
- package/lib/yoke/maintenance.js +12 -0
- package/lib/yoke/mcp-proxy.js +32 -0
- package/lib/yoke/mcp-source-adapters.js +91 -0
- package/lib/yoke/mcp-source-context.js +42 -0
- package/lib/yoke/mcp-source-discovery.js +169 -0
- package/lib/yoke/mcp-source-plugins.js +68 -0
- package/lib/yoke/mcp-source-restrictions.js +47 -0
- package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
- package/lib/yoke/model-preferences.js +6 -0
- package/lib/yoke/muse-artifacts.js +36 -0
- package/lib/yoke/muse-controls.js +50 -0
- package/lib/yoke/muse-input.js +64 -0
- package/lib/yoke/muse-items.js +157 -0
- package/lib/yoke/muse-policy.js +52 -0
- package/lib/yoke/muse-query.js +428 -0
- package/lib/yoke/muse-runtime.js +211 -0
- package/lib/yoke/muse-services.js +79 -0
- package/lib/yoke/muse-skills.js +79 -0
- package/lib/yoke/muse-turns.js +71 -0
- package/lib/yoke/options/acp.js +2 -0
- package/lib/yoke/options/antigravity.js +2 -0
- package/lib/yoke/options/claude.js +21 -0
- package/lib/yoke/options/codex-defaults.js +29 -0
- package/lib/yoke/options/codex-settings.js +21 -0
- package/lib/yoke/options/codex.js +6 -0
- package/lib/yoke/options/kiro-defaults.js +22 -0
- package/lib/yoke/options/kiro.js +5 -0
- package/lib/yoke/options/muse.js +5 -0
- package/lib/yoke/provider-contract.js +5 -0
- package/lib/yoke/providers/antigravity-executable.js +8 -0
- package/lib/yoke/providers/claude-executable.js +40 -0
- package/lib/yoke/providers/claude-model-descriptions.js +14 -0
- package/lib/yoke/providers/claude-process.js +97 -0
- package/lib/yoke/providers/claude-provision.js +75 -0
- package/lib/yoke/providers/codex-errors.js +8 -0
- package/lib/yoke/providers/muse-executable.js +17 -0
- package/lib/yoke/provisioning.js +6 -0
- package/lib/yoke/query-options.js +10 -0
- package/lib/yoke/response-recovery.js +41 -0
- package/lib/yoke/sdk-mcp-descriptors.js +37 -0
- package/lib/yoke/sdk-server-factory.js +7 -0
- package/lib/yoke/session-history.js +8 -0
- package/lib/yoke/session-tool-transport.js +34 -13
- package/lib/yoke/settings.js +23 -0
- package/lib/yoke/source-locations.js +4 -0
- package/lib/yoke/title-query.js +18 -7
- package/lib/yoke/tui-transcript-index.js +132 -0
- package/lib/yoke/usage.js +48 -0
- package/lib/yoke/user-input.js +13 -0
- package/lib/yoke/vendor-registry.js +81 -1
- package/package.json +11 -4
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
import { getCachedSessions } from './sidebar-sessions.js';
|
|
4
|
+
import { takeComposerDraft, restoreComposerDraft } from './input.js';
|
|
5
|
+
import { resetHistoryReplayBatch } from './history-replay-batch.js';
|
|
6
|
+
import { updateContextPanel } from './app-panels.js';
|
|
7
|
+
import { paneTarget, samePaneBinding, samePaneTarget } from './pane-binding.js';
|
|
8
|
+
|
|
9
|
+
function enabled() {
|
|
10
|
+
return store.get('paneMode') && !store.get('paneActivationUnsupported') && !store.get('activeProjectMateId') && !/^\/p\/mate-/.test(location.pathname) && !new URLSearchParams(location.search).has('contextual') && window.parent !== window;
|
|
11
|
+
}
|
|
12
|
+
function block(value) {
|
|
13
|
+
var app = document.getElementById('app');
|
|
14
|
+
if (app) app.inert = value;
|
|
15
|
+
document.documentElement.dataset.paneReady = value ? 'false' : 'true';
|
|
16
|
+
}
|
|
17
|
+
function draftKey() { return String(store.get('myUserId')) + ':' + store.get('sessionOriginId'); }
|
|
18
|
+
function clearDeadline() {
|
|
19
|
+
if (store.get('paneActivationTimer')) clearTimeout(store.get('paneActivationTimer'));
|
|
20
|
+
store.set({ paneActivationTimer: null });
|
|
21
|
+
}
|
|
22
|
+
function failed(requestId) {
|
|
23
|
+
var pending = store.get('panePendingBinding');
|
|
24
|
+
if (!pending || requestId !== pending.requestId) return;
|
|
25
|
+
clearDeadline();
|
|
26
|
+
store.set({ paneReady: false, panePendingBinding: null });
|
|
27
|
+
block(true);
|
|
28
|
+
var frame = window.frameElement;
|
|
29
|
+
if (frame) frame.dispatchEvent(new window.parent.CustomEvent('clay-pane-activation-failed'));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Claim ordinary initial pins before the legacy session-list handler runs.
|
|
33
|
+
// Authentication, list and group metadata can arrive in either order; the
|
|
34
|
+
// subscription retries when those authoritative prerequisites become ready.
|
|
35
|
+
export function primePaneSession() {
|
|
36
|
+
if (!enabled() || !window.frameElement || !window.frameElement.clayPane) return false;
|
|
37
|
+
var id = store.get('paneSessionId');
|
|
38
|
+
var session = (getCachedSessions() || []).find(function (item) { return item.id === id; });
|
|
39
|
+
if (!session || session.isMate || (session.runtimeMode || session.mode || 'gui') !== 'gui' || session.tuiSuspended) return false;
|
|
40
|
+
activatePaneSession(id);
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function activatePaneSession(id, force, expectedTarget) {
|
|
45
|
+
var state = store.snap(), ws = getWs();
|
|
46
|
+
if (state.authIdentityLoaded === false) return false;
|
|
47
|
+
if (state.isMultiUserMode && !state.myUserId) return false;
|
|
48
|
+
if (!enabled() || !state.connected || !ws || ws.readyState !== 1 || state.splitGroupsProjectSlug !== state.currentSlug) return false;
|
|
49
|
+
var target = paneTarget(state, getCachedSessions(), id);
|
|
50
|
+
if (!target) return false;
|
|
51
|
+
if (expectedTarget && !samePaneTarget(target, expectedTarget)) return false;
|
|
52
|
+
var sourceFrame = window.frameElement;
|
|
53
|
+
if (!expectedTarget && sourceFrame && Number(sourceFrame.dataset && sourceFrame.dataset.sessionId) === id && sourceFrame.dataset.sessionOriginId && sourceFrame.dataset.sessionOriginId !== target.sessionOriginId) return false;
|
|
54
|
+
var old = state.paneCommittedBinding, pending = state.panePendingBinding;
|
|
55
|
+
if (!force && !state.paneSuspended && samePaneTarget(pending || old, target)) return true;
|
|
56
|
+
if (!pending && state.sessionOriginId) {
|
|
57
|
+
var draft;
|
|
58
|
+
try { draft = takeComposerDraft(); } catch (error) { return false; }
|
|
59
|
+
var drafts = Object.assign({}, state.paneRichDrafts || {});
|
|
60
|
+
drafts[draftKey()] = draft;
|
|
61
|
+
store.set({ paneRichDrafts: drafts });
|
|
62
|
+
}
|
|
63
|
+
clearDeadline();
|
|
64
|
+
resetHistoryReplayBatch();
|
|
65
|
+
var generation = (store.get('paneActivationGeneration') || 0) + 1;
|
|
66
|
+
target = Object.assign({}, target, { generation: generation, requestId: 'pane-' + generation + '-' + Math.random().toString(36).slice(2, 12) });
|
|
67
|
+
var path = new URL(store.get('wsPath'), location.origin);
|
|
68
|
+
path.searchParams.set('session', String(id));
|
|
69
|
+
store.set({ paneActivationGeneration: generation, panePendingBinding: target, paneReady: false, paneSuspended: false,
|
|
70
|
+
paneSessionId: id, panePinPending: false, wsPath: path.pathname + path.search });
|
|
71
|
+
block(true);
|
|
72
|
+
store.set({ paneActivationTimer: setTimeout(function () { failed(target.requestId); }, 12000) });
|
|
73
|
+
ws.send(JSON.stringify({ type: 'switch_session', id: id, paneActivation: target }));
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Runs before replay batching, so an obsolete history_meta cannot open a batch
|
|
78
|
+
// that later consumes destination messages.
|
|
79
|
+
export function filterPaneActivation(message) {
|
|
80
|
+
if (!enabled()) return false;
|
|
81
|
+
var pending = store.get('panePendingBinding'), committed = store.get('paneCommittedBinding');
|
|
82
|
+
if (message.type === 'pane_activation_rejected') { failed(message.requestId); return true; }
|
|
83
|
+
if (!pending && !committed) return !!message.paneActivation;
|
|
84
|
+
if (['session_list', 'split_groups', 'session_presence', 'pong', 'account_auth_required', 'project_removed', 'project_access_revoked'].indexOf(message.type) >= 0 && !message.paneActivation) return false;
|
|
85
|
+
var expected = pending || committed;
|
|
86
|
+
if (!samePaneBinding(expected, message.paneActivation)) return true;
|
|
87
|
+
if (message.type === 'pane_activation_started') return true;
|
|
88
|
+
if (message.type === 'pane_activation_snapshot_done') {
|
|
89
|
+
if (!pending) return true;
|
|
90
|
+
var draft = (store.get('paneRichDrafts') || {})[String(store.get('myUserId')) + ':' + expected.sessionOriginId];
|
|
91
|
+
restoreComposerDraft(draft || { text: '', start: 0, end: 0 });
|
|
92
|
+
function paint() {
|
|
93
|
+
if (store.get('panePendingBinding') !== expected || !store.get('connected') || store.get('paneSuspended')) return;
|
|
94
|
+
var current = paneTarget(store.snap(), getCachedSessions(), expected.sessionId);
|
|
95
|
+
var messages = document.getElementById('messages');
|
|
96
|
+
if (!samePaneTarget(current, expected) ||
|
|
97
|
+
store.get('activeSessionId') !== expected.sessionId || store.get('sessionOriginId') !== expected.sessionOriginId || store.get('replayingHistory') ||
|
|
98
|
+
!messages || messages.dataset.controlSessionId !== String(expected.sessionId) || messages.dataset.controlSessionOrigin !== expected.sessionOriginId) { failed(expected.requestId); return; }
|
|
99
|
+
clearDeadline();
|
|
100
|
+
store.set({ paneCommittedBinding: expected, panePendingBinding: null, paneReady: true });
|
|
101
|
+
block(false);
|
|
102
|
+
var frame = window.frameElement;
|
|
103
|
+
if (frame) frame.dispatchEvent(new window.parent.CustomEvent('clay-pane-ready'));
|
|
104
|
+
updateContextPanel();
|
|
105
|
+
}
|
|
106
|
+
requestAnimationFrame(function () { requestAnimationFrame(paint); });
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function paneOutgoing(data) {
|
|
113
|
+
var message;
|
|
114
|
+
try { message = JSON.parse(data); } catch (error) { return null; }
|
|
115
|
+
if (['ping', 'pong', 'clay_ui_ready'].indexOf(message.type) >= 0) return data;
|
|
116
|
+
if (store.get('deferredSessionSwitch') && store.get('deferredSessionSwitch').draining) return null;
|
|
117
|
+
if (message.type === 'switch_session') {
|
|
118
|
+
var entry = store.get('pendingSessionEntryNavigation');
|
|
119
|
+
if (entry && entry.projectSlug === store.get('currentSlug') && String(entry.sessionId) !== String(message.id)) store.set({ pendingSessionEntryNavigation: null });
|
|
120
|
+
if (enabled() && (store.get('panePendingBinding') || store.get('paneCommittedBinding')) && !message.paneActivation) return null;
|
|
121
|
+
return data;
|
|
122
|
+
}
|
|
123
|
+
if (store.get('deferredSessionSwitch')) {
|
|
124
|
+
var source = store.get('deferredSessionSwitch');
|
|
125
|
+
if (source.draining) return null;
|
|
126
|
+
if (message.type === 'stop') return JSON.stringify(Object.assign({}, message, { sessionId: source.sessionId, sessionOriginId: source.origin }));
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
if (!enabled()) return data;
|
|
130
|
+
var binding = store.get('paneCommittedBinding');
|
|
131
|
+
if (store.get('panePendingBinding') || store.get('paneSuspended') || binding && !store.get('paneReady')) return null;
|
|
132
|
+
if (!binding) return ['stop', 'user_message', 'permission_response', 'ask_user_response', 'elicitation_response', 'user_dialog_response', 'input_sync'].indexOf(message.type) >= 0 ? null : data;
|
|
133
|
+
if (message.paneBinding && !samePaneBinding(binding, message.paneBinding)) return null;
|
|
134
|
+
var gesture = (store.get('paneActionEvents') || []).find(function (entry) { return entry.event.isTrusted && entry.event.eventPhase && samePaneBinding(entry.binding, binding); });
|
|
135
|
+
var action = store.get('paneCallbackBinding') || gesture && gesture.binding;
|
|
136
|
+
var read = /^(get_|list_)|(_get|_list|_options)$/.test(message.type) || message.type === 'load_more_history';
|
|
137
|
+
if (!message.paneBinding && !read && !samePaneBinding(action, binding)) return null;
|
|
138
|
+
return JSON.stringify(Object.assign({}, message, { paneBinding: message.paneBinding || action || binding }));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function refreshPaneActivation() {
|
|
142
|
+
if (!enabled()) return;
|
|
143
|
+
var binding = store.get('panePendingBinding') || store.get('paneCommittedBinding');
|
|
144
|
+
if (!binding) return;
|
|
145
|
+
var current = paneTarget(store.snap(), getCachedSessions(), binding.sessionId);
|
|
146
|
+
if (samePaneTarget(current, binding)) return;
|
|
147
|
+
if (store.get('panePendingBinding')) failed(binding.requestId);
|
|
148
|
+
else { store.set({ paneReady: false }); block(true); }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function initPaneActivation() {
|
|
152
|
+
if (!enabled() || !window.frameElement) return;
|
|
153
|
+
var frame = window.frameElement;
|
|
154
|
+
var latestId = Number(frame.dataset && (frame.dataset.requestedSessionId || frame.dataset.sessionId));
|
|
155
|
+
if (Number.isSafeInteger(latestId) && latestId > 0 && frame.dataset.projectSlug === store.get('currentSlug')) {
|
|
156
|
+
var latestPath = new URL(store.get('wsPath'), location.origin);
|
|
157
|
+
latestPath.searchParams.set('session', String(latestId));
|
|
158
|
+
store.set({ paneSessionId: latestId, panePinPending: true, wsPath: latestPath.pathname + latestPath.search });
|
|
159
|
+
}
|
|
160
|
+
block(true);
|
|
161
|
+
frame.clayPane = {
|
|
162
|
+
source: window, document: document,
|
|
163
|
+
identity: function () {
|
|
164
|
+
var binding = store.get('paneCommittedBinding');
|
|
165
|
+
return binding && { ownerId: binding.viewerId, projectSlug: binding.projectSlug, sessionId: binding.sessionId,
|
|
166
|
+
binding: binding, ready: store.get('connected') && store.get('paneReady') && !store.get('paneSuspended') };
|
|
167
|
+
},
|
|
168
|
+
activate: activatePaneSession,
|
|
169
|
+
checkDraft: function () { if (!store.get('panePendingBinding')) { var draft = takeComposerDraft(); restoreComposerDraft(draft); } },
|
|
170
|
+
suspend: function () { store.set({ paneSuspended: true, paneReady: false }); block(true); },
|
|
171
|
+
};
|
|
172
|
+
// A pointer that began on the previous conversation cannot become a Stop or
|
|
173
|
+
// approval click on the replacement conversation after hydration.
|
|
174
|
+
document.addEventListener('pointerdown', function () { store.set({ panePointerBinding: store.get('paneCommittedBinding') }); }, true);
|
|
175
|
+
document.addEventListener('click', function (event) {
|
|
176
|
+
if (store.get('paneSuspended') || !store.get('paneReady') && store.get('panePendingBinding') || event.detail && store.get('panePointerBinding') !== store.get('paneCommittedBinding')) {
|
|
177
|
+
event.preventDefault(); event.stopImmediatePropagation();
|
|
178
|
+
}
|
|
179
|
+
}, true);
|
|
180
|
+
['click', 'input', 'change', 'keydown', 'keyup', 'submit', 'blur'].forEach(function (name) {
|
|
181
|
+
document.addEventListener(name, function (event) {
|
|
182
|
+
var keys = store.get('paneHeldKeys') || {};
|
|
183
|
+
var binding = store.get('paneCommittedBinding');
|
|
184
|
+
var previousKey = keys[event.code || event.key];
|
|
185
|
+
var staleKey = (name === 'keyup' || name === 'keydown' && event.repeat) && previousKey && !samePaneBinding(previousKey, binding);
|
|
186
|
+
if (name === 'keydown' && !event.repeat) keys[event.code || event.key] = binding;
|
|
187
|
+
if (name === 'keyup') delete keys[event.code || event.key];
|
|
188
|
+
if (staleKey || store.get('panePendingBinding') || store.get('paneSuspended') || !store.get('paneReady')) {
|
|
189
|
+
event.preventDefault(); event.stopImmediatePropagation(); return;
|
|
190
|
+
}
|
|
191
|
+
var events = (store.get('paneActionEvents') || []).filter(function (entry) { return entry.event.eventPhase; });
|
|
192
|
+
events.push({ event: event, binding: binding });
|
|
193
|
+
store.set({ paneHeldKeys: keys, paneActionEvents: events });
|
|
194
|
+
}, true);
|
|
195
|
+
});
|
|
196
|
+
store.subscribe(function (state, previous) {
|
|
197
|
+
if (state.activeSessionMode === 'tui' && previous.activeSessionMode !== 'tui') {
|
|
198
|
+
delete frame.clayPane; store.set({ paneActivationUnsupported: true }); block(false); return;
|
|
199
|
+
}
|
|
200
|
+
if (!state.connected && previous.connected) {
|
|
201
|
+
clearDeadline();
|
|
202
|
+
store.set({ paneReady: false, panePendingBinding: null, paneCommittedBinding: null }); block(true);
|
|
203
|
+
}
|
|
204
|
+
if (state.connected && (state.splitGroups !== previous.splitGroups || state.splitGroupsProjectSlug !== previous.splitGroupsProjectSlug || state.paneBindingSessions !== previous.paneBindingSessions || state.authIdentityLoaded !== previous.authIdentityLoaded || state.myUserId !== previous.myUserId || state.activeSessionId !== previous.activeSessionId || state.connected !== previous.connected)) {
|
|
205
|
+
queueMicrotask(function () {
|
|
206
|
+
refreshPaneActivation();
|
|
207
|
+
if (!store.get('panePendingBinding') && !store.get('paneSuspended')) {
|
|
208
|
+
if (store.get('panePinPending')) primePaneSession();
|
|
209
|
+
else if (store.get('activeSessionId') === store.get('paneSessionId')) activatePaneSession(store.get('paneSessionId'));
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
|
|
4
|
+
export function captureSessionAction() {
|
|
5
|
+
var state = store.snap();
|
|
6
|
+
return { projectSlug: state.currentSlug, ownerId: state.myUserId, sessionId: state.activeSessionId,
|
|
7
|
+
origin: state.sessionOriginId, socket: getWs(), binding: state.paneCommittedBinding || null,
|
|
8
|
+
epoch: state.sessionActionEpoch || 0 };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function sessionActionCurrent(action, draftCompletion) {
|
|
12
|
+
var state = store.snap();
|
|
13
|
+
return !!action && action.socket === getWs() && state.connected &&
|
|
14
|
+
action.projectSlug === state.currentSlug && action.ownerId === state.myUserId &&
|
|
15
|
+
action.sessionId === state.activeSessionId && action.origin === state.sessionOriginId &&
|
|
16
|
+
action.epoch === (state.sessionActionEpoch || 0) &&
|
|
17
|
+
(draftCompletion || !state.deferredSessionSwitch) && !state.panePendingBinding && !state.paneSuspended &&
|
|
18
|
+
(action.binding ? state.paneReady && samePaneBinding(action.binding, state.paneCommittedBinding) : !state.paneCommittedBinding);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Capture at callback creation, never when an old callback eventually sends.
|
|
22
|
+
export function sessionCallback(callback, draftCompletion) {
|
|
23
|
+
var action = captureSessionAction();
|
|
24
|
+
return function () {
|
|
25
|
+
if (!sessionActionCurrent(action, draftCompletion)) return;
|
|
26
|
+
var previous = store.get('paneCallbackBinding');
|
|
27
|
+
store.set({ paneCallbackBinding: action.binding });
|
|
28
|
+
try { return callback.apply(this, arguments); }
|
|
29
|
+
finally { store.set({ paneCallbackBinding: previous }); }
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function samePaneBinding(a, b) {
|
|
34
|
+
return !!a && !!b && ['requestId', 'generation', 'projectSlug', 'viewerId', 'ownerId', 'sessionId', 'sessionOriginId', 'role', 'workerGeneration', 'groupStamp', 'parentSessionOriginId'].every(function (key) { return a[key] === b[key]; });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function samePaneTarget(a, b) {
|
|
38
|
+
return !!a && !!b && ['projectSlug', 'viewerId', 'ownerId', 'sessionId', 'sessionOriginId', 'role', 'workerGeneration', 'groupStamp', 'parentSessionOriginId'].every(function (key) { return a[key] === b[key]; });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function paneTarget(state, sessions, id) {
|
|
42
|
+
var session = (sessions || []).find(function (item) { return item.id === id; });
|
|
43
|
+
if (!session || session.isMate || !session.sessionOriginId || (session.runtimeMode || session.mode || 'gui') !== 'gui' || session.tuiSuspended) return null;
|
|
44
|
+
var group = (state.splitGroups || []).find(function (item) { return item.members.indexOf(id) >= 0; });
|
|
45
|
+
var parent = session.sessionRole === 'worker' && sessions.find(function (item) { return item.id === session.parentSessionId; });
|
|
46
|
+
if (session.sessionRole === 'worker' && (!parent || !session.parentAvailable || !Number.isSafeInteger(session.workerGeneration) || !parent.sessionOriginId || parent.ownerId !== session.ownerId || !group || !group.pair || group.pair.driverId !== parent.id)) return null;
|
|
47
|
+
return {
|
|
48
|
+
projectSlug: state.currentSlug, viewerId: state.myUserId || null, ownerId: session.ownerId || null,
|
|
49
|
+
sessionId: session.id, sessionOriginId: session.sessionOriginId,
|
|
50
|
+
role: session.sessionRole === 'worker' ? 'worker' : 'driver', workerGeneration: session.workerGeneration || null,
|
|
51
|
+
parentSessionOriginId: parent ? parent.sessionOriginId : null,
|
|
52
|
+
groupStamp: group ? JSON.stringify({ id: group.id, members: group.members, pair: group.pair || null }) : null,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Ordinary reusable panes have a live document binding; legacy/canonical frames
|
|
57
|
+
// retain their existing URL and receipt checks in their own bridge paths.
|
|
58
|
+
export function livePaneBinding(frame, message) {
|
|
59
|
+
if (!frame || !frame.clayPane) return false;
|
|
60
|
+
var api = frame.clayPane, live = api.identity();
|
|
61
|
+
var state = store.snap(), split = state.splitPanes;
|
|
62
|
+
var target = live && paneTarget(state, state.paneBindingSessions || [], live.sessionId);
|
|
63
|
+
return api.source === frame.contentWindow && api.document === frame.contentDocument && live && live.ready &&
|
|
64
|
+
samePaneTarget(target, live.binding) &&
|
|
65
|
+
live.ownerId === (state.myUserId || null) && live.projectSlug === state.currentSlug &&
|
|
66
|
+
split && split.panes.some(function (pane) { return pane.slug === live.projectSlug && pane.sessionId === live.sessionId; }) &&
|
|
67
|
+
(!message || samePaneBinding(live.binding, message.paneBinding));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function paneMessageBinding() {
|
|
71
|
+
return store.get('paneReady') && !store.get('paneSuspended') ? store.get('paneCommittedBinding') : null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function currentPaneReview(container) {
|
|
75
|
+
if (!container || !container.paneBinding) return true;
|
|
76
|
+
return container.isConnected !== false && store.get('paneReady') && !store.get('paneSuspended') && samePaneBinding(container.paneBinding, store.get('paneCommittedBinding'));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function paneCallbackCurrent(binding) {
|
|
80
|
+
var current = store.get('panePendingBinding') || store.get('paneCommittedBinding');
|
|
81
|
+
return current ? samePaneBinding(current, binding) : !binding;
|
|
82
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { forwardStudioPresentation } from './clay-studio-render.js';
|
|
1
2
|
// Pane-side postMessage bridge for the split-view shell. A chrome-less pane
|
|
2
3
|
// iframe reports its context usage up to the parent (which renders a chip in
|
|
3
4
|
// the pane header) and honors panel-toggle requests coming back down.
|
|
4
5
|
// Same-origin messages only, both directions.
|
|
5
6
|
|
|
6
7
|
import { store } from './store.js';
|
|
8
|
+
import { paneMessageBinding, samePaneBinding } from './pane-binding.js';
|
|
7
9
|
import { getEffectiveContextView } from './context-view-preference.js';
|
|
8
10
|
import { forceExternalLinkToNewTab } from './pane-links.js';
|
|
9
11
|
|
|
@@ -11,6 +13,7 @@ export function reportPaneContext(data) {
|
|
|
11
13
|
if (!store.get('paneMode') || window.parent === window) return;
|
|
12
14
|
window.parent.postMessage({
|
|
13
15
|
type: "clay-pane-context",
|
|
16
|
+
paneBinding: paneMessageBinding(),
|
|
14
17
|
sessionId: store.get('activeSessionId'),
|
|
15
18
|
pct: data.pct,
|
|
16
19
|
used: data.used,
|
|
@@ -26,19 +29,18 @@ export function reportPaneContext(data) {
|
|
|
26
29
|
// Hand the event to the parent shell, which owns the single flow.
|
|
27
30
|
export function forwardPaneAuthRequired(message) {
|
|
28
31
|
if (!store.get('paneMode') || window.parent === window) return false;
|
|
29
|
-
window.parent.postMessage({ type: "clay-pane-auth-required", message: message }, window.location.origin);
|
|
32
|
+
window.parent.postMessage({ type: "clay-pane-auth-required", paneBinding: paneMessageBinding(), message: message }, window.location.origin);
|
|
30
33
|
return true;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
export function forwardPaneMarkdownPresentation(message) {
|
|
34
37
|
if (!store.get('paneMode') || window.parent === window) return false;
|
|
35
|
-
|
|
36
|
-
return true;
|
|
38
|
+
return forwardStudioPresentation(message, "clay-pane-present-markdown");
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
export function forwardPaneIssueReference(ref, projectSlug) {
|
|
40
42
|
if (!store.get('paneMode') || window.parent === window) return false;
|
|
41
|
-
window.parent.postMessage({ type: "clay-pane-open-issue", ref: ref, projectSlug: projectSlug || store.get('currentSlug') }, window.location.origin);
|
|
43
|
+
window.parent.postMessage({ type: "clay-pane-open-issue", paneBinding: paneMessageBinding(), ref: ref, projectSlug: projectSlug || store.get('currentSlug') }, window.location.origin);
|
|
42
44
|
return true;
|
|
43
45
|
}
|
|
44
46
|
|
|
@@ -70,6 +72,7 @@ export function initPaneBridge() {
|
|
|
70
72
|
if (event.origin !== window.location.origin) return;
|
|
71
73
|
var msg = event.data;
|
|
72
74
|
if (!msg || msg.type !== "clay-pane-toggle-context") return;
|
|
75
|
+
if (event.source !== window.parent || store.get('paneCommittedBinding') && !samePaneBinding(paneMessageBinding(), msg.paneBinding)) return;
|
|
73
76
|
togglePaneContextPanel();
|
|
74
77
|
});
|
|
75
78
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { livePaneBinding, paneMessageBinding } from './pane-binding.js';
|
|
3
|
+
import { showToast } from './utils.js';
|
|
4
|
+
|
|
5
|
+
export function forwardPaneBrowserLink(url) {
|
|
6
|
+
if (!store.get('paneMode') || window.parent === window) return false;
|
|
7
|
+
window.parent.postMessage({ type: 'clay-pane-open-browser', paneBinding: paneMessageBinding(), url: url, projectSlug: store.get('currentSlug'), sessionId: String(store.get('activeSessionId')) }, window.location.origin);
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
export function handlePaneBrowserMessage(event, host) {
|
|
11
|
+
if (!event || event.origin !== window.location.origin || !host || !event.data || event.data.type !== 'clay-pane-open-browser') return false;
|
|
12
|
+
var msg = event.data, s = store.snap();
|
|
13
|
+
var frame = Array.from(host.querySelectorAll('.split-pane-frame')).find(function (item) { return item.contentWindow === event.source; });
|
|
14
|
+
var pane = frame && s.splitPanes && s.splitPanes.panes && s.splitPanes.panes.find(function (item) { return String(item.slug) === frame.dataset.projectSlug && String(item.sessionId) === frame.dataset.sessionId; });
|
|
15
|
+
if (!pane || msg.projectSlug !== s.currentSlug || msg.projectSlug !== frame.dataset.projectSlug || String(msg.sessionId) !== frame.dataset.sessionId) return true;
|
|
16
|
+
var expected = new URL('/p/' + encodeURIComponent(pane.slug) + '/?pane=1&session=' + encodeURIComponent(pane.sessionId), window.location.href).href;
|
|
17
|
+
if (frame.clayPane ? !livePaneBinding(frame, msg) : frame.src !== expected) return true;
|
|
18
|
+
// The authenticated host owns the browser; a live same-project pane supplies only a URL.
|
|
19
|
+
var binding = frame.clayPane && frame.clayPane.identity().binding;
|
|
20
|
+
import('./shared-browser.js').then(function (module) { if (binding && (!livePaneBinding(frame, msg) || frame.clayPane.identity().binding !== binding)) return; module.openSharedBrowserAt(msg.url); }).catch(function (error) { showToast(error.message || 'Could not open the browser.', 'warn'); });
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { store } from './store.js';
|
|
2
|
+
import { livePaneBinding, paneMessageBinding } from './pane-binding.js';
|
|
2
3
|
|
|
3
4
|
function paneFrame(host, source) {
|
|
4
5
|
if (!host || !source) return null;
|
|
@@ -19,6 +20,7 @@ function matchingPane(frame, split) {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
function hasLivePaneSource(frame, pane) {
|
|
23
|
+
if (frame && frame.clayPane) return livePaneBinding(frame);
|
|
22
24
|
if (!frame || !pane || typeof frame.src !== "string") return false;
|
|
23
25
|
var expected = "/p/" + encodeURIComponent(pane.slug) + "/?pane=1&session=" + encodeURIComponent(pane.sessionId);
|
|
24
26
|
try { return new URL(expected, window.location.href).href === frame.src; } catch (e) { return false; }
|
|
@@ -41,6 +43,7 @@ export function forwardPaneFileReference(path, opts) {
|
|
|
41
43
|
if (!store.get('paneMode') || window.parent === window || typeof path !== "string" || !path) return false;
|
|
42
44
|
window.parent.postMessage({
|
|
43
45
|
type: "clay-pane-open-file",
|
|
46
|
+
paneBinding: paneMessageBinding(),
|
|
44
47
|
path: path,
|
|
45
48
|
line: opts && opts.line != null ? opts.line : null,
|
|
46
49
|
column: opts && opts.column != null ? opts.column : null,
|
|
@@ -57,6 +60,7 @@ export function handlePaneFileMessage(event, host, openFile, openFiles) {
|
|
|
57
60
|
var frame = paneFrame(host, event.source);
|
|
58
61
|
var state = store.snap();
|
|
59
62
|
var pane = matchingPane(frame, state.splitPanes);
|
|
63
|
+
if (frame && frame.clayPane && !livePaneBinding(frame, msg)) return true;
|
|
60
64
|
if (!pane || !hasLivePaneSource(frame, pane) || String(pane.slug) !== String(state.currentSlug) || msg.projectSlug !== frame.dataset.projectSlug || String(msg.sessionId) !== String(frame.dataset.sessionId) || !validLocation(msg.line) || !validLocation(msg.column)) return true;
|
|
61
65
|
if (typeof msg.path !== "string" || !msg.path) return true;
|
|
62
66
|
if (!state.connected || typeof openFile !== "function") return true;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { store } from './store.js';
|
|
2
|
+
import { livePaneBinding } from './pane-binding.js';
|
|
2
3
|
import { openIssues } from './issues.js';
|
|
3
4
|
|
|
4
5
|
function isIssueReference(ref) {
|
|
@@ -8,7 +9,7 @@ function isIssueReference(ref) {
|
|
|
8
9
|
function isPaneSource(host, source) {
|
|
9
10
|
var frames = host.querySelectorAll(".split-pane-frame");
|
|
10
11
|
for (var i = 0; i < frames.length; i++) {
|
|
11
|
-
if (frames[i].contentWindow === source) return
|
|
12
|
+
if (frames[i].contentWindow === source) return !frames[i].clayPane || livePaneBinding(frames[i]);
|
|
12
13
|
}
|
|
13
14
|
return false;
|
|
14
15
|
}
|
|
@@ -18,6 +19,8 @@ export function handlePaneIssueMessage(event, host) {
|
|
|
18
19
|
var msg = event.data;
|
|
19
20
|
if (!msg || msg.type !== "clay-pane-open-issue") return false;
|
|
20
21
|
if (!isIssueReference(msg.ref) || !isPaneSource(host, event.source)) return true;
|
|
22
|
+
var frame = Array.from(host.querySelectorAll('.split-pane-frame')).find(function (item) { return item.contentWindow === event.source; });
|
|
23
|
+
if (frame && frame.clayPane && !livePaneBinding(frame, msg)) return true;
|
|
21
24
|
|
|
22
25
|
var issueTarget = store.get('issuesCache') && store.get('issuesCache')[msg.ref];
|
|
23
26
|
var projectSlug = (issueTarget && issueTarget.projectSlug) || msg.projectSlug || store.get('currentSlug');
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
function decode(value) {
|
|
2
|
+
var base64 = value.replace(/-/g, '+').replace(/_/g, '/');
|
|
3
|
+
return Uint8Array.from(atob(base64), function (character) { return character.charCodeAt(0); });
|
|
4
|
+
}
|
|
5
|
+
function encode(value) {
|
|
6
|
+
var bytes = new Uint8Array(value); var binary = '';
|
|
7
|
+
bytes.forEach(function (byte) { binary += String.fromCharCode(byte); });
|
|
8
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
|
9
|
+
}
|
|
10
|
+
function serialize(credential) {
|
|
11
|
+
if (!credential) throw new Error('No passkey was selected.');
|
|
12
|
+
var response = { clientDataJSON: encode(credential.response.clientDataJSON) };
|
|
13
|
+
['attestationObject', 'authenticatorData', 'signature', 'userHandle'].forEach(function (key) {
|
|
14
|
+
if (credential.response[key]) response[key] = encode(credential.response[key]);
|
|
15
|
+
});
|
|
16
|
+
if (credential.response.getTransports) response.transports = credential.response.getTransports();
|
|
17
|
+
return { id: credential.id, rawId: encode(credential.rawId), type: credential.type, response: response,
|
|
18
|
+
clientExtensionResults: credential.getClientExtensionResults(), authenticatorAttachment: credential.authenticatorAttachment };
|
|
19
|
+
}
|
|
20
|
+
function prepare(options) {
|
|
21
|
+
var publicKey = Object.assign({}, options, { challenge: decode(options.challenge) });
|
|
22
|
+
['allowCredentials', 'excludeCredentials'].forEach(function (field) {
|
|
23
|
+
if (options[field]) publicKey[field] = options[field].map(function (key) { return Object.assign({}, key, { id: decode(key.id) }); });
|
|
24
|
+
});
|
|
25
|
+
if (options.user) publicKey.user = Object.assign({}, options.user, { id: decode(options.user.id) });
|
|
26
|
+
return publicKey;
|
|
27
|
+
}
|
|
28
|
+
export function supported() { return !!(window.isSecureContext && window.PublicKeyCredential && navigator.credentials); }
|
|
29
|
+
export function passkeyError(error) {
|
|
30
|
+
if (error.name === 'NotAllowedError' || error.name === 'AbortError') return 'Passkey request cancelled or timed out. You can try again or use your password.';
|
|
31
|
+
if (error.name === 'InvalidStateError') return 'This passkey is already registered. Choose a different device or passkey.';
|
|
32
|
+
return error.message || 'Could not use this passkey.';
|
|
33
|
+
}
|
|
34
|
+
export async function createPasskey(options) {
|
|
35
|
+
if (!supported()) throw new Error('Passkeys need a supported browser and a secure connection.');
|
|
36
|
+
return serialize(await navigator.credentials.create({ publicKey: prepare(options) }));
|
|
37
|
+
}
|
|
38
|
+
export async function getPasskey(options) {
|
|
39
|
+
if (!supported()) throw new Error('Passkeys need a supported browser and a secure connection.');
|
|
40
|
+
return serialize(await navigator.credentials.get({ publicKey: prepare(options) }));
|
|
41
|
+
}
|
|
42
|
+
export async function request(url, data) {
|
|
43
|
+
var response = await fetch(url, data === undefined ? { credentials: 'same-origin' } : {
|
|
44
|
+
method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data),
|
|
45
|
+
});
|
|
46
|
+
var result = await response.json();
|
|
47
|
+
if (!response.ok) throw new Error(result.error || 'Could not complete this request.');
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
export async function initPasskeyLogin() {
|
|
51
|
+
var button = document.getElementById('passkey-login');
|
|
52
|
+
if (!button || !supported()) return;
|
|
53
|
+
try {
|
|
54
|
+
var status = await request('/auth/passkeys/status');
|
|
55
|
+
if (status.origin !== location.origin || document.getElementById('mode-row').hidden) return;
|
|
56
|
+
button.hidden = false;
|
|
57
|
+
button.onclick = async function () {
|
|
58
|
+
button.disabled = true;
|
|
59
|
+
var error = document.getElementById('error'); error.textContent = '';
|
|
60
|
+
try {
|
|
61
|
+
var options = await request('/auth/passkeys/login/options', {});
|
|
62
|
+
var response = await getPasskey(options.options);
|
|
63
|
+
await request('/auth/passkeys/login/verify', { response: response });
|
|
64
|
+
location.href = '/';
|
|
65
|
+
} catch (failure) { error.textContent = passkeyError(failure); }
|
|
66
|
+
finally { button.disabled = false; }
|
|
67
|
+
};
|
|
68
|
+
} catch (failure) { /* Password sign-in remains available when passkeys cannot load. */ }
|
|
69
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { setSettingsDraft, clearSettingsDraft } from './server-settings-state.js';
|
|
3
|
+
|
|
4
|
+
function render(state) {
|
|
5
|
+
var section = document.getElementById('passkey-policy');
|
|
6
|
+
if (!section) return;
|
|
7
|
+
section.hidden = !state.available;
|
|
8
|
+
var input = section.querySelector('[name=origin]');
|
|
9
|
+
if (state.draft === undefined) input.value = state.origin || '';
|
|
10
|
+
input.disabled = !!state.pending || !!state.locked;
|
|
11
|
+
section.querySelector('[name=currentPassword]').disabled = !!state.pending;
|
|
12
|
+
section.querySelector('button').disabled = !!state.pending || !!state.locked;
|
|
13
|
+
section.querySelector('[data-passkey-editor]').hidden = !!state.locked;
|
|
14
|
+
section.querySelector('[role=status]').textContent = state.error || (state.pending ? 'Saving…' : state.origin ?
|
|
15
|
+
'Passkeys are available at ' + state.origin + (state.locked ? '. Remove registered passkeys before changing this address.' : '.') : 'Not configured. Password sign-in remains available.');
|
|
16
|
+
}
|
|
17
|
+
export async function loadPasskeyServerSettings() {
|
|
18
|
+
if (!document.getElementById('passkey-policy') || (store.get('passkeyPolicy') || {}).draft !== undefined) return;
|
|
19
|
+
try {
|
|
20
|
+
var response = await fetch('/api/passkey-policy'); var data = await response.json();
|
|
21
|
+
if (!response.ok) throw new Error(data.error || 'Could not load passkey settings.');
|
|
22
|
+
store.set({ passkeyPolicy: data }); render(data);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
var state = Object.assign({}, store.get('passkeyPolicy'), { error: error.message });
|
|
25
|
+
store.set({ passkeyPolicy: state }); render(state);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function initPasskeyServerSettings() {
|
|
29
|
+
var anchor = document.getElementById('account-auth-policy');
|
|
30
|
+
if (!anchor || document.getElementById('passkey-policy')) return;
|
|
31
|
+
var section = document.createElement('section'); section.id = 'passkey-policy'; section.className = 'settings-card'; section.hidden = true;
|
|
32
|
+
section.innerHTML = '<h3>Passkey sign-in address</h3><p class="settings-hint">Configure the shared server address for passkey sign-in. Users register and manage their own passkeys in Personal settings → Account. Passwords remain available.</p>' +
|
|
33
|
+
'<form><label class="settings-label" for="passkey-origin">Sign-in address</label><input class="us-text-input" id="passkey-origin" name="origin" type="url" placeholder="https://clay.example.com" required>' +
|
|
34
|
+
'<p class="settings-hint">Use the permanent HTTPS address for this server. Local development can use http://localhost with its port.</p>' +
|
|
35
|
+
'<div data-passkey-editor><label class="settings-label" for="passkey-admin-password">Administrator password</label><input class="us-text-input" id="passkey-admin-password" name="currentPassword" type="password" autocomplete="current-password" required>' +
|
|
36
|
+
'<div class="settings-form-actions"><button class="settings-btn-sm" type="submit">Save passkey address</button></div></div></form><p class="settings-hint" role="status"></p>';
|
|
37
|
+
anchor.after(section);
|
|
38
|
+
var input = section.querySelector('[name=origin]');
|
|
39
|
+
input.oninput = function () {
|
|
40
|
+
var state = Object.assign({}, store.get('passkeyPolicy'), { draft: input.value, error: '' });
|
|
41
|
+
if (input.value === (state.origin || '')) { delete state.draft; clearSettingsDraft('passkeys'); }
|
|
42
|
+
else setSettingsDraft('passkeys', true);
|
|
43
|
+
store.set({ passkeyPolicy: state }); render(state);
|
|
44
|
+
};
|
|
45
|
+
section.querySelector('form').onsubmit = async function (event) {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
var state = Object.assign({}, store.get('passkeyPolicy'), { pending: true, error: '' });
|
|
48
|
+
store.set({ passkeyPolicy: state }); render(state);
|
|
49
|
+
var password = section.querySelector('[name=currentPassword]');
|
|
50
|
+
try {
|
|
51
|
+
var response = await fetch('/api/passkey-policy', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ origin: input.value, currentPassword: password.value }) });
|
|
52
|
+
var data = await response.json(); if (!response.ok) throw new Error(data.error || 'Could not save passkey settings.');
|
|
53
|
+
state = data; clearSettingsDraft('passkeys');
|
|
54
|
+
} catch (error) { state.pending = false; state.error = error.message; }
|
|
55
|
+
finally { password.value = ''; store.set({ passkeyPolicy: state }); render(state); }
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -330,6 +330,7 @@ function renderItem(item, index) {
|
|
|
330
330
|
var disabled = controlsDisabled ? ' disabled aria-disabled="true"' : '';
|
|
331
331
|
var text = (item.message && item.message.text || "").trim() || "Attachment-only message";
|
|
332
332
|
var html = '<div class="pending-message-chip' + (item.state === "claimed" ? ' is-claimed' : '') + (scheduled ? ' is-scheduled' : '') + (futureScheduled ? ' is-future' : '') + '" data-pending-id="' + escapeHtml(item.id) + '">';
|
|
333
|
+
if (item.schedule && item.schedule.logicalScheduleId) html = html.replace('data-pending-id=', 'data-control-schedule-id="' + escapeHtml(item.schedule.logicalScheduleId) + '" data-control-revision="' + escapeHtml(item.schedule.logicalRevision || '') + '" data-control-runtime="' + escapeHtml(store.get('controlRuntimeId') || '') + '" data-pending-id=');
|
|
333
334
|
html += '<span class="pending-message-number" aria-hidden="true">' + (index + 1) + '</span>';
|
|
334
335
|
if (own && item.state === "pending") html += '<button class="pending-message-drag" type="button" data-action="drag" aria-label="Reorder queued message ' + (index + 1) + '" title="Drag, or use arrow keys to reorder"' + disabled + '>' + '<i data-lucide="grip-vertical"></i></button>';
|
|
335
336
|
else html += '<span class="pending-message-drag is-static"><i data-lucide="' + (item.state === "claimed" ? "loader-circle" : "lock-keyhole") + '"></i></span>';
|
|
@@ -66,7 +66,7 @@ export function permissionStatusText(state, pending, autoSupported, autoVisible)
|
|
|
66
66
|
if (state.permissionMode === "plan") return "Plan workflow";
|
|
67
67
|
if (state.permissionMode === "acceptEdits") return "Auto-accept edits workflow";
|
|
68
68
|
if (state.permissionMode === "dontAsk") return "Don't ask workflow";
|
|
69
|
-
if (autoVisible && !autoSupported) return "Auto unavailable for this
|
|
69
|
+
if (autoVisible && !autoSupported) return "Auto unavailable for this session";
|
|
70
70
|
if (state.permissionMode === "auto" && !state.effectivePermissionMode) return "Auto selected · waiting for runtime";
|
|
71
71
|
if (state.permissionMode === "auto" && state.effectivePermissionMode !== "auto") {
|
|
72
72
|
return "Auto unavailable at runtime · using " + modeLabel(state.effectivePermissionMode);
|
|
@@ -91,7 +91,8 @@ export function renderPermissionControl(control, state) {
|
|
|
91
91
|
var projectSlug = state.projectSlug || "";
|
|
92
92
|
var sessionId = state.sessionId || null;
|
|
93
93
|
var pending = permissionPendingFor(projectSlug, sessionId);
|
|
94
|
-
var
|
|
94
|
+
var description = ((store.get("vendorInfo") || {})[state.vendor] || {}).configuration || {};
|
|
95
|
+
var autoVisible = description.auto === true || !!(state.permissionCapabilities && state.permissionCapabilities.auto === true);
|
|
95
96
|
var autoSupported = !!(state.permissionCapabilities && state.permissionCapabilities.auto === true);
|
|
96
97
|
var globallyForced = state.globalPermissionModeForced === true;
|
|
97
98
|
var connected = state.connected !== false && !!getWs() && getWs().readyState === 1;
|
|
@@ -114,7 +115,7 @@ export function renderPermissionControl(control, state) {
|
|
|
114
115
|
buttons[i].classList.toggle("pending", requested);
|
|
115
116
|
buttons[i].setAttribute("aria-pressed", selected ? "true" : "false");
|
|
116
117
|
buttons[i].setAttribute("aria-busy", requested ? "true" : "false");
|
|
117
|
-
buttons[i].title = unsupported ? "Auto permissions are unavailable for this
|
|
118
|
+
buttons[i].title = unsupported ? "Auto permissions are unavailable for this session." : buttonTitles[mode];
|
|
118
119
|
}
|
|
119
120
|
var status = control.querySelector(".session-permission-status");
|
|
120
121
|
if (status) {
|
|
@@ -138,7 +139,7 @@ export function bindPermissionControl(control, getState) {
|
|
|
138
139
|
var autoSupported = !!(state.permissionCapabilities && state.permissionCapabilities.auto === true);
|
|
139
140
|
if (state.visible === false || state.locked === true || state.globalPermissionModeForced === true || state.connected === false || store.get('connected') === false) return;
|
|
140
141
|
if (!state.projectSlug || state.projectSlug !== store.get('currentSlug') || !state.sessionId) return;
|
|
141
|
-
if (mode === "auto" &&
|
|
142
|
+
if (mode === "auto" && !autoSupported) return;
|
|
142
143
|
sendPermissionMode(state.projectSlug, state.sessionId, mode);
|
|
143
144
|
});
|
|
144
145
|
}
|
|
@@ -17,7 +17,13 @@ export function preparePersonalConnectionDialog(overlay, inline) {
|
|
|
17
17
|
if (label && input) label.htmlFor = input.id;
|
|
18
18
|
});
|
|
19
19
|
enhanceSettingsSelects(overlay);
|
|
20
|
-
|
|
20
|
+
var fields = Array.from(overlay.querySelectorAll('input,select,textarea'));
|
|
21
|
+
function value(field) {return field.type === 'checkbox' ? field.checked : field.value;}
|
|
22
|
+
var baseline = fields.map(value);
|
|
23
|
+
function markDirty() {
|
|
24
|
+
dirty = fields.some(function (field, index) {return value(field) !== baseline[index];});
|
|
25
|
+
if (inline) store.set({personalEmailDirty:dirty});
|
|
26
|
+
}
|
|
21
27
|
overlay.addEventListener('input', markDirty);
|
|
22
28
|
overlay.addEventListener('change', markDirty);
|
|
23
29
|
var unsubscribe = inline ? store.subscribe(function (state, previousState) {
|