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
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
var crypto = require('crypto');
|
|
2
2
|
var Client = require('@modelcontextprotocol/sdk/client/index.js').Client;
|
|
3
|
+
var SSEClientTransport = require('@modelcontextprotocol/sdk/client/sse.js').SSEClientTransport;
|
|
4
|
+
var localTransport = require('./mcp-local-transport').localTransport;
|
|
3
5
|
var StreamableHTTPClientTransport = require('@modelcontextprotocol/sdk/client/streamableHttp.js').StreamableHTTPClientTransport;
|
|
4
6
|
var network = require('./mcp-network');
|
|
5
7
|
var oauth = require('./mcp-oauth');
|
|
@@ -9,12 +11,33 @@ function createRemoteConnections(ctx) {
|
|
|
9
11
|
var accounts = new Map(), live = new Map(), flows = new Map(), queues = new Map();
|
|
10
12
|
var remoteFetch = ctx.remoteFetch || network.createRemoteFetch();
|
|
11
13
|
var closed = false;
|
|
14
|
+
function sameRuntimeConfig(left, right) {
|
|
15
|
+
return left && right && left.url === right.url && left.enabled === right.enabled && left.authMode === right.authMode && left.token === right.token && JSON.stringify(left.auth || null) === JSON.stringify(right.auth || null) && JSON.stringify([left.transport, left.command, left.args, left.env, left.cwd, left.headers, left.envHeaders, left.references, left.disabledTools, left.enabledTools, left.toolPatterns, left.toolPrefix]) === JSON.stringify([right.transport, right.command, right.args, right.env, right.cwd, right.headers, right.envHeaders, right.references, right.disabledTools, right.enabledTools, right.toolPatterns, right.toolPrefix]);
|
|
16
|
+
}
|
|
17
|
+
function invalidate(owner, previous, current) {
|
|
18
|
+
var byId = new Map(current.filter(function (row) { return row.source !== 'computer'; }).map(function (row) { return [row.id, row]; }));
|
|
19
|
+
previous.filter(function (row) { return row.source !== 'computer'; }).forEach(function (row) {
|
|
20
|
+
var next = byId.get(row.id);
|
|
21
|
+
if (!next || !sameRuntimeConfig(row, next)) disconnect(owner, row.id);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
12
24
|
function records(owner) {
|
|
13
25
|
ctx.authorize(owner);
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
var account = accounts.get(owner), snapshot = typeof ctx.storage.snapshot === 'function' ? ctx.storage.snapshot(owner) : { records: ctx.storage.load(owner), revision: typeof ctx.storage.revision === 'function' ? ctx.storage.revision(owner) : null };
|
|
27
|
+
var loaded = snapshot.records, revision = snapshot.revision;
|
|
28
|
+
if (!account) accounts.set(owner, account = { records: loaded, revision: revision });
|
|
29
|
+
else if (account.revision !== revision) { invalidate(owner, account.records, loaded); account.records = loaded; account.revision = revision; }
|
|
30
|
+
return account.records;
|
|
31
|
+
}
|
|
32
|
+
function persist(owner) {
|
|
33
|
+
ctx.authorize(owner); if (closed) throw new Error('MCP connections closed.');
|
|
34
|
+
var account = accounts.get(owner);
|
|
35
|
+
if (!account) throw new Error('MCP connection snapshot is unavailable.');
|
|
36
|
+
var revision;
|
|
37
|
+
try { revision = ctx.storage.save(owner, account.records, account.revision); }
|
|
38
|
+
catch (error) { accounts.delete(owner); invalidate(owner, account.records, []); throw error; }
|
|
39
|
+
if (account) account.revision = revision;
|
|
16
40
|
}
|
|
17
|
-
function persist(owner) { ctx.authorize(owner); if (closed) throw new Error('MCP connections closed.'); ctx.storage.save(owner, records(owner)); }
|
|
18
41
|
function find(owner, id) {
|
|
19
42
|
var row = records(owner).find(function (item) { return item.id === id; });
|
|
20
43
|
if (!row) throw new Error('Connection is unavailable.');
|
|
@@ -23,14 +46,15 @@ function createRemoteConnections(ctx) {
|
|
|
23
46
|
function key(owner, id) { return JSON.stringify([owner, id]); }
|
|
24
47
|
function check(owner, row) {
|
|
25
48
|
if (closed || find(owner, row.id) !== row) throw new Error('Connection changed.');
|
|
49
|
+
if (row.source === 'local' && ctx.ownerIdentity) ctx.ownerIdentity(owner);
|
|
26
50
|
}
|
|
27
51
|
function changed(owner) { if (!closed) ctx.changed(owner); }
|
|
28
52
|
function view(owner) {
|
|
29
|
-
return records(owner).filter(function (row) { return row.source
|
|
53
|
+
return records(owner).filter(function (row) { return row.source !== 'computer'; }).map(function (row) {
|
|
30
54
|
var entry = live.get(key(owner, row.id));
|
|
31
|
-
return { id: row.id, name: row.id, label: row.label, source:
|
|
55
|
+
return { id: row.id, name: row.id, label: row.label, source: row.source, transport: row.transport || 'http', url: row.url ? new URL(row.url).origin + new URL(row.url).pathname : null, provenance: row.provenance, references: require('./mcp-import-credentials').requiredNames(row),
|
|
32
56
|
projectEnabled: !!row.enabled, extensionEnabled: true, tools: row.tools || [], toolCount: (row.tools || []).length,
|
|
33
|
-
status: entry ? entry.status : (row.tools ? 'idle' : 'unavailable'), error: entry ? entry.error : '', authMode: row.authMode || 'auto' };
|
|
57
|
+
status: entry ? entry.status : (row.provenance || row.tools ? 'idle' : 'unavailable'), error: entry ? entry.error : '', authMode: row.authMode || 'auto' };
|
|
34
58
|
});
|
|
35
59
|
}
|
|
36
60
|
async function disconnect(owner, id) {
|
|
@@ -39,7 +63,7 @@ function createRemoteConnections(ctx) {
|
|
|
39
63
|
if (entry && entry.client) await entry.client.close().catch(function () {});
|
|
40
64
|
}
|
|
41
65
|
function provider(owner, row, flow) {
|
|
42
|
-
return oauth.createOAuthProvider(row, function () { check(owner, row); persist(owner); }, flow);
|
|
66
|
+
return oauth.createOAuthProvider(row, function () { check(owner, row); persist(owner); }, flow, function () { check(owner, row); });
|
|
43
67
|
}
|
|
44
68
|
async function connect(owner, row, flow) {
|
|
45
69
|
check(owner, row);
|
|
@@ -47,17 +71,20 @@ function createRemoteConnections(ctx) {
|
|
|
47
71
|
check(owner, row);
|
|
48
72
|
if (flow && flow.cancelled) throw new Error('Sign-in expired.');
|
|
49
73
|
var client = new Client({ name: 'clay', version: '1.0.0' }, { capabilities: {} });
|
|
50
|
-
|
|
51
|
-
|
|
74
|
+
if (row.source !== 'local' && ((row.references || []).length || Object.keys(row.envHeaders || {}).length)) throw new Error('Configure required credentials in Clay before connecting.');
|
|
75
|
+
var options = { fetch: async function (input, init) { check(owner, row); var response = await remoteFetch.fetch(input, init); check(owner, row); return response; }, requestInit: { headers: row.headers || {} } };
|
|
76
|
+
if (row.authMode === 'token' && row.token) options.requestInit = { headers: Object.assign({}, row.headers || {}, { Authorization: 'Bearer ' + row.token }) };
|
|
52
77
|
else if (flow || (row.auth && row.auth.tokens)) options.authProvider = provider(owner, row, flow);
|
|
53
|
-
var transport = new StreamableHTTPClientTransport(new URL(row.url), options);
|
|
78
|
+
var transport = row.source === 'local' ? localTransport(row, ctx.ownerIdentity ? ctx.ownerIdentity(owner) : null) : (row.transport === 'sse' ? new SSEClientTransport(new URL(row.url), options) : new StreamableHTTPClientTransport(new URL(row.url), options));
|
|
54
79
|
var entry = { client: client, transport: transport, status: 'connecting', error: '' };
|
|
55
80
|
live.set(key(owner, row.id), entry); changed(owner);
|
|
56
81
|
try {
|
|
57
82
|
await client.connect(transport, { timeout: 30000 });
|
|
83
|
+
check(owner, row);
|
|
58
84
|
var tools = [], cursor, seen = new Set();
|
|
59
85
|
do {
|
|
60
86
|
var page = await client.listTools(cursor ? { cursor: cursor } : {}, { timeout: 30000 });
|
|
87
|
+
check(owner, row);
|
|
61
88
|
tools = tools.concat(page.tools);
|
|
62
89
|
if (tools.length > 1000 || seen.size >= 100 || (page.nextCursor && seen.has(page.nextCursor))) throw new Error('Tool catalog exceeds the supported limit.');
|
|
63
90
|
cursor = page.nextCursor; seen.add(cursor);
|
|
@@ -65,13 +92,16 @@ function createRemoteConnections(ctx) {
|
|
|
65
92
|
if (JSON.stringify(tools).length > 2 * 1024 * 1024) throw new Error('Tool catalog exceeds the supported limit.');
|
|
66
93
|
check(owner, row);
|
|
67
94
|
if (live.get(key(owner, row.id)) !== entry || (flow && flow.cancelled)) throw new Error('Connection changed.');
|
|
95
|
+
tools = tools.filter(function (tool) {
|
|
96
|
+
return require('./mcp-tool-policy').permits(row, tool.name);
|
|
97
|
+
});
|
|
68
98
|
require('./mcp-proxy').validateDefinitions(tools);
|
|
69
99
|
row.tools = tools; entry.status = 'ready'; persist(owner);
|
|
70
100
|
return entry;
|
|
71
101
|
} catch (error) {
|
|
72
102
|
var requiresAuth = error.code === 401 || error.code === 403 || error.name === 'UnauthorizedError' || (flow && flow.authorizationUrl);
|
|
73
103
|
entry.status = requiresAuth ? 'auth_required' : 'unavailable';
|
|
74
|
-
entry.error = requiresAuth ? 'Sign in or provide an access token to connect.' : 'Could not connect. Check the address and try again.';
|
|
104
|
+
entry.error = requiresAuth ? 'Sign in or provide an access token to connect.' : row.source === 'local' ? 'Could not start the command. Check its dependency and working directory.' : 'Could not connect. Check the address and try again.';
|
|
75
105
|
if (!flow) await client.close().catch(function () {});
|
|
76
106
|
return entry;
|
|
77
107
|
} finally { changed(owner); }
|
|
@@ -101,6 +131,7 @@ function createRemoteConnections(ctx) {
|
|
|
101
131
|
if (ready.status !== 'ready') throw new Error('Connection failed after sign-in.');
|
|
102
132
|
setTimeout(function () { if (flows.get(key(owner, row.id)) === flow) { cancelLogin(owner, row.id); changed(owner); } }, 500);
|
|
103
133
|
});
|
|
134
|
+
try { check(owner, row); } catch (error) { flow.close(); throw error; }
|
|
104
135
|
flows.set(key(owner, row.id), flow);
|
|
105
136
|
flow.timer = setTimeout(function () { cancelLogin(owner, row.id); }, 10 * 60 * 1000); flow.timer.unref();
|
|
106
137
|
row.authMode = 'auto'; delete row.token;
|
|
@@ -123,40 +154,61 @@ function createRemoteConnections(ctx) {
|
|
|
123
154
|
pending.finally(function () { if (queues.get(owner) === pending) queues.delete(owner); }).catch(function () {});
|
|
124
155
|
return pending;
|
|
125
156
|
}
|
|
157
|
+
function commitImport(owner, select, authorize) {
|
|
158
|
+
authorize();
|
|
159
|
+
var imported = select();
|
|
160
|
+
records(owner);
|
|
161
|
+
if (accounts.get(owner).revision !== imported.revision) throw new Error('Connections changed. Scan again.');
|
|
162
|
+
if (records(owner).some(function (item) { return item.importSignature === imported.signature || imported.config.url && item.url === imported.config.url; })) throw new Error('This server is already imported.');
|
|
163
|
+
authorize();
|
|
164
|
+
var row = Object.assign({}, imported.config, { id: 'remote-' + crypto.randomBytes(8).toString('hex'), importSignature: imported.signature, enabled: false });
|
|
165
|
+
records(owner).push(row); persist(owner);
|
|
166
|
+
return row;
|
|
167
|
+
}
|
|
168
|
+
function importConnection(owner, select, authorize) {
|
|
169
|
+
return serial(owner, function () { var row = commitImport(owner, select, authorize); changed(owner); return row.id; });
|
|
170
|
+
}
|
|
126
171
|
function command(owner, msg, ws) {
|
|
127
172
|
// Revocation takes effect before any queued network work completes.
|
|
128
173
|
if (msg.action === 'remove' || (msg.action === 'enable' && msg.enabled !== true)) {
|
|
129
174
|
try {
|
|
130
175
|
var revoked = find(owner, msg.id);
|
|
131
|
-
if (revoked.source
|
|
176
|
+
if (revoked.source === 'computer') throw new Error('Not a remote connection.');
|
|
132
177
|
revoked.enabled = false; cancelLogin(owner, revoked.id); persist(owner);
|
|
133
178
|
disconnect(owner, revoked.id); changed(owner);
|
|
134
179
|
} catch (error) { return Promise.reject(error); }
|
|
135
180
|
}
|
|
136
181
|
return serial(owner, async function () {
|
|
137
182
|
var row;
|
|
138
|
-
if (msg.action === '
|
|
183
|
+
if (msg.action === 'import') {
|
|
184
|
+
row = commitImport(owner, function () { return ctx.selectImport(owner, ws, msg); }, function () { if (!ctx.canAccess(ws, owner)) throw new Error('MCP account is unavailable.'); });
|
|
185
|
+
} else if (msg.action === 'add') {
|
|
139
186
|
var url = network.remoteUrl(msg.url).href;
|
|
140
|
-
if (records(owner).filter(function (item) { return item.source
|
|
187
|
+
if (records(owner).filter(function (item) { return item.source !== 'computer'; }).length >= 30) throw new Error('You can add up to 30 remote connections per project.');
|
|
141
188
|
if (records(owner).some(function (item) { return item.url === url; })) throw new Error('This server is already connected. Open it from your connections.');
|
|
142
189
|
row = { id: 'remote-' + crypto.randomBytes(8).toString('hex'), source: 'url', url: url, label: new URL(url).hostname, enabled: false };
|
|
143
190
|
records(owner).push(row); persist(owner);
|
|
144
191
|
await connect(owner, row);
|
|
145
192
|
} else {
|
|
146
193
|
row = find(owner, msg.id);
|
|
147
|
-
if (row.source
|
|
148
|
-
if (msg.action === 'enable') { row.enabled = msg.enabled === true; persist(owner); }
|
|
194
|
+
if (row.source === 'computer') throw new Error('Not a remote connection.');
|
|
195
|
+
if (msg.action === 'enable') { row.enabled = msg.enabled === true; persist(owner); if (row.enabled && row.provenance) { try { await connect(owner, row); } catch (error) { row.enabled = false; persist(owner); throw error; } } }
|
|
149
196
|
else if (msg.action === 'rename') {
|
|
150
197
|
if (typeof msg.label !== 'string' || !msg.label.trim() || msg.label.length > 100) throw new Error('Use a name between 1 and 100 characters.');
|
|
151
198
|
row.label = msg.label.trim(); persist(owner);
|
|
152
199
|
} else if (msg.action === 'remove') {
|
|
153
200
|
cancelLogin(owner, row.id); await disconnect(owner, row.id);
|
|
154
|
-
|
|
201
|
+
var account = accounts.get(owner);
|
|
202
|
+
accounts.set(owner, { records: records(owner).filter(function (item) { return item !== row; }), revision: account && account.revision }); persist(owner);
|
|
155
203
|
} else if (msg.action === 'test') { cancelLogin(owner, row.id); await connect(owner, row); }
|
|
156
|
-
else if (msg.action === '
|
|
204
|
+
else if (msg.action === 'credentials') {
|
|
205
|
+
if (!msg.values || typeof msg.values !== 'object' || Array.isArray(msg.values)) throw new Error('Enter required credential values.');
|
|
206
|
+
var next = require('./mcp-import-credentials').applyCredentials(row, msg.values);
|
|
207
|
+
cancelLogin(owner, row.id); Object.assign(row, next); persist(owner); await disconnect(owner, row.id);
|
|
208
|
+
} else if (msg.action === 'token') {
|
|
157
209
|
if (typeof msg.token !== 'string' || !msg.token.trim() || msg.token.length > 8192 || /[\r\n]/.test(msg.token)) throw new Error('Enter a valid access token.');
|
|
158
210
|
cancelLogin(owner, row.id); row.token = msg.token.trim(); row.authMode = 'token'; delete row.auth; persist(owner); await connect(owner, row);
|
|
159
|
-
} else if (msg.action === 'signin') await signIn(owner, row, ws);
|
|
211
|
+
} else if (msg.action === 'signin') { if (row.source === 'local') throw new Error('This server uses process environment credentials.'); await signIn(owner, row, ws); }
|
|
160
212
|
else throw new Error('Unsupported connection action.');
|
|
161
213
|
}
|
|
162
214
|
changed(owner);
|
|
@@ -174,6 +226,7 @@ function createRemoteConnections(ctx) {
|
|
|
174
226
|
return serial(owner, async function () {
|
|
175
227
|
authorize(); var row = find(owner, id);
|
|
176
228
|
if (!row.enabled) throw new Error('Connection is disabled.');
|
|
229
|
+
if (!require('./mcp-tool-policy').permits(row, name)) throw new Error('Tool is excluded by the imported vendor policy.');
|
|
177
230
|
var entry = live.get(key(owner, id));
|
|
178
231
|
if (!entry || entry.status !== 'ready') entry = await connect(owner, row);
|
|
179
232
|
authorize(); check(owner, row);
|
|
@@ -183,6 +236,7 @@ function createRemoteConnections(ctx) {
|
|
|
183
236
|
var result;
|
|
184
237
|
try { result = await entry.client.callTool({ name: name, arguments: args || {} }, undefined, { timeout: 60000 }); }
|
|
185
238
|
catch (error) {
|
|
239
|
+
authorize(); check(owner, row);
|
|
186
240
|
if (live.get(key(owner, id)) === entry) {
|
|
187
241
|
entry.status = error.code === 401 || error.code === 403 || error.name === 'UnauthorizedError' ? 'auth_required' : 'unavailable';
|
|
188
242
|
entry.error = entry.status === 'auth_required' ? 'Sign in again to reconnect.' : 'The tool call could not complete. Check the service before retrying.';
|
|
@@ -209,7 +263,7 @@ function createRemoteConnections(ctx) {
|
|
|
209
263
|
closed = true; live.forEach(function (entry) { entry.client.close().catch(function () {}); }); live.clear();
|
|
210
264
|
remoteFetch.close();
|
|
211
265
|
}
|
|
212
|
-
return { view: view, command: command, call: call, handleBrowser: handleBrowser, destroy: destroy,
|
|
266
|
+
return { view: view, command: command, importConnection: importConnection, call: call, handleBrowser: handleBrowser, destroy: destroy,
|
|
213
267
|
computerEnabled: computerEnabled, toggleComputer: toggleComputer };
|
|
214
268
|
}
|
|
215
269
|
module.exports = { createRemoteConnections: createRemoteConnections };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./yoke/mcp-source-adapters");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./yoke/mcp-source-context");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./yoke/mcp-source-discovery");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./yoke/mcp-source-plugins");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./yoke/mcp-source-restrictions");
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
var normalize = require("./yoke/mcp-tool-policy-normalize").normalize;
|
|
2
|
+
function matches(pattern, name) {
|
|
3
|
+
return new RegExp('^' + pattern.split('').map(function (letter) { return letter === '*' ? '.*' : letter === '?' ? '.' : letter.replace(/[\\^$+.[\]{}()|]/g, '\\$&'); }).join('') + '$').test(name);
|
|
4
|
+
}
|
|
5
|
+
function permits(row, name) {
|
|
6
|
+
if ((row.disabledTools || []).indexOf(name) >= 0 || row.enabledTools && row.enabledTools.indexOf(name) < 0) return false;
|
|
7
|
+
return !(row.toolPatterns || []).some(function (pattern) { return matches(pattern, row.toolPrefix ? row.toolPrefix + name : name); });
|
|
8
|
+
}
|
|
9
|
+
module.exports = { normalize: normalize, permits: permits, matches: matches };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Bounded source identities shared by checklist validation and reconciliation.
|
|
2
|
+
function items(text) {
|
|
3
|
+
var lines = (text || '').split('\n').slice(1);
|
|
4
|
+
var occurrences = Object.create(null);
|
|
5
|
+
var out = [];
|
|
6
|
+
var fence = null;
|
|
7
|
+
for (var i = 0; i < lines.length; i++) {
|
|
8
|
+
var line = lines[i];
|
|
9
|
+
var match = line.match(/^\s*(\x60{3,}|~{3,})/);
|
|
10
|
+
if (match) { fence = fence === match[1].charAt(0) ? null : (fence || match[1].charAt(0)); continue; }
|
|
11
|
+
if (fence || !line.trim() || /^\s*#{1,6}\s/.test(line)) continue;
|
|
12
|
+
var occurrence = occurrences[line] || 0;
|
|
13
|
+
occurrences[line] = occurrence + 1;
|
|
14
|
+
var key = line + '\u0000' + occurrence;
|
|
15
|
+
if (i <= 1000 && key.length <= 2000 && encodeURIComponent(key).length <= 2000) out.push({ index: i, key: key });
|
|
16
|
+
}
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function validState(value) {
|
|
21
|
+
if (!Array.isArray(value) && (!value || typeof value !== 'object')) return false;
|
|
22
|
+
var keys = Object.keys(value);
|
|
23
|
+
if (keys.length > 1000) return false;
|
|
24
|
+
for (var i = 0; i < keys.length; i++) {
|
|
25
|
+
if (keys[i].length > 2000 || typeof value[keys[i]] !== 'boolean') return false;
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function normalizeState(value, text) {
|
|
31
|
+
var state = {};
|
|
32
|
+
items(text).forEach(function (item) {
|
|
33
|
+
var checked = value && value[Array.isArray(value) ? item.index : item.key];
|
|
34
|
+
if (typeof checked === 'boolean' && Object.keys(state).length < 1000) state[item.key] = checked;
|
|
35
|
+
});
|
|
36
|
+
return state;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function validateChange(note, changes) {
|
|
40
|
+
if (changes.checklistIndex === undefined) return null;
|
|
41
|
+
if (!Number.isInteger(changes.checklistIndex) || changes.checklistIndex < 0 || changes.checklistIndex > 1000) return null;
|
|
42
|
+
if (typeof changes.checklistChecked !== 'boolean' || typeof changes.checklistSource !== 'string' || typeof changes.checklistKey !== 'string') return null;
|
|
43
|
+
if (changes.checklistSource !== note.text || changes.checklistKey.length > 2000 || (changes.text !== undefined && changes.text !== note.text)) return null;
|
|
44
|
+
var item = items(note.text).find(function (item) { return item.index === changes.checklistIndex; });
|
|
45
|
+
var state = normalizeState(note.checklistState, note.text);
|
|
46
|
+
if (item && state[item.key] === undefined && Object.keys(state).length >= 1000) return null;
|
|
47
|
+
try { return item && item.key === decodeURIComponent(changes.checklistKey) ? item.key : null; } catch (error) { return null; }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Saved booleans win over Markdown markers, matching the native task controls.
|
|
51
|
+
var MARKER = /^\s*(?:[-*+]\s+)?\[([ xX])\]\s*(.*)$/;
|
|
52
|
+
|
|
53
|
+
function describe(note) {
|
|
54
|
+
var text = note && typeof note.text === 'string' ? note.text : '';
|
|
55
|
+
var state = normalizeState(note && note.checklistState, text);
|
|
56
|
+
var lines = text.split('\n');
|
|
57
|
+
return items(text).map(function (item) {
|
|
58
|
+
var line = lines[item.index + 1];
|
|
59
|
+
var marker = line.match(MARKER);
|
|
60
|
+
var saved = typeof state[item.key] === 'boolean' ? state[item.key] : null;
|
|
61
|
+
return {
|
|
62
|
+
item: encodeURIComponent(item.key),
|
|
63
|
+
index: item.index,
|
|
64
|
+
text: marker ? marker[2] : line.trim(),
|
|
65
|
+
checked: saved !== null ? saved : !!(marker && marker[1].toLowerCase() === 'x'),
|
|
66
|
+
saved: saved,
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Prompt/knowledge projection of a checklist note with its effective checks.
|
|
72
|
+
function effectiveText(note) {
|
|
73
|
+
var text = note && typeof note.text === 'string' ? note.text : '';
|
|
74
|
+
if (!note || note.checklistMode !== true) return text;
|
|
75
|
+
var lines = text.split('\n');
|
|
76
|
+
describe(note).forEach(function (entry) {
|
|
77
|
+
lines[entry.index + 1] = '- [' + (entry.checked ? 'x' : ' ') + '] ' + entry.text;
|
|
78
|
+
});
|
|
79
|
+
return lines.join('\n');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function findItem(note, encodedKey) {
|
|
83
|
+
if (typeof encodedKey !== 'string') return null;
|
|
84
|
+
var key;
|
|
85
|
+
try { key = decodeURIComponent(encodedKey); } catch (error) { return null; }
|
|
86
|
+
return items(note && note.text).find(function (item) { return item.key === key; }) || null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
validState: validState, normalizeState: normalizeState, validateChange: validateChange,
|
|
91
|
+
describe: describe, effectiveText: effectiveText, findItem: findItem,
|
|
92
|
+
};
|
package/lib/notes.js
CHANGED
|
@@ -4,6 +4,7 @@ var crypto = require("crypto");
|
|
|
4
4
|
var config = require("./config");
|
|
5
5
|
var utils = require("./utils");
|
|
6
6
|
var lifecycle = require("./notes-lifecycle");
|
|
7
|
+
var checklist = require("./notes-checklist");
|
|
7
8
|
|
|
8
9
|
function createNotesManager(opts) {
|
|
9
10
|
var cwd = opts.cwd;
|
|
@@ -61,6 +62,8 @@ function createNotesManager(opts) {
|
|
|
61
62
|
h: typeof data.h === "number" ? data.h : 180,
|
|
62
63
|
color: data.color || "purple",
|
|
63
64
|
opacity: typeof data.opacity === "number" ? data.opacity : 0.64,
|
|
65
|
+
checklistMode: data.checklistMode === true,
|
|
66
|
+
checklistState: checklist.validState(data.checklistState) ? checklist.normalizeState(data.checklistState, data.text || "") : [],
|
|
64
67
|
minimized: false,
|
|
65
68
|
// A new note is always an open attention item.
|
|
66
69
|
state: lifecycle.STATE_OPEN,
|
|
@@ -84,13 +87,33 @@ function createNotesManager(opts) {
|
|
|
84
87
|
function update(id, changes) {
|
|
85
88
|
for (var i = 0; i < notes.length; i++) {
|
|
86
89
|
if (notes[i].id === id) {
|
|
87
|
-
|
|
90
|
+
if (changes.checklistConvert === true) {
|
|
91
|
+
if (changes.checklistSource !== notes[i].text || changes.checklistVersion !== notes[i].updatedAt || notes[i].checklistMode === true) return null;
|
|
92
|
+
changes = Object.assign({}, changes, { text: "", checklistState: {}, checklistMode: true });
|
|
93
|
+
}
|
|
94
|
+
if (changes.checklistEdit === true && (notes[i].checklistMode !== true || changes.checklistSource !== notes[i].text || changes.checklistVersion !== notes[i].updatedAt || typeof changes.text !== "string")) return null;
|
|
95
|
+
if (changes.checklistMode !== undefined && typeof changes.checklistMode !== "boolean") return null;
|
|
96
|
+
if (changes.checklistState !== undefined && !checklist.validState(changes.checklistState)) return null;
|
|
97
|
+
var checklistKey = checklist.validateChange(notes[i], changes);
|
|
98
|
+
if (changes.checklistIndex !== undefined && !checklistKey) return null;
|
|
99
|
+
var previous = {};
|
|
100
|
+
var snapshotKeys = ["text", "x", "y", "w", "h", "color", "minimized", "zIndex", "opacity", "checklistMode", "checklistState", "hidden", "state", "closedAt", "closedBy", "updatedAt"];
|
|
101
|
+
for (var s = 0; s < snapshotKeys.length; s++) previous[snapshotKeys[s]] = notes[i][snapshotKeys[s]];
|
|
102
|
+
var allowed = ["text", "x", "y", "w", "h", "color", "minimized", "zIndex", "opacity", "checklistMode", "checklistState"];
|
|
88
103
|
for (var j = 0; j < allowed.length; j++) {
|
|
89
104
|
var key = allowed[j];
|
|
90
105
|
if (changes[key] !== undefined) {
|
|
91
106
|
notes[i][key] = changes[key];
|
|
92
107
|
}
|
|
93
108
|
}
|
|
109
|
+
if (checklistKey) {
|
|
110
|
+
var state = checklist.normalizeState(notes[i].checklistState, notes[i].text);
|
|
111
|
+
state[checklistKey] = changes.checklistChecked === true;
|
|
112
|
+
notes[i].checklistState = state;
|
|
113
|
+
}
|
|
114
|
+
if (changes.text !== undefined || changes.checklistState !== undefined || checklistKey) {
|
|
115
|
+
notes[i].checklistState = checklist.normalizeState(notes[i].checklistState, notes[i].text);
|
|
116
|
+
}
|
|
94
117
|
// `hidden` is the legacy spelling of the lifecycle. Route it through the
|
|
95
118
|
// transitions so state, hidden, and the close provenance can never
|
|
96
119
|
// disagree, and so an old client cannot half-apply a close.
|
|
@@ -98,8 +121,11 @@ function createNotesManager(opts) {
|
|
|
98
121
|
if (changes.hidden === true) lifecycle.applyClose(notes[i], changes.actor || null, Date.now());
|
|
99
122
|
else lifecycle.applyReopen(notes[i]);
|
|
100
123
|
}
|
|
101
|
-
notes[i].updatedAt = Date.now();
|
|
102
|
-
saveToDisk()
|
|
124
|
+
notes[i].updatedAt = Math.max(Date.now(), (previous.updatedAt || 0) + 1);
|
|
125
|
+
if (!saveToDisk()) {
|
|
126
|
+
for (var p = 0; p < snapshotKeys.length; p++) notes[i][snapshotKeys[p]] = previous[snapshotKeys[p]];
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
103
129
|
return notes[i];
|
|
104
130
|
}
|
|
105
131
|
}
|
|
@@ -120,6 +146,25 @@ function createNotesManager(opts) {
|
|
|
120
146
|
return null;
|
|
121
147
|
}
|
|
122
148
|
|
|
149
|
+
// Human close includes the visible draft and an exact canonical snapshot.
|
|
150
|
+
// Recheck it here, then persist draft + lifecycle/removal in one transaction.
|
|
151
|
+
function closeHuman(id, changes, actor) {
|
|
152
|
+
for (var i = 0; i < notes.length; i++) {
|
|
153
|
+
var note = notes[i];
|
|
154
|
+
if (note.id !== id) continue;
|
|
155
|
+
if (note.text !== changes.expectedText || note.updatedAt !== changes.expectedVersion || typeof changes.draftText !== "string") return null;
|
|
156
|
+
if (!changes.draftText.trim()) {
|
|
157
|
+
notes.splice(i, 1);
|
|
158
|
+
if (saveToDisk()) return { removed: note };
|
|
159
|
+
notes.splice(i, 0, note);
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
var updated = update(id, { text: changes.draftText, hidden: true, actor: actor });
|
|
163
|
+
return updated ? { note: updated } : null;
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
123
168
|
// Reopen a closed note. Idempotent.
|
|
124
169
|
function reopen(id) {
|
|
125
170
|
for (var i = 0; i < notes.length; i++) {
|
|
@@ -199,7 +244,8 @@ function createNotesManager(opts) {
|
|
|
199
244
|
for (var j = 0; j < active.length; j++) {
|
|
200
245
|
var n = active[j];
|
|
201
246
|
var label = n.color ? "[" + n.color + "]" : "";
|
|
202
|
-
|
|
247
|
+
// Checklist notes project their saved completion, not stale Markdown marks.
|
|
248
|
+
lines.push("- " + label + " " + checklist.effectiveText(n).trim());
|
|
203
249
|
}
|
|
204
250
|
return lines.join("\n");
|
|
205
251
|
}
|
|
@@ -211,6 +257,7 @@ function createNotesManager(opts) {
|
|
|
211
257
|
create: create,
|
|
212
258
|
update: update,
|
|
213
259
|
close: close,
|
|
260
|
+
closeHuman: closeHuman,
|
|
214
261
|
reopen: reopen,
|
|
215
262
|
remove: remove,
|
|
216
263
|
removeClosed: removeClosed,
|
|
@@ -17,12 +17,10 @@ function commandAvailable(command, execFile) {
|
|
|
17
17
|
|
|
18
18
|
function credentialPaths(home) {
|
|
19
19
|
if (!home) return [];
|
|
20
|
-
return [
|
|
21
|
-
home + "/.claude",
|
|
22
|
-
home + "/.codex",
|
|
20
|
+
return require("./yoke/maintenance").credentialPaths(home).concat([
|
|
23
21
|
home + "/.config/gh",
|
|
24
22
|
home + "/.config/gcloud",
|
|
25
|
-
];
|
|
23
|
+
]);
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
function accessStatus(checks) {
|
package/lib/os-users.js
CHANGED
|
@@ -153,6 +153,19 @@ function fsAsUser(op, args, osUserInfo) {
|
|
|
153
153
|
});
|
|
154
154
|
var binOutput = execFileSync(binSpawn.command, binSpawn.args, binSpawn.options);
|
|
155
155
|
return { buffer: Buffer.from(binOutput.trim(), "base64") };
|
|
156
|
+
} else if (op === 'write_exact') {
|
|
157
|
+
script = [
|
|
158
|
+
"var fs = require('fs'), crypto = require('crypto'), path = require('path');",
|
|
159
|
+
"var f = " + JSON.stringify(args.file) + "; var expected = " + JSON.stringify(args.expected) + ";",
|
|
160
|
+
"var root = " + JSON.stringify(args.root) + "; var relative = path.relative(root, f);",
|
|
161
|
+
"function checkPath() { if (fs.realpathSync(root) !== root || path.isAbsolute(relative) || relative.split(path.sep).indexOf('..') >= 0) throw new Error('The canonical file boundary changed.'); var at = root; relative.split(path.sep).forEach(function (part) { at = path.join(at, part); if (fs.lstatSync(at).isSymbolicLink()) throw new Error('File parent symlinks are unavailable.'); }); }",
|
|
162
|
+
"checkPath();",
|
|
163
|
+
"var fd = fs.openSync(f, fs.constants.O_RDWR | fs.constants.O_NOFOLLOW);",
|
|
164
|
+
"try { var s = fs.fstatSync(fd);",
|
|
165
|
+
"if (!s.isFile() || s.nlink !== 1 || s.dev !== expected.dev || s.ino !== expected.ino || s.mode !== expected.mode || s.uid !== expected.uid || s.gid !== expected.gid || s.size !== expected.size || s.mtimeMs !== expected.mtime || crypto.createHash('sha256').update(fs.readFileSync(fd, 'utf8')).digest('hex') !== expected.hash) throw new Error('The exact file revision changed.');",
|
|
166
|
+
"checkPath(); fs.ftruncateSync(fd, 0); var bytes = Buffer.from(" + JSON.stringify(args.content) + ", 'utf8'), offset = 0; while (offset < bytes.length) { var written = fs.writeSync(fd, bytes, offset, bytes.length - offset, offset); if (!written) throw new Error('File write made no progress.'); offset += written; } fs.fsyncSync(fd); } finally { fs.closeSync(fd); }",
|
|
167
|
+
"process.stdout.write(JSON.stringify({ ok: true }));",
|
|
168
|
+
].join(' ');
|
|
156
169
|
} else if (op === "write") {
|
|
157
170
|
script = [
|
|
158
171
|
"var fs = require('fs');",
|
|
@@ -267,18 +280,18 @@ function isHomeDirectory(dirPath) {
|
|
|
267
280
|
* Uses setfacl to add recursive + default ACL entries.
|
|
268
281
|
* Skips home directories to avoid slow recursive ACL on large trees.
|
|
269
282
|
*/
|
|
270
|
-
function grantProjectAccess(projectPath, linuxUser) {
|
|
283
|
+
function grantProjectAccess(projectPath, linuxUser, options) {
|
|
271
284
|
if (isHomeDirectory(projectPath)) {
|
|
272
285
|
console.log("[os-users] Skipping ACL for home directory: " + projectPath);
|
|
273
|
-
return;
|
|
286
|
+
return true;
|
|
274
287
|
}
|
|
275
288
|
if (!isSafeLinuxUsername(linuxUser)) {
|
|
276
289
|
console.error("[os-users] Invalid Linux username for ACL grant: " + linuxUser);
|
|
277
|
-
return;
|
|
290
|
+
return false;
|
|
278
291
|
}
|
|
279
292
|
var cacheKey = aclCacheKey(projectPath, linuxUser);
|
|
280
|
-
if (_aclGrantCache[cacheKey]) {
|
|
281
|
-
return;
|
|
293
|
+
if (_aclGrantCache[cacheKey] && !(options && options.force)) {
|
|
294
|
+
return true;
|
|
282
295
|
}
|
|
283
296
|
try {
|
|
284
297
|
// Recursive ACL for existing files
|
|
@@ -295,6 +308,7 @@ function grantProjectAccess(projectPath, linuxUser) {
|
|
|
295
308
|
});
|
|
296
309
|
_aclGrantCache[cacheKey] = true;
|
|
297
310
|
console.log("[os-users] Granted ACL access for " + linuxUser + " on " + projectPath);
|
|
311
|
+
return true;
|
|
298
312
|
} catch (e) {
|
|
299
313
|
delete _aclGrantCache[cacheKey];
|
|
300
314
|
var errMsg = (e.stderr || e.message || "").toString();
|
|
@@ -305,6 +319,7 @@ function grantProjectAccess(projectPath, linuxUser) {
|
|
|
305
319
|
} else {
|
|
306
320
|
console.error("[os-users] Failed to grant ACL access for " + linuxUser + " on " + projectPath + ": " + errMsg);
|
|
307
321
|
}
|
|
322
|
+
return false;
|
|
308
323
|
}
|
|
309
324
|
}
|
|
310
325
|
|
|
@@ -460,72 +475,11 @@ function getLinuxUserUid(username) {
|
|
|
460
475
|
* hardcoded ~/.local/bin/claude path.
|
|
461
476
|
* Returns true if claude resolves, false otherwise.
|
|
462
477
|
*/
|
|
463
|
-
function
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
var out = execFileSync("su", ["-", linuxName, "-c", "command -v claude"], {
|
|
467
|
-
encoding: "utf8",
|
|
468
|
-
timeout: 10000,
|
|
469
|
-
stdio: "pipe",
|
|
470
|
-
}).trim();
|
|
471
|
-
return out.length > 0;
|
|
472
|
-
} catch (e) {
|
|
473
|
-
return false;
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
/**
|
|
478
|
-
* Install Claude CLI for a Linux user account.
|
|
479
|
-
* Downloads and runs the install script, then ensures PATH is configured.
|
|
480
|
-
* Non-fatal: logs errors but does not throw.
|
|
481
|
-
* Skips entirely when claude is already resolvable for the user, or when
|
|
482
|
-
* CLAY_SKIP_CLAUDE_INSTALL is set (bring-your-own-claude).
|
|
483
|
-
*/
|
|
484
|
-
function installClaudeCli(linuxName) {
|
|
485
|
-
if (process.env.CLAY_SKIP_CLAUDE_INSTALL) {
|
|
486
|
-
console.log("[os-users] CLAY_SKIP_CLAUDE_INSTALL set, skipping Claude CLI install for " + linuxName);
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
if (claudeAvailableForUser(linuxName)) {
|
|
490
|
-
console.log("[os-users] Claude CLI already available for " + linuxName + ", skipping install");
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
try {
|
|
494
|
-
if (!isSafeLinuxUsername(linuxName)) throw new Error("Invalid Linux username");
|
|
495
|
-
// Download and run the Claude CLI install script as the target user
|
|
496
|
-
execFileSync("su", ["-", linuxName, "-c", "curl -fsSL https://claude.ai/install.sh | bash"], {
|
|
497
|
-
encoding: "utf8",
|
|
498
|
-
timeout: 60000,
|
|
499
|
-
stdio: "pipe",
|
|
500
|
-
});
|
|
501
|
-
console.log("[os-users] Claude CLI installed for " + linuxName);
|
|
502
|
-
} catch (e) {
|
|
503
|
-
var msg = (e.stderr || e.message || "").trim();
|
|
504
|
-
console.error("[os-users] Failed to install Claude CLI for " + linuxName + ": " + msg);
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// Append PATH export to the user's shell config if not already present
|
|
509
|
-
try {
|
|
510
|
-
var userInfo = resolveOsUserInfo(linuxName);
|
|
511
|
-
var home = userInfo.home || ("/home/" + linuxName);
|
|
512
|
-
var rcPath = fs.existsSync(path.join(home, ".zshrc")) ? path.join(home, ".zshrc") : path.join(home, ".bashrc");
|
|
513
|
-
var exportLine = 'export PATH="$HOME/.local/bin:$PATH"';
|
|
514
|
-
var existing = "";
|
|
515
|
-
try { existing = fs.readFileSync(rcPath, "utf8"); } catch (e2) {}
|
|
516
|
-
if (existing.indexOf(exportLine) === -1) {
|
|
517
|
-
var prefix = existing && !/\n$/.test(existing) ? "\n" : "";
|
|
518
|
-
fs.appendFileSync(rcPath, prefix + exportLine + "\n", "utf8");
|
|
519
|
-
try { fs.chownSync(rcPath, userInfo.uid, userInfo.gid); } catch (e3) {}
|
|
520
|
-
console.log("[os-users] PATH export appended to " + rcPath + " for " + linuxName);
|
|
521
|
-
} else {
|
|
522
|
-
console.log("[os-users] PATH already configured in " + rcPath + " for " + linuxName);
|
|
523
|
-
}
|
|
524
|
-
} catch (e) {
|
|
525
|
-
var rcMsg = (e.stderr || e.message || "").trim();
|
|
526
|
-
console.error("[os-users] Failed to configure PATH for " + linuxName + ": " + rcMsg);
|
|
527
|
-
}
|
|
478
|
+
function defaultRuntimeProvisioning() {
|
|
479
|
+
return require("./yoke/provisioning").forProvider("claude", { isSafeLinuxUsername: isSafeLinuxUsername, resolveOsUserInfo: resolveOsUserInfo });
|
|
528
480
|
}
|
|
481
|
+
function claudeAvailableForUser(user) { return defaultRuntimeProvisioning().available(user); }
|
|
482
|
+
function installClaudeCli(user) { return defaultRuntimeProvisioning().install(user); }
|
|
529
483
|
|
|
530
484
|
/**
|
|
531
485
|
* Provision a Linux user account for a Clay user.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Pending requests can precede the initial history window. Restate their exact
|
|
2
|
+
// display payloads before snapshot completion, without resolving or replaying
|
|
3
|
+
// any human decision. Client renderers deduplicate by their original IDs.
|
|
4
|
+
function send(session, emit) {
|
|
5
|
+
Object.keys(session.pendingAskUser || {}).forEach(function (id) {
|
|
6
|
+
var pending = session.pendingAskUser[id];
|
|
7
|
+
var input = pending.input || { questions: pending.request && pending.request.questions || [] };
|
|
8
|
+
emit({ type: 'ask_user_pending', toolId: id, input: input });
|
|
9
|
+
});
|
|
10
|
+
Object.keys(session.pendingElicitations || {}).forEach(function (id) {
|
|
11
|
+
var request = session.pendingElicitations[id].request || {};
|
|
12
|
+
emit({ type: 'elicitation_request', requestId: id, serverName: request.serverName, message: request.message,
|
|
13
|
+
mode: request.mode || 'form', url: request.url || null, elicitationId: request.elicitationId || null, requestedSchema: request.requestedSchema || null });
|
|
14
|
+
});
|
|
15
|
+
Object.keys(session.pendingUserDialogs || {}).forEach(function (id) {
|
|
16
|
+
var request = session.pendingUserDialogs[id].request || {};
|
|
17
|
+
emit({ type: 'user_dialog_request', requestId: id, dialogKind: request.dialogKind, payload: request.payload || {}, toolUseId: request.toolUseID || null });
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
module.exports = { send: send };
|