clay-server 5.2.0-beta.1 → 5.2.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -4
- package/lib/account-auth-socket.js +1 -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 +52 -0
- package/lib/clay-product-control.js +250 -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-vendor-usage.js +44 -0
- 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 +78 -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/github-star-count.js +147 -0
- 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/notes-checklist.js +92 -0
- package/lib/notes.js +51 -4
- 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-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 +40 -11
- 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 +160 -290
- package/lib/project-shared-browser.js +78 -17
- package/lib/project-start-protocol.js +29 -0
- package/lib/project-studio-presentation.js +58 -0
- package/lib/project-user-message.js +67 -1
- package/lib/project-vendor-login.js +8 -36
- package/lib/project-workspace-operations.js +126 -0
- package/lib/project-workspace-query.js +19 -2
- package/lib/project.js +181 -45
- package/lib/public/app.js +71 -17
- package/lib/public/appearance-bootstrap.js +16 -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/filebrowser.css +1 -1
- 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/mate-loading-scene.css +21 -0
- package/lib/public/css/messages.css +6 -2
- package/lib/public/css/overlays.css +68 -258
- package/lib/public/css/project-admin-overview.css +13 -0
- package/lib/public/css/project-mate-creation.css +5 -6
- package/lib/public/css/project-start.css +108 -0
- package/lib/public/css/projects-hub.css +53 -14
- package/lib/public/css/session-folders.css +11 -0
- package/lib/public/css/session-github.css +46 -1
- package/lib/public/css/settings-shell.css +103 -0
- package/lib/public/css/shared-browser.css +35 -1
- package/lib/public/css/sidebar.css +7 -0
- package/lib/public/css/sticky-notes.css +87 -1
- package/lib/public/css/title-bar.css +79 -0
- package/lib/public/index.html +61 -68
- 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/admin-settings-invitations.js +2 -2
- package/lib/public/modules/admin-settings-projects.js +8 -4
- package/lib/public/modules/admin-settings-ui.js +20 -4
- package/lib/public/modules/admin-settings-users.js +4 -4
- 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-home-hub.js +2 -1
- 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 +125 -19
- 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 +14 -407
- package/lib/public/modules/app-rate-limit.js +19 -28
- 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 +343 -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 +252 -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/github-star.js +66 -0
- 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-loading-scene.js +17 -0
- 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/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 +12 -241
- 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 +3 -0
- package/lib/public/modules/project-mate-creation-workspace.js +13 -4
- package/lib/public/modules/project-mate-navigation.js +144 -22
- package/lib/public/modules/project-session-visibility-settings.js +19 -16
- package/lib/public/modules/project-settings.js +119 -129
- package/lib/public/modules/project-start-dialog.js +130 -0
- package/lib/public/modules/project-start-folder-state.js +78 -0
- package/lib/public/modules/project-start-folder-view.js +190 -0
- package/lib/public/modules/project-start-forms.js +66 -0
- package/lib/public/modules/project-start-path.js +60 -0
- package/lib/public/modules/project-start-state.js +54 -0
- package/lib/public/modules/project-start-submit.js +67 -0
- package/lib/public/modules/projects-hub-view.js +33 -14
- package/lib/public/modules/projects-hub.js +10 -6
- 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.js +36 -91
- 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/settings-project-target.js +56 -0
- package/lib/public/modules/settings-select.js +1 -1
- package/lib/public/modules/settings-shell-registry.js +88 -0
- package/lib/public/modules/settings-shell-view.js +104 -0
- package/lib/public/modules/settings-shell.js +342 -0
- 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 +12 -33
- package/lib/public/modules/sidebar-projects.js +3 -1
- 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 +18 -3
- 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-appearance.js +10 -3
- package/lib/public/modules/user-settings-editors.js +1 -1
- package/lib/public/modules/user-settings-layout.js +14 -30
- package/lib/public/modules/user-settings-preferences.js +6 -2
- package/lib/public/modules/user-settings-profile.js +13 -3
- package/lib/public/modules/user-settings.js +18 -84
- 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/vendor-usage-format.js +93 -0
- package/lib/public/modules/vendor-usage-list.js +45 -0
- package/lib/public/modules/vendor-usage-model.js +215 -0
- package/lib/public/modules/vendor-usage-overview.js +312 -0
- package/lib/public/modules/wireframe-workbench.js +5 -2
- package/lib/public/muse-avatar.svg +4 -0
- package/lib/public/style.css +14 -6
- package/lib/public/sw.js +3 -1
- package/lib/public/welcome-art/conversation-desk.png +0 -0
- package/lib/public/welcome-art/mate-clay.png +0 -0
- package/lib/public/welcome-art/project-clay.png +0 -0
- 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 +348 -402
- package/lib/sdk-foreground-admission.js +16 -0
- package/lib/sdk-mcp-descriptors.js +2 -37
- package/lib/sdk-message-processor.js +61 -18
- package/lib/sdk-quota-snapshot.js +21 -3
- package/lib/sdk-response-recovery.js +1 -0
- package/lib/sdk-worker.js +2 -677
- package/lib/server-admin.js +63 -16
- package/lib/server-appearance-settings.js +13 -1
- 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-github-stars.js +39 -0
- package/lib/server-global-ws.js +26 -32
- 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 +6 -1
- package/lib/server.js +167 -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-notes-mcp-server.js +26 -4
- package/lib/session-notes-writes.js +88 -0
- package/lib/session-permission-mode.js +4 -3
- package/lib/session-skill-scope.js +11 -0
- package/lib/session-visibility.js +25 -10
- package/lib/session-work-primary.js +50 -0
- package/lib/sessions.js +66 -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/users-contextual-clay-preferences.js +31 -0
- package/lib/users-permissions.js +2 -8
- package/lib/users.js +7 -0
- package/lib/vendor-login-browser.js +1 -11
- package/lib/vendor-usage-acp-readers.js +97 -0
- package/lib/vendor-usage-capabilities.js +88 -0
- package/lib/vendor-usage-http-readers.js +214 -0
- package/lib/vendor-usage-metrics.js +47 -0
- package/lib/vendor-usage-native-readers.js +106 -0
- package/lib/vendor-usage-overview.js +406 -0
- package/lib/vendor-usage-service.js +281 -0
- 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 +22 -4
- 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 +66 -50
- package/lib/yoke/adapters/codex-query-contract.js +25 -0
- package/lib/yoke/adapters/codex.js +98 -123
- 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 +272 -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-dynamic-tool-names.js +80 -0
- package/lib/yoke/codex-idle-recovery.js +81 -1
- package/lib/yoke/codex-model-catalog.js +37 -3
- 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 +92 -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 +34 -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 +87 -3
- package/package.json +11 -4
- package/lib/public/modules/server-settings-navigation.js +0 -39
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
import { contextualFrame } from './contextual-mate-identity.js';
|
|
4
|
+
|
|
5
|
+
function identity(frame) {
|
|
6
|
+
try { return frame && frame.conversation && frame.conversation.identity(); } catch (error) { return null; }
|
|
7
|
+
}
|
|
8
|
+
function contextKey(frame, canonical) {
|
|
9
|
+
var current = identity(frame);
|
|
10
|
+
return JSON.stringify([store.get('currentSlug'), store.get('activeSessionId'), store.get('sessionOriginId'), store.get('activeProjectSlug'), store.get('sessionActivatedProjectSlug'), store.get('replayingHistory'), (store.get('contextualClay') || {}).mode, store.get('homeShellVisible'), store.get('projectsHubVisible'), store.get('dmMode'), store.get('rightWorkbenchOwner'), store.get('homeSubSurface'), store.get('rightWorkbenchRevision'), store.get('myUserId'), store.get('connected'), current && current.mateId, current && current.sessionId, current && (canonical ? current.connected : current.ready), canonical && current && current.sessionOriginId]);
|
|
11
|
+
}
|
|
12
|
+
export function updateMateContext(surface, mate, frame, snapshot) {
|
|
13
|
+
var current = identity(frame), ws = getWs(), key = contextKey(frame, mate && mate.builtinKey === 'clay'), prepared = store.get('contextualPrepared');
|
|
14
|
+
var canonical = mate && mate.builtinKey === 'clay';
|
|
15
|
+
var capabilities = surface.querySelector('.contextual-capabilities');
|
|
16
|
+
capabilities.hidden = !canonical;
|
|
17
|
+
capabilities.setAttribute('aria-label', 'Clay capabilities');
|
|
18
|
+
capabilities.textContent = "I can control Clay Studio for you—manage projects, coordinate work, set up schedules, and navigate your workspace. Just tell me what you’d like done.";
|
|
19
|
+
var privateWorkspace = (store.get('currentSlug') || '').indexOf('mate-') === 0;
|
|
20
|
+
var parentReady = store.get('activeProjectSlug') === store.get('currentSlug') && store.get('sessionActivatedProjectSlug') === store.get('currentSlug') && !store.get('replayingHistory');
|
|
21
|
+
var available = (store.get('contextualClay') || {}).mode === 'popover' && parentReady && !canonical && !privateWorkspace && current && current.ready && store.get('connected') && !store.get('homeShellVisible') && !store.get('projectsHubVisible') && !store.get('dmMode') && !store.get('rightWorkbenchOwner') && ws && ws.readyState === 1;
|
|
22
|
+
var changed = !prepared || prepared.key !== key || prepared.socket !== ws;
|
|
23
|
+
if (changed) {
|
|
24
|
+
var requestId = 'context-' + crypto.randomUUID();
|
|
25
|
+
prepared = { key: key, requestId: requestId, socket: ws, mateId: current && current.mateId, canonical: !!canonical, status: available ? 'preparing' : 'unavailable' };
|
|
26
|
+
}
|
|
27
|
+
// Stamp the reference before publishing a new preparation: store subscribers
|
|
28
|
+
// may render synchronously, and the composer must never see the prior view ID.
|
|
29
|
+
snapshot = Object.assign({}, snapshot, { viewId: prepared.requestId });
|
|
30
|
+
surface.dataset.screenReference = JSON.stringify(snapshot);
|
|
31
|
+
if (changed) {
|
|
32
|
+
store.set({ contextualPrepared: prepared });
|
|
33
|
+
if (ws && ws.readyState === 1) ws.send(JSON.stringify({ type: 'mate_context_prepare', requestId: requestId, available: !!available, mateId: current && current.mateId, sessionId: current && current.sessionId }));
|
|
34
|
+
}
|
|
35
|
+
var shared = ((store.get('contextualSubmitted') || {})[mate && mate.id]);
|
|
36
|
+
var ready = prepared.status === 'ready' && prepared.expiresAt > Date.now();
|
|
37
|
+
var label = surface.querySelector('[data-clay-context]');
|
|
38
|
+
var detail = surface.querySelector('.contextual-clay-context p');
|
|
39
|
+
var summary = ready ? prepared.summary.project + ' / ' + prepared.summary.conversation : null;
|
|
40
|
+
var projectName = (ready && prepared.summary.project) || snapshot.projectTitle || snapshot.screen || 'Current view';
|
|
41
|
+
if (canonical) {
|
|
42
|
+
var currentSummary = (snapshot.projectTitle || snapshot.screen || 'Current view') + (snapshot.conversationTitle ? ' / ' + snapshot.conversationTitle : '');
|
|
43
|
+
var disconnected = !store.get('connected') || current && current.connected === false;
|
|
44
|
+
var sameSnapshot = shared && shared.viewId === prepared.requestId && shared.summary.project + (snapshot.conversationTitle ? ' / ' + shared.summary.conversation : '') === currentSummary;
|
|
45
|
+
var contextStatus = disconnected ? 'Disconnected' : current && current.available === false ? 'Unavailable' : !current || !current.ready ? 'Preparing' : sameSnapshot ? 'Shared' : shared ? 'New view' : 'Next message';
|
|
46
|
+
detail.textContent = "I can help manage your projects, coordinate work with Drivers, and use Studio’s tools. I’ll ask you to review actions when needed.\n"
|
|
47
|
+
+ 'Current view: ' + currentSummary + '. ' + (disconnected ? 'Reconnect before sharing a new snapshot. ' : !current || !current.ready ? 'Wait for this conversation before sharing a new snapshot. ' : sameSnapshot ? 'This metadata snapshot was shared with your last message. Your next message captures the current view again. ' : 'Your next message includes this metadata snapshot. ')
|
|
48
|
+
+ 'Clay receives project and conversation metadata, not continuous screen capture. Its authenticated product tools inspect supported objects separately; changes require their existing review.';
|
|
49
|
+
} else {
|
|
50
|
+
contextStatus = !store.get('connected') || current && current.connected === false ? 'Disconnected' : current && current.available === false ? 'Unavailable' : current && !current.ready || prepared.status === 'preparing' ? 'Preparing' : ready ? (shared && shared.viewId === prepared.requestId ? 'Shared' : shared ? 'New view' : 'Next message') : 'Unavailable';
|
|
51
|
+
detail.textContent = ready ? (shared && shared.viewId === prepared.requestId ? 'Shared with your last message: ' : 'With your next message: ') + summary + '. This Mate can read up to 20 text turns from this selected conversation and request to open it in this window after your review. Tool results, attachments and hidden entries are excluded.' : 'Current view: ' + projectName + '. This view has no supported conversation context. Open an accessible project conversation to share it with your next message.';
|
|
52
|
+
detail.textContent += '\nNo continuous screen capture. Issues, documents, other tabs, files and settings are unavailable through this context.';
|
|
53
|
+
}
|
|
54
|
+
if (prepared.status === 'expired' && !canonical) { contextStatus = 'Expired'; detail.textContent = 'This five-minute context has expired. Close and reopen this Mate to prepare a fresh snapshot. No previous navigation request will replay.'; }
|
|
55
|
+
if (shared) detail.textContent += '\nLast submitted: ' + shared.summary.project + ' / ' + shared.summary.conversation + ((canonical ? sameSnapshot : shared.viewId === prepared.requestId) ? '.' : canonical ? '. The view or connection has changed; that snapshot is stale.' : '. Your view has changed; that context is stale.');
|
|
56
|
+
var projectLabel = label.querySelector('[data-context-project]');
|
|
57
|
+
if (!projectLabel) { projectLabel = document.createElement('span'); projectLabel.dataset.contextProject = ''; var statusLabel = document.createElement('span'); statusLabel.dataset.contextStatus = ''; label.replaceChildren(projectLabel, statusLabel); }
|
|
58
|
+
projectLabel.textContent = projectName;
|
|
59
|
+
label.querySelector('[data-context-status]').textContent = ' · ' + contextStatus;
|
|
60
|
+
label.title = label.textContent;
|
|
61
|
+
surface.contextReference = function (source, session) {
|
|
62
|
+
var live = store.get('contextualPrepared');
|
|
63
|
+
if (!frame || frame.hidden || frame.contentWindow !== source || !session || !current || session.mateId !== current.mateId || session.sessionId !== current.sessionId || !session.ready || !live || live.key !== contextKey(frame, canonical) || live.socket !== getWs() || live.status !== 'ready' || live.expiresAt <= Date.now()) return null;
|
|
64
|
+
return live.contextRef;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function handleMateContextMessage(msg) {
|
|
68
|
+
if (msg.type === 'mate_context_prepared') {
|
|
69
|
+
var pending = store.get('contextualPrepared');
|
|
70
|
+
if (pending && pending.requestId === msg.requestId && pending.socket === getWs() && pending.key === contextKey(contextualFrame(), pending.canonical)) {
|
|
71
|
+
store.set({ contextualPrepared: Object.assign({}, pending, msg, { status: msg.contextRef ? 'ready' : 'unavailable' }) });
|
|
72
|
+
if (msg.contextRef) setTimeout(function () {
|
|
73
|
+
var current = store.get('contextualPrepared');
|
|
74
|
+
if (current && current.contextRef === msg.contextRef) store.set({ contextualPrepared: Object.assign({}, current, { status: 'expired' }) });
|
|
75
|
+
}, Math.max(0, msg.expiresAt - Date.now()));
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
if ((msg.type === 'message_ack' || msg.type === 'user_message') && window.parent !== window && window.frameElement && window.frameElement.dataset.canonical === 'true') {
|
|
80
|
+
var recorded = msg.type === 'message_ack' ? msg.message : msg;
|
|
81
|
+
var outbound = (store.get('contextualSnapshotSubmissions') || []).find(function (item) { return item.clientMessageId === msg.clientMessageId; });
|
|
82
|
+
if (!outbound || outbound.confirmed || outbound.accountId !== (store.get('myUserId') || '_default') || !recorded || recorded.clientMessageId !== outbound.clientMessageId || !recorded.contextualSnapshot || msg.type === 'message_ack' && (msg.projectSlug !== outbound.projectSlug || String(msg.sessionId) !== String(outbound.sessionId)) || recorded.projectSlug !== outbound.projectSlug || String(recorded.sessionId) !== String(outbound.sessionId) || recorded.sessionOriginId !== outbound.sessionOriginId || recorded.from && recorded.from !== outbound.accountId || JSON.stringify(recorded.contextualSnapshot) !== JSON.stringify(outbound.snapshot)) return false;
|
|
83
|
+
var snapshot = recorded.contextualSnapshot;
|
|
84
|
+
store.set({ contextualSnapshotSubmissions: store.get('contextualSnapshotSubmissions').map(function (item) { return item === outbound ? Object.assign({}, item, { confirmed: true }) : item; }) });
|
|
85
|
+
try {
|
|
86
|
+
var host = window.parent.document.getElementById('contextual-clay');
|
|
87
|
+
if (host) host.dispatchEvent(new window.parent.CustomEvent('contextual-context-submitted', { detail: { source: window, message: { status: 'submitted', canonical: true, clientMessageId: msg.clientMessageId, viewId: snapshot.viewId, summary: { project: snapshot.projectTitle || snapshot.projectSlug || 'Home', conversation: snapshot.conversationTitle || snapshot.screen } } } }));
|
|
88
|
+
} catch (error) { /* A disconnected authentication view cannot share metadata. */ }
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
if (msg.type !== 'mate_context_shared') return false;
|
|
92
|
+
try {
|
|
93
|
+
var surface = window.parent.document.getElementById('contextual-clay');
|
|
94
|
+
if (surface && window.frameElement && surface.contains(window.frameElement)) surface.dispatchEvent(new window.parent.CustomEvent('contextual-context-submitted', { detail: { source: window, message: msg } }));
|
|
95
|
+
} catch (error) { /* A disconnected authentication view cannot share context. */ }
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
export function recordMateContextSubmission(surface, event) {
|
|
99
|
+
var frame = Array.from(surface.querySelectorAll('iframe')).find(function (item) { return item.contentWindow === event.detail.source; });
|
|
100
|
+
var pending = store.get('contextualPrepared'), msg = event.detail.message;
|
|
101
|
+
if (!frame || frame.dataset.ownerId !== (store.get('myUserId') || '') || (!msg.canonical && frame.hidden) || !pending) return;
|
|
102
|
+
if (msg.status === 'unavailable') {
|
|
103
|
+
if (pending.mateId === frame.dataset.mateId) store.set({ contextualPrepared: Object.assign({}, pending, { status: 'unavailable' }) });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (msg.status !== 'submitted' || !msg.summary || (msg.canonical ? frame.dataset.canonical !== 'true' || typeof msg.viewId !== 'string' : msg.contextRef !== pending.contextRef)) return;
|
|
107
|
+
var submitted = Object.assign({}, store.get('contextualSubmitted'));
|
|
108
|
+
submitted[frame.dataset.mateId] = { key: msg.canonical ? null : pending.key, viewId: msg.canonical ? msg.viewId : pending.requestId, summary: msg.summary };
|
|
109
|
+
store.set({ contextualSubmitted: submitted });
|
|
110
|
+
}
|
|
111
|
+
export function contextualAccessReference() {
|
|
112
|
+
if (window.parent === window || !store.get('paneMode')) return null;
|
|
113
|
+
try {
|
|
114
|
+
var surface = window.parent.document.getElementById('contextual-clay');
|
|
115
|
+
return surface && surface.contextReference && surface.contextReference(window, { mateId: window.frameElement.dataset.mateId, sessionId: store.get('paneSessionId'), ready: store.get('contextualSessionReady') && store.get('connected') });
|
|
116
|
+
} catch (error) { return null; }
|
|
117
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { contextualMate, contextualTrigger } from './contextual-mate-identity.js';
|
|
3
|
+
import { getHomeMateName } from './home-mate-selection.js';
|
|
4
|
+
|
|
5
|
+
export function renderContextualMateHint() {
|
|
6
|
+
var state = store.get('contextualClay') || {};
|
|
7
|
+
var mate = contextualMate(state.mateId);
|
|
8
|
+
var active = state.mode === 'popover' && mate;
|
|
9
|
+
var narrow = window.matchMedia('(max-width: 768px)').matches;
|
|
10
|
+
var moved = document.querySelector('.contextual-mate-mobile-trigger');
|
|
11
|
+
if (moved && (!active || !narrow || moved.dataset.mateId !== mate.id)) {
|
|
12
|
+
moved.classList.remove('contextual-mate-mobile-trigger');
|
|
13
|
+
document.getElementById('icon-strip-projects').appendChild(moved);
|
|
14
|
+
}
|
|
15
|
+
var anchor = active && contextualTrigger(mate.id);
|
|
16
|
+
if (anchor && narrow && mate.builtinKey !== 'clay') {
|
|
17
|
+
anchor.classList.add('contextual-mate-mobile-trigger'); if (anchor.parentNode !== document.body) document.body.appendChild(anchor);
|
|
18
|
+
}
|
|
19
|
+
document.body.classList.toggle('contextual-mate-hint-mobile', !!active && narrow);
|
|
20
|
+
document.body.classList.toggle('contextual-mate-ordinary-mobile', !!active && narrow && mate.builtinKey !== 'clay');
|
|
21
|
+
document.querySelectorAll('[aria-describedby="contextual-mate-hint"]').forEach(function (item) { if (item !== anchor) item.removeAttribute('aria-describedby'); });
|
|
22
|
+
var hint = document.getElementById('contextual-mate-hint');
|
|
23
|
+
if (!hint || !active || !anchor || !anchor.getClientRects().length) { if (hint) hint.hidden = true; return null; }
|
|
24
|
+
anchor.setAttribute('aria-describedby', hint.id);
|
|
25
|
+
var name = getHomeMateName(mate);
|
|
26
|
+
hint.textContent = (window.matchMedia('(pointer: coarse)').matches ? 'Tap' : 'Click') + ' again to open ' + name;
|
|
27
|
+
hint.title = hint.textContent;
|
|
28
|
+
hint.setAttribute('aria-label', 'Open ' + name + ' workspace');
|
|
29
|
+
hint.hidden = false;
|
|
30
|
+
var rect = anchor.getBoundingClientRect();
|
|
31
|
+
hint.style.maxWidth = (narrow ? window.innerWidth - 64 : Math.min(260, window.innerWidth - rect.right - 24)) + 'px';
|
|
32
|
+
hint.style.left = (narrow ? 50 : rect.right + 8) + 'px';
|
|
33
|
+
hint.style.top = (narrow ? 8 : Math.max(8, Math.min(window.innerHeight - 38, rect.top + (rect.height - 28) / 2))) + 'px';
|
|
34
|
+
return hint.getBoundingClientRect();
|
|
35
|
+
}
|
|
36
|
+
export function initContextualMateHint(activate) {
|
|
37
|
+
var hint = document.createElement('button'); hint.type = 'button'; hint.id = 'contextual-mate-hint'; hint.hidden = true;
|
|
38
|
+
hint.addEventListener('click', function () { activate((store.get('contextualClay') || {}).mateId); });
|
|
39
|
+
document.body.appendChild(hint);
|
|
40
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
|
|
3
|
+
export function contextualMate(id) {
|
|
4
|
+
var mate = (store.get('cachedMatesList') || []).find(function (item) { return item && item.id === id; });
|
|
5
|
+
if (!mate || mate.archived || mate.contentAccess === false || mate.accessible === false) return null;
|
|
6
|
+
var owner = store.get('myUserId');
|
|
7
|
+
if (owner && mate.createdBy && mate.createdBy !== owner) return null;
|
|
8
|
+
var project = (store.get('projectsHubList') || []).find(function (item) { return item.slug === 'mate-' + id; });
|
|
9
|
+
if (project && project.contentAccess === false) return null;
|
|
10
|
+
return mate;
|
|
11
|
+
}
|
|
12
|
+
export function contextualMateStamp(mate) { return JSON.stringify([mate.id, mate.createdBy || null, mate.createdAt || null, mate.builtinKey || null]); }
|
|
13
|
+
export function contextualFrame(id, sessionId) {
|
|
14
|
+
var mateId = id || (store.get('contextualClay') || {}).mateId;
|
|
15
|
+
var current = store.get('contextualClay') || {};
|
|
16
|
+
if (!sessionId && current.mateId === mateId && current.startingAsk) return null;
|
|
17
|
+
var selected = sessionId || (current.mateId === mateId && current.sessionId) || (store.get('contextualSessionSelection') || {})[mateId];
|
|
18
|
+
return Array.from(document.querySelectorAll('#contextual-clay iframe')).find(function (frame) { return frame.dataset.mateId === mateId && (!selected || String(selected) === frame.dataset.sessionId); }) || null;
|
|
19
|
+
}
|
|
20
|
+
export function contextualTrigger(id) {
|
|
21
|
+
var mate = contextualMate(id || (store.get('contextualClay') || {}).mateId);
|
|
22
|
+
return mate && mate.builtinKey !== 'clay' ? document.querySelector('.icon-strip-project-mate[data-mate-id="' + CSS.escape(mate.id) + '"]') : document.querySelector('.icon-strip-brand');
|
|
23
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// Saved conversations are independent of which compact renderers are mounted.
|
|
2
|
+
import { store } from './store.js';
|
|
3
|
+
import { getWs } from './ws-ref.js';
|
|
4
|
+
import { contextualMate, contextualMateStamp, contextualFrame } from './contextual-mate-identity.js';
|
|
5
|
+
import { selectContextualConversation } from './contextual-clay.js';
|
|
6
|
+
import { pauseContextualSearchForSelection } from './contextual-search.js';
|
|
7
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
8
|
+
import { showToast } from './utils.js';
|
|
9
|
+
|
|
10
|
+
function selection() { var value = store.get('contextualClay') || {}; return JSON.stringify([value.mateId, value.sessionId, value.startingAsk]); }
|
|
11
|
+
function host() { return document.getElementById('contextual-clay'); }
|
|
12
|
+
function requestState(kind) { return store.get(kind === 'list' ? 'contextualConversationHistory' : 'contextualConversationRequest'); }
|
|
13
|
+
function save(kind, value) { var update = {}; update[kind === 'list' ? 'contextualConversationHistory' : 'contextualConversationRequest'] = value; store.set(update); }
|
|
14
|
+
function valid(request) { var mate = request && contextualMate(request.mateId); return request && request.ownerId === store.get('myUserId') && mate && contextualMateStamp(mate) === request.stamp; }
|
|
15
|
+
function guardDraft() {
|
|
16
|
+
var frame = contextualFrame();
|
|
17
|
+
try {
|
|
18
|
+
if (frame && frame.conversation) frame.conversation.checkDraft();
|
|
19
|
+
return true;
|
|
20
|
+
} catch (error) { showToast(error.message, 'warn'); return false; }
|
|
21
|
+
}
|
|
22
|
+
function send(kind, item, lookup) {
|
|
23
|
+
var mate = contextualMate((store.get('contextualClay') || {}).mateId), socket = getWs();
|
|
24
|
+
if (!mate) return;
|
|
25
|
+
var old = requestState(kind);
|
|
26
|
+
if (kind !== 'list' && old && old.status === 'loading') { showToast('Wait for the current conversation request to finish.', 'warn'); return; }
|
|
27
|
+
if (kind !== 'list' && !guardDraft()) return;
|
|
28
|
+
var request = lookup ? Object.assign({}, old) : { requestId: 'mate-conversations-' + crypto.randomUUID(), mateId: mate.id, stamp: contextualMateStamp(mate), ownerId: store.get('myUserId'), selection: selection(), kind: kind, item: item };
|
|
29
|
+
if (!valid(request)) return;
|
|
30
|
+
request.status = 'loading'; request.error = null; request.socket = socket;
|
|
31
|
+
save(kind, request);
|
|
32
|
+
if (!store.get('connected') || !socket || socket.readyState !== 1) { save(kind, Object.assign({}, request, { status: 'error', error: 'Reconnect to load or start a conversation.' })); return; }
|
|
33
|
+
var payload = { type: kind === 'list' ? 'home_mate_sessions_list' : kind === 'new' ? 'home_mate_new_session' : 'home_mate_session_open', presentation: 'contextual', mateId: request.mateId, mateStamp: request.stamp, requestId: request.requestId };
|
|
34
|
+
if (item) { payload.sessionId = item.id; payload.sessionOriginId = item.sessionOriginId; }
|
|
35
|
+
if (lookup && kind === 'new') payload.lookupOnly = true;
|
|
36
|
+
try { socket.send(JSON.stringify(payload)); }
|
|
37
|
+
catch (error) { save(kind, Object.assign({}, request, { status: 'error', error: 'The request is unconfirmed. Check again after reconnecting.' })); }
|
|
38
|
+
setTimeout(function () {
|
|
39
|
+
var current = requestState(kind);
|
|
40
|
+
if (current && current.requestId === request.requestId && current.status === 'loading') save(kind, Object.assign({}, current, { status: 'error', error: kind === 'new' ? 'Creation is unconfirmed. Check the same request or browse history.' : 'Conversation history did not respond. Try again.' }));
|
|
41
|
+
}, 15000);
|
|
42
|
+
}
|
|
43
|
+
function age(timestamp) {
|
|
44
|
+
if (!timestamp) return '';
|
|
45
|
+
var date = new Date(timestamp), today = new Date();
|
|
46
|
+
return date.toDateString() === today.toDateString() ? 'Today' : date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
|
|
47
|
+
}
|
|
48
|
+
function render() {
|
|
49
|
+
var surface = host(); if (!surface) return;
|
|
50
|
+
var mateId = (store.get('contextualClay') || {}).mateId;
|
|
51
|
+
var request = requestState('action'), history = requestState('list');
|
|
52
|
+
var busy = request && request.mateId === mateId && request.status === 'loading';
|
|
53
|
+
surface.querySelector('[data-mate-new]').disabled = !!busy;
|
|
54
|
+
surface.querySelector('[data-mate-new]').setAttribute('aria-busy', String(!!busy));
|
|
55
|
+
var notice = surface.querySelector('[data-conversation-notice]');
|
|
56
|
+
notice.hidden = !request || request.mateId !== mateId || request.status === 'done';
|
|
57
|
+
if (!notice.hidden) {
|
|
58
|
+
notice.querySelector('span').textContent = request.error || (request.kind === 'new' ? 'Starting a new chat…' : 'Opening conversation…');
|
|
59
|
+
notice.querySelector('button').hidden = request.status !== 'error';
|
|
60
|
+
notice.querySelector('button').textContent = request.kind === 'new' ? 'Check request' : 'Try again';
|
|
61
|
+
}
|
|
62
|
+
var list = surface.querySelector('[data-mate-session-list]');
|
|
63
|
+
if (!surface.querySelector('[data-mate-history]').open) return;
|
|
64
|
+
var key = JSON.stringify([history && history.requestId, history && history.status, history && history.error, mateId, (store.get('contextualClay') || {}).sessionId, !!busy]);
|
|
65
|
+
if (list.dataset.renderKey === key) return;
|
|
66
|
+
list.dataset.renderKey = key;
|
|
67
|
+
list.replaceChildren();
|
|
68
|
+
if (!history || history.mateId !== mateId || history.status !== 'done') {
|
|
69
|
+
var status = document.createElement('p'); status.setAttribute('role', 'status');
|
|
70
|
+
status.textContent = history && history.mateId === mateId && history.error || 'Loading conversations…'; list.appendChild(status);
|
|
71
|
+
if (history && history.status === 'error') { var retry = document.createElement('button'); retry.type = 'button'; retry.textContent = 'Try again'; retry.onclick = function () { send('list'); }; list.appendChild(retry); }
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!history.sessions.length) { var empty = document.createElement('p'); empty.textContent = 'No saved conversations yet.'; list.appendChild(empty); }
|
|
75
|
+
history.sessions.forEach(function (item) {
|
|
76
|
+
var button = document.createElement('button'); button.type = 'button'; button.dataset.sessionId = String(item.localId);
|
|
77
|
+
button.setAttribute('aria-current', String(String((store.get('contextualClay') || {}).sessionId) === String(item.localId)));
|
|
78
|
+
var title = document.createElement('span'); title.textContent = item.title || 'New conversation';
|
|
79
|
+
var detail = document.createElement('small'); detail.textContent = item.isProcessing ? 'Working' : age(item.lastActivity || item.createdAt);
|
|
80
|
+
button.append(title, detail); button.title = title.textContent; button.disabled = !!busy;
|
|
81
|
+
button.onclick = function () { send('open', item); };
|
|
82
|
+
list.appendChild(button);
|
|
83
|
+
});
|
|
84
|
+
if (history.truncated) { var limit = document.createElement('p'); limit.textContent = 'Showing the 500 most recent conversations.'; list.appendChild(limit); }
|
|
85
|
+
}
|
|
86
|
+
export function attachContextualConversations(surface) {
|
|
87
|
+
var actions = surface.querySelector('.contextual-clay-actions');
|
|
88
|
+
var tools = document.createElement('div'); tools.className = 'contextual-conversation-tools';
|
|
89
|
+
tools.innerHTML = '<button type="button" data-mate-new aria-label="New chat" title="New chat">' + iconHtml('square-pen') + '<span>New chat</span></button><details data-mate-history><summary role="button" aria-label="Conversation history" aria-haspopup="dialog" aria-expanded="false" aria-controls="contextual-conversation-history" title="Conversation history">' + iconHtml('history') + '</summary><div id="contextual-conversation-history" role="dialog" aria-label="Conversation history"><span class="contextual-history-label">Conversations</span><div data-mate-session-list></div></div></details>';
|
|
90
|
+
actions.prepend(tools);
|
|
91
|
+
var notice = document.createElement('div'); notice.dataset.conversationNotice = ''; notice.hidden = true;
|
|
92
|
+
notice.innerHTML = '<span role="status"></span><button type="button">Check request</button>';
|
|
93
|
+
surface.insertBefore(notice, surface.querySelector('.contextual-clay-body'));
|
|
94
|
+
tools.querySelector('[data-mate-new]').onclick = function () { send('new'); };
|
|
95
|
+
tools.querySelector('details').addEventListener('toggle', function () { this.querySelector('summary').setAttribute('aria-expanded', String(this.open)); if (this.open) send('list'); });
|
|
96
|
+
surface.addEventListener('pointerdown', function (event) { var menu = tools.querySelector('details'); if (menu.open && !menu.contains(event.target)) menu.open = false; });
|
|
97
|
+
|
|
98
|
+
notice.querySelector('button').onclick = function () { var value = requestState('action'); if (value) send(value.kind, value.item, true); };
|
|
99
|
+
tools.addEventListener('keydown', function (event) {
|
|
100
|
+
if (event.key === 'Tab') {
|
|
101
|
+
var menu = tools.querySelector('details'), items = Array.from(tools.querySelectorAll('[data-mate-session-list] button:not(:disabled)'));
|
|
102
|
+
if (menu.open && (event.shiftKey && event.target === menu.querySelector('summary') || !event.shiftKey && event.target === items[items.length - 1])) queueMicrotask(function () { menu.open = false; });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (!/^Arrow(Down|Up)$/.test(event.key)) return;
|
|
106
|
+
var buttons = Array.from(tools.querySelectorAll('[data-mate-session-list] button:not(:disabled)'));
|
|
107
|
+
if (!buttons.length) return;
|
|
108
|
+
var index = buttons.indexOf(document.activeElement);
|
|
109
|
+
buttons[index < 0 ? (event.key === 'ArrowDown' ? 0 : buttons.length - 1) : (index + (event.key === 'ArrowDown' ? 1 : buttons.length - 1)) % buttons.length].focus(); event.preventDefault();
|
|
110
|
+
});
|
|
111
|
+
refreshIcons(); render();
|
|
112
|
+
}
|
|
113
|
+
export function handleContextualConversations(msg) {
|
|
114
|
+
if (msg.type !== 'contextual_mate_sessions_result') return false;
|
|
115
|
+
var kind = requestState('list') && requestState('list').requestId === msg.requestId ? 'list' : 'action';
|
|
116
|
+
var request = requestState(kind);
|
|
117
|
+
if (!request || request.status !== 'loading' || request.requestId !== msg.requestId || request.socket !== getWs() || !valid(request) || msg.mateId !== request.mateId || msg.mateStamp !== request.stamp) return true;
|
|
118
|
+
if (!msg.ok) { save(kind, Object.assign({}, request, { status: 'error', error: msg.error || 'Conversation unavailable.' })); return true; }
|
|
119
|
+
if (kind === 'list') { save(kind, Object.assign({}, request, { status: 'done', sessions: msg.sessions || [], truncated: msg.truncated })); return true; }
|
|
120
|
+
if (!Number.isSafeInteger(msg.sessionId) || msg.sessionId <= 0 || typeof msg.sessionOriginId !== 'string') return true;
|
|
121
|
+
if (request.selection !== selection() || (store.get('contextualClay') || {}).mode !== 'popover') { save(kind, Object.assign({}, request, { status: 'error', error: 'Your selection changed. The conversation remains in history.' })); return true; }
|
|
122
|
+
if (!guardDraft()) { save(kind, Object.assign({}, request, { status: 'error', error: 'Finish uploading or recording, then check this conversation again.' })); return true; }
|
|
123
|
+
pauseContextualSearchForSelection();
|
|
124
|
+
if (!selectContextualConversation(contextualMate(request.mateId), msg.sessionId, msg.sessionOriginId)) { save(kind, Object.assign({}, request, { status: 'error', error: 'This conversation could not be opened. Your draft is retained.' })); return true; }
|
|
125
|
+
surfaceClose(true); save(kind, Object.assign({}, request, { status: 'done' })); return true;
|
|
126
|
+
}
|
|
127
|
+
function surfaceClose(restoreFocus) { var surface = host(); if (surface) { var menu = surface.querySelector('[data-mate-history]'); var focused = menu.contains(document.activeElement); menu.open = false; if (focused || restoreFocus) menu.querySelector('summary').focus({ preventScroll: true }); } }
|
|
128
|
+
store.subscribe(function (value, previous) {
|
|
129
|
+
if (value.paneMode) return;
|
|
130
|
+
if (value.myUserId !== previous.myUserId) { store.set({ contextualConversationHistory: null, contextualConversationRequest: null }); return; }
|
|
131
|
+
if ((value.contextualClay || {}).mateId !== (previous.contextualClay || {}).mateId) surfaceClose();
|
|
132
|
+
if (previous.connected && !value.connected) ['list', 'action'].forEach(function (kind) { var request = requestState(kind); if (request && request.status === 'loading') save(kind, Object.assign({}, request, { status: 'error', error: 'Disconnected. Check again when connected; your conversation is retained.' })); });
|
|
133
|
+
render();
|
|
134
|
+
});
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
import { activateContextualMate } from './project-mate-navigation.js';
|
|
4
|
+
import { contextualMate, contextualMateStamp, contextualFrame } from './contextual-mate-identity.js';
|
|
5
|
+
import { showContextualAsk, enterComposer } from './contextual-clay.js';
|
|
6
|
+
import { showToast } from './utils.js';
|
|
7
|
+
|
|
8
|
+
function current() { return store.get('contextualSearchAsk'); }
|
|
9
|
+
function view() { return JSON.stringify([store.get('myUserId'), store.get('currentSlug'), store.get('activeSessionId'), store.get('homeShellVisible'), store.get('homeSubSurface'), store.get('dmMode'), store.get('rightWorkbenchOwner'), store.get('rightWorkbenchRevision')]); }
|
|
10
|
+
function patch(change) { store.set({ contextualSearchAsk: Object.assign({}, current(), change) }); }
|
|
11
|
+
function live(request) {
|
|
12
|
+
var mate = contextualMate(request.mateId);
|
|
13
|
+
return request.ownerId === store.get('myUserId') && mate && mate.builtinKey === 'clay' && contextualMateStamp(mate) === request.stamp;
|
|
14
|
+
}
|
|
15
|
+
function sendCreation() {
|
|
16
|
+
var request = current(), ws = getWs();
|
|
17
|
+
if (!request || !live(request)) { patch({ status: 'error', error: 'Clay is unavailable. Your question is retained.' }); return; }
|
|
18
|
+
if (!store.get('connected') || !ws || ws.readyState !== 1) { patch({ status: 'error', error: 'Reconnect, then retry. Your question is retained.' }); return; }
|
|
19
|
+
patch({ status: 'creating', socket: ws, view: view(), error: null });
|
|
20
|
+
try { ws.send(JSON.stringify({ type: 'home_clay_ask', presentation: 'contextual', requestId: request.requestId, text: request.text, sessionOriginId: request.sessionOriginId || null })); }
|
|
21
|
+
catch (error) { patch({ status: 'error', error: 'Creation is unconfirmed. Retry checks the same request.' }); }
|
|
22
|
+
setTimeout(function () { if (current() && current().requestId === request.requestId && current().status === 'creating') patch({ status: 'error', error: 'Conversation creation is unconfirmed. Retry checks the same request.' }); }, 15000);
|
|
23
|
+
}
|
|
24
|
+
export function pauseContextualSearchForSelection() {
|
|
25
|
+
if (current() && /^(creating|opening)$/.test(current().status)) stop();
|
|
26
|
+
}
|
|
27
|
+
function stop(execution) {
|
|
28
|
+
var request = current(), frame = request && request.sessionId && contextualFrame(request.mateId, request.sessionId);
|
|
29
|
+
if (frame && frame.conversation) { if (execution === true) frame.conversation.stopAsk(); else frame.conversation.pauseAsk(); }
|
|
30
|
+
patch({ status: 'stopped', error: request && request.clientMessageId ? 'Automatic delivery is paused. Inspect the conversation to confirm whether work stopped.' : 'Stopped before submission. Your question is retained; it will not be submitted automatically.' });
|
|
31
|
+
}
|
|
32
|
+
function resume() {
|
|
33
|
+
var request = current();
|
|
34
|
+
if (!request || !live(request)) return;
|
|
35
|
+
if (request.clientMessageId) { showToast('Inspect this conversation before retrying an uncertain message.', 'warn'); return; }
|
|
36
|
+
showContextualAsk(contextualMate(request.mateId), request.requestId, request.sessionId);
|
|
37
|
+
sendCreation();
|
|
38
|
+
}
|
|
39
|
+
function submit() {
|
|
40
|
+
var request = current();
|
|
41
|
+
if (!request || request.status !== 'opening') return;
|
|
42
|
+
if (!live(request) || request.view !== view()) { patch({ status: 'error', error: 'The view changed. Retry explicitly from the current view.' }); return; }
|
|
43
|
+
var frame = contextualFrame(request.mateId, request.sessionId);
|
|
44
|
+
if (!frame || frame.hidden || !frame.conversation || !frame.conversation.identity().ready) return;
|
|
45
|
+
var identity = frame.conversation.identity();
|
|
46
|
+
if (identity.ownerId !== request.ownerId || identity.sessionId !== request.sessionId || identity.sessionOriginId !== request.sessionOriginId || identity.mateId !== request.mateId) { patch({ status: 'error', error: 'The exact conversation identity changed. Nothing was submitted.' }); return; }
|
|
47
|
+
patch({ status: 'sending' });
|
|
48
|
+
var receipt = frame.conversation.submitAsk({ requestId: request.requestId, text: request.text, ownerId: request.ownerId, sessionId: request.sessionId, sessionOriginId: request.sessionOriginId });
|
|
49
|
+
if (!receipt || !receipt.clientMessageId) { patch({ status: 'error', error: 'Submission is unconfirmed. Inspect the retained question before retrying.' }); return; }
|
|
50
|
+
patch({ status: 'sent', clientMessageId: receipt.clientMessageId });
|
|
51
|
+
}
|
|
52
|
+
function render() {
|
|
53
|
+
var host = document.getElementById('contextual-clay');
|
|
54
|
+
if (!host) return;
|
|
55
|
+
var status = host.querySelector('[data-contextual-ask-status]');
|
|
56
|
+
if (!status) {
|
|
57
|
+
status = document.createElement('section'); status.dataset.contextualAskStatus = ''; status.setAttribute('role', 'region'); status.setAttribute('aria-label', 'Pending question');
|
|
58
|
+
status.innerHTML = '<div class="contextual-pending-question"><span>Pending question</span><blockquote data-ask-question></blockquote></div><div class="contextual-pending-progress"><p role="status" aria-live="polite" aria-atomic="true"></p><div><button type="button" data-ask-retry>Retry</button><button type="button" data-ask-stop>Stop</button><button type="button" data-ask-inspect>Open conversation</button></div></div>';
|
|
59
|
+
host.querySelector('.contextual-clay-body').appendChild(status);
|
|
60
|
+
status.querySelector('[data-ask-inspect]').addEventListener('click', function () { var request = current(); if (request && live(request)) activateContextualMate(request.mateId); });
|
|
61
|
+
status.querySelector('[data-ask-retry]').addEventListener('click', resume);
|
|
62
|
+
status.querySelector('[data-ask-stop]').addEventListener('click', function () { stop(true); });
|
|
63
|
+
host.addEventListener('contextual-clay-ready', submit);
|
|
64
|
+
host.addEventListener('contextual-clay-availability', function () {
|
|
65
|
+
var request = current(), frame = request && contextualFrame(request.mateId, request.sessionId);
|
|
66
|
+
if (request && request.status === 'opening' && frame && frame.conversation && frame.conversation.identity().available === false) patch({ status: 'error', error: 'This new conversation is unavailable. Your question is retained.' });
|
|
67
|
+
});
|
|
68
|
+
host.addEventListener('contextual-context-submitted', function (event) {
|
|
69
|
+
var request = current(), frame = request && contextualFrame(request.mateId, request.sessionId);
|
|
70
|
+
if (request && frame && frame.contentWindow === event.detail.source && request.clientMessageId && request.clientMessageId === event.detail.message.clientMessageId) patch({ status: 'acknowledged', acknowledged: true });
|
|
71
|
+
});
|
|
72
|
+
host.addEventListener('contextual-ask-stopped', function (event) { var request = current(), frame = request && contextualFrame(request.mateId, request.sessionId); if (frame && frame.contentWindow === event.detail.source) stop(); });
|
|
73
|
+
}
|
|
74
|
+
var focused = document.activeElement, ownedFocus = status.contains(focused);
|
|
75
|
+
var request = current(), selected = store.get('contextualClay') || {};
|
|
76
|
+
status.hidden = !request || selected.mateId !== request.mateId || request.acknowledged || request.status === 'acknowledged' || selected.sessionId && selected.sessionId !== request.sessionId;
|
|
77
|
+
if (request) {
|
|
78
|
+
status.querySelector('[data-ask-question]').textContent = request.text;
|
|
79
|
+
status.querySelector('p').textContent = request.error || (request.status === 'creating' ? 'Starting a new conversation. Your question is waiting.' : request.status === 'opening' ? 'Preparing this conversation. Nothing submitted yet.' : 'Waiting for confirmation. Delivery is not confirmed yet.');
|
|
80
|
+
status.querySelector('[data-ask-inspect]').hidden = !request.clientMessageId;
|
|
81
|
+
status.querySelector('[data-ask-retry]').hidden = request.status !== 'error' && request.status !== 'stopped' || !!request.clientMessageId;
|
|
82
|
+
status.querySelector('[data-ask-stop]').hidden = request.status === 'stopped';
|
|
83
|
+
}
|
|
84
|
+
host.dataset.askPending = String(!status.hidden);
|
|
85
|
+
var selectedFrame = contextualFrame();
|
|
86
|
+
host.querySelector('[data-clay-loading]').hidden = !status.hidden || !!(selectedFrame && selectedFrame.conversation && selectedFrame.conversation.identity().ready);
|
|
87
|
+
host.querySelectorAll('iframe').forEach(function (frame) { frame.inert = !status.hidden && frame.dataset.mateId === request.mateId && String(frame.dataset.sessionId) === String(request.sessionId); });
|
|
88
|
+
if (status.hidden) {
|
|
89
|
+
enterComposer();
|
|
90
|
+
if (ownedFocus && selectedFrame && selectedFrame.conversation && selectedFrame.conversation.identity().ready) selectedFrame.contentDocument.getElementById('input').focus({ preventScroll: true });
|
|
91
|
+
} else if (ownedFocus && focused.hidden) {
|
|
92
|
+
var nextControl = status.querySelector('[data-ask-retry]:not([hidden]), [data-ask-inspect]:not([hidden]), [data-ask-stop]:not([hidden])');
|
|
93
|
+
if (nextControl) nextControl.focus({ preventScroll: true });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function startContextualSearch(text) {
|
|
99
|
+
text = typeof text === 'string' ? text.trim().slice(0, 12000) : '';
|
|
100
|
+
var mate = (store.get('cachedMatesList') || []).find(function (item) { return item.builtinKey === 'clay' && contextualMate(item.id); });
|
|
101
|
+
if (!text || !mate) { showToast('Clay is unavailable. Your question remains in Search.', 'warn'); return false; }
|
|
102
|
+
var request = current();
|
|
103
|
+
if (request && /^(creating|opening|sending|sent)$/.test(request.status)) { showToast('Clay is still starting the previous question. This question remains in Search.', 'warn'); return false; }
|
|
104
|
+
var requestId = 'contextual-search-' + crypto.randomUUID();
|
|
105
|
+
if (!showContextualAsk(mate, requestId, null)) return false;
|
|
106
|
+
store.set({ contextualSearchAsk: { requestId: requestId, text: text, mateId: mate.id, ownerId: store.get('myUserId'), stamp: contextualMateStamp(mate), status: 'creating', view: view() } });
|
|
107
|
+
render(); sendCreation(); return true;
|
|
108
|
+
}
|
|
109
|
+
export function retryContextualSearch() {
|
|
110
|
+
var request = current();
|
|
111
|
+
if (!request || !live(request) || request.clientMessageId || !/^(error|stopped)$/.test(request.status)) return false;
|
|
112
|
+
resume(); return true;
|
|
113
|
+
}
|
|
114
|
+
export function handleContextualSearchMessage(msg) {
|
|
115
|
+
var request = current();
|
|
116
|
+
if (!request || request.requestId !== msg.requestId) return false;
|
|
117
|
+
if (msg.type === 'home_mate_error') { patch({ status: 'error', error: msg.text || 'The conversation could not be started. Your question is retained.' }); return true; }
|
|
118
|
+
if (msg.type !== 'home_clay_contextual_session') return false;
|
|
119
|
+
if (request.status !== 'creating' || request.socket !== getWs() || !live(request) || request.mateId !== msg.mateId || !Number.isSafeInteger(msg.sessionId) || msg.sessionId <= 0 || typeof msg.sessionOriginId !== 'string' || request.sessionOriginId && request.sessionOriginId !== msg.sessionOriginId) return true;
|
|
120
|
+
if (request.view !== view()) { patch({ sessionId: msg.sessionId, sessionOriginId: msg.sessionOriginId, status: 'error', error: 'The view changed. Retry explicitly from the current view.' }); return true; }
|
|
121
|
+
patch({ sessionId: msg.sessionId, sessionOriginId: msg.sessionOriginId, status: 'opening' });
|
|
122
|
+
showContextualAsk(contextualMate(request.mateId), request.requestId, msg.sessionId);
|
|
123
|
+
var frame = contextualFrame(request.mateId, msg.sessionId);
|
|
124
|
+
if (frame) frame.dataset.contextualTitle = request.text.slice(0, 80);
|
|
125
|
+
setTimeout(function () { if (current() && current().requestId === request.requestId && current().status === 'opening') patch({ status: 'error', error: 'The conversation is not ready. Retry checks this same conversation.' }); }, 15000);
|
|
126
|
+
submit(); return true;
|
|
127
|
+
}
|
|
128
|
+
store.subscribe(function (value, previous) {
|
|
129
|
+
if (current() && current().ownerId !== value.myUserId) { store.set({ contextualSearchAsk: null }); return; }
|
|
130
|
+
if (current() && !live(current()) && /^(creating|opening)$/.test(current().status)) patch({ status: 'error', error: 'Clay is no longer available. Your question is retained.' });
|
|
131
|
+
if (current() && previous.connected && !value.connected && /^(creating|opening)$/.test(current().status)) patch({ status: 'error', error: 'Disconnected. Retry checks the same new conversation; your question is retained.' });
|
|
132
|
+
render();
|
|
133
|
+
});
|
|
134
|
+
document.addEventListener('click', function (event) {
|
|
135
|
+
var request = current();
|
|
136
|
+
if (request && store.get('currentSlug') === 'mate-' + request.mateId && store.get('activeSessionId') === request.sessionId && event.target.closest('#generation-stop, #autonomous-run-stop, #send-btn.stop')) stop();
|
|
137
|
+
}, true);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Human citation clicks leave the pinned pane intact and use the parent viewer's
|
|
2
|
+
// existing authenticated reference resolver, never a project label as a target.
|
|
3
|
+
import { store } from './store.js';
|
|
4
|
+
import { getWs } from './ws-ref.js';
|
|
5
|
+
import { contextualFrame, contextualMate, contextualMateStamp } from './contextual-mate-identity.js';
|
|
6
|
+
import { parseClaySessionReference } from './clay-log-links.js';
|
|
7
|
+
import { requestClayRecordLink } from './command-palette.js';
|
|
8
|
+
|
|
9
|
+
function capture() {
|
|
10
|
+
var frame = contextualFrame(), state = store.get('contextualClay') || {}, mate = contextualMate(state.mateId);
|
|
11
|
+
var identity = frame && frame.conversation && frame.conversation.identity();
|
|
12
|
+
if (!mate || state.mode !== 'popover' || !frame || frame.hidden || frame.inert || !identity || !identity.ready || frame.conversation.source !== frame.contentWindow || identity.ownerId !== store.get('myUserId') || identity.mateId !== mate.id || frame.dataset.identityStamp !== contextualMateStamp(mate)) return null;
|
|
13
|
+
var surface = document.getElementById('contextual-clay');
|
|
14
|
+
return { mateId: mate.id, stamp: contextualMateStamp(mate), sessionId: identity.sessionId, originId: identity.sessionOriginId, ownerId: identity.ownerId, view: surface.dataset.screenReference, socket: getWs() };
|
|
15
|
+
}
|
|
16
|
+
export function validContextualCitation(context) {
|
|
17
|
+
var live = capture();
|
|
18
|
+
return !!(context && live && live.socket === context.socket && live.mateId === context.mateId && live.stamp === context.stamp && live.sessionId === context.sessionId && live.originId === context.originId && live.ownerId === context.ownerId && live.view === context.view);
|
|
19
|
+
}
|
|
20
|
+
export function contextualCitationLink(context, requestId) {
|
|
21
|
+
var frames = Array.from(document.querySelectorAll('#contextual-clay iframe'));
|
|
22
|
+
for (var frame of frames) {
|
|
23
|
+
var mate = contextualMate(frame.dataset.mateId), identity = frame.conversation && frame.conversation.identity();
|
|
24
|
+
if (!mate || !identity || identity.ownerId !== store.get('myUserId') || frame.dataset.identityStamp !== contextualMateStamp(mate)) continue;
|
|
25
|
+
if (context && (identity.mateId !== context.mateId || identity.sessionId !== context.sessionId || identity.sessionOriginId !== context.originId || context.ownerId !== identity.ownerId)) continue;
|
|
26
|
+
var link = Array.from(frame.contentDocument.querySelectorAll('.clayos-session-link')).find(function (item) { return item.dataset.sessionRequest === requestId; });
|
|
27
|
+
if (link) return link;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
export function attachContextualSessionCitations(surface) {
|
|
32
|
+
surface.resolveSessionCitation = function (source, link) {
|
|
33
|
+
var context = capture(), frame = contextualFrame();
|
|
34
|
+
if (!context || !frame || frame.contentWindow !== source || !link || link.ownerDocument !== frame.contentDocument || !link.closest('.msg-assistant') || !parseClaySessionReference(link.dataset.sessionRef || '')) return false;
|
|
35
|
+
context.ref = link.dataset.sessionRef;
|
|
36
|
+
return requestClayRecordLink(link, context);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function forwardContextualSessionCitation(link) {
|
|
40
|
+
if (!store.get('paneMode') || new URLSearchParams(location.search).get('contextual') !== '1') return false;
|
|
41
|
+
try {
|
|
42
|
+
var surface = window.parent.document.getElementById('contextual-clay');
|
|
43
|
+
if (surface && surface.resolveSessionCitation && surface.resolveSessionCitation(window, link)) return true;
|
|
44
|
+
} catch (error) { /* A changed authentication document cannot receive clicks. */ }
|
|
45
|
+
if (link.classList.contains('is-error')) return true;
|
|
46
|
+
link.classList.add('is-error'); link.title = 'This conversation or view changed. Reopen it before navigating.';
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
// Project transport replacement may discard an old reply before the palette
|
|
50
|
+
// sees it. Retire that pending UI receipt at the context change itself.
|
|
51
|
+
store.subscribe(function (value) {
|
|
52
|
+
var pending = value.sessionNavigationRequestContext;
|
|
53
|
+
if (value.paneMode || !pending || !pending.citation) return;
|
|
54
|
+
if (pending.projectSlug === value.currentSlug && pending.sessionId === value.activeSessionId && validContextualCitation(pending.citation)) return;
|
|
55
|
+
var link = contextualCitationLink(pending.citation, value.sessionNavigationRequestId);
|
|
56
|
+
if (link) { link.classList.remove('is-loading'); link.classList.add('is-error'); link.title = 'The view changed. Click again from the current conversation.'; delete link.dataset.sessionRequest; }
|
|
57
|
+
store.set({ sessionNavigationRequestId: null, sessionNavigationRequestContext: null });
|
|
58
|
+
});
|
|
@@ -58,6 +58,7 @@ function buildAvatarUrl(meta) {
|
|
|
58
58
|
return mateAvatarUrl({
|
|
59
59
|
id: meta.mateId,
|
|
60
60
|
profile: {
|
|
61
|
+
avatarCatalogId: meta.avatarCatalogId || "",
|
|
61
62
|
avatarStyle: meta.avatarStyle || "imprint",
|
|
62
63
|
avatarSeed: meta.avatarSeed || meta.mateId || "mate",
|
|
63
64
|
avatarColor: meta.avatarColor || "#5857fc",
|
|
@@ -110,6 +110,13 @@ function inlineCurrentSelection(state, draft) {
|
|
|
110
110
|
return state.preference || state.selection || draft || {};
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
function updateDraft(draft) {
|
|
114
|
+
var state = store.get('defaultAiState') || {};
|
|
115
|
+
var saved = state.preference || state.selection || {};
|
|
116
|
+
var dirty = ['vendor', 'model', 'effort'].some(function (key) {return (draft[key] || '') !== (saved[key] || '');});
|
|
117
|
+
store.set({defaultAiDraft:draft, defaultAiDraftDirty:dirty});
|
|
118
|
+
}
|
|
119
|
+
|
|
113
120
|
function renderInlineSummary() {
|
|
114
121
|
var state = store.get("defaultAiState") || {};
|
|
115
122
|
var draft = store.get("defaultAiDraft") || {};
|
|
@@ -209,16 +216,16 @@ function render() {
|
|
|
209
216
|
effort.disabled = !models.length || state.saving === true;
|
|
210
217
|
|
|
211
218
|
vendor.addEventListener("change", function () {
|
|
212
|
-
|
|
219
|
+
updateDraft({ vendor: vendor.value, model: "", effort: "" });
|
|
213
220
|
requestCatalog(vendor.value);
|
|
214
221
|
render();
|
|
215
222
|
});
|
|
216
223
|
model.addEventListener("change", function () {
|
|
217
|
-
|
|
224
|
+
updateDraft({ vendor: vendor.value, model: model.value, effort: "" });
|
|
218
225
|
render();
|
|
219
226
|
});
|
|
220
227
|
effort.addEventListener("change", function () {
|
|
221
|
-
|
|
228
|
+
updateDraft({ vendor: vendor.value, model: model.value, effort: effort.value });
|
|
222
229
|
render();
|
|
223
230
|
});
|
|
224
231
|
addFieldLabel("Provider", vendor);
|
|
@@ -304,6 +311,7 @@ function applyCatalogMessage(msg, state) {
|
|
|
304
311
|
draft = Object.assign({}, draft, { model: msg.selection.model, effort: msg.selection.effort || "" });
|
|
305
312
|
}
|
|
306
313
|
store.set({ defaultAiState: next, defaultAiDraft: draft });
|
|
314
|
+
updateDraft(draft);
|
|
307
315
|
}
|
|
308
316
|
|
|
309
317
|
function applyStateMessage(msg, state) {
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import { escapeHtml } from './utils.js';
|
|
5
5
|
import { iconHtml } from './icons.js';
|
|
6
6
|
import { getWs } from './ws-ref.js';
|
|
7
|
+
import { store } from './store.js';
|
|
8
|
+
import { currentPaneReview } from './pane-binding.js';
|
|
7
9
|
import { fieldInfo, patternIsBounded, validateForm } from './elicitation-schema.js';
|
|
8
10
|
|
|
9
11
|
var UNSET = "__clay_unset__";
|
|
@@ -154,12 +156,14 @@ function showFormError(container, message) {
|
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
function send(container, action, content, onSent) {
|
|
159
|
+
if (!currentPaneReview(container)) return false;
|
|
157
160
|
var ws = getWs();
|
|
158
161
|
if (!ws || ws.readyState !== 1) {
|
|
159
162
|
showFormError(container, "Not connected. Try again when the connection is restored.");
|
|
160
163
|
return false;
|
|
161
164
|
}
|
|
162
165
|
var msg = { type: "elicitation_response", requestId: container.dataset.requestId, action: action };
|
|
166
|
+
if (container.paneBinding) msg.paneBinding = container.paneBinding;
|
|
163
167
|
if (action === "accept") msg.content = content;
|
|
164
168
|
ws.send(JSON.stringify(msg));
|
|
165
169
|
setBusy(container, true);
|
|
@@ -177,6 +181,7 @@ function actionButton(label, className, handler) {
|
|
|
177
181
|
|
|
178
182
|
export function buildElicitationCard(msg, onSent) {
|
|
179
183
|
var container = el("div", "permission-container elicitation-container");
|
|
184
|
+
container.paneBinding = store.get('panePendingBinding') || store.get('paneCommittedBinding') || null;
|
|
180
185
|
container.dataset.requestId = msg.requestId;
|
|
181
186
|
var header = el("div", "permission-header");
|
|
182
187
|
header.innerHTML = '<span class="permission-icon">' + iconHtml("key") + '</span>' +
|