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
package/lib/sessions.js
CHANGED
|
@@ -3,7 +3,7 @@ var path = require("path");
|
|
|
3
3
|
var config = require("./config");
|
|
4
4
|
var utils = require("./utils");
|
|
5
5
|
var users = require("./users");
|
|
6
|
-
var
|
|
6
|
+
var providerDefaults = require("./yoke/settings").defaults();
|
|
7
7
|
var hygiene = require("./session-hygiene");
|
|
8
8
|
var backgroundTaskTiming = require("./background-task-timing");
|
|
9
9
|
var sessionProvenance = require("./session-provenance");
|
|
@@ -39,16 +39,16 @@ function createSessionManager(opts) {
|
|
|
39
39
|
var permissionRequestIndex = {}; // requestId -> sessionLocalId (O(1) lookup)
|
|
40
40
|
var capabilitiesByVendor = null; // set by sdk-bridge after adapter init
|
|
41
41
|
var defaultVendor = null; // set by sdk-bridge
|
|
42
|
-
var codexApproval =
|
|
43
|
-
var codexSandbox =
|
|
44
|
-
var codexWebSearch =
|
|
42
|
+
var codexApproval = providerDefaults.codexApproval;
|
|
43
|
+
var codexSandbox = providerDefaults.codexSandbox;
|
|
44
|
+
var codexWebSearch = providerDefaults.codexWebSearch;
|
|
45
45
|
|
|
46
46
|
// --- Session persistence (centralized in ~/.clay/sessions/{encoded-cwd}/) ---
|
|
47
47
|
var sessionsBase = opts.sessionsBase || path.join(config.CONFIG_DIR, "sessions");
|
|
48
48
|
var encodedCwd = utils.resolveEncodedDir(sessionsBase, cwd);
|
|
49
49
|
var sessionsDir = path.join(sessionsBase, encodedCwd);
|
|
50
50
|
fs.mkdirSync(sessionsDir, { recursive: true });
|
|
51
|
-
var cliSessionsDir = opts.cliSessionsDir ||
|
|
51
|
+
var cliSessionsDir = opts.cliSessionsDir || require("./yoke/legacy-sessions").directory(config.REAL_HOME, cwd);
|
|
52
52
|
var deletedCliSessionsPath = path.join(sessionsDir, "deleted-cli-sessions.json");
|
|
53
53
|
var deletedCliSessionIds = new Set();
|
|
54
54
|
try {
|
|
@@ -77,29 +77,6 @@ function createSessionManager(opts) {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
function readCliTranscriptHead(filePath) {
|
|
81
|
-
var MAX_READ = 64 * 1024;
|
|
82
|
-
try {
|
|
83
|
-
var stat = fs.statSync(filePath);
|
|
84
|
-
var fd = fs.openSync(filePath, "r");
|
|
85
|
-
var bytesToRead = Math.min(stat.size, MAX_READ);
|
|
86
|
-
var buf = Buffer.alloc(bytesToRead);
|
|
87
|
-
fs.readSync(fd, buf, 0, bytesToRead, 0);
|
|
88
|
-
fs.closeSync(fd);
|
|
89
|
-
var lines = buf.toString("utf8").split("\n");
|
|
90
|
-
var events = [];
|
|
91
|
-
for (var i = 0; i < lines.length; i++) {
|
|
92
|
-
if (!lines[i]) continue;
|
|
93
|
-
try {
|
|
94
|
-
var event = JSON.parse(lines[i]);
|
|
95
|
-
if (event && typeof event === "object") events.push(event);
|
|
96
|
-
} catch (e) {}
|
|
97
|
-
}
|
|
98
|
-
return events;
|
|
99
|
-
} catch (e) {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
80
|
|
|
104
81
|
// Auto-migrate sessions from legacy locations:
|
|
105
82
|
// v1: {cwd}/.claude-relay/sessions/
|
|
@@ -179,6 +156,7 @@ function createSessionManager(opts) {
|
|
|
179
156
|
};
|
|
180
157
|
if (session.githubLinks) metaObj.githubLinks = session.githubLinks;
|
|
181
158
|
if (session.linearLinks) metaObj.linearLinks = session.linearLinks;
|
|
159
|
+
if (session.workPrimary) metaObj.workPrimary = session.workPrimary;
|
|
182
160
|
if (session.ownerId) metaObj.ownerId = session.ownerId;
|
|
183
161
|
if (session.vendor) metaObj.vendor = session.vendor;
|
|
184
162
|
if (session.codexDynamicToolCatalogVersion) metaObj.codexDynamicToolCatalogVersion = session.codexDynamicToolCatalogVersion;
|
|
@@ -188,6 +166,7 @@ function createSessionManager(opts) {
|
|
|
188
166
|
if (session.codexLinearToolCatalogVersion) metaObj.codexLinearToolCatalogVersion = session.codexLinearToolCatalogVersion;
|
|
189
167
|
if (session.codexSharedBrowserToolCatalogVersion) metaObj.codexSharedBrowserToolCatalogVersion = session.codexSharedBrowserToolCatalogVersion;
|
|
190
168
|
if (session.codexIssuesToolCatalogVersion) metaObj.codexIssuesToolCatalogVersion = session.codexIssuesToolCatalogVersion;
|
|
169
|
+
if (session.codexNotesToolCatalogVersion) metaObj.codexNotesToolCatalogVersion = session.codexNotesToolCatalogVersion;
|
|
191
170
|
if (session.model) metaObj.model = session.model;
|
|
192
171
|
if (session.effort) metaObj.effort = session.effort;
|
|
193
172
|
// Persist the session's "born" mode so TUI sessions reappear after a
|
|
@@ -226,10 +205,18 @@ function createSessionManager(opts) {
|
|
|
226
205
|
if (session.homeDebatePlanning) metaObj.homeDebatePlanning = true;
|
|
227
206
|
if (session.homeDebatePhase) metaObj.homeDebatePhase = session.homeDebatePhase;
|
|
228
207
|
if (session.homeDebateInitialTopic) metaObj.homeDebateInitialTopic = session.homeDebateInitialTopic;
|
|
208
|
+
if (session.mateScheduleDraft) metaObj.mateScheduleDraft = session.mateScheduleDraft;
|
|
209
|
+
if (session.mateSchedules) metaObj.mateSchedules = session.mateSchedules;
|
|
210
|
+
if (session.clayWorkspaceReceipts) metaObj.clayWorkspaceReceipts = session.clayWorkspaceReceipts;
|
|
211
|
+
if (session.clayMateChatReceipts) metaObj.clayMateChatReceipts = session.clayMateChatReceipts;
|
|
212
|
+
if (session.claySchedulingReceipts) metaObj.claySchedulingReceipts = session.claySchedulingReceipts;
|
|
229
213
|
if (session.mateCreationMode) metaObj.mateCreationMode = true;
|
|
230
214
|
if (session.homeMateCreationPhase) metaObj.homeMateCreationPhase = session.homeMateCreationPhase;
|
|
215
|
+
if (session.contextualCreationMateStamp) metaObj.contextualCreationMateStamp = session.contextualCreationMateStamp;
|
|
216
|
+
if (session.contextualCreationRequestId) metaObj.contextualCreationRequestId = session.contextualCreationRequestId;
|
|
231
217
|
if (session.homeClayEntryRequestId) metaObj.homeClayEntryRequestId = session.homeClayEntryRequestId;
|
|
232
218
|
if (session.homeClayEntryMode) metaObj.homeClayEntryMode = session.homeClayEntryMode;
|
|
219
|
+
if (session.homeClayEntryText) metaObj.homeClayEntryText = session.homeClayEntryText;
|
|
233
220
|
metaObj.sessionOriginId = provenanceMeta.sessionOriginId;
|
|
234
221
|
if (provenanceMeta.sessionProvenance) metaObj.sessionProvenance = provenanceMeta.sessionProvenance;
|
|
235
222
|
if (Array.isArray(session._workerGenerations)) metaObj.workerGenerations = session._workerGenerations;
|
|
@@ -356,6 +343,7 @@ function createSessionManager(opts) {
|
|
|
356
343
|
titleAutoGenerated: m.titleAutoGenerated === true,
|
|
357
344
|
githubLinks: Array.isArray(m.githubLinks) ? m.githubLinks.slice(0, 8) : [],
|
|
358
345
|
linearLinks: Array.isArray(m.linearLinks) ? m.linearLinks.slice(0, 8) : [],
|
|
346
|
+
workPrimary: m.workPrimary || {},
|
|
359
347
|
titleManuallySet: m.titleManuallySet === true || legacyTitleProtected,
|
|
360
348
|
createdAt: m.createdAt || Date.now(),
|
|
361
349
|
lastActivity: loaded[i].mtime || m.createdAt || Date.now(),
|
|
@@ -371,6 +359,7 @@ function createSessionManager(opts) {
|
|
|
371
359
|
session.codexLinearToolCatalogVersion = Number(m.codexLinearToolCatalogVersion || 0);
|
|
372
360
|
session.codexSharedBrowserToolCatalogVersion = Number(m.codexSharedBrowserToolCatalogVersion || 0);
|
|
373
361
|
session.codexIssuesToolCatalogVersion = Number(m.codexIssuesToolCatalogVersion || 0);
|
|
362
|
+
session.codexNotesToolCatalogVersion = Number(m.codexNotesToolCatalogVersion || 0);
|
|
374
363
|
session.model = m.model || deriveSessionModel(loaded[i].history);
|
|
375
364
|
session.effort = m.effort || null;
|
|
376
365
|
if (m.loop) session.loop = m.loop;
|
|
@@ -384,10 +373,18 @@ function createSessionManager(opts) {
|
|
|
384
373
|
if (m.homeDebatePlanning) session.homeDebatePlanning = true;
|
|
385
374
|
if (m.homeDebatePhase) session.homeDebatePhase = m.homeDebatePhase;
|
|
386
375
|
if (m.homeDebateInitialTopic) session.homeDebateInitialTopic = m.homeDebateInitialTopic;
|
|
376
|
+
if (m.mateScheduleDraft) session.mateScheduleDraft = m.mateScheduleDraft;
|
|
377
|
+
if (m.mateSchedules) session.mateSchedules = m.mateSchedules;
|
|
378
|
+
if (Array.isArray(m.clayWorkspaceReceipts)) session.clayWorkspaceReceipts = m.clayWorkspaceReceipts;
|
|
379
|
+
if (Array.isArray(m.clayMateChatReceipts)) session.clayMateChatReceipts = m.clayMateChatReceipts;
|
|
380
|
+
if (Array.isArray(m.claySchedulingReceipts)) session.claySchedulingReceipts = m.claySchedulingReceipts;
|
|
387
381
|
if (m.mateCreationMode) session.mateCreationMode = true;
|
|
388
382
|
if (m.homeMateCreationPhase) session.homeMateCreationPhase = m.homeMateCreationPhase;
|
|
383
|
+
if (m.contextualCreationMateStamp) session.contextualCreationMateStamp = m.contextualCreationMateStamp;
|
|
384
|
+
if (m.contextualCreationRequestId) session.contextualCreationRequestId = m.contextualCreationRequestId;
|
|
389
385
|
if (m.homeClayEntryRequestId) session.homeClayEntryRequestId = m.homeClayEntryRequestId;
|
|
390
386
|
if (m.homeClayEntryMode) session.homeClayEntryMode = m.homeClayEntryMode;
|
|
387
|
+
if (m.homeClayEntryText) session.homeClayEntryText = m.homeClayEntryText;
|
|
391
388
|
if (m.ownerId) session.ownerId = m.ownerId;
|
|
392
389
|
session.sessionOriginId = m.sessionOriginId || null;
|
|
393
390
|
session._provenanceMigrationNeeded = sessionProvenance.restore(m, session);
|
|
@@ -458,9 +455,6 @@ function createSessionManager(opts) {
|
|
|
458
455
|
// - Warmup shape: 1 real "hi" prompt, optional automatic interruption,
|
|
459
456
|
// and 0 assistant messages (covered by daemon cleanup but defensive)
|
|
460
457
|
function adoptOrphanedCliSessions() {
|
|
461
|
-
var files;
|
|
462
|
-
try { files = fs.readdirSync(cliSessionsDir); } catch (e) { return; }
|
|
463
|
-
|
|
464
458
|
// Build set of cliSessionIds Clay already tracks
|
|
465
459
|
var knownCliIds = new Set();
|
|
466
460
|
sessions.forEach(function (s) {
|
|
@@ -469,56 +463,10 @@ function createSessionManager(opts) {
|
|
|
469
463
|
|
|
470
464
|
var adopted = 0;
|
|
471
465
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
var
|
|
475
|
-
|
|
476
|
-
if (deletedCliSessionIds.has(cliSid)) continue;
|
|
477
|
-
|
|
478
|
-
var fp = path.join(cliSessionsDir, files[i]);
|
|
479
|
-
var events = readCliTranscriptHead(fp);
|
|
480
|
-
if (!events) continue;
|
|
481
|
-
var userCount = 0;
|
|
482
|
-
var firstUserText = null;
|
|
483
|
-
var createdAtIso = null;
|
|
484
|
-
for (var li = 0; li < events.length; li++) {
|
|
485
|
-
var ev = events[li];
|
|
486
|
-
if (ev.type === "user" && ev.message && ev.message.role === "user") {
|
|
487
|
-
userCount++;
|
|
488
|
-
if (firstUserText == null) {
|
|
489
|
-
var c = ev.message.content;
|
|
490
|
-
if (typeof c === "string") {
|
|
491
|
-
firstUserText = c;
|
|
492
|
-
} else if (Array.isArray(c)) {
|
|
493
|
-
var parts = [];
|
|
494
|
-
for (var ci = 0; ci < c.length; ci++) {
|
|
495
|
-
if (c[ci] && c[ci].type === "text" && typeof c[ci].text === "string") parts.push(c[ci].text);
|
|
496
|
-
}
|
|
497
|
-
firstUserText = parts.join("");
|
|
498
|
-
}
|
|
499
|
-
if (ev.timestamp && !createdAtIso) createdAtIso = ev.timestamp;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
if (userCount === 0) continue;
|
|
505
|
-
// Defensive warmup skip (daemon also cleans these)
|
|
506
|
-
if (hygiene.isClaudeWarmupTranscript(events)) continue;
|
|
507
|
-
|
|
508
|
-
// Title: first user message trimmed/truncated. Fall back to a
|
|
509
|
-
// neutral label so the sidebar entry is identifiable.
|
|
510
|
-
var title = (firstUserText || "").trim().replace(/\s+/g, " ");
|
|
511
|
-
if (title.length > 60) title = title.slice(0, 57) + "...";
|
|
512
|
-
if (!title) title = "Imported CLI session";
|
|
513
|
-
|
|
514
|
-
var createdAt = Date.now();
|
|
515
|
-
if (createdAtIso) {
|
|
516
|
-
var t = Date.parse(createdAtIso);
|
|
517
|
-
if (!isNaN(t)) createdAt = t;
|
|
518
|
-
}
|
|
519
|
-
var lastActivity = createdAt;
|
|
520
|
-
try { lastActivity = fs.statSync(fp).mtimeMs; } catch (e) {}
|
|
521
|
-
|
|
466
|
+
var candidates = require("./yoke/legacy-sessions").candidates(cliSessionsDir, knownCliIds, deletedCliSessionIds);
|
|
467
|
+
for (var i = 0; i < candidates.length; i++) {
|
|
468
|
+
var candidate = candidates[i], cliSid = candidate.id;
|
|
469
|
+
var title = candidate.title, createdAt = candidate.createdAt, lastActivity = candidate.lastActivity;
|
|
522
470
|
var localId = nextLocalId++;
|
|
523
471
|
var session = {
|
|
524
472
|
localId: localId,
|
|
@@ -536,7 +484,7 @@ function createSessionManager(opts) {
|
|
|
536
484
|
history: [],
|
|
537
485
|
messageUUIDs: [],
|
|
538
486
|
lastRewindUuid: null,
|
|
539
|
-
vendor:
|
|
487
|
+
vendor: candidate.vendor,
|
|
540
488
|
mode: "tui",
|
|
541
489
|
// Adopted from an external `claude` run in this cwd, not started by
|
|
542
490
|
// Clay. Notification emitters must stay silent for these until the
|
|
@@ -568,10 +516,7 @@ function createSessionManager(opts) {
|
|
|
568
516
|
var stale = [];
|
|
569
517
|
sessions.forEach(function (session) {
|
|
570
518
|
if (!session.adopted || !session.cliSessionId) return;
|
|
571
|
-
|
|
572
|
-
var events = readCliTranscriptHead(transcriptPath);
|
|
573
|
-
var missingEmptySource = !fs.existsSync(transcriptPath) && (!session.history || session.history.length === 0);
|
|
574
|
-
if (missingEmptySource || (events && hygiene.isClaudeWarmupTranscript(events))) stale.push(session.localId);
|
|
519
|
+
if (require("./yoke/legacy-sessions").obsolete(cliSessionsDir, session)) stale.push(session.localId);
|
|
575
520
|
});
|
|
576
521
|
for (var i = 0; i < stale.length; i++) deleteSessionQuiet(stale[i]);
|
|
577
522
|
if (stale.length > 0) {
|
|
@@ -624,11 +569,13 @@ function createSessionManager(opts) {
|
|
|
624
569
|
var unreadMap = wsUnread || singleUserUnread;
|
|
625
570
|
return {
|
|
626
571
|
id: s.localId,
|
|
572
|
+
sessionOriginId: s.sessionOriginId || null,
|
|
627
573
|
cliSessionId: s.cliSessionId || null,
|
|
628
574
|
createdAt: s.createdAt || 0,
|
|
629
575
|
title: s.title || "New Session",
|
|
630
576
|
githubLinks: s.githubLinks || [],
|
|
631
577
|
linearLinks: s.linearLinks || [],
|
|
578
|
+
workPrimary: s.workPrimary || {},
|
|
632
579
|
active: isActive,
|
|
633
580
|
isProcessing: s.isProcessing,
|
|
634
581
|
// Sidebar badge: user work only. Ambient housekeeping is surfaced in the
|
|
@@ -833,8 +780,8 @@ function createSessionManager(opts) {
|
|
|
833
780
|
}
|
|
834
781
|
|
|
835
782
|
// History entries include tool activity and streamed output, so opening a
|
|
836
|
-
// conversation
|
|
837
|
-
var INITIAL_HISTORY_SIZE =
|
|
783
|
+
// conversation starts with a 300-entry target, aligned to a complete user turn.
|
|
784
|
+
var INITIAL_HISTORY_SIZE = 300;
|
|
838
785
|
var HISTORY_PAGE_SIZE = 100;
|
|
839
786
|
|
|
840
787
|
function findTurnBoundary(history, targetIndex) {
|
|
@@ -844,8 +791,9 @@ function createSessionManager(opts) {
|
|
|
844
791
|
return 0;
|
|
845
792
|
}
|
|
846
793
|
|
|
847
|
-
function replayHistory(session, fromIndex, targetWs, transform) {
|
|
848
|
-
var _send = (targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send;
|
|
794
|
+
function replayHistory(session, fromIndex, targetWs, transform, snapshotSend) {
|
|
795
|
+
var _send = snapshotSend || ((targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send);
|
|
796
|
+
var sendHistory = snapshotSend && snapshotSend.history || _send;
|
|
849
797
|
var total = session.history.length;
|
|
850
798
|
if (typeof fromIndex !== "number") {
|
|
851
799
|
if (total <= INITIAL_HISTORY_SIZE) {
|
|
@@ -855,7 +803,7 @@ function createSessionManager(opts) {
|
|
|
855
803
|
}
|
|
856
804
|
}
|
|
857
805
|
|
|
858
|
-
|
|
806
|
+
sendHistory({ type: "history_meta", total: total, from: fromIndex });
|
|
859
807
|
|
|
860
808
|
for (var i = fromIndex; i < total; i++) {
|
|
861
809
|
var _item = session.history[i];
|
|
@@ -864,7 +812,10 @@ function createSessionManager(opts) {
|
|
|
864
812
|
if (_item && (_item.type === "mention_user" || _item.type === "mention_response")) {
|
|
865
813
|
console.log("[DEBUG replayHistory] sending mention at index=" + i + " from=" + fromIndex + " total=" + total + " type=" + _item.type + " mate=" + (_item.mateName || ""));
|
|
866
814
|
}
|
|
867
|
-
|
|
815
|
+
var normalizedItem = require("./yoke/usage").clientEvent(_item, session.vendor || "claude");
|
|
816
|
+
var replayItem = transform ? transform(normalizedItem) : normalizedItem;
|
|
817
|
+
if (replayItem && typeof replayItem === "object") replayItem = Object.assign({}, replayItem, { _historyIndex: i });
|
|
818
|
+
sendHistory(replayItem);
|
|
868
819
|
}
|
|
869
820
|
|
|
870
821
|
// Find the last result message in the full history for accurate context data
|
|
@@ -872,9 +823,11 @@ function createSessionManager(opts) {
|
|
|
872
823
|
var lastModelUsage = null;
|
|
873
824
|
var lastCost = null;
|
|
874
825
|
var lastStreamInputTokens = null;
|
|
826
|
+
var lastContext = null;
|
|
875
827
|
for (var j = total - 1; j >= 0; j--) {
|
|
876
828
|
if (session.history[j].type === "result") {
|
|
877
|
-
var r = session.history[j];
|
|
829
|
+
var r = require("./yoke/usage").clientEvent(session.history[j], session.vendor || "claude");
|
|
830
|
+
lastContext = r.context || null;
|
|
878
831
|
lastUsage = r.usage || null;
|
|
879
832
|
lastModelUsage = r.modelUsage || null;
|
|
880
833
|
lastCost = r.cost != null ? r.cost : null;
|
|
@@ -883,16 +836,17 @@ function createSessionManager(opts) {
|
|
|
883
836
|
}
|
|
884
837
|
}
|
|
885
838
|
|
|
886
|
-
|
|
839
|
+
sendHistory({ type: "history_done", controlHistoryRevision: require("./clay-control-target-projection").digest(session.history || []), sessionId: session.localId, sessionOriginId: session.sessionOriginId || null, lastUsage: lastUsage, lastModelUsage: lastModelUsage, lastCost: lastCost, lastStreamInputTokens: lastStreamInputTokens, context: lastContext, contextUsage: require("./yoke/usage").context(session.lastContextUsage, session.vendor || "claude") });
|
|
887
840
|
for (var vi = 0; vi < sessionViewedListeners.length; vi++) {
|
|
888
841
|
try { sessionViewedListeners[vi](session, targetWs, _send); } catch (e) {}
|
|
889
842
|
}
|
|
890
843
|
}
|
|
891
844
|
|
|
892
|
-
function switchSession(localId, targetWs, transform) {
|
|
845
|
+
function switchSession(localId, targetWs, transform, snapshotSend, snapshotGuard) {
|
|
893
846
|
var session = sessions.get(localId);
|
|
894
847
|
if (!session) return;
|
|
895
848
|
if (typeof onSessionHydrate === "function") onSessionHydrate(session);
|
|
849
|
+
if (snapshotGuard && !snapshotGuard()) return;
|
|
896
850
|
|
|
897
851
|
// Pane sockets (split-view iframes) pin their session via switch_session
|
|
898
852
|
// but must not move the project-global active pointer: reloads and
|
|
@@ -913,7 +867,7 @@ function createSessionManager(opts) {
|
|
|
913
867
|
singleUserUnread[localId] = 0;
|
|
914
868
|
|
|
915
869
|
// In multi-user mode with a specific client, only send to that client
|
|
916
|
-
var _send = (targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send;
|
|
870
|
+
var _send = snapshotSend || ((targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send);
|
|
917
871
|
|
|
918
872
|
var _capsByVendor = capabilitiesByVendor || {};
|
|
919
873
|
var _sessionVendor = session.vendor || defaultVendor || "claude";
|
|
@@ -926,7 +880,7 @@ function createSessionManager(opts) {
|
|
|
926
880
|
|| [];
|
|
927
881
|
_send({ type: "slash_commands", commands: _vendorCmds, vendor: _sessionVendor });
|
|
928
882
|
broadcastSessionList();
|
|
929
|
-
replayHistory(session, undefined, targetWs, transform);
|
|
883
|
+
replayHistory(session, undefined, targetWs, transform, snapshotSend);
|
|
930
884
|
|
|
931
885
|
if (session.isProcessing) {
|
|
932
886
|
_send({ type: "status", status: "processing" });
|
|
@@ -944,10 +898,15 @@ function createSessionManager(opts) {
|
|
|
944
898
|
toolInput: p.toolInput,
|
|
945
899
|
toolUseId: p.toolUseId,
|
|
946
900
|
decisionReason: p.decisionReason,
|
|
901
|
+
defaultToNo: p.defaultToNo,
|
|
902
|
+
suppressAlwaysAllowRule: p.suppressAlwaysAllowRule,
|
|
903
|
+
mateId: p.mateId || undefined,
|
|
904
|
+
vendor: p.vendor || session.vendor || undefined,
|
|
947
905
|
});
|
|
948
906
|
}
|
|
949
907
|
|
|
950
908
|
// Re-send active mention indicator so returning clients restore the mate avatar state
|
|
909
|
+
if (snapshotSend) require('./pane-pending-interactions').send(session, _send);
|
|
951
910
|
if (session._mentionInProgress && session._mentionActiveMateId) {
|
|
952
911
|
_send({ type: "mention_processing", mateId: session._mentionActiveMateId, active: true });
|
|
953
912
|
}
|
|
@@ -1080,6 +1039,14 @@ function createSessionManager(opts) {
|
|
|
1080
1039
|
}
|
|
1081
1040
|
}
|
|
1082
1041
|
|
|
1042
|
+
// An activated pane socket only accepts frames carrying its exact binding;
|
|
1043
|
+
// the transport adds it, or withholds the frame if the binding is stale.
|
|
1044
|
+
function sendLiveToSocket(ws, session, obj, data) {
|
|
1045
|
+
if (!ws._clayPaneActivation) { ws.send(data); return; }
|
|
1046
|
+
var panePayload = require("./pane-session-transport").outbound(ws, obj, session.localId);
|
|
1047
|
+
if (panePayload) ws.send(JSON.stringify(panePayload));
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1083
1050
|
function doSendToSession(session, obj) {
|
|
1084
1051
|
// Send to active clients without recording to history/disk (ephemeral data)
|
|
1085
1052
|
if (sendEach) {
|
|
@@ -1088,7 +1055,7 @@ function createSessionManager(opts) {
|
|
|
1088
1055
|
if (filterFn && !filterFn(session)) return;
|
|
1089
1056
|
if (session.homeDebatePlanning === true) return;
|
|
1090
1057
|
if (ws._clayActiveSession === session.localId && ws.readyState === 1) {
|
|
1091
|
-
ws
|
|
1058
|
+
sendLiveToSocket(ws, session, obj, data);
|
|
1092
1059
|
}
|
|
1093
1060
|
});
|
|
1094
1061
|
} else if (session.localId === activeSessionId) {
|
|
@@ -1120,7 +1087,7 @@ function createSessionManager(opts) {
|
|
|
1120
1087
|
if (filterFn && !filterFn(session)) return;
|
|
1121
1088
|
if (session.homeDebatePlanning === true) return;
|
|
1122
1089
|
if (ws._clayActiveSession === session.localId) {
|
|
1123
|
-
if (ws.readyState === 1) ws
|
|
1090
|
+
if (ws.readyState === 1) sendLiveToSocket(ws, session, outgoingObj, data);
|
|
1124
1091
|
} else if (session.isProcessing && !session._ioThrottle) {
|
|
1125
1092
|
if (!ioData) ioData = JSON.stringify({ type: "session_io", id: session.localId });
|
|
1126
1093
|
if (ws.readyState === 1) ws.send(ioData);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var cookieKey = require('./shared-browser-cookies').cookieKey;
|
|
2
|
+
|
|
3
|
+
// Only the private worker pipe carries cookies. They never enter browser state or tool output.
|
|
4
|
+
function attachCookieSync(context, initial, send) {
|
|
5
|
+
var pending = null;
|
|
6
|
+
var previous = initial;
|
|
7
|
+
var nextId = 0;
|
|
8
|
+
function receive(message) {
|
|
9
|
+
if (!pending || pending.id !== message.id) return;
|
|
10
|
+
var entry = pending; pending = null; clearTimeout(entry.timer);
|
|
11
|
+
if (message.error) entry.reject(new Error(message.error));
|
|
12
|
+
else entry.resolve(message.cookies);
|
|
13
|
+
}
|
|
14
|
+
async function sync() {
|
|
15
|
+
var current = await context.cookies();
|
|
16
|
+
var cookies = await new Promise(function (resolve, reject) {
|
|
17
|
+
pending = { id: ++nextId, resolve: resolve, reject: reject, timer: setTimeout(function () { pending = null; reject(new Error('Could not synchronize browser cookies')); }, 4000) };
|
|
18
|
+
try { send({ type: 'cookies', id: pending.id, previous: previous, cookies: current }); }
|
|
19
|
+
catch (error) { clearTimeout(pending.timer); pending = null; reject(error); }
|
|
20
|
+
});
|
|
21
|
+
var remote = new Map(cookies.map(function (cookie) { return [cookieKey(cookie), cookie]; }));
|
|
22
|
+
var local = new Map(current.map(function (cookie) { return [cookieKey(cookie), cookie]; }));
|
|
23
|
+
var updates = cookies.filter(function (cookie) { return JSON.stringify(local.get(cookieKey(cookie))) !== JSON.stringify(cookie); });
|
|
24
|
+
current.forEach(function (cookie) {
|
|
25
|
+
if (!remote.has(cookieKey(cookie))) updates.push(Object.assign({}, cookie, { expires: 1 }));
|
|
26
|
+
});
|
|
27
|
+
if (updates.length) await context.addCookies(updates);
|
|
28
|
+
previous = cookies;
|
|
29
|
+
}
|
|
30
|
+
return { start: function () { return context.addCookies(initial); }, sync: sync, receive: receive };
|
|
31
|
+
}
|
|
32
|
+
module.exports = { attachCookieSync: attachCookieSync };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var fs = require('fs');
|
|
2
|
+
var path = require('path');
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
function cookieKey(cookie) {
|
|
6
|
+
return JSON.stringify([cookie.domain, cookie.path, cookie.name, cookie.partitionKey || '']);
|
|
7
|
+
}
|
|
8
|
+
function cookieMap(cookies) {
|
|
9
|
+
if (!Array.isArray(cookies) || cookies.length > 10000 || JSON.stringify(cookies).length > 2 * 1024 * 1024) throw new Error('Browser cookies exceed the storage limit');
|
|
10
|
+
var result = new Map();
|
|
11
|
+
cookies.forEach(function (cookie) {
|
|
12
|
+
if (!cookie || typeof cookie.name !== 'string' || typeof cookie.value !== 'string' || typeof cookie.domain !== 'string' || typeof cookie.path !== 'string') throw new Error('Invalid browser cookie');
|
|
13
|
+
result.set(cookieKey(cookie), cookie);
|
|
14
|
+
});
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
function same(a, b) { return JSON.stringify(a) === JSON.stringify(b); }
|
|
18
|
+
|
|
19
|
+
// Merge only a tab's changes, so an idle tab cannot overwrite another tab's login or logout.
|
|
20
|
+
function mergeCookies(saved, previous, current) {
|
|
21
|
+
var merged = cookieMap(saved), before = cookieMap(previous), after = cookieMap(current);
|
|
22
|
+
before.forEach(function (cookie, key) {
|
|
23
|
+
if (!after.has(key) && same(merged.get(key), cookie)) merged.delete(key);
|
|
24
|
+
});
|
|
25
|
+
after.forEach(function (cookie, key) {
|
|
26
|
+
if (!same(before.get(key), cookie)) merged.set(key, cookie);
|
|
27
|
+
});
|
|
28
|
+
return Array.from(merged.values()).filter(function (cookie) { return cookie.expires === -1 || cookie.expires > Date.now() / 1000; });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function attachEncryptedStore(root, name, empty) {
|
|
32
|
+
var directory = path.join(root, name);
|
|
33
|
+
function ownerKey(owner) {
|
|
34
|
+
if (typeof owner !== 'string' || !owner || owner.length > 256) throw new Error('Browser data owner is required');
|
|
35
|
+
return crypto.createHash('sha256').update(owner).digest('hex');
|
|
36
|
+
}
|
|
37
|
+
function masterKey() {
|
|
38
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
39
|
+
var file = path.join(directory, '.key');
|
|
40
|
+
try { fs.writeFileSync(file, crypto.randomBytes(32), { flag: 'wx', mode: 0o600 }); }
|
|
41
|
+
catch (error) { if (error.code !== 'EEXIST') throw error; }
|
|
42
|
+
return fs.readFileSync(file);
|
|
43
|
+
}
|
|
44
|
+
function read(owner) {
|
|
45
|
+
var id = ownerKey(owner), raw;
|
|
46
|
+
try { raw = fs.readFileSync(path.join(directory, id + '.json'), 'utf8'); }
|
|
47
|
+
catch (error) { if (error.code === 'ENOENT') return empty(); throw new Error('Could not read saved browser data'); }
|
|
48
|
+
try {
|
|
49
|
+
var parts = JSON.parse(raw).map(function (part) { return Buffer.from(part, 'base64'); });
|
|
50
|
+
var cipher = crypto.createDecipheriv('aes-256-gcm', masterKey(), parts[0]);
|
|
51
|
+
cipher.setAAD(Buffer.from(id)); cipher.setAuthTag(parts[1]);
|
|
52
|
+
var cookies = JSON.parse(Buffer.concat([cipher.update(parts[2]), cipher.final()]).toString('utf8'));
|
|
53
|
+
return cookies;
|
|
54
|
+
} catch (error) { throw new Error('Could not decrypt saved browser data'); }
|
|
55
|
+
}
|
|
56
|
+
function write(owner, cookies) {
|
|
57
|
+
var id = ownerKey(owner), iv = crypto.randomBytes(12);
|
|
58
|
+
var cipher = crypto.createCipheriv('aes-256-gcm', masterKey(), iv);
|
|
59
|
+
cipher.setAAD(Buffer.from(id));
|
|
60
|
+
var bytes = Buffer.concat([cipher.update(JSON.stringify(cookies), 'utf8'), cipher.final()]);
|
|
61
|
+
var file = path.join(directory, id + '.json'), temp = file + '.' + crypto.randomBytes(8).toString('hex') + '.tmp';
|
|
62
|
+
try {
|
|
63
|
+
fs.writeFileSync(temp, JSON.stringify([iv, cipher.getAuthTag(), bytes].map(function (part) { return part.toString('base64'); })), { mode: 0o600 });
|
|
64
|
+
fs.renameSync(temp, file);
|
|
65
|
+
} finally { try { fs.unlinkSync(temp); } catch (error) { if (error.code !== 'ENOENT') throw error; } }
|
|
66
|
+
return cookies;
|
|
67
|
+
}
|
|
68
|
+
return { read: read, write: write };
|
|
69
|
+
}
|
|
70
|
+
function attachCookieStore(root) {
|
|
71
|
+
var disk = attachEncryptedStore(root, 'browser-cookies', function () { return []; });
|
|
72
|
+
function read(owner) { return mergeCookies(disk.read(owner), [], []); }
|
|
73
|
+
return { read: read, clear: function (owner) { disk.write(owner, []); }, exchange: function (owner, previous, current) {
|
|
74
|
+
var saved = read(owner), merged = mergeCookies(saved, previous, current);
|
|
75
|
+
if (!same(saved, merged)) disk.write(owner, merged);
|
|
76
|
+
return merged;
|
|
77
|
+
} };
|
|
78
|
+
}
|
|
79
|
+
module.exports = { attachEncryptedStore: attachEncryptedStore, attachCookieStore: attachCookieStore, mergeCookies: mergeCookies, cookieKey: cookieKey };
|
|
@@ -5,6 +5,8 @@ var buildUserEnv = require("./build-user-env").buildUserEnv;
|
|
|
5
5
|
var wrapSpawnAsUser = require("./os-users").wrapSpawnAsUser;
|
|
6
6
|
|
|
7
7
|
function createRuntime(options) {
|
|
8
|
+
var initialStorage = options.storage ? options.storage.read() : null;
|
|
9
|
+
var initialCookies = options.cookies ? options.cookies.read() : null;
|
|
8
10
|
var identity = options.identity;
|
|
9
11
|
var env = buildUserEnv(identity);
|
|
10
12
|
if (process.platform === "win32" && !identity) {
|
|
@@ -14,7 +16,9 @@ function createRuntime(options) {
|
|
|
14
16
|
if (identity) { opts.uid = identity.uid; opts.gid = identity.gid; }
|
|
15
17
|
var spec = wrapSpawnAsUser(process.execPath, [path.join(__dirname, "shared-browser-worker.js")], opts);
|
|
16
18
|
var child = spawn(spec.command, spec.args, spec.options);
|
|
19
|
+
var exited = new Promise(function (resolve) { child.once("close", resolve); });
|
|
17
20
|
var closed = false;
|
|
21
|
+
var closing = false;
|
|
18
22
|
var nextId = 0;
|
|
19
23
|
var pending = new Map();
|
|
20
24
|
var buffer = "";
|
|
@@ -25,19 +29,30 @@ function createRuntime(options) {
|
|
|
25
29
|
function fail(message) {
|
|
26
30
|
pending.forEach(function (entry) { clearTimeout(entry.timer); entry.reject(new Error(message)); });
|
|
27
31
|
pending.clear();
|
|
28
|
-
if (!closed) options.onEvent({ type: "error", error: message });
|
|
32
|
+
if (!closed && !closing) options.onEvent({ type: "error", error: message });
|
|
29
33
|
}
|
|
30
34
|
child.stdin.on("error", function () {});
|
|
31
35
|
child.stdout.setEncoding("utf8");
|
|
32
36
|
child.stdout.on("data", function (chunk) {
|
|
33
37
|
buffer += chunk;
|
|
34
|
-
if (buffer.length >
|
|
38
|
+
if (buffer.length > 32 * 1024 * 1024) { fail("Browser response too large"); child.kill(); return; }
|
|
35
39
|
var at;
|
|
36
40
|
while ((at = buffer.indexOf("\n")) >= 0) {
|
|
37
41
|
var line = buffer.slice(0, at); buffer = buffer.slice(at + 1);
|
|
38
42
|
try {
|
|
39
43
|
var message = JSON.parse(line);
|
|
40
|
-
if (message.type === "
|
|
44
|
+
if (message.type === "storage") {
|
|
45
|
+
try {
|
|
46
|
+
if (!options.storage) throw new Error("Personal site data is unavailable");
|
|
47
|
+
send({ type: "storage", id: message.id, storage: options.storage.exchange(message.previous, message.storage) });
|
|
48
|
+
} catch (error) { send({ type: "storage", id: message.id, error: "Could not save personal browser site data" }); }
|
|
49
|
+
} else if (message.type === "cookies") {
|
|
50
|
+
try {
|
|
51
|
+
if (!options.cookies) throw new Error("Personal cookies are unavailable");
|
|
52
|
+
var cookies = options.cookies.exchange(message.previous, message.cookies);
|
|
53
|
+
send({ type: "cookies", id: message.id, cookies: cookies });
|
|
54
|
+
} catch (error) { send({ type: "cookies", id: message.id, error: "Could not save personal browser cookies" }); }
|
|
55
|
+
} else if (message.type === "result") {
|
|
41
56
|
var entry = pending.get(message.id);
|
|
42
57
|
if (entry) { clearTimeout(entry.timer); pending.delete(message.id); if (message.error) entry.reject(new Error(message.error)); else entry.resolve(message.value); }
|
|
43
58
|
} else options.onEvent(message);
|
|
@@ -45,8 +60,8 @@ function createRuntime(options) {
|
|
|
45
60
|
}
|
|
46
61
|
});
|
|
47
62
|
child.on("error", function () { fail("Browser process could not start"); });
|
|
48
|
-
child.on("exit", function () { fail("Browser process ended"); });
|
|
49
|
-
send({ type: "start" });
|
|
63
|
+
child.on("exit", function () { fail("Browser process ended"); closed = true; });
|
|
64
|
+
send({ type: "start", cookies: initialCookies, storage: initialStorage });
|
|
50
65
|
return {
|
|
51
66
|
control: function (epoch) {
|
|
52
67
|
return new Promise(function (resolve, reject) {
|
|
@@ -78,13 +93,14 @@ function createRuntime(options) {
|
|
|
78
93
|
});
|
|
79
94
|
},
|
|
80
95
|
close: function () {
|
|
81
|
-
if (closed) return;
|
|
82
|
-
|
|
96
|
+
if (closed || closing) return exited;
|
|
97
|
+
closing = true;
|
|
83
98
|
fail("Browser closed");
|
|
84
|
-
child.stdin.end();
|
|
85
|
-
var timer = setTimeout(function () { child.kill("SIGKILL"); },
|
|
99
|
+
try { send({ type: "close" }); } catch (error) { child.stdin.end(); }
|
|
100
|
+
var timer = setTimeout(function () { child.kill("SIGKILL"); }, 30000);
|
|
86
101
|
timer.unref();
|
|
87
102
|
child.once("exit", function () { clearTimeout(timer); });
|
|
103
|
+
return exited;
|
|
88
104
|
},
|
|
89
105
|
};
|
|
90
106
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
var cookieKey = require('./shared-browser-cookies').cookieKey;
|
|
2
|
+
// Saved website data only crosses the private worker pipe, never the agent tool channel.
|
|
3
|
+
function attachStorageSync(context, initial, send) {
|
|
4
|
+
var previous = initial, pending = null, nextId = 0;
|
|
5
|
+
function receive(message) {
|
|
6
|
+
if (!pending || pending.id !== message.id) return;
|
|
7
|
+
var entry = pending; pending = null; clearTimeout(entry.timer);
|
|
8
|
+
if (message.error) entry.reject(new Error(message.error)); else entry.resolve(message.storage);
|
|
9
|
+
}
|
|
10
|
+
async function sync() {
|
|
11
|
+
var current = await context.storageState({ indexedDB: true });
|
|
12
|
+
var saved = await new Promise(function (resolve, reject) {
|
|
13
|
+
pending = { id: ++nextId, resolve: resolve, reject: reject, timer: setTimeout(function () { pending = null; reject(new Error('Could not synchronize browser site data')); }, 10000) };
|
|
14
|
+
try { send({ type: 'storage', id: pending.id, previous: previous, storage: current }); }
|
|
15
|
+
catch (error) { clearTimeout(pending.timer); pending = null; reject(error); }
|
|
16
|
+
});
|
|
17
|
+
var remote = new Map(saved.cookies.map(function (cookie) { return [cookieKey(cookie), cookie]; }));
|
|
18
|
+
var local = new Map(current.cookies.map(function (cookie) { return [cookieKey(cookie), cookie]; }));
|
|
19
|
+
var updates = saved.cookies.filter(function (cookie) { return JSON.stringify(local.get(cookieKey(cookie))) !== JSON.stringify(cookie); });
|
|
20
|
+
current.cookies.forEach(function (cookie) { if (!remote.has(cookieKey(cookie))) updates.push(Object.assign({}, cookie, { expires: 1 })); });
|
|
21
|
+
if (updates.length) await context.addCookies(updates);
|
|
22
|
+
if (previous.generation !== saved.generation) {
|
|
23
|
+
var deletions = (saved.deletions || []).filter(function (entry) { return entry.generation > previous.generation; });
|
|
24
|
+
var unknown = !deletions.length || deletions[0].generation > previous.generation + 1;
|
|
25
|
+
var removed = current.origins.filter(function (origin) {
|
|
26
|
+
return unknown || deletions.some(function (entry) { return entry.operation === 'clear_data' || (entry.operation === 'delete_site' && new URL(origin.origin).hostname === entry.target); });
|
|
27
|
+
});
|
|
28
|
+
if (removed.length) {
|
|
29
|
+
var page = context.pages()[0] || await context.newPage();
|
|
30
|
+
var cdp = await context.newCDPSession(page);
|
|
31
|
+
try {
|
|
32
|
+
for (var origin of removed) await cdp.send('Storage.clearDataForOrigin', { origin: origin.origin, storageTypes: 'local_storage,indexeddb' });
|
|
33
|
+
} finally { await cdp.detach(); }
|
|
34
|
+
}
|
|
35
|
+
current = await context.storageState({ indexedDB: true });
|
|
36
|
+
}
|
|
37
|
+
// Restore origin storage on new tabs, rather than replacing live IndexedDB connections.
|
|
38
|
+
// Each open tab contributes only its own changes. Human removals also clear live origins.
|
|
39
|
+
previous = { generation: saved.generation, cookies: saved.cookies, origins: current.origins };
|
|
40
|
+
}
|
|
41
|
+
return { start: function () { return context.setStorageState({ cookies: initial.cookies, origins: initial.origins }); }, sync: sync, receive: receive };
|
|
42
|
+
}
|
|
43
|
+
module.exports = { attachStorageSync: attachStorageSync };
|