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,112 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
import { escapeHtml as escapeText } from './utils.js';
|
|
4
|
+
|
|
5
|
+
function escapeHtml(value) { return escapeText(String(value)).replace(/"/g, '"').replace(/'/g, '''); }
|
|
6
|
+
function state() { return store.get('sharedBrowserSettings') || {}; }
|
|
7
|
+
function set(patch) { store.set({ sharedBrowserSettings: Object.assign({}, state(), patch) }); }
|
|
8
|
+
function root() { return document.getElementById('shared-browser-settings'); }
|
|
9
|
+
function button(label, action, target, description) {
|
|
10
|
+
return '<button type="button" data-settings-action="' + action + '" data-target="' + escapeHtml(target || '') + '" data-label="' + escapeHtml(description || target || '') + '">' + escapeHtml(label) + '</button>';
|
|
11
|
+
}
|
|
12
|
+
function request(operation, target) {
|
|
13
|
+
var ws = getWs();
|
|
14
|
+
if (!ws || ws.readyState !== 1) { set({ error: 'Reconnect to manage browser data.', pending: false }); renderBrowserSettings(); return; }
|
|
15
|
+
var id = crypto.randomUUID();
|
|
16
|
+
set({ pending: true, requestId: id, error: '', notice: '' });
|
|
17
|
+
ws.send(JSON.stringify({ type: 'shared_browser_settings', sessionId: store.get('activeSessionId'), requestId: id, operation: operation, target: target }));
|
|
18
|
+
renderBrowserSettings();
|
|
19
|
+
setTimeout(function () {
|
|
20
|
+
if (state().requestId === id && state().pending) { set({ pending: false, error: 'The request timed out. Refresh to check the saved state.' }); renderBrowserSettings(); }
|
|
21
|
+
}, 15000);
|
|
22
|
+
}
|
|
23
|
+
export function closeBrowserSettings(restoreFocus) {
|
|
24
|
+
var wasOpen = !!state().open;
|
|
25
|
+
set({ open: false, review: null }); renderBrowserSettings();
|
|
26
|
+
var trigger = document.querySelector('[data-action="settings"]'); if (trigger && wasOpen && restoreFocus !== false) trigger.focus();
|
|
27
|
+
}
|
|
28
|
+
export function browserSettingsHtml() {
|
|
29
|
+
return '<section id="shared-browser-settings" class="shared-browser-settings" aria-label="Browser settings" hidden></section>';
|
|
30
|
+
}
|
|
31
|
+
export function bindBrowserSettings(panel) {
|
|
32
|
+
panel.querySelector('[data-action="settings"]').onclick = function () {
|
|
33
|
+
set({ open: true, page: 'sites', data: null, review: null, filter: '' });
|
|
34
|
+
request('list');
|
|
35
|
+
root().querySelector('[data-settings-action="back"]').focus();
|
|
36
|
+
};
|
|
37
|
+
root().addEventListener('keydown', function (event) {
|
|
38
|
+
if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); closeBrowserSettings(); }
|
|
39
|
+
});
|
|
40
|
+
root().addEventListener('input', function (event) {
|
|
41
|
+
if (event.target.matches('[data-settings-filter]')) { set({ filter: event.target.value }); renderRows(); root().dataset.key = JSON.stringify([state(), store.get('connected')]); }
|
|
42
|
+
});
|
|
43
|
+
root().addEventListener('click', function (event) {
|
|
44
|
+
var control = event.target.closest('[data-settings-action]');
|
|
45
|
+
if (!control || control.disabled) return;
|
|
46
|
+
var action = control.dataset.settingsAction;
|
|
47
|
+
if (action === 'back') { closeBrowserSettings(); return; }
|
|
48
|
+
if (action === 'sites' || action === 'history') { set({ page: action, filter: '', review: null, notice: '', error: '' }); renderBrowserSettings(); return; }
|
|
49
|
+
if (action === 'refresh') { request('list'); return; }
|
|
50
|
+
if (action === 'cancel') { set({ review: null }); renderBrowserSettings(); root().querySelector('[data-settings-action="refresh"]').focus(); return; }
|
|
51
|
+
if (action === 'confirm') { var review = state().review; if (review) request(review.action, review.target); return; }
|
|
52
|
+
set({ notice: '', error: '', review: { action: action, target: control.dataset.target, label: control.dataset.label || control.dataset.target } });
|
|
53
|
+
renderBrowserSettings(); root().querySelector('[data-settings-action="cancel"]').focus();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function renderRows() {
|
|
57
|
+
var el = root(), s = state(); if (!el || !s.open) return;
|
|
58
|
+
var rows = el.querySelector('.browser-settings-rows'); if (!rows) return;
|
|
59
|
+
var filter = (s.filter || '').toLowerCase();
|
|
60
|
+
var data = s.data || { sites: [], history: [] };
|
|
61
|
+
if (s.page === 'history') {
|
|
62
|
+
rows.innerHTML = data.history.filter(function (entry) { return entry.url.toLowerCase().includes(filter); }).map(function (entry) {
|
|
63
|
+
return '<div class="browser-settings-row"><div><span class="browser-settings-url">' + escapeHtml(entry.url) + '</span><small>' + escapeHtml(new Date(entry.at).toLocaleString()) + '</small></div>' + button('Remove', 'delete_history', entry.id, entry.url) + '</div>';
|
|
64
|
+
}).join('');
|
|
65
|
+
} else {
|
|
66
|
+
rows.innerHTML = data.sites.filter(function (site) { return site.host.toLowerCase().includes(filter); }).map(function (site) {
|
|
67
|
+
return '<details><summary>' + escapeHtml(site.host) + '<small>' + site.cookies.length + (site.cookies.length === 1 ? ' cookie · ' : ' cookies · ') + site.origins.length + (site.origins.length === 1 ? ' storage origin' : ' storage origins') + '</small></summary><div class="browser-settings-row"><span>Cookies and site storage</span>' + button('Remove site data', 'delete_site', site.host) + '</div>' +
|
|
68
|
+
site.origins.map(function (origin) { return '<p class="browser-settings-origin">' + escapeHtml(origin.origin) + '<small>' + origin.localStorage + ' localStorage entries · ' + origin.databases + ' IndexedDB databases</small></p>'; }).join('') +
|
|
69
|
+
site.cookies.map(function (cookie) {
|
|
70
|
+
var info = cookie.domain + cookie.path + ' · ' + (cookie.expires === -1 ? 'Session cookie' : 'Expires ' + new Date(cookie.expires * 1000).toLocaleDateString()) + (cookie.httpOnly ? ' · HttpOnly' : '') + (cookie.secure ? ' · Secure' : '') + (cookie.partitioned ? ' · Partitioned' : '');
|
|
71
|
+
return '<div class="browser-settings-row"><div><span>' + escapeHtml(cookie.name) + '</span><small>' + escapeHtml(info) + '</small></div>' + button('Remove cookie', 'delete_cookie', cookie.id, cookie.name + ' · ' + cookie.domain + cookie.path) + '</div>';
|
|
72
|
+
}).join('') + '</details>';
|
|
73
|
+
}).join('');
|
|
74
|
+
}
|
|
75
|
+
if (!rows.innerHTML) rows.innerHTML = '<p class="browser-settings-muted">' + (s.pending && !s.data ? 'Loading saved data…' : filter ? 'No matching entries.' : s.page === 'history' ? 'No saved browsing history.' : 'No saved cookies or site data.') + '</p>';
|
|
76
|
+
rows.querySelectorAll('button').forEach(function (control) { control.disabled = !!s.pending || !store.get('connected'); });
|
|
77
|
+
}
|
|
78
|
+
export function renderBrowserSettings() {
|
|
79
|
+
var el = root(); if (!el) return;
|
|
80
|
+
var s = state(), panel = el.closest('.shared-browser-panel');
|
|
81
|
+
var browser = store.get('sharedBrowser');
|
|
82
|
+
var trigger = panel.querySelector('[data-action="settings"]');
|
|
83
|
+
trigger.hidden = !(browser && browser.personalCookiesAvailable);
|
|
84
|
+
trigger.disabled = !store.get('connected');
|
|
85
|
+
trigger.setAttribute('aria-expanded', String(!!s.open));
|
|
86
|
+
el.hidden = !s.open;
|
|
87
|
+
panel.classList.toggle('browser-settings-open', !!s.open);
|
|
88
|
+
if (!s.open) return;
|
|
89
|
+
var key = JSON.stringify([s, store.get('connected')]); if (el.dataset.key === key) return; el.dataset.key = key;
|
|
90
|
+
var page = s.page || 'sites';
|
|
91
|
+
el.innerHTML = '<div class="browser-settings-heading">' + button('Back to browser', 'back') + '<h3>Browser settings</h3></div><p class="browser-settings-muted">Personal · Shared across your Mates. Incognito tabs do not save data here.</p>' +
|
|
92
|
+
'<nav aria-label="Browser settings sections">' + button('Cookies & site data', 'sites') + button('History', 'history') + '</nav>' +
|
|
93
|
+
'<p class="browser-settings-muted">' + (page === 'sites' ? 'Cookies, localStorage and IndexedDB are saved for your account. New personal tabs restore saved site storage. Removing data may sign you out. Removals also apply to open personal tabs. Sites may create new data afterwards.' : 'Your latest 500 page visits. Clearing this list leaves open tabs, their Back/Forward navigation and conversation activity unchanged.') + '</p>' +
|
|
94
|
+
'<div class="browser-settings-tools"><input data-settings-filter aria-label="Filter saved browser data" placeholder="' + (page === 'sites' ? 'Find a site' : 'Find a page') + '" value="' + escapeHtml(s.filter || '') + '">' + button('Refresh', 'refresh') + button(page === 'sites' ? 'Clear all site data' : 'Clear history', page === 'sites' ? 'clear_data' : 'clear_history') + '</div>' +
|
|
95
|
+
'<p class="browser-settings-feedback" role="status">' + escapeHtml(s.error || (!store.get('connected') ? 'Disconnected. Reconnect and refresh to see current saved data.' : s.pending ? 'Updating…' : s.notice || '')) + '</p>' +
|
|
96
|
+
(s.review ? '<div class="browser-settings-review" role="group" aria-label="Confirm removal"><strong>' + (s.review.action.includes('history') ? 'Remove browsing history?' : 'Remove saved site data?') + '</strong><p>' + (s.review.action.includes('history') ? 'This removes ' + (s.review.action === 'clear_history' ? 'all saved visits' : 'this saved visit') + ' from your personal history.' : s.review.action === 'delete_cookie' ? 'This removes ' + escapeHtml(s.review.label) + ' across your personal Mate browsers and may sign you out.' : 'This removes ' + (s.review.action === 'clear_data' ? 'all cookies and site storage' : 'cookies and storage for ' + escapeHtml(s.review.target)) + ' across your personal Mate browsers and may sign you out.') + '</p>' + button('Cancel', 'cancel') + button('Remove', 'confirm') + '</div>' : '') +
|
|
97
|
+
'<div class="browser-settings-rows"></div>';
|
|
98
|
+
el.querySelector('[data-settings-action="' + page + '"]').setAttribute('aria-current', 'page');
|
|
99
|
+
el.querySelectorAll('button').forEach(function (control) { control.disabled = control.dataset.settingsAction !== 'back' && (!!s.pending || !store.get('connected')); });
|
|
100
|
+
renderRows();
|
|
101
|
+
}
|
|
102
|
+
export function handleBrowserSettingsMessage(msg) {
|
|
103
|
+
if (!msg.requestId || msg.requestId !== state().requestId) return false;
|
|
104
|
+
if (msg.type === 'shared_browser_settings') {
|
|
105
|
+
var removed = !!state().review;
|
|
106
|
+
set({ data: msg.settings, pending: false, review: null, error: '', notice: removed ? 'Removed from your saved browser data.' : '' });
|
|
107
|
+
} else if (msg.type === 'shared_browser_error') set({ pending: false, error: msg.error });
|
|
108
|
+
else return false;
|
|
109
|
+
renderBrowserSettings();
|
|
110
|
+
if (state().open && removed) root().querySelector('[data-settings-action="refresh"]').focus();
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
1
2
|
import { store } from './store.js';
|
|
2
3
|
|
|
3
4
|
export function renderBrowserTabs(el, select, send) {
|
|
4
5
|
var bar = el.querySelector('.shared-browser-tabs');
|
|
5
6
|
var tabs = store.get('sharedBrowsers') || [];
|
|
6
7
|
var selected = store.get('sharedBrowser');
|
|
7
|
-
var key = JSON.stringify([tabs.map(function (tab) { return [tab.id, tab.url, tab.control, tab.phase]; }), selected && selected.id, store.get('connected')]);
|
|
8
|
+
var key = JSON.stringify([tabs.map(function (tab) { return [tab.id, tab.url, tab.control, tab.phase, tab.incognito, tab.personalCookiesAvailable]; }), selected && selected.id, store.get('connected')]);
|
|
8
9
|
if (bar.dataset.key === key) return;
|
|
9
10
|
bar.dataset.key = key;
|
|
10
11
|
bar.replaceChildren();
|
|
@@ -14,9 +15,9 @@ export function renderBrowserTabs(el, select, send) {
|
|
|
14
15
|
button.setAttribute('aria-selected', String(!!selected && selected.id === tab.id));
|
|
15
16
|
var title = 'Tab ' + (index + 1);
|
|
16
17
|
try { if (tab.url) title = new URL(tab.url).hostname; } catch (e) {}
|
|
17
|
-
var label = document.createElement('span'); label.textContent = title;
|
|
18
|
+
var label = document.createElement('span'); label.textContent = title + (tab.personalCookiesAvailable && tab.incognito ? ' · Incognito' : '');
|
|
18
19
|
var owner = document.createElement('small'); owner.textContent = tab.phase === 'ended' ? 'Ended' : tab.control === 'agent' ? 'Shared' : 'You only';
|
|
19
|
-
button.append(label, owner); button.title = title + ' · ' + (tab.phase === 'ended' ? 'Ended' : tab.control === 'agent' ? 'You and Clay can control this tab' : 'Only you can control this tab. Clay is paused.');
|
|
20
|
+
button.append(label, owner); button.title = title + ' · ' + (tab.incognito === false ? 'Personal browser' : 'Incognito') + ' · ' + (tab.phase === 'ended' ? 'Ended' : tab.control === 'agent' ? 'You and Clay can control this tab' : 'Only you can control this tab. Clay is paused.');
|
|
20
21
|
button.onclick = function () { select(tab.id); };
|
|
21
22
|
button.onkeydown = function (event) {
|
|
22
23
|
var next = event.key === 'ArrowRight' ? (index + 1) % tabs.length : event.key === 'ArrowLeft' ? (index + tabs.length - 1) % tabs.length : event.key === 'Home' ? 0 : event.key === 'End' ? tabs.length - 1 : -1;
|
|
@@ -28,6 +29,15 @@ export function renderBrowserTabs(el, select, send) {
|
|
|
28
29
|
item.append(button, close); bar.appendChild(item);
|
|
29
30
|
});
|
|
30
31
|
var add = document.createElement('button'); add.type = 'button'; add.textContent = '+'; add.setAttribute('aria-label', 'New browser tab'); add.disabled = !store.get('connected');
|
|
32
|
+
add.title = selected && selected.personalCookiesAvailable ? 'New tab · Personal browser' : 'New incognito tab';
|
|
31
33
|
add.onclick = function () { send('open', { newTab: true }); };
|
|
32
34
|
bar.appendChild(add);
|
|
35
|
+
if (selected && selected.personalCookiesAvailable) {
|
|
36
|
+
var incognito = document.createElement('button'); incognito.type = 'button';
|
|
37
|
+
incognito.innerHTML = iconHtml('glasses');
|
|
38
|
+
incognito.setAttribute('aria-label', 'New incognito tab'); incognito.title = 'New incognito tab · Site data is not saved';
|
|
39
|
+
incognito.disabled = !store.get('connected');
|
|
40
|
+
incognito.onclick = function () { send('open', { newTab: true, incognito: true }); };
|
|
41
|
+
bar.appendChild(incognito); refreshIcons();
|
|
42
|
+
}
|
|
33
43
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { registerStudioPaint } from './clay-studio-render.js';
|
|
2
|
+
import { browserLinkTarget, initBrowserLinks } from './clay-browser-links.js';
|
|
3
|
+
import { browserSettingsHtml, bindBrowserSettings, renderBrowserSettings, closeBrowserSettings, handleBrowserSettingsMessage } from './shared-browser-settings.js';
|
|
1
4
|
import { renderBrowserTabs } from './shared-browser-tabs.js';
|
|
2
5
|
import { store } from './store.js';
|
|
3
6
|
import { getWs } from './ws-ref.js';
|
|
@@ -50,15 +53,15 @@ function ensurePanel() {
|
|
|
50
53
|
el.className = 'shared-browser-panel hidden';
|
|
51
54
|
el.setAttribute('aria-label', 'Shared browser');
|
|
52
55
|
el.innerHTML = '<header class="shared-browser-header"><span class="shared-browser-title">' + iconHtml('globe') + 'Browser</span><span class="shared-browser-phase" role="status">Ready</span><div class="shared-browser-window">' +
|
|
53
|
-
iconButton('wide', 'chevrons-left-right', 'Widen browser panel') + iconButton('fullscreen', 'maximize-2', 'Toggle browser fullscreen') + iconButton('hide', 'x', 'Hide browser panel') + '</div></header>' +
|
|
56
|
+
iconButton('settings', 'settings-2', 'Browser settings') + iconButton('wide', 'chevrons-left-right', 'Widen browser panel') + iconButton('fullscreen', 'maximize-2', 'Toggle browser fullscreen') + iconButton('hide', 'x', 'Hide browser panel') + '</div></header>' +
|
|
54
57
|
'<div class="shared-browser-tabs" role="tablist" aria-label="Browser tabs"></div><form class="shared-browser-address">' + iconButton('back', 'arrow-left', 'Back') + iconButton('forward', 'arrow-right', 'Forward') + iconButton('reload', 'rotate-cw', 'Reload') +
|
|
55
58
|
'<input aria-label="Browser address" placeholder="Enter a URL" type="text" autocomplete="off" spellcheck="false"><button type="submit" aria-label="Open address">' + iconHtml('arrow-right') + '</button></form>' +
|
|
56
|
-
'<div class="shared-browser-viewport"><div class="shared-browser-monitor"><div class="shared-browser-pointer-layer" aria-hidden="true"><div class="shared-browser-pointer" hidden><svg viewBox="0 0 24 28"><path d="M3 2 L3 22 L8 17 L12 26 L16 24 L12 15 L20 15 Z"/></svg><i></i></div></div><canvas width="1280" height="800" tabindex="0" aria-label="Shared browser page"></canvas>' +
|
|
57
|
-
'<div class="shared-browser-empty">' + iconHtml('globe') + '<h3>A browser you can
|
|
59
|
+
browserSettingsHtml() + '<div class="shared-browser-viewport"><div class="shared-browser-monitor"><div class="shared-browser-pointer-layer" aria-hidden="true"><div class="shared-browser-pointer" hidden><svg viewBox="0 0 24 28"><path d="M3 2 L3 22 L8 17 L12 26 L16 24 L12 15 L20 15 Z"/></svg><i></i></div></div><canvas width="1280" height="800" tabindex="0" aria-label="Shared browser page"></canvas>' +
|
|
60
|
+
'<div class="shared-browser-empty">' + iconHtml('globe') + '<h3>A browser you can use with Clay</h3><p>Enter an address to browse together.<br>Localhost connects to the Clay host.</p><p class="shared-browser-private">Site data lasts only for this browser session.</p></div>' +
|
|
58
61
|
'<textarea class="shared-browser-keyboard" aria-label="Type into shared browser" autocomplete="off" autocapitalize="off" spellcheck="false"></textarea><span class="shared-browser-monitor-brand" aria-hidden="true">Clay Studio</span><span class="shared-browser-monitor-detail" aria-hidden="true"></span><span class="shared-browser-monitor-stand" aria-hidden="true"></span></div><div class="shared-browser-caption"><span class="shared-browser-monitor-label"></span>' + activityHtml() + '</div></div>' +
|
|
59
62
|
'<p class="shared-browser-error hidden" role="status"></p>' +
|
|
60
63
|
'<footer class="shared-browser-footer"><div class="shared-browser-control"><span class="shared-browser-control-status" role="status" aria-live="polite">You and Clay can control this browser</span><button type="button" data-action="control" aria-pressed="false"></button></div>' +
|
|
61
|
-
'<div class="shared-browser-details">' + viewportMenuHtml() + '<button type="button" data-action="end">End browser</button></div></footer>';
|
|
64
|
+
'<div class="shared-browser-details"><span class="shared-browser-cookie-mode"></span>' + viewportMenuHtml() + '<button type="button" data-action="end">End browser</button></div></footer>';
|
|
62
65
|
root.appendChild(el);
|
|
63
66
|
el.querySelector('[data-action="hide"]').onclick = hideSharedBrowser;
|
|
64
67
|
el.querySelector('[data-action="wide"]').onclick = function () { var wide = !(store.get('sharedBrowserUi') || {}).wide; ui({ wide: wide }); render(); };
|
|
@@ -69,8 +72,9 @@ function ensurePanel() {
|
|
|
69
72
|
var browser = store.get('sharedBrowser');
|
|
70
73
|
if (browser) send('control', { control: browser.control === 'user' ? 'agent' : 'user' });
|
|
71
74
|
};
|
|
72
|
-
el.querySelector('[data-action="end"]').onclick = function () { var browser = store.get('sharedBrowser'); send(browser && browser.phase === 'ended' ? 'open' : 'end'); };
|
|
75
|
+
el.querySelector('[data-action="end"]').onclick = function () { var browser = store.get('sharedBrowser'); send(browser && browser.phase === 'ended' ? 'open' : 'end', browser && browser.phase === 'ended' ? { incognito: browser.incognito } : undefined); };
|
|
73
76
|
bindViewportMenu(el);
|
|
77
|
+
bindBrowserSettings(el);
|
|
74
78
|
var observer = new ResizeObserver(layoutMonitor);
|
|
75
79
|
observer.observe(el.querySelector('.shared-browser-viewport'));
|
|
76
80
|
bindBrowserInput(el.querySelector('canvas'), el.querySelector('textarea'));
|
|
@@ -141,11 +145,16 @@ function render() {
|
|
|
141
145
|
el.querySelector('[data-action="control"]').hidden = !live;
|
|
142
146
|
el.querySelector('[data-action="end"]').disabled = !browser || !connected;
|
|
143
147
|
el.querySelector('[data-action="end"]').textContent = browser && browser.phase === 'ended' ? 'New browser' : 'End browser';
|
|
148
|
+
var personal = browser && browser.incognito === false;
|
|
149
|
+
el.querySelector('.shared-browser-cookie-mode').textContent = personal ? 'Personal browser' : 'Incognito';
|
|
150
|
+
el.querySelector('.shared-browser-cookie-mode').title = personal ? 'Cookies and site storage are saved for your account across your Mates.' : 'Cookies and site storage are isolated and discarded when this tab ends.';
|
|
151
|
+
el.querySelector('.shared-browser-private').textContent = personal ? 'Your cookies and site storage are remembered across your Mates and browser restarts.' : 'Site data lasts only for this browser session.';
|
|
144
152
|
var error = state.error || (browser && browser.error) || '';
|
|
145
153
|
el.querySelector('.shared-browser-error').textContent = error;
|
|
146
154
|
el.querySelector('.shared-browser-error').classList.toggle('hidden', !error);
|
|
147
155
|
el.querySelector('.shared-browser-empty').classList.toggle('hidden', !!(browser && browser.url && state.hasFrame));
|
|
148
156
|
renderViewportMenu(el, browser, operable);
|
|
157
|
+
renderBrowserSettings();
|
|
149
158
|
renderBrowserActivity(el, browser, connected);
|
|
150
159
|
layoutMonitor();
|
|
151
160
|
}
|
|
@@ -163,6 +172,16 @@ function selectBrowserTab(id) {
|
|
|
163
172
|
setBrowserTab(browser);
|
|
164
173
|
send('view', { visible: desktop() && !document.hidden }); render();
|
|
165
174
|
}
|
|
175
|
+
export function openSharedBrowserAt(value) {
|
|
176
|
+
var url = browserLinkTarget('browser:' + value);
|
|
177
|
+
if (!url) throw new Error('Enter a valid HTTP or HTTPS browser address.');
|
|
178
|
+
if (!desktop()) throw new Error('Clay Browser is available on desktop screens.');
|
|
179
|
+
if (!eligible()) throw new Error('Browser access is unavailable in this conversation.');
|
|
180
|
+
if (!store.get('connected')) throw new Error('Reconnect before opening this browser link.');
|
|
181
|
+
ensurePanel(); closeBrowserSettings(false);
|
|
182
|
+
claimRightWorkbench('browser'); store.set({ sharedBrowserOpen: true });
|
|
183
|
+
ui({ error: '' }); send('open', { url: url }); render();
|
|
184
|
+
}
|
|
166
185
|
export function openSharedBrowser() {
|
|
167
186
|
if (!eligible() || !store.get('connected')) return;
|
|
168
187
|
ensurePanel();
|
|
@@ -175,6 +194,7 @@ export function openSharedBrowser() {
|
|
|
175
194
|
}
|
|
176
195
|
export function hideSharedBrowser() {
|
|
177
196
|
closeViewportMenu();
|
|
197
|
+
closeBrowserSettings();
|
|
178
198
|
clearBrowserInput();
|
|
179
199
|
if (store.get('sharedBrowserOpen')) send('view', { visible: false });
|
|
180
200
|
store.set({ sharedBrowserOpen: false });
|
|
@@ -184,6 +204,7 @@ export function hideSharedBrowser() {
|
|
|
184
204
|
export function handleSharedBrowserMessage(msg) {
|
|
185
205
|
if (!msg.type || msg.type.indexOf('shared_browser_') !== 0) return false;
|
|
186
206
|
if (String(msg.sessionId) !== String(store.get('activeSessionId'))) return true;
|
|
207
|
+
if (handleBrowserSettingsMessage(msg)) return true;
|
|
187
208
|
if (msg.type === 'shared_browser_state') {
|
|
188
209
|
var old = store.get('sharedBrowser');
|
|
189
210
|
var tabs = msg.browsers || (msg.browser ? [msg.browser] : []);
|
|
@@ -209,6 +230,7 @@ export function handleSharedBrowserMessage(msg) {
|
|
|
209
230
|
var canvas = panel().querySelector('canvas'); canvas.width = image.naturalWidth; canvas.height = image.naturalHeight;
|
|
210
231
|
canvas.getContext('2d').drawImage(image, 0, 0);
|
|
211
232
|
ui({ decoding: false, hasFrame: true }); render();
|
|
233
|
+
registerStudioPaint(msg, canvas, null, canvas);
|
|
212
234
|
}
|
|
213
235
|
};
|
|
214
236
|
image.onerror = function () { if (store.get('activeSessionId') === sessionId) ui({ decoding: false }); };
|
|
@@ -217,6 +239,7 @@ export function handleSharedBrowserMessage(msg) {
|
|
|
217
239
|
return true;
|
|
218
240
|
}
|
|
219
241
|
export function initSharedBrowser() {
|
|
242
|
+
initBrowserLinks();
|
|
220
243
|
var button = document.getElementById('shared-browser-btn');
|
|
221
244
|
if (button) button.onclick = openSharedBrowser;
|
|
222
245
|
var toggle = document.getElementById('shared-browser-toggle-btn');
|
|
@@ -233,7 +256,7 @@ registerRightWorkbench('browser', hideSharedBrowser);
|
|
|
233
256
|
store.subscribe(function (state, previous) {
|
|
234
257
|
if (state.currentSlug !== previous.currentSlug || state.activeSessionId !== previous.activeSessionId || state.myUserId !== previous.myUserId) {
|
|
235
258
|
clearBrowserInput(); releaseRightWorkbench('browser');
|
|
236
|
-
store.set({ sharedBrowser: null, sharedBrowsers: [], sharedBrowserOpen: false, sharedBrowserUi: {} });
|
|
259
|
+
store.set({ sharedBrowser: null, sharedBrowsers: [], sharedBrowserOpen: false, sharedBrowserUi: {}, sharedBrowserSettings: {} });
|
|
237
260
|
if (state.connected) send('state_request');
|
|
238
261
|
render();
|
|
239
262
|
} else if (state.connected !== previous.connected) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { contextualMate } from './contextual-mate-identity.js';
|
|
2
|
+
import { activateContextualMate, isMateWorkspace } from './project-mate-navigation.js';
|
|
2
3
|
import { appendGithubWork } from './session-github.js';
|
|
3
4
|
// sidebar-mobile.js - Mobile sheet overlays, tab bar, and mobile-specific rendering
|
|
4
5
|
// Extracted from sidebar.js (PR-38)
|
|
@@ -258,7 +259,7 @@ function renderSheetSessions(listEl) {
|
|
|
258
259
|
}
|
|
259
260
|
|
|
260
261
|
var visibleChipMates = getCachedMates().filter(function (m) {
|
|
261
|
-
return m && !m.archived;
|
|
262
|
+
return m && !m.archived && contextualMate(m.id);
|
|
262
263
|
});
|
|
263
264
|
var sortedChipMates = visibleChipMates.sort(function (a, b) {
|
|
264
265
|
var aBuiltin = a.builtinKey ? 1 : 0;
|
|
@@ -327,7 +328,7 @@ function renderSheetSessions(listEl) {
|
|
|
327
328
|
renderMobileSessionsInto(sessionListEl);
|
|
328
329
|
} else if (type === "mate") {
|
|
329
330
|
closeMobileSheet();
|
|
330
|
-
|
|
331
|
+
activateContextualMate(mateId);
|
|
331
332
|
}
|
|
332
333
|
|
|
333
334
|
refreshIcons();
|
|
@@ -822,6 +822,7 @@ function createIconItem(p, currentSlug) {
|
|
|
822
822
|
var el = document.createElement("a");
|
|
823
823
|
var isActive = p.slug === currentSlug && !currentDmUserId;
|
|
824
824
|
el.className = "icon-strip-item" + (isActive ? " active" : "");
|
|
825
|
+
el.dataset.controlRuntime = p.controlRuntimeId || "";
|
|
825
826
|
el.href = "/p/" + p.slug + "/";
|
|
826
827
|
el.dataset.slug = p.slug;
|
|
827
828
|
|
|
@@ -353,7 +353,7 @@ function renderSection(section, ctx, kind) {
|
|
|
353
353
|
body.appendChild(empty);
|
|
354
354
|
}
|
|
355
355
|
var view = currentFolderState().view;
|
|
356
|
-
var dateGroups = isFavorites ? null : groupUnitsByDate(section.units, view.sort, view.direction);
|
|
356
|
+
var dateGroups = isFavorites || view.showDateHeadings === false ? null : groupUnitsByDate(section.units, view.sort, view.direction);
|
|
357
357
|
if (dateGroups) {
|
|
358
358
|
for (var g = 0; g < dateGroups.length; g++) {
|
|
359
359
|
var ids = groupRootSessionIds(dateGroups[g].units);
|
|
@@ -826,6 +826,7 @@ function renderSessionItem(s, options) {
|
|
|
826
826
|
el.className = "session-item" + (displaySession.active ? " active" : "") + (isMatch ? " search-match" : "");
|
|
827
827
|
if (itemOptions.worker) el.classList.add("session-worker-item");
|
|
828
828
|
el.dataset.sessionId = s.id;
|
|
829
|
+
el.dataset.controlSessionOrigin = s.sessionOriginId || '';
|
|
829
830
|
|
|
830
831
|
var textSpan = document.createElement("span");
|
|
831
832
|
textSpan.className = "session-item-text";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
import { getCachedSessions } from './sidebar-sessions.js';
|
|
4
|
+
import { isCurrentProjectSessionReady } from './split-session-boundary.js';
|
|
5
|
+
import { splitPanesMatchProject, reconcileRestoredSplit } from './project-activation.js';
|
|
6
|
+
import { splitGroupMemberIds } from './split-group-helpers.js';
|
|
7
|
+
import { splitPaneForSession } from './split-pane-reconciler.js';
|
|
8
|
+
import { clearProjectSplitState } from './split-session-boundary.js';
|
|
9
|
+
|
|
10
|
+
export function reconcileSplitIdentity(state, previous, host) {
|
|
11
|
+
var ownerChanged = (previous.authIdentityLoaded === true || state.splitIdentityHydrated) && state.myUserId !== previous.myUserId;
|
|
12
|
+
if (state.authIdentityLoaded && !state.splitIdentityHydrated) store.set({ splitIdentityHydrated: true });
|
|
13
|
+
if (state.currentSlug === previous.currentSlug && state.myUserId === previous.myUserId) return false;
|
|
14
|
+
Array.from(host.querySelectorAll('.split-pane-frame')).forEach(function (frame) {
|
|
15
|
+
if (frame.clayPane) frame.clayPane.suspend();
|
|
16
|
+
});
|
|
17
|
+
host.innerHTML = '';
|
|
18
|
+
if (ownerChanged) {
|
|
19
|
+
// This socket was authenticated as the previous owner. Fresh metadata on
|
|
20
|
+
// that connection cannot establish the replacement owner's pane boundary.
|
|
21
|
+
store.set({ splitIdentityBlockedSocket: getWs(), paneBindingSessions: [] });
|
|
22
|
+
clearProjectSplitState();
|
|
23
|
+
} else if (state.splitPanes) store.set({ splitPanes: null });
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// The initial owner response can arrive after history and split metadata.
|
|
28
|
+
// Wait for it so identity cleanup cannot discard panes we just restored.
|
|
29
|
+
export function restoreSplitGroup(openGroup) {
|
|
30
|
+
var state = store.snap();
|
|
31
|
+
if (state.authIdentityLoaded === false || state.isMultiUserMode && !state.myUserId) return;
|
|
32
|
+
if (!isCurrentProjectSessionReady(state, getWs())) return;
|
|
33
|
+
var split = state.splitPanes;
|
|
34
|
+
if (split && !splitPanesMatchProject(split, state.currentSlug)) {
|
|
35
|
+
store.set({ splitPanes: null });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (state.paneMode) return;
|
|
39
|
+
if (split) {
|
|
40
|
+
var reconciliation = reconcileRestoredSplit(split, state.splitGroups);
|
|
41
|
+
if (reconciliation.action === "clear") {
|
|
42
|
+
store.set({ splitPanes: null });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (reconciliation.action === "rebuild") {
|
|
46
|
+
var rebuilt = reconciliation.group;
|
|
47
|
+
if (rebuilt.members.some(function (id) { return !getCachedSessions().some(function (session) { return session.id === id; }); })) {
|
|
48
|
+
store.set({ splitPanes: null });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
store.set({ splitPanes: {
|
|
52
|
+
groupId: rebuilt.id,
|
|
53
|
+
panes: splitGroupMemberIds(rebuilt).map(function (id) { return splitPaneForSession(id, state.currentSlug, getCachedSessions()); }),
|
|
54
|
+
} });
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
var activeId = store.get('activeSessionId');
|
|
59
|
+
if (!activeId) return;
|
|
60
|
+
var groups = store.get('splitGroups') || [];
|
|
61
|
+
for (var i = 0; i < groups.length; i++) {
|
|
62
|
+
var members = groups[i].members || [];
|
|
63
|
+
if (members.indexOf(activeId) !== -1) {
|
|
64
|
+
openGroup(groups[i]);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -236,6 +236,7 @@ function sendSetPair(groupId, driverId) {
|
|
|
236
236
|
|
|
237
237
|
export function syncPairChrome(host, split) {
|
|
238
238
|
if (!host || !split || !split.groupId) return;
|
|
239
|
+
if (Array.from(host.querySelectorAll('.split-pane-frame')).some(function (frame) { return !!frame.dataset.requestedSessionId; })) return;
|
|
239
240
|
var groups = store.get('splitGroups') || [];
|
|
240
241
|
var group = null;
|
|
241
242
|
for (var i = 0; i < groups.length; i++) {
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
// (and their iframe browsing contexts) are reused by stable project/session
|
|
3
3
|
// identity while metadata and visual order are refreshed.
|
|
4
4
|
|
|
5
|
+
export function splitPaneForSession(id, slug, sessions) {
|
|
6
|
+
var session = (sessions || []).find(function (item) { return item.id === id; });
|
|
7
|
+
return { slug: slug, sessionId: id, title: session && session.title || ('Session ' + id) };
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
export function splitPaneIdentity(pane) {
|
|
6
11
|
return String(pane && pane.slug || "") + "#" + String(pane && pane.sessionId || "");
|
|
7
12
|
}
|
|
@@ -16,9 +21,19 @@ export function reconcileSplitPanes(host, panes, createPane, updatePane) {
|
|
|
16
21
|
var pane = desired[pi];
|
|
17
22
|
var key = splitPaneIdentity(pane);
|
|
18
23
|
var paneEl = byKey.get(key);
|
|
24
|
+
if (!paneEl) {
|
|
25
|
+
for (var ci = 0; ci < existing.length; ci++) {
|
|
26
|
+
var candidate = existing[ci], frame = candidate.querySelector('.split-pane-frame');
|
|
27
|
+
if (!used.has(candidate) && frame && frame.dataset.projectSlug === pane.slug && frame.clayPane &&
|
|
28
|
+
!desired.some(function (item) { return splitPaneIdentity(item) === candidate.dataset.splitPaneKey; })) {
|
|
29
|
+
paneEl = candidate; break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
19
33
|
if (!paneEl) paneEl = createPane(pane, pi);
|
|
20
34
|
paneEl.dataset.splitPaneKey = key;
|
|
21
35
|
updatePane(paneEl, pane, pi);
|
|
36
|
+
if (paneEl.style) paneEl.style.order = String(pi);
|
|
22
37
|
used.add(paneEl);
|
|
23
38
|
if (!paneEl.parentNode) host.appendChild(paneEl);
|
|
24
39
|
}
|
|
@@ -6,6 +6,8 @@ import { formatTokens } from './app-panels.js';
|
|
|
6
6
|
import { VENDOR_AVATARS, VENDOR_NAMES } from './app-rendering.js';
|
|
7
7
|
import { createPermissionControl, bindPermissionControl, renderPermissionControl } from './permission-control.js';
|
|
8
8
|
import { splitGroupRoles } from './split-group-helpers.js';
|
|
9
|
+
import { paneTarget, livePaneBinding, samePaneTarget } from './pane-binding.js';
|
|
10
|
+
import { syncPairChrome } from './split-pair-ui.js';
|
|
9
11
|
|
|
10
12
|
function sessionById(sessionId) {
|
|
11
13
|
var sessions = getCachedSessions() || [];
|
|
@@ -17,17 +19,31 @@ function paneUrl(pane) {
|
|
|
17
19
|
return "/p/" + encodeURIComponent(pane.slug) + "/?pane=1&session=" + encodeURIComponent(pane.sessionId);
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
function headerBindingStamp(frame) {
|
|
23
|
+
var live = frame.clayPane && frame.clayPane.identity();
|
|
24
|
+
return JSON.stringify([frame.dataset.sessionId, frame.dataset.sessionOriginId,
|
|
25
|
+
live && live.binding && live.binding.requestId, live && live.binding && live.binding.generation]);
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
function startPaneRename(header, titleEl, pane) {
|
|
21
29
|
if (header.querySelector(".split-pane-rename-input")) return;
|
|
22
30
|
var input = document.createElement("input");
|
|
23
31
|
input.type = "text"; input.className = "split-pane-rename-input"; input.value = pane.title;
|
|
24
32
|
titleEl.style.display = "none"; header.insertBefore(input, titleEl); input.focus(); input.select();
|
|
25
33
|
var done = false;
|
|
34
|
+
var section = header.parentNode, frame = section.querySelector('.split-pane-frame');
|
|
35
|
+
var origin = frame.dataset.sessionOriginId, binding = frame.clayPane && frame.clayPane.identity().binding, socket = getWs();
|
|
36
|
+
function current() {
|
|
37
|
+
var live = frame.clayPane && frame.clayPane.identity();
|
|
38
|
+
return header.isConnected && !header.inert && socket === getWs() && store.get('connected') &&
|
|
39
|
+
frame.dataset.sessionId === String(pane.sessionId) && frame.dataset.sessionOriginId === origin && !frame.dataset.requestedSessionId &&
|
|
40
|
+
(!frame.clayPane || livePaneBinding(frame) && live.binding === binding);
|
|
41
|
+
}
|
|
26
42
|
function finish(commit) {
|
|
27
43
|
if (done) return;
|
|
28
44
|
done = true;
|
|
29
45
|
var newTitle = input.value.trim(); input.remove(); titleEl.style.display = "";
|
|
30
|
-
if (!commit || !newTitle || newTitle === pane.title) return;
|
|
46
|
+
if (!commit || !current() || !newTitle || newTitle === pane.title) return;
|
|
31
47
|
pane.title = newTitle; titleEl.textContent = newTitle;
|
|
32
48
|
var ws = getWs();
|
|
33
49
|
if (ws && ws.readyState === 1) ws.send(JSON.stringify({ type: "rename_session", id: pane.sessionId, title: newTitle }));
|
|
@@ -37,6 +53,7 @@ function startPaneRename(header, titleEl, pane) {
|
|
|
37
53
|
if (event.key === "Escape") { event.preventDefault(); finish(false); }
|
|
38
54
|
});
|
|
39
55
|
input.addEventListener("blur", function () { finish(true); });
|
|
56
|
+
header.addEventListener('clay-pane-retarget', function cancel() { finish(false); header.removeEventListener('clay-pane-retarget', cancel); });
|
|
40
57
|
input.addEventListener("click", function (event) { event.stopPropagation(); });
|
|
41
58
|
}
|
|
42
59
|
|
|
@@ -73,33 +90,97 @@ export function createSplitPane(pane, closePane) {
|
|
|
73
90
|
var vendorIcon = document.createElement("img"); vendorIcon.className = "split-pane-vendor";
|
|
74
91
|
vendorIcon.src = VENDOR_AVATARS[vendor] || VENDOR_AVATARS.claude; vendorIcon.alt = ""; vendorIcon.title = VENDOR_NAMES[vendor] || vendor; header.appendChild(vendorIcon);
|
|
75
92
|
var title = document.createElement("span"); title.className = "split-pane-title"; title.textContent = pane.title; title.title = "Rename session";
|
|
76
|
-
title.addEventListener("click", function () { startPaneRename(header, title,
|
|
93
|
+
title.addEventListener("click", function () { var current = sessionById(Number(paneEl.dataset.sessionId)); if (current) startPaneRename(header, title, { sessionId: current.id, title: current.title }); }); header.appendChild(title);
|
|
77
94
|
var frame = document.createElement("iframe"); frame.className = "split-pane-frame"; frame.dataset.projectSlug = pane.slug;
|
|
78
95
|
frame.dataset.sessionId = String(pane.sessionId); frame.src = paneUrl(pane); frame.title = pane.title;
|
|
96
|
+
frame.dataset.sessionOriginId = session && session.sessionOriginId || '';
|
|
97
|
+
header.addEventListener('pointerdown', function () { header.dataset.pointerSessionId = frame.dataset.sessionId; header.dataset.pointerBinding = headerBindingStamp(frame); });
|
|
98
|
+
header.addEventListener('click', function (event) {
|
|
99
|
+
if (frame.clayPane && (!livePaneBinding(frame) || event.detail && header.dataset.pointerBinding !== headerBindingStamp(frame))) {
|
|
100
|
+
event.preventDefault(); event.stopImmediatePropagation();
|
|
101
|
+
}
|
|
102
|
+
}, true);
|
|
103
|
+
['keydown', 'keyup'].forEach(function (name) {
|
|
104
|
+
header.addEventListener(name, function (event) {
|
|
105
|
+
var stamp = headerBindingStamp(frame);
|
|
106
|
+
if (name === 'keydown' && !event.repeat) header.dataset.keyBinding = stamp;
|
|
107
|
+
if (header.inert || header.dataset.keyBinding !== stamp) { event.preventDefault(); event.stopImmediatePropagation(); }
|
|
108
|
+
}, true);
|
|
109
|
+
});
|
|
79
110
|
var ctxChip = document.createElement("button"); ctxChip.type = "button"; ctxChip.className = "split-pane-context"; ctxChip.title = "Context usage";
|
|
80
111
|
ctxChip.innerHTML = '<span class="split-pane-context-bar"><span class="split-pane-context-fill"></span></span><span class="split-pane-context-label"></span>';
|
|
81
|
-
ctxChip.addEventListener("click", function () { if (frame.contentWindow) frame.contentWindow.postMessage({ type: "clay-pane-toggle-context" }, window.location.origin); }); header.appendChild(ctxChip);
|
|
112
|
+
ctxChip.addEventListener("click", function () { if (frame.contentWindow && (!frame.clayPane || livePaneBinding(frame))) frame.contentWindow.postMessage({ type: "clay-pane-toggle-context", paneBinding: frame.clayPane && frame.clayPane.identity().binding }, window.location.origin); }); header.appendChild(ctxChip);
|
|
82
113
|
var fullAccess = createPermissionControl("split-pane-full-access hidden", "Driver session permission mode");
|
|
83
|
-
updatePaneFullAccessButton(fullAccess, session); bindPermissionControl(fullAccess, function () { return permissionState(sessionById(
|
|
114
|
+
updatePaneFullAccessButton(fullAccess, session); bindPermissionControl(fullAccess, function () { return permissionState(sessionById(Number(paneEl.dataset.sessionId))); }); header.appendChild(fullAccess); header.insertBefore(fullAccess, ctxChip);
|
|
84
115
|
var close = document.createElement("button"); close.type = "button"; close.className = "split-pane-close"; close.title = "Close pane"; close.setAttribute("aria-label", "Close pane"); close.innerHTML = iconHtml("x");
|
|
85
116
|
close.dataset.sessionId = String(pane.sessionId); close.addEventListener("click", function () { closePane(Number(this.dataset.sessionId)); }); header.appendChild(close);
|
|
117
|
+
frame.addEventListener('clay-pane-ready', function () {
|
|
118
|
+
var id = Number(frame.dataset.requestedSessionId || frame.dataset.sessionId), current = sessionById(id);
|
|
119
|
+
var live = frame.clayPane && frame.clayPane.identity(), target = paneTarget(store.snap(), getCachedSessions(), id);
|
|
120
|
+
if (!current || !live || !live.ready || !samePaneTarget(target, live.binding) || live.sessionId !== id) return;
|
|
121
|
+
frame.dataset.sessionId = String(id); delete frame.dataset.requestedSessionId;
|
|
122
|
+
frame.dataset.sessionOriginId = live.binding.sessionOriginId;
|
|
123
|
+
updateSplitPaneMetadata(paneEl, { slug: frame.dataset.projectSlug, sessionId: id, title: current.title });
|
|
124
|
+
syncPairChrome(paneEl.parentNode, store.get('splitPanes'));
|
|
125
|
+
});
|
|
126
|
+
frame.addEventListener('clay-pane-activation-failed', function () {
|
|
127
|
+
var id = Number(frame.dataset.requestedSessionId || frame.dataset.sessionId);
|
|
128
|
+
var fallbackTarget = paneTarget(store.snap(), getCachedSessions(), id);
|
|
129
|
+
if (!fallbackTarget) { header.inert = true; return; }
|
|
130
|
+
frame.dataset.sessionOriginId = fallbackTarget.sessionOriginId;
|
|
131
|
+
frame.src = paneUrl({ slug: frame.dataset.projectSlug, sessionId: id });
|
|
132
|
+
frame.dataset.sessionId = String(id); delete frame.dataset.requestedSessionId;
|
|
133
|
+
});
|
|
86
134
|
paneEl.appendChild(header); paneEl.appendChild(frame); return paneEl;
|
|
87
135
|
}
|
|
88
136
|
|
|
89
137
|
export function updateSplitPaneMetadata(paneEl, pane) {
|
|
90
138
|
var session = sessionById(pane.sessionId); var header = paneEl.querySelector(".split-pane-header");
|
|
91
139
|
var title = paneEl.querySelector(".split-pane-title"); var frame = paneEl.querySelector(".split-pane-frame"); var vendor = paneEl.querySelector(".split-pane-vendor");
|
|
140
|
+
var live = frame && frame.clayPane && frame.clayPane.identity();
|
|
141
|
+
var retarget = frame && (Number(frame.dataset.sessionId) !== pane.sessionId || frame.dataset.sessionOriginId !== (session && session.sessionOriginId || '') || frame.clayPane && (!live || !live.ready));
|
|
142
|
+
if (retarget && header) {
|
|
143
|
+
header.dispatchEvent(new Event('clay-pane-retarget'));
|
|
144
|
+
header.inert = true;
|
|
145
|
+
header.title = 'Loading conversation';
|
|
146
|
+
if (title) { title.style.display = ''; title.textContent = 'Loading conversation'; }
|
|
147
|
+
if (vendor) vendor.hidden = true;
|
|
148
|
+
var permission = paneEl.querySelector('.split-pane-full-access');
|
|
149
|
+
if (permission) permission.classList.add('hidden');
|
|
150
|
+
resetPaneContextChip(paneEl);
|
|
151
|
+
}
|
|
152
|
+
if (frame && frame.clayPane && retarget) {
|
|
153
|
+
var target = paneTarget(store.snap(), getCachedSessions(), pane.sessionId);
|
|
154
|
+
if (target && frame.clayPane.source === frame.contentWindow && frame.clayPane.document === frame.contentDocument && frame.clayPane.activate(pane.sessionId, false, target)) {
|
|
155
|
+
frame.dataset.requestedSessionId = String(pane.sessionId);
|
|
156
|
+
if (header) header.inert = true;
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
frame.src = paneUrl(pane);
|
|
160
|
+
frame.dataset.sessionId = String(pane.sessionId); frame.dataset.projectSlug = pane.slug;
|
|
161
|
+
frame.dataset.sessionOriginId = session && session.sessionOriginId || '';
|
|
162
|
+
}
|
|
163
|
+
if (header) header.inert = false;
|
|
92
164
|
paneEl.dataset.sessionId = String(pane.sessionId); paneEl.dataset.projectSlug = pane.slug;
|
|
93
165
|
if (header) header.title = pane.title; if (title && title.style.display !== "none") title.textContent = pane.title; if (frame) frame.title = pane.title;
|
|
94
|
-
if (vendor) { var vendorName = session && session.vendor || "claude"; vendor.src = VENDOR_AVATARS[vendorName] || VENDOR_AVATARS.claude; vendor.title = VENDOR_NAMES[vendorName] || vendorName; }
|
|
166
|
+
if (vendor) { vendor.hidden = false; var vendorName = session && session.vendor || "claude"; vendor.src = VENDOR_AVATARS[vendorName] || VENDOR_AVATARS.claude; vendor.title = VENDOR_NAMES[vendorName] || vendorName; }
|
|
167
|
+
updatePaneFullAccessButton(paneEl.querySelector('.split-pane-full-access'), session);
|
|
95
168
|
var close = paneEl.querySelector(".split-pane-close");
|
|
96
169
|
if (close) {
|
|
97
170
|
close.dataset.sessionId = String(pane.sessionId); close.disabled = false; close.title = "Close pane"; close.setAttribute("aria-label", close.title);
|
|
98
171
|
}
|
|
99
172
|
}
|
|
100
173
|
|
|
174
|
+
function resetPaneContextChip(paneEl) {
|
|
175
|
+
var chip = paneEl.querySelector('.split-pane-context'); if (!chip) return;
|
|
176
|
+
chip.classList.remove('has-data'); chip.title = 'Context usage';
|
|
177
|
+
var fill = chip.querySelector('.split-pane-context-fill'), label = chip.querySelector('.split-pane-context-label');
|
|
178
|
+
if (fill) { fill.style.width = '0%'; fill.className = 'split-pane-context-fill'; }
|
|
179
|
+
if (label) label.textContent = '';
|
|
180
|
+
}
|
|
181
|
+
|
|
101
182
|
export function updatePaneContextChip(paneEl, msg) {
|
|
102
|
-
if (!paneEl) return; var chip = paneEl.querySelector(".split-pane-context"); if (!chip) return; var pct = msg.pct || 0; if (pct <= 0) return;
|
|
183
|
+
if (!paneEl) return; var chip = paneEl.querySelector(".split-pane-context"); if (!chip) return; var pct = msg.pct || 0; if (pct <= 0) { resetPaneContextChip(paneEl); return; }
|
|
103
184
|
chip.classList.add("has-data"); var fill = chip.querySelector(".split-pane-context-fill"); var label = chip.querySelector(".split-pane-context-label");
|
|
104
185
|
fill.style.width = Math.min(100, pct).toFixed(1) + "%"; fill.className = "split-pane-context-fill" + (msg.cls || ""); label.textContent = pct.toFixed(0) + "%";
|
|
105
186
|
var tip = "Context " + pct.toFixed(0) + "% (" + formatTokens(msg.used || 0) + " / " + formatTokens(msg.win || 0) + " tokens)";
|
|
@@ -2,7 +2,7 @@ import { store } from './store.js';
|
|
|
2
2
|
import { isProjectSessionReady } from './project-activation.js';
|
|
3
3
|
|
|
4
4
|
export function isCurrentProjectSessionReady(state, socket) {
|
|
5
|
-
return isProjectSessionReady(state, socket);
|
|
5
|
+
return socket !== state.splitIdentityBlockedSocket && isProjectSessionReady(state, socket);
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export function clearProjectSplitState() {
|