clay-server 5.2.0-beta.1 → 5.2.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/account-auth-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 +51 -0
- package/lib/clay-product-control.js +247 -0
- package/lib/clay-project-lifecycle.js +154 -0
- package/lib/clay-project-record-input.js +44 -0
- package/lib/clay-project-records.js +84 -0
- package/lib/clay-scheduling-input.js +21 -0
- package/lib/clay-scheduling-receipts.js +26 -0
- package/lib/clay-scheduling.js +119 -0
- package/lib/clay-screen-controls.js +104 -0
- package/lib/clay-skill-install.js +1 -33
- package/lib/clay-workspace-controls.js +84 -0
- package/lib/clay-workspace-input.js +17 -0
- package/lib/clay-workspace-receipts.js +26 -0
- package/lib/cli-sessions.js +1 -300
- package/lib/codex-defaults.js +1 -28
- package/lib/context-usage.js +3 -2
- package/lib/contextual-screen-snapshot.js +38 -0
- package/lib/daemon-project-access.js +11 -0
- package/lib/daemon-project-lifecycle-callbacks.js +15 -0
- package/lib/daemon-project-lifecycle.js +262 -0
- package/lib/daemon-projects.js +1 -1
- package/lib/daemon.js +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/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 +50 -0
- package/lib/notes.js +49 -3
- package/lib/os-user-diagnostics.js +2 -4
- package/lib/os-users.js +24 -70
- package/lib/pane-pending-interactions.js +20 -0
- package/lib/pane-session-activation.js +114 -0
- package/lib/pane-session-transport.js +26 -0
- package/lib/project-admin-overview.js +51 -0
- package/lib/project-ask-user.js +8 -4
- package/lib/project-connection.js +14 -10
- package/lib/project-control-git-view.js +12 -0
- package/lib/project-debate.js +1 -0
- package/lib/project-delegated-follow-up.js +2 -1
- package/lib/project-directory-claim.js +65 -0
- package/lib/project-file-operations.js +61 -0
- package/lib/project-filesystem.js +15 -85
- package/lib/project-full-access.js +23 -2
- package/lib/project-http.js +7 -4
- package/lib/project-knowledge.js +32 -18
- package/lib/project-lifecycle-operations.js +98 -0
- package/lib/project-lifecycle-process-witness.js +32 -0
- package/lib/project-lifecycle-runtime.js +50 -0
- package/lib/project-linux-access.js +22 -0
- package/lib/project-logs-canonical-clay.js +27 -0
- package/lib/project-logs-clay-query.js +16 -0
- package/lib/project-logs-schema.js +4 -2
- package/lib/project-logs-service.js +8 -7
- package/lib/project-logs.js +1 -0
- package/lib/project-loop.js +1 -0
- package/lib/project-mate-chat-control.js +55 -0
- package/lib/project-mate-creation-proposal.js +18 -3
- package/lib/project-mate-interaction.js +40 -62
- package/lib/project-mcp.js +54 -16
- package/lib/project-models.js +14 -31
- package/lib/project-notifications.js +76 -17
- package/lib/project-ownership.js +77 -0
- package/lib/project-pair-result-delivery.js +14 -3
- package/lib/project-pair-usage.js +12 -13
- package/lib/project-pending-message-queue.js +4 -1
- package/lib/project-product-control.js +89 -0
- package/lib/project-product-session-queue.js +46 -0
- package/lib/project-push-access.js +28 -0
- package/lib/project-scheduled-message-queue.js +30 -0
- package/lib/project-scheduled-messages.js +67 -68
- package/lib/project-scheduled-task-control.js +83 -0
- package/lib/project-scheduled-tasks.js +13 -2
- package/lib/project-scheduling-access.js +10 -0
- package/lib/project-session-actions.js +65 -0
- package/lib/project-session-delete.js +8 -1
- package/lib/project-session-document.js +27 -7
- package/lib/project-session-github.js +63 -19
- package/lib/project-session-history-actions.js +167 -0
- package/lib/project-session-linear.js +14 -6
- package/lib/project-session-notes.js +7 -3
- package/lib/project-session-pair.js +1 -1
- package/lib/project-session-runtime-actions.js +64 -0
- package/lib/project-session-spawn.js +2 -3
- package/lib/project-session-vendor.js +55 -0
- package/lib/project-sessions.js +103 -272
- package/lib/project-shared-browser.js +78 -17
- package/lib/project-studio-presentation.js +58 -0
- package/lib/project-user-message.js +67 -1
- package/lib/project-vendor-login.js +6 -36
- package/lib/project-workspace-operations.js +126 -0
- package/lib/project-workspace-query.js +19 -2
- package/lib/project.js +178 -45
- package/lib/public/app.js +46 -0
- package/lib/public/appearance-bootstrap.js +16 -0
- package/lib/public/css/clay-tool-activity.css +51 -0
- package/lib/public/css/clay-workspace.css +29 -0
- package/lib/public/css/command-palette.css +12 -33
- package/lib/public/css/contextual-clay.css +240 -0
- package/lib/public/css/home-debate-planning.css +2 -0
- package/lib/public/css/home-mate-creation.css +5 -0
- package/lib/public/css/input.css +6 -0
- package/lib/public/css/mate-avatar-gallery.css +12 -0
- package/lib/public/css/mate-conversation.css +10 -5
- package/lib/public/css/messages.css +6 -2
- package/lib/public/css/overlays.css +4 -2
- package/lib/public/css/project-admin-overview.css +13 -0
- package/lib/public/css/session-folders.css +11 -0
- package/lib/public/css/session-github.css +46 -1
- package/lib/public/css/shared-browser.css +35 -1
- package/lib/public/css/sticky-notes.css +87 -1
- package/lib/public/index.html +11 -5
- 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-projects.js +6 -2
- package/lib/public/modules/app-connection.js +11 -1
- package/lib/public/modules/app-favicon.js +18 -9
- package/lib/public/modules/app-header.js +7 -4
- package/lib/public/modules/app-loop-ui.js +2 -0
- package/lib/public/modules/app-message-router.js +22 -1
- package/lib/public/modules/app-messages.js +115 -17
- package/lib/public/modules/app-misc.js +3 -1
- package/lib/public/modules/app-notifications.js +11 -5
- package/lib/public/modules/app-panels.js +61 -123
- package/lib/public/modules/app-projects.js +13 -0
- package/lib/public/modules/app-rate-limit.js +7 -27
- package/lib/public/modules/app-rendering.js +4 -3
- package/lib/public/modules/avatar.js +15 -41
- package/lib/public/modules/chat-render-runtime.js +20 -0
- package/lib/public/modules/clay-browser-links.js +47 -0
- package/lib/public/modules/clay-control-activity.js +214 -0
- package/lib/public/modules/clay-control-copy.js +36 -0
- package/lib/public/modules/clay-control-detail-targets.js +44 -0
- package/lib/public/modules/clay-control-object-targets.js +52 -0
- package/lib/public/modules/clay-control-target-visibility.js +12 -0
- package/lib/public/modules/clay-control-targets.js +44 -0
- package/lib/public/modules/clay-log-links.js +23 -0
- package/lib/public/modules/clay-navigation-render.js +52 -0
- package/lib/public/modules/clay-owner-navigation.js +33 -0
- package/lib/public/modules/clay-session-links.js +31 -0
- package/lib/public/modules/clay-studio-bridge.js +20 -0
- package/lib/public/modules/clay-studio-document.js +67 -0
- package/lib/public/modules/clay-studio-render.js +146 -0
- package/lib/public/modules/clay-tool-activity.js +140 -0
- package/lib/public/modules/clay-tool-presentation.js +342 -0
- package/lib/public/modules/command-palette.js +162 -40
- package/lib/public/modules/contextual-ask-session.js +26 -0
- package/lib/public/modules/contextual-clay-geometry.js +155 -0
- package/lib/public/modules/contextual-clay-session.js +130 -0
- package/lib/public/modules/contextual-clay-workspace.js +169 -0
- package/lib/public/modules/contextual-clay.js +250 -0
- package/lib/public/modules/contextual-composer.js +91 -0
- package/lib/public/modules/contextual-mate-context.js +117 -0
- package/lib/public/modules/contextual-mate-hint.js +40 -0
- package/lib/public/modules/contextual-mate-identity.js +23 -0
- package/lib/public/modules/contextual-mate-sessions.js +134 -0
- package/lib/public/modules/contextual-search.js +137 -0
- package/lib/public/modules/contextual-session-citations.js +58 -0
- package/lib/public/modules/debate.js +1 -0
- package/lib/public/modules/default-ai.js +11 -3
- package/lib/public/modules/elicitation-form.js +5 -0
- package/lib/public/modules/filebrowser.js +20 -1
- package/lib/public/modules/generation-stop.js +8 -5
- package/lib/public/modules/git-panel.js +3 -1
- package/lib/public/modules/history-replay-batch.js +13 -1
- package/lib/public/modules/home-debate-live.js +2 -0
- package/lib/public/modules/home-debate-planning.js +7 -7
- package/lib/public/modules/home-mate-avatar-editor.js +127 -208
- package/lib/public/modules/home-mate-chat.js +8 -6
- package/lib/public/modules/home-mate-creation.js +73 -1
- package/lib/public/modules/home-mate-settings.js +19 -12
- package/lib/public/modules/icon-strip-tooltip.js +2 -1
- package/lib/public/modules/input.js +88 -10
- package/lib/public/modules/issues-render.js +3 -2
- package/lib/public/modules/knowledge-db-workbench.js +4 -4
- package/lib/public/modules/markdown.js +6 -34
- package/lib/public/modules/mate-avatar-catalog.js +97 -0
- package/lib/public/modules/mate-knowledge-workbench.js +1 -1
- package/lib/public/modules/mate-management.js +40 -7
- package/lib/public/modules/mcp-connection-view.js +31 -13
- package/lib/public/modules/mcp-discovery-view.js +31 -0
- package/lib/public/modules/mcp-ui.js +23 -4
- package/lib/public/modules/mention.js +3 -0
- package/lib/public/modules/message-delivery.js +20 -2
- package/lib/public/modules/model-picker.js +2 -0
- package/lib/public/modules/pane-activation.js +214 -0
- package/lib/public/modules/pane-binding.js +82 -0
- package/lib/public/modules/pane-bridge.js +7 -4
- package/lib/public/modules/pane-browser-bridge.js +22 -0
- package/lib/public/modules/pane-file-bridge.js +4 -0
- package/lib/public/modules/pane-issue-bridge.js +4 -1
- package/lib/public/modules/pending-message-queue.js +1 -0
- package/lib/public/modules/permission-control.js +5 -4
- package/lib/public/modules/personal-settings-dialog.js +7 -1
- package/lib/public/modules/product-review.js +26 -0
- package/lib/public/modules/profile.js +1 -238
- package/lib/public/modules/project-access-recovery.js +17 -0
- package/lib/public/modules/project-admin-overview.js +21 -0
- package/lib/public/modules/project-chat-identity.js +13 -4
- package/lib/public/modules/project-logs-render.js +3 -0
- package/lib/public/modules/project-mate-navigation.js +144 -22
- package/lib/public/modules/rewind.js +5 -0
- package/lib/public/modules/scheduled-tasks.js +2 -0
- package/lib/public/modules/scheduler.js +2 -0
- package/lib/public/modules/search-clay-chat.js +5 -440
- package/lib/public/modules/session-actions.js +5 -2
- package/lib/public/modules/session-context-menu.js +5 -0
- package/lib/public/modules/session-create-form.js +10 -10
- package/lib/public/modules/session-folder-layout.js +1 -1
- package/lib/public/modules/session-folder-view-menu.js +9 -0
- package/lib/public/modules/session-github.js +85 -14
- package/lib/public/modules/session-rich-drafts.js +21 -0
- package/lib/public/modules/session-switch-defer.js +67 -0
- package/lib/public/modules/session-work-primary.js +51 -0
- package/lib/public/modules/settings-defaults.js +27 -28
- package/lib/public/modules/shared-browser-settings.js +112 -0
- package/lib/public/modules/shared-browser-tabs.js +13 -3
- package/lib/public/modules/shared-browser.js +29 -6
- package/lib/public/modules/sidebar-mobile.js +4 -3
- package/lib/public/modules/sidebar-projects.js +1 -0
- package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
- package/lib/public/modules/sidebar-sessions.js +1 -0
- package/lib/public/modules/split-group-restore.js +68 -0
- package/lib/public/modules/split-pair-ui.js +1 -0
- package/lib/public/modules/split-pane-reconciler.js +15 -0
- package/lib/public/modules/split-pane-renderer.js +87 -6
- package/lib/public/modules/split-session-boundary.js +1 -1
- package/lib/public/modules/split-view.js +60 -68
- package/lib/public/modules/sticky-note-markdown.js +72 -6
- package/lib/public/modules/sticky-notes-actions.js +30 -0
- package/lib/public/modules/sticky-notes-browser.js +9 -2
- package/lib/public/modules/sticky-notes-card.js +23 -7
- package/lib/public/modules/sticky-notes-checklist.js +116 -0
- package/lib/public/modules/sticky-notes-editor.js +108 -44
- package/lib/public/modules/sticky-notes-shared.js +50 -2
- package/lib/public/modules/sticky-notes-state.js +66 -0
- package/lib/public/modules/sticky-notes.js +34 -51
- package/lib/public/modules/stt-controller.js +4 -1
- package/lib/public/modules/stt-recording.js +1 -1
- package/lib/public/modules/stt.js +7 -2
- package/lib/public/modules/terminal.js +9 -0
- package/lib/public/modules/theme.js +8 -1
- package/lib/public/modules/thinking-lifecycle.js +33 -3
- package/lib/public/modules/thinking-view.js +23 -1
- package/lib/public/modules/tools.js +60 -11
- package/lib/public/modules/tui-grab.js +1 -2
- package/lib/public/modules/user-settings-appearance.js +10 -3
- package/lib/public/modules/user-settings-editors.js +1 -1
- package/lib/public/modules/user-settings-layout.js +11 -2
- package/lib/public/modules/user-settings-preferences.js +6 -2
- package/lib/public/modules/user-settings-profile.js +12 -2
- package/lib/public/modules/user-settings.js +3 -2
- package/lib/public/modules/vendor-login-browser.js +5 -3
- package/lib/public/modules/vendor-login.js +2 -2
- package/lib/public/modules/vendor-priority.js +15 -1
- package/lib/public/modules/wireframe-workbench.js +5 -2
- package/lib/public/muse-avatar.svg +4 -0
- package/lib/public/style.css +5 -0
- package/lib/public/sw.js +3 -1
- package/lib/safe-bash-commands.js +3 -45
- package/lib/scheduled-task-records.js +3 -1
- package/lib/scheduler.js +2 -0
- package/lib/sdk-bridge.js +342 -401
- package/lib/sdk-foreground-admission.js +16 -0
- package/lib/sdk-mcp-descriptors.js +2 -37
- package/lib/sdk-message-processor.js +52 -17
- package/lib/sdk-quota-snapshot.js +1 -1
- package/lib/sdk-response-recovery.js +1 -0
- package/lib/sdk-worker.js +2 -677
- package/lib/server-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-global-ws.js +10 -20
- package/lib/server-home-chat-events.js +18 -4
- package/lib/server-home-chat.js +22 -20
- package/lib/server-home-clay-entry.js +23 -4
- package/lib/server-home-clay-session-links.js +29 -9
- package/lib/server-home-mate-creation.js +1 -0
- package/lib/server-home-mcp-consent.js +14 -0
- package/lib/server-mates.js +25 -62
- package/lib/server-owner-ui.js +118 -0
- package/lib/server-path-access.js +38 -0
- package/lib/server-project-removal.js +22 -0
- package/lib/server-settings.js +6 -1
- package/lib/server.js +163 -43
- package/lib/session-config-transition.js +45 -0
- package/lib/session-folders.js +7 -2
- package/lib/session-fork-history.js +21 -0
- package/lib/session-github.js +9 -2
- package/lib/session-hygiene.js +3 -35
- package/lib/session-permission-mode.js +4 -3
- package/lib/session-skill-scope.js +11 -0
- package/lib/session-visibility.js +5 -2
- package/lib/session-work-primary.js +50 -0
- package/lib/sessions.js +64 -99
- package/lib/shared-browser-cookie-sync.js +32 -0
- package/lib/shared-browser-cookies.js +79 -0
- package/lib/shared-browser-runtime.js +25 -9
- package/lib/shared-browser-storage-sync.js +43 -0
- package/lib/shared-browser-storage.js +101 -0
- package/lib/shared-browser-tools.js +2 -1
- package/lib/shared-browser-worker.js +46 -10
- package/lib/terminal-manager.js +65 -6
- package/lib/tool-llm.js +1 -1
- package/lib/tui-transcript-index.js +1 -132
- package/lib/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/workspace-assignment-service.js +25 -0
- package/lib/workspace-query-access.js +4 -1
- package/lib/workspace-query-mcp-server.js +1 -1
- package/lib/workspace-query-service.js +13 -2
- package/lib/ws-request.js +1 -0
- package/lib/ws-schema.js +18 -2
- package/lib/yoke/acp-agent-profiles.js +7 -5
- package/lib/yoke/adapters/antigravity.js +3 -14
- package/lib/yoke/adapters/claude-query-contract.js +9 -0
- package/lib/yoke/adapters/claude.js +54 -50
- package/lib/yoke/adapters/codex-query-contract.js +24 -0
- package/lib/yoke/adapters/codex.js +53 -111
- package/lib/yoke/adapters/kiro.js +3 -1
- package/lib/yoke/adapters/muse-query-contract.js +7 -0
- package/lib/yoke/adapters/muse.js +122 -0
- package/lib/yoke/auth-events.js +17 -0
- package/lib/yoke/claude-hook-installer.js +271 -0
- package/lib/yoke/claude-jsonl-watcher.js +204 -0
- package/lib/yoke/claude-maintenance.js +55 -0
- package/lib/yoke/claude-permission-patterns.js +53 -0
- package/lib/yoke/claude-response-recovery.js +155 -0
- package/lib/yoke/claude-transcript-hygiene.js +34 -0
- package/lib/yoke/claude-worker-startup.js +28 -0
- package/lib/yoke/clay-skill-install.js +33 -0
- package/lib/yoke/cli-sessions.js +300 -0
- package/lib/yoke/codex-app-server.js +7 -12
- package/lib/yoke/codex-idle-recovery.js +81 -1
- package/lib/yoke/codex-recovery-admission.js +164 -0
- package/lib/yoke/configuration.js +13 -0
- package/lib/yoke/discovery.js +70 -0
- package/lib/yoke/errors.js +8 -0
- package/lib/yoke/host-environment.js +7 -0
- package/lib/yoke/index.js +9 -51
- package/lib/yoke/interface.js +116 -0
- package/lib/yoke/kiro-acp-server.js +5 -5
- package/lib/yoke/legacy-sessions.js +89 -0
- package/lib/yoke/login-protocol.js +25 -0
- package/lib/yoke/maintenance.js +12 -0
- package/lib/yoke/mcp-proxy.js +32 -0
- package/lib/yoke/mcp-source-adapters.js +91 -0
- package/lib/yoke/mcp-source-context.js +42 -0
- package/lib/yoke/mcp-source-discovery.js +169 -0
- package/lib/yoke/mcp-source-plugins.js +68 -0
- package/lib/yoke/mcp-source-restrictions.js +47 -0
- package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
- package/lib/yoke/model-preferences.js +6 -0
- package/lib/yoke/muse-artifacts.js +36 -0
- package/lib/yoke/muse-controls.js +50 -0
- package/lib/yoke/muse-input.js +64 -0
- package/lib/yoke/muse-items.js +157 -0
- package/lib/yoke/muse-policy.js +52 -0
- package/lib/yoke/muse-query.js +428 -0
- package/lib/yoke/muse-runtime.js +211 -0
- package/lib/yoke/muse-services.js +79 -0
- package/lib/yoke/muse-skills.js +79 -0
- package/lib/yoke/muse-turns.js +71 -0
- package/lib/yoke/options/acp.js +2 -0
- package/lib/yoke/options/antigravity.js +2 -0
- package/lib/yoke/options/claude.js +21 -0
- package/lib/yoke/options/codex-defaults.js +29 -0
- package/lib/yoke/options/codex-settings.js +21 -0
- package/lib/yoke/options/codex.js +6 -0
- package/lib/yoke/options/kiro-defaults.js +22 -0
- package/lib/yoke/options/kiro.js +5 -0
- package/lib/yoke/options/muse.js +5 -0
- package/lib/yoke/provider-contract.js +5 -0
- package/lib/yoke/providers/antigravity-executable.js +8 -0
- package/lib/yoke/providers/claude-executable.js +40 -0
- package/lib/yoke/providers/claude-model-descriptions.js +14 -0
- package/lib/yoke/providers/claude-process.js +97 -0
- package/lib/yoke/providers/claude-provision.js +75 -0
- package/lib/yoke/providers/codex-errors.js +8 -0
- package/lib/yoke/providers/muse-executable.js +17 -0
- package/lib/yoke/provisioning.js +6 -0
- package/lib/yoke/query-options.js +10 -0
- package/lib/yoke/response-recovery.js +41 -0
- package/lib/yoke/sdk-mcp-descriptors.js +37 -0
- package/lib/yoke/sdk-server-factory.js +7 -0
- package/lib/yoke/session-history.js +8 -0
- package/lib/yoke/session-tool-transport.js +34 -13
- package/lib/yoke/settings.js +23 -0
- package/lib/yoke/source-locations.js +4 -0
- package/lib/yoke/title-query.js +18 -7
- package/lib/yoke/tui-transcript-index.js +132 -0
- package/lib/yoke/usage.js +48 -0
- package/lib/yoke/user-input.js +13 -0
- package/lib/yoke/vendor-registry.js +81 -1
- package/package.json +10 -4
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
var path = require('path');
|
|
2
|
+
var presentation = require('./clay-control-presentation');
|
|
3
|
+
|
|
4
|
+
function bindPresentation(ctx) {
|
|
5
|
+
function stamp(mate) { return mate && JSON.stringify([mate.id, mate.createdBy || null, mate.createdAt || null, mate.builtinKey || null]); }
|
|
6
|
+
var sourceRoot, sourceIdentity;
|
|
7
|
+
var sourceOrigin = ctx.session.sessionOriginId, sourceGeneration = ctx.session._sdkQueryGeneration;
|
|
8
|
+
var sourceStamp = stamp(ctx.resolveMate(ctx.ownerId, ctx.mateId));
|
|
9
|
+
function sourceValid() {
|
|
10
|
+
ctx.authorize();
|
|
11
|
+
if (!sourceOrigin || ctx.session.sessionOriginId !== sourceOrigin || ctx.session._sdkQueryGeneration !== sourceGeneration || stamp(ctx.resolveMate(ctx.ownerId, ctx.mateId)) !== sourceStamp) throw new Error('The exact presentation source changed.');
|
|
12
|
+
if (ctx.session._pendingMessageDrainPaused) throw new Error('The source was stopped.');
|
|
13
|
+
var project = ctx.getProjects().get(ctx.sourceSlug), status = project.getStatus();
|
|
14
|
+
if (ctx.getMateDir && path.resolve(status.path) !== path.resolve(ctx.getMateDir(ctx.ownerId || 'default', ctx.mateId))) throw new Error('Source directory changed.');
|
|
15
|
+
var identity = project.getMateChatControl && project.getMateChatControl().validate(ctx.session);
|
|
16
|
+
if (sourceRoot !== undefined && (sourceRoot !== status.path || sourceIdentity !== identity)) throw new Error('Source runtime identity changed.');
|
|
17
|
+
sourceRoot = status.path; sourceIdentity = identity;
|
|
18
|
+
}
|
|
19
|
+
var source = { sourceSessionOriginId: sourceOrigin, sourceMateStamp: sourceStamp, sourceQueryGeneration: sourceGeneration || 0 };
|
|
20
|
+
|
|
21
|
+
var engine = presentation.attachControlPresentation({ session: ctx.session, authorize: ctx.authorize,
|
|
22
|
+
open: function (description) {
|
|
23
|
+
var service = ctx.getOwnerUi && ctx.getOwnerUi();
|
|
24
|
+
var principal = ctx.authorize();
|
|
25
|
+
return service && service.activity && service.activity(principal.userId || null, ctx.sourceSlug, ctx.session.localId, ctx.mateId, description.viewer, source, sourceValid, description.target);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
function describe(domain, bucket, args) {
|
|
29
|
+
var entry = bucket && bucket.targets.get(args.targetToken);
|
|
30
|
+
if (!entry) return null;
|
|
31
|
+
var op = entry.op || entry.intent || {}, live = entry.live || entry.initial || entry.snapshot && entry.snapshot.live || {};
|
|
32
|
+
var project = entry.project || entry.runtime || live.project;
|
|
33
|
+
var session = entry.session || live.session;
|
|
34
|
+
var slug = entry.slug || live.slug || op.projectSlug || entry.intent && entry.intent.projectSlug;
|
|
35
|
+
if (!slug && project) ctx.getProjects().forEach(function (item, key) { if (item === project) slug = key; });
|
|
36
|
+
var initialStatus = project && project.getStatus(), root = initialStatus && initialStatus.path;
|
|
37
|
+
var action = args.action || op.action;
|
|
38
|
+
// These are fixed adapter identities, never selectors supplied by a tool.
|
|
39
|
+
var target = require('./clay-control-target-projection').describe(domain, entry, project, slug, session);
|
|
40
|
+
function targetValid(exact, removed) {
|
|
41
|
+
sourceValid();
|
|
42
|
+
var principal = ctx.authorize();
|
|
43
|
+
if (exact && entry.mate && JSON.stringify(ctx.resolveMate(ctx.ownerId, entry.mate.id)) !== JSON.stringify(entry.mate)) throw new Error('Target Mate revision changed.');
|
|
44
|
+
if (exact && entry.presentationValid) entry.presentationValid();
|
|
45
|
+
if (!project) return;
|
|
46
|
+
if (removed && !ctx.getProjects().has(slug)) return;
|
|
47
|
+
if (ctx.getProjects().get(slug) !== project || project.getStatus().path !== root) throw new Error('Target runtime changed.');
|
|
48
|
+
var current = project.getStatus();
|
|
49
|
+
if (current.isMate) {
|
|
50
|
+
var mate = ctx.resolveMate(ctx.ownerId, current.mateId);
|
|
51
|
+
if (!mate || mate.lifecycleDeletion || current.projectOwnerId !== ctx.ownerId || ctx.multiUser() && mate.createdBy !== ctx.ownerId || ctx.getMateDir && path.resolve(current.path) !== path.resolve(ctx.getMateDir(ctx.ownerId || 'default', mate.id))) throw new Error('Target Mate revoked.');
|
|
52
|
+
} else {
|
|
53
|
+
var decision = ctx.access.evaluate(principal, current);
|
|
54
|
+
if (!decision.owned || !decision.accessible || ctx.canUsePath && !ctx.canUsePath(principal.userId, current.path)) throw new Error('Target project access changed.');
|
|
55
|
+
if (current.isWorktree) {
|
|
56
|
+
var parent = ctx.getProjects().get(current.parentSlug), parentStatus = parent && parent.getStatus();
|
|
57
|
+
if (!parentStatus || !ctx.access.evaluate(principal, parentStatus).owned || !ctx.access.evaluate(principal, parentStatus).accessible) throw new Error('Parent access changed.');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (session && !(removed && !project.getSessionManager().sessions.has(session.localId)) && (project.getSessionManager().sessions.get(session.localId) !== session || !removed && (session.hidden || session.destroying) || (session.ownerId || null) !== (principal.userId || null))) throw new Error('Target conversation changed.');
|
|
61
|
+
}
|
|
62
|
+
return { domain: domain, action: action, target: target,
|
|
63
|
+
viewer: domain === 'screen' && op.action === 'navigate' ? entry.snapshot.viewer : null,
|
|
64
|
+
validSource: sourceValid, removesTarget: action === 'delete' || action === 'remove',
|
|
65
|
+
valid: function () { targetValid(true); },
|
|
66
|
+
validTerminal: function (removed) { targetValid(false, removed); }
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function track(domain, action, target, valid, phase) {
|
|
70
|
+
try {
|
|
71
|
+
sourceValid();
|
|
72
|
+
var observer, release, description;
|
|
73
|
+
var pending = new Promise(function (resolve) { release = resolve; });
|
|
74
|
+
var expiry;
|
|
75
|
+
engine.wrap(function () { observer = engine.current(); observer.start(phase || 'running'); return pending; }, function () {
|
|
76
|
+
description = { domain: domain, action: action, target: target || null, validSource: sourceValid, valid: function () { sourceValid(); if (valid) valid(); }, validTerminal: function () { sourceValid(); if (valid) valid(); } }; return description;
|
|
77
|
+
})({});
|
|
78
|
+
expiry = setTimeout(function () { release({ outcome: 'uncertain' }); }, 300000); expiry.unref();
|
|
79
|
+
return { id: observer.id, guard: function () { sourceValid(); if (valid) valid(); }, focus: observer.focus, target: function (value, check) { description.target = value; if (check) valid = check; }, phase: observer.update, finish: function (result) { clearTimeout(expiry); release(result); }, cancel: function () { clearTimeout(expiry); observer.cancel(); release({ status: 'cancelled' }); } };
|
|
80
|
+
} catch (error) { return null; }
|
|
81
|
+
}
|
|
82
|
+
function decorate(api) {
|
|
83
|
+
var methods = { act: ['session', null], actProject: ['project', 'lifecycle'], actMate: ['mate', 'mates'],
|
|
84
|
+
actMateKnowledge: ['knowledge', 'knowledge'], actProjectRecords: ['records', 'records'],
|
|
85
|
+
actSchedules: ['schedule', 'scheduling'], actMateChat: ['conversation', 'mateChat'],
|
|
86
|
+
actWorkspace: ['workspace', 'workspace'], actScreen: ['screen', 'screen'] };
|
|
87
|
+
Object.keys(methods).forEach(function (name) {
|
|
88
|
+
if (!api[name]) return;
|
|
89
|
+
var adapter = methods[name];
|
|
90
|
+
api[name] = engine.wrap(api[name], function (args) { return describe(adapter[0], adapter[1] ? ctx.state[adapter[1]] : ctx.state, args); });
|
|
91
|
+
});
|
|
92
|
+
return api;
|
|
93
|
+
}
|
|
94
|
+
return { decorate: decorate, review: engine.review, current: engine.current, track: track, source: function () { sourceValid(); return Object.assign({ ownerId: ctx.session.ownerId || null, sourceSlug: ctx.sourceSlug, sourceSessionId: ctx.session.localId, mateId: ctx.mateId, runtimeId: require('./clay-control-target-projection').runtime(ctx.getProjects().get(ctx.sourceSlug).getSessionManager()) }, source); } };
|
|
95
|
+
}
|
|
96
|
+
module.exports = { bindPresentation: bindPresentation };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
var crypto = require('crypto');
|
|
2
|
+
var AsyncLocalStorage = require('async_hooks').AsyncLocalStorage;
|
|
3
|
+
var z = require('zod');
|
|
4
|
+
var slug = z.string().min(1).max(200).refine(function (value) { return !/[\u0000-\u001f\u007f]/.test(value); });
|
|
5
|
+
var activitySchema = z.object({
|
|
6
|
+
version: z.literal(1), id: z.string().regex(/^activity:[\w-]{36}$/), sequence: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
7
|
+
phase: z.enum(['review', 'running', 'proposed', 'persisted', 'completed', 'queued', 'delivered', 'acknowledged', 'rendered', 'render_unknown', 'cancelled', 'failed', 'partial', 'unknown']),
|
|
8
|
+
terminal: z.boolean(),
|
|
9
|
+
domain: z.enum(['session', 'project', 'mate', 'knowledge', 'records', 'schedule', 'conversation', 'workspace', 'screen', 'assignment', 'studio']),
|
|
10
|
+
action: z.string().regex(/^[a-z_]{1,60}$/),
|
|
11
|
+
target: z.discriminatedUnion('kind', [
|
|
12
|
+
z.object({ kind: z.literal('surface'), sourceSlug: slug, sourceSessionId: z.number().int().positive(), sourceSessionOriginId: slug, runtimeId: slug, surface: z.enum(['document', 'sketch', 'browser']), key: z.string().min(1).max(400), revision: slug }).strict(),
|
|
13
|
+
z.object({ kind: z.literal('notifications'), items: z.array(z.object({ id: slug, revision: slug }).strict()).min(1).max(50) }).strict(),
|
|
14
|
+
z.object({ kind: z.literal('knowledge'), projectSlug: slug, runtimeId: slug, object: z.enum(['document', 'database', 'record']), objectId: slug.nullable(), revision: z.string().max(200), databaseId: slug.nullable(), databaseRevision: z.string().max(200).nullable(), name: z.string().max(300).nullable() }).strict(),
|
|
15
|
+
z.object({ kind: z.literal('git-set'), projectSlug: slug, runtimeId: slug, repository: slug, files: z.array(z.object({ path: z.string().min(1).max(300), revision: slug }).strict()).min(1).max(30) }).strict(),
|
|
16
|
+
z.object({ kind: z.literal('session'), projectSlug: slug, sessionId: z.number().int().positive(), sessionOriginId: z.string().min(1).max(128) }).strict(),
|
|
17
|
+
z.object({ kind: z.literal('project'), projectSlug: slug, runtimeId: slug }).strict(),
|
|
18
|
+
z.object({ kind: z.literal('mate'), mateId: slug, mateStamp: z.string().max(1000) }).strict(),
|
|
19
|
+
z.object({ kind: z.literal('record'), projectSlug: slug, runtimeId: slug, area: z.enum(['issues', 'logs']), ref: slug, revision: slug }).strict(),
|
|
20
|
+
z.object({ kind: z.literal('file'), projectSlug: slug, runtimeId: slug, path: z.string().min(1).max(300), revision: slug }).strict(),
|
|
21
|
+
z.object({ kind: z.literal('git'), projectSlug: slug, runtimeId: slug, path: z.string().min(1).max(300), repository: slug, revision: slug }).strict(),
|
|
22
|
+
z.object({ kind: z.literal('terminal'), projectSlug: slug, runtimeId: slug, id: z.number().int().positive(), identity: slug, revision: slug }).strict(),
|
|
23
|
+
z.object({ kind: z.literal('schedule'), projectSlug: slug, runtimeId: slug, id: slug, revision: slug, sessionId: z.number().int().positive(), sessionOriginId: slug }).strict()
|
|
24
|
+
]).nullable()
|
|
25
|
+
}).strict();
|
|
26
|
+
|
|
27
|
+
// Presentation observes typed service calls; it cannot approve or dispatch effects.
|
|
28
|
+
function attachControlPresentation(ctx) {
|
|
29
|
+
var local = new AsyncLocalStorage();
|
|
30
|
+
function current() { return local.getStore(); }
|
|
31
|
+
function wrap(fn, describe) {
|
|
32
|
+
return function (args) {
|
|
33
|
+
var description;
|
|
34
|
+
try { description = describe(args || {}); } catch (error) { return fn(args); }
|
|
35
|
+
if (!description) return fn(args);
|
|
36
|
+
var receiptViewer, activity, stopped = false, started = false, seq = 0, timer, expiry, abort, signal, reviewCheck;
|
|
37
|
+
var id = 'activity:' + crypto.randomUUID();
|
|
38
|
+
function close() {
|
|
39
|
+
clearInterval(timer);
|
|
40
|
+
clearTimeout(expiry);
|
|
41
|
+
if (abort && signal) signal.removeEventListener('abort', abort);
|
|
42
|
+
}
|
|
43
|
+
function emit(phase, terminal) {
|
|
44
|
+
if (stopped) return;
|
|
45
|
+
try {
|
|
46
|
+
ctx.authorize();
|
|
47
|
+
if (description.validSource) description.validSource();
|
|
48
|
+
if (terminal) { if (description.validTerminal) description.validTerminal(description.removesTarget && ['completed', 'persisted', 'partial'].indexOf(phase) >= 0); }
|
|
49
|
+
else if (description.valid) description.valid();
|
|
50
|
+
if (!activity) activity = ctx.open(description);
|
|
51
|
+
var event = activitySchema.parse({ version: 1, id: id, sequence: ++seq, phase: phase,
|
|
52
|
+
terminal: !!terminal, domain: description.domain, action: description.action, target: terminal && phase !== 'rendered' ? null : description.target || null });
|
|
53
|
+
if (activity) activity.send(event, receiptViewer);
|
|
54
|
+
} catch (error) { cancel(); }
|
|
55
|
+
}
|
|
56
|
+
function cancel() {
|
|
57
|
+
if (stopped) return;
|
|
58
|
+
// A withdrawal carries no target or result and is safe after revocation.
|
|
59
|
+
if (activity) activity.clear(id, ++seq);
|
|
60
|
+
stopped = true; close();
|
|
61
|
+
}
|
|
62
|
+
var observer = {
|
|
63
|
+
id: id,
|
|
64
|
+
start: function (phase, validateReview) {
|
|
65
|
+
reviewCheck = phase === 'review' ? validateReview : null;
|
|
66
|
+
if (!started) {
|
|
67
|
+
started = true;
|
|
68
|
+
abort = cancel;
|
|
69
|
+
signal = ctx.session.abortController && ctx.session.abortController.signal;
|
|
70
|
+
if (signal) signal.addEventListener('abort', abort, { once: true });
|
|
71
|
+
expiry = setTimeout(function () { emit('unknown'); stopped = true; close(); }, 300000);
|
|
72
|
+
expiry.unref();
|
|
73
|
+
timer = setInterval(function () {
|
|
74
|
+
try { ctx.authorize(); if (reviewCheck) reviewCheck(); if (description.valid) description.valid(); }
|
|
75
|
+
catch (error) { cancel(); }
|
|
76
|
+
}, 250);
|
|
77
|
+
timer.unref();
|
|
78
|
+
}
|
|
79
|
+
emit(phase || 'running');
|
|
80
|
+
},
|
|
81
|
+
focus: function (viewer) { receiptViewer = viewer; },
|
|
82
|
+
update: function (phase) { if (!stopped) emit(phase); },
|
|
83
|
+
navigation: function (phase) { if (!stopped) emit(phase, true); },
|
|
84
|
+
cancel: cancel
|
|
85
|
+
};
|
|
86
|
+
return local.run(observer, function () {
|
|
87
|
+
function finish(result) {
|
|
88
|
+
if (started && !stopped) {
|
|
89
|
+
var phase = outcome(result);
|
|
90
|
+
emit(phase, true);
|
|
91
|
+
}
|
|
92
|
+
close(); return result;
|
|
93
|
+
}
|
|
94
|
+
// Retain synchronous authorization failures and original return semantics.
|
|
95
|
+
try {
|
|
96
|
+
var result = fn(args);
|
|
97
|
+
if (!result || typeof result.then !== 'function') return finish(result);
|
|
98
|
+
return result.then(finish, function (error) { if (started) emit('unknown'); close(); throw error; });
|
|
99
|
+
} catch (error) { close(); throw error; }
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async function review(fn, question, check, presentation) {
|
|
104
|
+
check();
|
|
105
|
+
var observer = current();
|
|
106
|
+
if (observer) observer.start('review', check);
|
|
107
|
+
var result = await fn(question, check, presentation);
|
|
108
|
+
if (result.status === 'submitted' && result.answers && result.answers.control && result.answers.control.length === 1 && result.answers.control[0] === 'Apply exact change') {
|
|
109
|
+
check();
|
|
110
|
+
if (observer) observer.start('running');
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
return { wrap: wrap, review: review, current: current };
|
|
115
|
+
}
|
|
116
|
+
function outcome(result) {
|
|
117
|
+
if (!result || result.persisted === 'unknown' || result.applied === 'unknown' || result.runtimeEffect === 'unknown' || result.outcome === 'uncertain') return 'unknown';
|
|
118
|
+
if (result.status === 'rendered' || result.status === 'render_unknown') return result.status;
|
|
119
|
+
if (result.status === 'cancelled') return 'cancelled';
|
|
120
|
+
if (result.status === 'failed') return result.persisted === true || result.runtimeEffect === 'applied' ? 'partial' : 'failed';
|
|
121
|
+
if (result.status === 'delivered') return 'delivered';
|
|
122
|
+
if (result.status === 'proposed') return 'proposed';
|
|
123
|
+
if (result.status === 'queued' || result.delivery === 'queued') return 'queued';
|
|
124
|
+
if (result.persisted === true) return 'persisted';
|
|
125
|
+
if (result.status === 'completed') return 'completed';
|
|
126
|
+
return 'unknown';
|
|
127
|
+
}
|
|
128
|
+
module.exports = { attachControlPresentation: attachControlPresentation, outcome: outcome };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
var crypto = require('crypto');
|
|
2
|
+
var runtimes = new WeakMap();
|
|
3
|
+
function runtime(manager) {
|
|
4
|
+
if (!runtimes.has(manager)) runtimes.set(manager, 'runtime:' + crypto.randomUUID());
|
|
5
|
+
return runtimes.get(manager);
|
|
6
|
+
}
|
|
7
|
+
function digest(value) { return crypto.createHash('sha256').update(JSON.stringify(value)).digest('hex'); }
|
|
8
|
+
function mateStamp(mate) { return JSON.stringify([mate.id, mate.createdBy || null, mate.createdAt || null, mate.builtinKey || null]); }
|
|
9
|
+
function describe(domain, entry, project, slug, session) {
|
|
10
|
+
var op = entry.op || entry.intent || {}, base = project && { projectSlug: slug, runtimeId: runtime(project.getSessionManager()) };
|
|
11
|
+
if (domain === 'screen' && op.action === 'dismiss_notifications') return { kind: 'notifications', items: entry.snapshot.notifications.map(function (item) { return { id: item.id, revision: item.controlRevision }; }) };
|
|
12
|
+
if (domain === 'knowledge') {
|
|
13
|
+
var snapshot = entry.snapshot || {};
|
|
14
|
+
return Object.assign({ kind: 'knowledge', object: op.recordId ? 'record' : op.databaseId ? 'database' : 'document', objectId: op.recordId || op.databaseId || snapshot.documentId || null, revision: String(op.recordId ? op.expectedRevision : snapshot.revision || ''), databaseId: op.databaseId || null, databaseRevision: op.databaseId ? String(snapshot.revision) : null, name: snapshot.name || op.name || null }, base);
|
|
15
|
+
}
|
|
16
|
+
if (domain === 'mate' && entry.mate) return { kind: 'mate', mateId: entry.mate.id, mateStamp: mateStamp(entry.mate) };
|
|
17
|
+
if (domain === 'records' && op.ref) return Object.assign({ kind: 'record', area: op.area, ref: op.ref, revision: String(op.expectedRevision) }, base);
|
|
18
|
+
if (domain === 'workspace' && op.domain === 'git' && op.paths.length === 1) { var file = entry.snapshot.status.files.find(function (item) { return item.path === op.paths[0]; }); return Object.assign({ kind: 'git', path: file.path, repository: digest(entry.snapshot.gitDirectory), revision: digest([entry.snapshot.status.oid, entry.snapshot.index, file]) }, base); }
|
|
19
|
+
if (domain === 'workspace' && op.domain === 'git') return Object.assign({ kind: 'git-set', repository: digest(entry.snapshot.gitDirectory), files: op.paths.map(function (name) { var file = entry.snapshot.status.files.find(function (item) { return item.path === name; }); return { path: name, revision: digest([entry.snapshot.status.oid, entry.snapshot.index, file]) }; }) }, base);
|
|
20
|
+
if (domain === 'workspace' && op.domain === 'terminal' && op.id) return Object.assign({ kind: 'terminal', id: op.id, identity: entry.snapshot.identity, revision: digest(entry.snapshot) }, base);
|
|
21
|
+
if (domain === 'workspace' && op.domain === 'files') return Object.assign({ kind: 'file', path: op.path, revision: digest(entry.snapshot) }, base);
|
|
22
|
+
if (domain === 'schedule' && op.id) return Object.assign({ kind: 'schedule', id: op.id, revision: String(op.revision), sessionId: session.localId, sessionOriginId: session.sessionOriginId }, base);
|
|
23
|
+
if (session && slug && session.sessionOriginId) return { kind: 'session', projectSlug: slug, sessionId: session.localId, sessionOriginId: session.sessionOriginId };
|
|
24
|
+
return base ? Object.assign({ kind: 'project' }, base) : null;
|
|
25
|
+
}
|
|
26
|
+
module.exports = { runtime: runtime, digest: digest, describe: describe };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Persist before execution; an interrupted application never retries blindly.
|
|
2
|
+
function attachReceipts(ctx) {
|
|
3
|
+
function entries() { return ctx.session.clayMateChatReceipts || []; }
|
|
4
|
+
function save(entry) {
|
|
5
|
+
ctx.authorize();
|
|
6
|
+
var previous = ctx.session.clayMateChatReceipts;
|
|
7
|
+
var all = entries().filter(function (item) {
|
|
8
|
+
var stamp = /_(\d{13})_/.exec(item.id);
|
|
9
|
+
return item.id !== entry.id && (item.status === 'applying' || !stamp || Date.now() - Number(stamp[1]) <= 86400000);
|
|
10
|
+
});
|
|
11
|
+
if (all.length >= 100) throw new Error('Mate chat receipt capacity is full for this 24-hour window; inspect pending attempts and wait for completed receipts to expire.');
|
|
12
|
+
ctx.session.clayMateChatReceipts = all.concat([entry]);
|
|
13
|
+
if (ctx.save() !== true) { ctx.session.clayMateChatReceipts = previous; throw new Error('The Mate chat retry receipt could not be saved.'); }
|
|
14
|
+
ctx.authorize();
|
|
15
|
+
}
|
|
16
|
+
function read(id, key) {
|
|
17
|
+
ctx.authorize();
|
|
18
|
+
var match = /^[A-Za-z][A-Za-z0-9-]*_(\d{13})_[A-Za-z0-9_-]{1,80}$/.exec(id || '');
|
|
19
|
+
if (!match || Math.abs(Date.now() - Number(match[1])) > 86400000) throw new Error('Mate chat requestId requires prefix_<13-digit creation time>_<unique suffix> within 24 hours.');
|
|
20
|
+
var entry = entries().find(function (item) { return item.id === id; });
|
|
21
|
+
if (entry && key !== undefined && entry.key !== key) throw new Error('requestId already names another Mate chat intent.');
|
|
22
|
+
return entry;
|
|
23
|
+
}
|
|
24
|
+
return { read: read, save: save };
|
|
25
|
+
}
|
|
26
|
+
module.exports = { attachReceipts: attachReceipts };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
var crypto = require('crypto');
|
|
2
|
+
var path = require('path');
|
|
3
|
+
var refs = require('./workspace-query-service');
|
|
4
|
+
var z = require('zod');
|
|
5
|
+
var targetSchema = z.object({ mateId: z.string().min(1).max(100), sessionRef: z.string().regex(/^session:[\w-]{24}$/) }).strict();
|
|
6
|
+
var operationSchema = z.discriminatedUnion('action', [z.object({ action: z.literal('send'), text: z.string().trim().min(1).max(1200) }).strict(), z.object({ action: z.enum(['model', 'vendor', 'effort']), value: z.string().min(1).max(200) }).strict(), z.object({ action: z.literal('stop') }).strict()]);
|
|
7
|
+
function hash(value) { return crypto.createHash('sha256').update(JSON.stringify(value)).digest('hex'); }
|
|
8
|
+
function revision(s) { return hash([s.ownerId, s.sessionOriginId, s.cliSessionId, s.vendor, s.model, s.effort, s.title, s.isProcessing, s._queryStarting, s._sdkQueryGeneration, s.taskStopRequested, s._pendingMessageDrainPaused, s.history, s.pendingPush, Object.keys(s.pendingAskUser || {}), Object.keys(s.pendingPermissions || {})]); }
|
|
9
|
+
function attachClayMateChat(ctx) {
|
|
10
|
+
var state = ctx.state, receipts = require('./clay-mate-chat-receipts').attachReceipts(ctx);
|
|
11
|
+
function authorize() {
|
|
12
|
+
var principal = ctx.authorize(), identity = ctx.sourceIdentity();
|
|
13
|
+
if (ctx.session._pendingMessageDrainPaused) throw new Error('The canonical source is stopped; explicit owner resumption is required.');
|
|
14
|
+
if (state.sourceIdentity !== undefined && state.sourceIdentity !== identity) throw new Error('The canonical source OS identity changed.');
|
|
15
|
+
state.sourceIdentity = identity;
|
|
16
|
+
return principal;
|
|
17
|
+
}
|
|
18
|
+
function resolve(selector, expected) {
|
|
19
|
+
var principal = authorize(), owner = principal.userId || principal.singleUserOwnerId || 'default';
|
|
20
|
+
var mate = ctx.resolveMate(owner, selector.mateId);
|
|
21
|
+
if (!mate || mate.lifecycleDeletion || ctx.multiUser() && mate.createdBy !== owner) throw new Error('The Mate is deleted, pending deletion or belongs to another owner.');
|
|
22
|
+
var project, slug;
|
|
23
|
+
ctx.getProjects().forEach(function (candidate, key) { var status = candidate.getStatus(); if (status.isMate && status.mateId === mate.id) { if (project) throw new Error('The Mate runtime is ambiguous.'); project = candidate; slug = key; } });
|
|
24
|
+
var status = project && project.getStatus();
|
|
25
|
+
if (!status || status.projectOwnerId !== owner || path.resolve(status.path) !== path.resolve(ctx.getMateDir(owner, mate.id))) throw new Error('The registered private Mate runtime is unavailable or replaced.');
|
|
26
|
+
var service = project.getMateChatControl && project.getMateChatControl(), session;
|
|
27
|
+
project.getSessionManager().sessions.forEach(function (candidate) { if (refs.sessionRef(slug, candidate) === selector.sessionRef) session = candidate; });
|
|
28
|
+
if (!session && expected && project === expected.project && project.getSessionManager().sessions.get(expected.session.localId) === expected.session) session = expected.session;
|
|
29
|
+
if (!service || !session || session === ctx.session || session.hidden || session.destroying || session.sessionVisibility !== 'private' || (session.ownerId || null) !== (principal.userId || null) || session.spawn || require('./session-provenance').isWorker(session) || session.delegated || session._delegatedBy || session._pairDelegation || session.mateCreationMode || session.homeDebatePlanning || session.debateSetupMode || session.homeDebatePhase || session.loop || session.terminalId != null || session.runtimeTerminalId != null || (session.runtimeMode || session.mode || 'gui') !== 'gui') throw new Error('Select an existing private owner Mate conversation, separate from this query, without orchestration or terminal runtime.');
|
|
30
|
+
var identity = service.validate(session);
|
|
31
|
+
return { mate: mate, project: project, slug: slug, session: session, service: service, identity: identity };
|
|
32
|
+
}
|
|
33
|
+
function check(target, exact) {
|
|
34
|
+
var live = resolve(target.selector, target.live);
|
|
35
|
+
if (live.project !== target.live.project || live.session !== target.live.session || live.identity !== target.live.identity || hash(live.mate) !== target.registry) throw new Error('The exact Mate runtime, OS identity or registry changed. Inspect again.');
|
|
36
|
+
if (exact && (Date.now() - target.created > 300000 || revision(live.session) !== target.revision)) throw new Error('The inspected conversation changed or expired. Inspect again.');
|
|
37
|
+
return live;
|
|
38
|
+
}
|
|
39
|
+
function read(args) {
|
|
40
|
+
var parsed = z.object({ target: targetSchema, requestId: z.string().optional() }).strict().parse(args), live = resolve(parsed.target), s = live.session, sm = live.project.getSessionManager();
|
|
41
|
+
if (parsed.requestId) { var receipt = receipts.read(parsed.requestId); if (!receipt || receipt.targetKey !== hash([parsed.target.mateId, live.session.sessionOriginId])) throw new Error('No receipt exists for this exact conversation.'); return receipt; }
|
|
42
|
+
return { target: parsed.target, title: s.title || 'New conversation', processing: !!s.isProcessing, starting: !!s._queryStarting, stopped: !!(s.taskStopRequested || s._pendingMessageDrainPaused || s.abortController && s.abortController.signal.aborted), vendor: s.vendor || sm.defaultVendor, model: s.model || null, effort: s.effort || null, models: (sm.modelsByVendor || {})[s.vendor || sm.defaultVendor] || [], vendors: sm.availableVendors || [], capabilities: (sm.capabilitiesByVendor || {})[s.vendor || sm.defaultVendor] || {}, routing: 'Exact existing conversation only. No implicit creation or resume.', actions: ['send', 'stop', 'model', 'vendor', 'effort'] };
|
|
43
|
+
}
|
|
44
|
+
function inspect(args) {
|
|
45
|
+
var parsed = z.object({ target: targetSchema, operation: operationSchema }).strict().parse(args), live = resolve(parsed.target);
|
|
46
|
+
if (JSON.stringify(parsed).length > 1400) throw new Error('The exact intent must fit the existing owner review.');
|
|
47
|
+
var token = 'mate-chat:' + crypto.randomUUID();
|
|
48
|
+
if (state.targets.size >= 100) state.targets.delete(state.targets.keys().next().value);
|
|
49
|
+
state.targets.set(token, { selector: parsed.target, op: parsed.operation, live: live, registry: hash(live.mate), revision: revision(live.session), created: Date.now() });
|
|
50
|
+
return { targetToken: token, target: parsed.target, operation: parsed.operation, expiresInSeconds: 300 };
|
|
51
|
+
}
|
|
52
|
+
function act(args) {
|
|
53
|
+
authorize();
|
|
54
|
+
args = z.object({ targetToken: z.string(), requestId: z.string().max(128), why: z.string().trim().min(1).max(300) }).strict().parse(args);
|
|
55
|
+
var target = state.targets.get(args.targetToken);
|
|
56
|
+
if (!target) throw new Error('Inspect the exact Mate conversation intent first.');
|
|
57
|
+
var key = hash([target.selector.mateId, target.live.session.sessionOriginId, target.op, args.why]), previous = state.requests.get(args.requestId), durable = receipts.read(args.requestId, key);
|
|
58
|
+
if (previous) { if (previous.key !== key) throw new Error('requestId names another intent.'); return previous.promise.then(function (result) { check(target, false); return result; }); }
|
|
59
|
+
if (durable) { check(target, false); return durable.status === 'applying' ? { status: 'failed', persisted: 'unknown', retrySafe: false, error: 'An interrupted attempt requires inspection; it will not be executed again.' } : durable.result; }
|
|
60
|
+
if (state.requests.size >= 100) throw new Error('Too many Mate chat requests in this query.');
|
|
61
|
+
var attempted = false;
|
|
62
|
+
var promise = Promise.resolve().then(async function () {
|
|
63
|
+
var live = check(target, true);
|
|
64
|
+
if (target.op.action !== 'stop') {
|
|
65
|
+
var question = 'Apply this exact Mate conversation change:\n' + JSON.stringify({ target: target.selector, operation: target.op }) + '\nWhy: ' + args.why;
|
|
66
|
+
if (question.length > 2000) throw new Error('The exact intent must fit the existing owner review.');
|
|
67
|
+
var response = await ctx.review(question, function () { check(target, true); });
|
|
68
|
+
if (response.status !== 'submitted' || !response.answers.control || response.answers.control.length !== 1 || response.answers.control[0] !== 'Apply exact change') return { status: 'cancelled', persisted: false };
|
|
69
|
+
live = check(target, true);
|
|
70
|
+
}
|
|
71
|
+
if (target.op.action !== 'stop') receipts.save({ id: args.requestId, key: key, targetKey: hash([target.selector.mateId, target.live.session.sessionOriginId]), status: 'applying' });
|
|
72
|
+
check(target, true);
|
|
73
|
+
if (target.op.action === 'stop' && ctx.activity && ctx.activity()) ctx.activity().start('running');
|
|
74
|
+
attempted = true;
|
|
75
|
+
var result = await live.service.apply(live.session, target.op, function () { check(target, target.op.action !== 'send'); }, ctx.actor());
|
|
76
|
+
result = Object.assign({ status: 'completed', action: target.op.action }, result);
|
|
77
|
+
try { receipts.save({ id: args.requestId, key: key, targetKey: hash([target.selector.mateId, target.live.session.sessionOriginId]), status: 'finished', result: result }); }
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (target.op.action === 'stop') return Object.assign({}, result, { receiptSaved: false, detail: 'Stop applied; its retry receipt could not be saved.' });
|
|
80
|
+
error.productControlResult = Object.assign({}, result, { status: 'failed', receiptSaved: false, retrySafe: false, error: 'The target outcome could not be saved to the source receipt. ' + error.message }); throw error;
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}).catch(function (error) { return Object.assign({ status: 'failed', retrySafe: false, persisted: attempted ? 'unknown' : false, error: error.message }, error.productControlResult || {}); });
|
|
84
|
+
state.requests.set(args.requestId, { key: key, promise: promise }); return promise;
|
|
85
|
+
}
|
|
86
|
+
return { readMateChat: read, inspectMateChat: inspect, actMateChat: act };
|
|
87
|
+
}
|
|
88
|
+
module.exports = { attachClayMateChat: attachClayMateChat, targetSchema: targetSchema, operationSchema: operationSchema };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
var z = require('zod');
|
|
2
|
+
var definitions = require('./mate-knowledge-mcp-server').getToolDefs(null, false);
|
|
3
|
+
var READS = { list_databases: 'list', read_database: 'read', query_database: 'query', read_database_record: 'readRecord', read_database_import_progress: 'readImportProgress' };
|
|
4
|
+
var WRITES = { create_database: 'create', rename_database: 'rename', archive_database: 'archive', recover_database: 'recover', update_database_schema: 'updateSchema', save_table_view: 'saveView', create_database_record: 'createRecord', update_database_record: 'updateRecord', archive_database_record: 'archiveRecord', recover_database_record: 'recoverRecord', retry_database_sync: 'retryProjection', import_database_records: 'importRecords' };
|
|
5
|
+
var document = { name: z.string().optional(), documentId: z.string().optional() };
|
|
6
|
+
function schema(action, fields) { return z.object(Object.assign({ action: z.literal(action) }, fields)).strict(); }
|
|
7
|
+
function databaseSchemas(names) {
|
|
8
|
+
return Object.keys(names).map(function (name) {
|
|
9
|
+
var fields = Object.assign({}, definitions.find(function (def) { return def.name === name; }).inputSchema);
|
|
10
|
+
delete fields.operationId;
|
|
11
|
+
return schema(name, fields);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
var readSchema = z.discriminatedUnion('action', [
|
|
15
|
+
schema('list_documents', { deleted: z.boolean().optional() }), schema('read_document', document), schema('document_history', document),
|
|
16
|
+
schema('read_document_version', Object.assign({}, document, { version: z.string() })),
|
|
17
|
+
].concat(databaseSchemas(READS)));
|
|
18
|
+
var writeSchema = z.discriminatedUnion('action', [
|
|
19
|
+
schema('create_document', { name: z.string(), content: z.string() }),
|
|
20
|
+
schema('update_document', Object.assign({}, document, { content: z.string(), expectedRevision: z.string() })),
|
|
21
|
+
schema('rename_document', Object.assign({}, document, { newName: z.string(), expectedRevision: z.string() })),
|
|
22
|
+
schema('delete_document', Object.assign({}, document, { expectedRevision: z.string() })),
|
|
23
|
+
schema('restore_document', Object.assign({}, document, { version: z.string(), expectedRevision: z.string().nullable() })),
|
|
24
|
+
schema('retry_document_sync', { names: z.array(z.string()).min(1).max(4) }),
|
|
25
|
+
].concat(databaseSchemas(WRITES)));
|
|
26
|
+
module.exports = { READS: READS, WRITES: WRITES, readSchema: readSchema, writeSchema: writeSchema };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
var crypto = require('crypto');
|
|
2
|
+
var path = require('path');
|
|
3
|
+
var input = require('./clay-mate-knowledge-input');
|
|
4
|
+
function fingerprint(value) { return crypto.createHash('sha256').update(JSON.stringify(value)).digest('hex'); }
|
|
5
|
+
function text(value, max) { return typeof value === 'string' && value.trim() && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value); }
|
|
6
|
+
function attachClayMateKnowledge(ctx) {
|
|
7
|
+
var state = ctx.state;
|
|
8
|
+
function resolve(mateId) {
|
|
9
|
+
var principal = ctx.authorize(), owner = principal.userId || principal.singleUserOwnerId || 'default';
|
|
10
|
+
var mate = ctx.resolveMate(owner, mateId), project = ctx.getProjects().get('mate-' + mateId);
|
|
11
|
+
if (!mate || mate.lifecycleDeletion || principal.userId && mate.createdBy !== owner || !project) throw new Error('Mate Knowledge is unavailable for this owner.');
|
|
12
|
+
var status = project.getStatus(), directory = ctx.getMateDir && ctx.getMateDir(owner, mateId);
|
|
13
|
+
if (!status.isMate || status.mateId !== mateId || status.projectOwnerId !== owner || !directory || path.resolve(status.path) !== path.resolve(directory)) throw new Error('Mate Knowledge runtime ownership or directory changed.');
|
|
14
|
+
project.getSessionManager().sessions.forEach(function (s) { if (s.sessionVisibility === 'shared' || s.ownerId && s.ownerId !== owner) throw new Error('Mate Knowledge runtime is not owner-private.'); });
|
|
15
|
+
var documents = project.getKnowledgeProductOperations && project.getKnowledgeProductOperations(), db = project.getKnowledgeDbService && project.getKnowledgeDbService();
|
|
16
|
+
if (!documents || !db) throw new Error('Mate Knowledge services are unavailable.');
|
|
17
|
+
return { mate: mate, project: project, documents: documents, db: db, owner: owner, actor: { type: principal.userId ? 'user' : 'system', userId: principal.userId, displayName: null } };
|
|
18
|
+
}
|
|
19
|
+
function targetCheck(target) {
|
|
20
|
+
var live = resolve(target.mateId);
|
|
21
|
+
if (live.project !== target.project || live.db !== target.db || fingerprint(live.mate) !== target.registry) throw new Error('Mate Knowledge target changed. Inspect again.');
|
|
22
|
+
return live;
|
|
23
|
+
}
|
|
24
|
+
function cachedDatabase(live, id) {
|
|
25
|
+
var db = live.db.listCached({}).databases.concat(live.db.listCached({ archived: true }).databases).find(function (item) { return item.id === id; });
|
|
26
|
+
if (!db) throw new Error('Knowledge database is unavailable.');
|
|
27
|
+
return { id: db.id, revision: db.revision, archivedAt: db.archivedAt };
|
|
28
|
+
}
|
|
29
|
+
async function read(args) {
|
|
30
|
+
if (!args || Object.keys(args).some(function (key) { return key !== 'mateId' && key !== 'operation'; }) || !text(args.mateId, 100)) throw new Error('Choose an exact owner-private Mate and typed Knowledge query.');
|
|
31
|
+
var op = JSON.parse(JSON.stringify(input.readSchema.parse(args.operation))), live = resolve(args.mateId);
|
|
32
|
+
var target = { mateId: args.mateId, project: live.project, db: live.db, registry: fingerprint(live.mate) };
|
|
33
|
+
var result = input.READS[op.action] ? await live.db[input.READS[op.action]](op) : live.documents.query(op);
|
|
34
|
+
targetCheck(target);
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
async function inspect(args) {
|
|
38
|
+
if (!args || Object.keys(args).some(function (key) { return key !== 'mateId' && key !== 'operation'; }) || !text(args.mateId, 100)) throw new Error('Choose an exact owner-private Mate and typed Knowledge change.');
|
|
39
|
+
var op = JSON.parse(JSON.stringify(input.writeSchema.parse(args.operation))), live = resolve(args.mateId);
|
|
40
|
+
var target = { mateId: args.mateId, project: live.project, db: live.db, registry: fingerprint(live.mate), op: op, created: Date.now() };
|
|
41
|
+
if (input.WRITES[op.action]) {
|
|
42
|
+
if (op.databaseId) { await live.db.read({ databaseId: op.databaseId, includeArchived: true }); target.snapshot = cachedDatabase(live, op.databaseId); }
|
|
43
|
+
} else target.snapshot = live.documents.snapshot(op);
|
|
44
|
+
targetCheck(target);
|
|
45
|
+
var exact = JSON.stringify(op);
|
|
46
|
+
if (exact.length > 1400) throw new Error('The exact Knowledge change is too large for the existing owner review; use smaller existing product operations.');
|
|
47
|
+
if (state.targets.size >= 100) state.targets.delete(state.targets.keys().next().value);
|
|
48
|
+
var token = 'knowledge-control:' + crypto.randomUUID(); target.presentationValid = function () { check(target); }; state.targets.set(token, target);
|
|
49
|
+
return { targetToken: token, mateId: args.mateId, operation: op, revision: target.snapshot, expiresInSeconds: 300 };
|
|
50
|
+
}
|
|
51
|
+
function check(target) {
|
|
52
|
+
var live = targetCheck(target);
|
|
53
|
+
if (Date.now() - target.created > 300000) throw new Error('Knowledge inspection expired.');
|
|
54
|
+
var snapshot = input.WRITES[target.op.action] ? target.op.databaseId && cachedDatabase(live, target.op.databaseId) : live.documents.snapshot(target.op);
|
|
55
|
+
if (fingerprint(snapshot || null) !== fingerprint(target.snapshot || null)) throw new Error('Knowledge revision changed. Inspect and review again.');
|
|
56
|
+
return live;
|
|
57
|
+
}
|
|
58
|
+
function act(args) {
|
|
59
|
+
ctx.authorize();
|
|
60
|
+
if (!args || Object.keys(args).some(function (key) { return ['targetToken', 'requestId', 'why'].indexOf(key) < 0; }) || !text(args.targetToken, 100) || !text(args.requestId, 128) || !text(args.why, 300)) throw new Error('Use an exact Knowledge token, requestId and reason.');
|
|
61
|
+
args = Object.assign({}, args);
|
|
62
|
+
var target = state.targets.get(args.targetToken), key = fingerprint(args), previous = state.requests.get(args.requestId);
|
|
63
|
+
if (!target) throw new Error('Inspect this exact Knowledge operation first.');
|
|
64
|
+
if (previous) { if (previous.key !== key) throw new Error('requestId already names another Knowledge operation.'); return previous.promise.then(function (result) { targetCheck(target); return result; }); }
|
|
65
|
+
if (state.requests.size >= 100) throw new Error('Too many Knowledge requests in this query.');
|
|
66
|
+
var stamp = /^[A-Za-z][A-Za-z0-9-]*_(\d{13})_[A-Za-z0-9_-]{1,80}$/.exec(args.requestId);
|
|
67
|
+
if (input.WRITES[target.op.action] && !stamp) throw new Error('Database requestId must use prefix_<13-digit creation time>_<unique suffix> for the existing durable retry window.');
|
|
68
|
+
var operationId = 'clay_' + (stamp ? stamp[1] : target.created) + '_' + fingerprint([ctx.sourceKey, args.requestId]).slice(0, 40);
|
|
69
|
+
var persisted = false;
|
|
70
|
+
var promise = Promise.resolve().then(async function () {
|
|
71
|
+
check(target);
|
|
72
|
+
var question = 'Apply this exact Mate Knowledge change:\n' + JSON.stringify(target.op) + (target.op.action === 'rename_document' ? '\nExisting local backlinks follow the Knowledge workbench rename behavior.' : '') + '\nMate: ' + target.mateId + '\nWhy: ' + args.why;
|
|
73
|
+
if (question.length > 2000) throw new Error('The exact change must fit the existing owner review.');
|
|
74
|
+
var response = await ctx.review(question, function () { check(target); });
|
|
75
|
+
if (response.status !== 'submitted' || !response.answers.control || response.answers.control.length !== 1 || response.answers.control[0] !== 'Apply exact change') return { status: 'cancelled' };
|
|
76
|
+
var live = check(target), op = Object.assign({}, target.op), result;
|
|
77
|
+
if (input.WRITES[op.action]) {
|
|
78
|
+
var parameters = Object.assign({}, op, { operationId: operationId, actor: live.actor, revalidate: function (current, phase) {
|
|
79
|
+
if (phase === 'saved') persisted = true;
|
|
80
|
+
targetCheck(target);
|
|
81
|
+
if (current && target.snapshot && current.revision !== target.snapshot.revision) throw Object.assign(new Error('Knowledge database revision changed after review.'), { code: 'STALE' });
|
|
82
|
+
if (phase === 'saving') persisted = 'unknown';
|
|
83
|
+
} }); delete parameters.action;
|
|
84
|
+
result = await live.db[input.WRITES[op.action]](parameters);
|
|
85
|
+
} else { persisted = 'unknown'; result = live.documents.mutate(op, live.actor); }
|
|
86
|
+
persisted = true; targetCheck(target);
|
|
87
|
+
if (result.linkUpdateFailures && result.linkUpdateFailures.length) return { status: 'failed', persisted: true, operationId: operationId, retrySafe: false, error: 'The document was renamed, but some backlink updates failed.', result: result };
|
|
88
|
+
return { status: 'completed', persisted: true, operationId: operationId, result: result };
|
|
89
|
+
}).catch(function (error) { return { status: 'failed', persisted: error.persisted === undefined ? persisted : error.persisted, operationId: operationId, retrySafe: false, code: error.code || 'FAILED', error: error.message }; });
|
|
90
|
+
state.requests.set(args.requestId, { key: key, promise: promise });
|
|
91
|
+
return promise;
|
|
92
|
+
}
|
|
93
|
+
return { readMateKnowledgeControl: read, inspectMateKnowledgeChange: inspect, actMateKnowledge: act };
|
|
94
|
+
}
|
|
95
|
+
module.exports = { attachClayMateKnowledge: attachClayMateKnowledge };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
var crypto = require('crypto');
|
|
2
|
+
var catalog = require('./mate-avatar-catalog');
|
|
3
|
+
var colors = require('./mate-workspace-color');
|
|
4
|
+
function string(value, max) { return typeof value === 'string' && value.trim() && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value); }
|
|
5
|
+
function revision(mate) { var copy = Object.assign({}, mate); delete copy.lifecycleDeletion; return JSON.stringify(copy); }
|
|
6
|
+
function runtime(project, sessionsOnly) {
|
|
7
|
+
if (!project) return null;
|
|
8
|
+
var status = project.getStatus();
|
|
9
|
+
return JSON.stringify([status.mateId, status.projectOwnerId, !sessionsOnly && project.inspectMateLifecycleRuntime && project.inspectMateLifecycleRuntime(), Array.from(project.getSessionManager().sessions.values()).map(function (s) { return [s.localId, s.ownerId, s.sessionVisibility, s.title, s.isProcessing, s._queryStarting, s._sdkQueryGeneration, s.history && s.history.length, s.terminalId, s.runtimeTerminalId]; })]);
|
|
10
|
+
}
|
|
11
|
+
function profileChanges(mate, patch) {
|
|
12
|
+
if (!patch || typeof patch !== 'object' || Array.isArray(patch) || !Object.keys(patch).length || Object.keys(patch).some(function (key) { return ['name', 'bio', 'workspaceColor', 'avatarCatalogId'].indexOf(key) < 0; })) throw new Error('Use only name, bio, workspaceColor or avatarCatalogId.');
|
|
13
|
+
if (mate.lifecycleDeletion) throw new Error('Mate deletion is pending.');
|
|
14
|
+
var changes = {}, profile = Object.assign({}, mate.profile);
|
|
15
|
+
if (patch.name !== undefined) {
|
|
16
|
+
if (mate.primary || !string(patch.name, 100)) throw new Error('This Mate name cannot be changed to that value.');
|
|
17
|
+
changes.name = patch.name.trim(); profile.displayName = changes.name;
|
|
18
|
+
}
|
|
19
|
+
if (patch.bio !== undefined) {
|
|
20
|
+
if (mate.primary || typeof patch.bio !== 'string' || patch.bio.length > 600 || /[\u0000-\u001f\u007f]/.test(patch.bio)) throw new Error('Use an introduction of at most 600 characters for an editable Mate.');
|
|
21
|
+
changes.bio = patch.bio.trim();
|
|
22
|
+
}
|
|
23
|
+
if (patch.workspaceColor !== undefined) {
|
|
24
|
+
if (mate.primary || mate.builtinKey === 'clay' || !colors.valid(patch.workspaceColor)) throw new Error('This workspace color is unavailable.');
|
|
25
|
+
changes.workspaceColor = patch.workspaceColor;
|
|
26
|
+
}
|
|
27
|
+
if (patch.avatarCatalogId !== undefined) {
|
|
28
|
+
if (profile.avatarLocked || !catalog.valid(patch.avatarCatalogId)) throw new Error('Choose an editable catalog avatar.');
|
|
29
|
+
profile.avatarCatalogId = patch.avatarCatalogId; profile.avatarCustom = '';
|
|
30
|
+
}
|
|
31
|
+
if (patch.name !== undefined || patch.avatarCatalogId !== undefined) changes.profile = profile;
|
|
32
|
+
return changes;
|
|
33
|
+
}
|
|
34
|
+
function attachClayMateLifecycle(ctx) {
|
|
35
|
+
var state = ctx.state;
|
|
36
|
+
function service() { var value = ctx.getService && ctx.getService(); if (!value) throw new Error('Mate lifecycle controls are unavailable.'); return value; }
|
|
37
|
+
function owner() { var p = ctx.authorize(); return p.userId || p.singleUserOwnerId || 'default'; }
|
|
38
|
+
function projection(m) { return { mateId: m.id, name: (m.profile || {}).displayName || m.name || 'New Mate', bio: m.bio || '', profile: m.profile || {}, workspaceColor: m.workspaceColor || null, primary: !!m.primary, canonicalClay: m.builtinKey === 'clay', deletionPending: !!m.lifecycleDeletion }; }
|
|
39
|
+
function list(args) {
|
|
40
|
+
if (args && Object.keys(args).length) throw new Error('Mate listing accepts no arguments.');
|
|
41
|
+
return { mates: service().list(owner()).map(projection) };
|
|
42
|
+
}
|
|
43
|
+
function inspect(args) {
|
|
44
|
+
if (!args || !string(args.mateId, 100) || Object.keys(args).some(function (k) { return k !== 'mateId'; })) throw new Error('An exact mateId is required.');
|
|
45
|
+
var mate = service().read(owner(), args.mateId), project = ctx.getProjects().get('mate-' + mate.id);
|
|
46
|
+
if (project) {
|
|
47
|
+
var status = project.getStatus();
|
|
48
|
+
if (!status.isMate || status.mateId !== mate.id || status.projectOwnerId !== owner()) throw new Error('Mate runtime ownership changed.');
|
|
49
|
+
project.getSessionManager().sessions.forEach(function (s) { if (s.sessionVisibility === 'shared' || s.ownerId && s.ownerId !== owner()) throw new Error('Mate runtime is not private to this owner.'); });
|
|
50
|
+
}
|
|
51
|
+
if (state.targets.size >= 100) state.targets.delete(state.targets.keys().next().value);
|
|
52
|
+
var token = 'mate-control:' + crypto.randomUUID();
|
|
53
|
+
state.targets.set(token, { mate: mate, revision: revision(mate), deletion: JSON.stringify(mate.lifecycleDeletion), project: project, runtime: runtime(project), cleanupRuntime: runtime(project, true), created: Date.now() });
|
|
54
|
+
return Object.assign(projection(mate), { targetToken: token, expiresInSeconds: 300, actions: mate.primary || mate.builtinKey === 'clay' ? ['profile'] : ['profile', 'delete'], profileFields: ['name', 'bio', 'workspaceColor', 'avatarCatalogId'] });
|
|
55
|
+
}
|
|
56
|
+
function check(target, cleanup) {
|
|
57
|
+
var mate = service().read(owner(), target.mate.id), project = ctx.getProjects().get('mate-' + mate.id);
|
|
58
|
+
if (Date.now() - target.created > 300000 || revision(mate) !== target.revision || !cleanup && JSON.stringify(mate.lifecycleDeletion) !== target.deletion) throw new Error('The exact Mate revision changed. Inspect again.');
|
|
59
|
+
if (!cleanup && (project !== target.project || runtime(project) !== target.runtime)) throw new Error('Mate runtime changed. Inspect again.');
|
|
60
|
+
if (cleanup && runtime(target.project, true) !== target.cleanupRuntime) throw new Error('Mate sessions changed during cleanup. Inspect again.');
|
|
61
|
+
if (cleanup && project && project !== target.project) throw new Error('Mate runtime was replaced during cleanup.');
|
|
62
|
+
return mate;
|
|
63
|
+
}
|
|
64
|
+
function act(args) {
|
|
65
|
+
owner();
|
|
66
|
+
if (!args || Object.keys(args).some(function (key) { return ['targetToken', 'action', 'patch', 'why', 'requestId'].indexOf(key) < 0; }) || ['profile', 'delete'].indexOf(args.action) < 0 || !string(args.why, 600) || !string(args.requestId, 128) || !string(args.targetToken, 100) || args.action === 'delete' && args.patch !== undefined) throw new Error('Use an exact Mate target, profile or delete action, why and requestId.');
|
|
67
|
+
args = JSON.parse(JSON.stringify(args));
|
|
68
|
+
var target = state.targets.get(args.targetToken), key = JSON.stringify(args), previous = state.requests.get(args.requestId);
|
|
69
|
+
if (!target) throw new Error('Inspect the exact Mate first.');
|
|
70
|
+
if (previous) {
|
|
71
|
+
if (previous.key !== key) throw new Error('requestId already names a different exact Mate action.');
|
|
72
|
+
return previous.promise.then(function (result) {
|
|
73
|
+
service().validateReceipt(owner(), target.mate.id, result.status === 'completed' && args.action === 'delete');
|
|
74
|
+
return result;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (state.requests.size >= 100) throw new Error('Too many Mate requests in this query.');
|
|
78
|
+
var promise = Promise.resolve().then(async function () {
|
|
79
|
+
var mate = check(target), changes;
|
|
80
|
+
if (args.action === 'profile') changes = profileChanges(mate, args.patch);
|
|
81
|
+
if (args.action === 'delete' && (mate.primary || mate.builtinKey === 'clay')) throw new Error('Canonical Clay and primary Mates cannot be deleted.');
|
|
82
|
+
var question = (args.action === 'delete' ? 'Permanently delete this Mate and its private directory after runtime cleanup. Stored transcripts and external provider history are retained.' : 'Edit this Mate profile: ' + JSON.stringify(args.patch)) + '\nMate: ' + ((mate.profile || {}).displayName || mate.name || 'New Mate') + ' (' + mate.id + ')\nWhy: ' + args.why;
|
|
83
|
+
if (question.length > 2000) throw new Error('The exact change must fit the owner review.');
|
|
84
|
+
var answer = await ctx.review(question, function () { check(target); });
|
|
85
|
+
if (answer.status !== 'submitted' || !answer.answers.control || answer.answers.control.length !== 1 || answer.answers.control[0] !== 'Apply exact change') return { status: 'cancelled' };
|
|
86
|
+
check(target);
|
|
87
|
+
if (args.action === 'profile') { service().update(owner(), mate.id, changes); return { status: 'completed', persisted: true, mateId: mate.id }; }
|
|
88
|
+
return Object.assign({ status: 'completed', mateId: mate.id }, await service().remove(owner(), mate.id, function (cleanup) { check(target, cleanup); }));
|
|
89
|
+
}).catch(function (error) { return Object.assign({ status: 'failed', error: error.message }, error.productControlResult || {}); });
|
|
90
|
+
state.requests.set(args.requestId, { key: key, promise: promise });
|
|
91
|
+
return promise;
|
|
92
|
+
}
|
|
93
|
+
return { listMates: list, inspectMate: inspect, actMate: act };
|
|
94
|
+
}
|
|
95
|
+
module.exports = { attachClayMateLifecycle: attachClayMateLifecycle };
|